All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrains.exodus.entitystore.tables.TwoColumnTable Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2010 - 2018 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.exodus.entitystore.tables;

import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.entitystore.PersistentEntityStoreImpl;
import jetbrains.exodus.entitystore.PersistentStoreTransaction;
import jetbrains.exodus.env.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@SuppressWarnings({"HardCodedStringLiteral"})
public final class TwoColumnTable extends Table {

    private final Store first;  // 1st column -> 2nd column
    private final Store second; // 2nd column -> 1st column

    public TwoColumnTable(@NotNull final PersistentStoreTransaction txn,
                          @NotNull final String name,
                          @NotNull final StoreConfig config) {
        final PersistentEntityStoreImpl store = txn.getStore();
        final Transaction envTxn = txn.getEnvironmentTransaction();
        final Environment env = store.getEnvironment();
        first = env.openStore(name, config, envTxn);
        second = env.openStore(secondColumnDatabaseName(name), config, envTxn);
        store.trackTableCreation(first, txn);
        store.trackTableCreation(second, txn);
    }

    public static String secondColumnDatabaseName(@NotNull final String name) {
        return name + "#reverse";
    }

    /**
     * Search for the first entry in the first database. Use this method for databases configured with no duplicates.
     *
     * @param txn   enclosing transaction
     * @param first first key.
     * @return null if no entry found, otherwise the value.
     */
    @Nullable
    public ByteIterable get(@NotNull final Transaction txn, @NotNull final ByteIterable first) {
        return this.first.get(txn, first);
    }

    /**
     * Search for the second entry in the second database. Use this method for databases configured with no duplicates.
     *
     * @param second second key (value for first).
     * @return null if no entry found, otherwise the value.
     */
    @Nullable
    public ByteIterable get2(@NotNull final Transaction txn, @NotNull final ByteIterable second) {
        return this.second.get(txn, second);
    }

    public boolean contains(@NotNull final Transaction txn,
                            @NotNull final ByteIterable first,
                            @NotNull final ByteIterable second) {
        try (Cursor cursor = getFirstIndexCursor(txn)) {
            return cursor.getSearchBoth(first, second);
        }
    }

    public boolean contains2(@NotNull final Transaction txn,
                             @NotNull final ByteIterable first,
                             @NotNull final ByteIterable second) {
        try (Cursor cursor = getSecondIndexCursor(txn)) {
            return cursor.getSearchBoth(second, first);
        }
    }

    public boolean put(@NotNull final Transaction txn,
                       @NotNull final ByteIterable first,
                       @NotNull final ByteIterable second) {
        final boolean result = this.first.put(txn, first, second);
        this.second.put(txn, second, first);
        return result;
    }

    public boolean delete(@NotNull final Transaction txn,
                          @NotNull final ByteIterable first,
                          @NotNull final ByteIterable second) {
        boolean success;
        try (Cursor cursor = getFirstIndexCursor(txn)) {
            success = cursor.getSearchBoth(first, second);
            if (!success) {
                return false;
            }
            success = cursor.deleteCurrent();
            checkStatus(success, "Failed to delete");
        }
        try (Cursor cursor = getSecondIndexCursor(txn)) {
            success = cursor.getSearchBoth(second, first);
            checkStatus(success, "Failed to delete: data mismatch in TwoColumnTable's stores");
            success = cursor.deleteCurrent();
            checkStatus(success, "Failed to delete");
        }
        return true;
    }

    @NotNull
    public Cursor getFirstIndexCursor(@NotNull final Transaction txn) {
        return first.openCursor(txn);
    }

    @NotNull
    public Cursor getSecondIndexCursor(@NotNull final Transaction txn) {
        return second.openCursor(txn);
    }

    public void truncateFirst(@NotNull final Transaction txn) {
        txn.getEnvironment().truncateStore(first.getName(), txn);
    }

    public long getPrimaryCount(@NotNull final Transaction txn) {
        return first.count(txn);
    }

    public long getSecondaryCount(@NotNull final Transaction txn) {
        return second.count(txn);
    }

    @Override
    public boolean canBeCached() {
        return !first.getConfig().temporaryEmpty && !second.getConfig().temporaryEmpty;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy