Search in sources :

Example 6 with Pair

use of jetbrains.exodus.core.dataStructures.Pair in project xodus by JetBrains.

the class MetaTree method create.

static Pair<MetaTree, Integer> create(@NotNull final EnvironmentImpl env) {
    final Log log = env.getLog();
    LogTip logTip = log.getTip();
    if (logTip.highAddress > EMPTY_LOG_BOUND) {
        Loggable rootLoggable = log.getLastLoggableOfType(DatabaseRoot.DATABASE_ROOT_TYPE);
        while (rootLoggable != null) {
            final DatabaseRoot dbRoot = new DatabaseRoot(rootLoggable);
            final long root = dbRoot.getAddress();
            if (dbRoot.isValid()) {
                try {
                    final LogTip updatedTip = log.setHighAddress(logTip, root + dbRoot.length());
                    final BTree metaTree = env.loadMetaTree(dbRoot.getRootAddress(), updatedTip);
                    if (metaTree != null) {
                        // try to traverse meta tree
                        cloneTree(metaTree);
                        return new Pair<>(new MetaTree(metaTree, root, updatedTip), dbRoot.getLastStructureId());
                    }
                    logTip = updatedTip;
                } catch (ExodusException e) {
                    logTip = log.getTip();
                    EnvironmentImpl.loggerError("Failed to recover to valid root" + LogUtil.getWrongAddressErrorMessage(dbRoot.getAddress(), env.getEnvironmentConfig().getLogFileSize()), e);
                // XD-449: try next database root if we failed to traverse whole MetaTree
                // TODO: this check should become obsolete after XD-334 is implemented
                }
            }
            // continue recovery
            rootLoggable = log.getLastLoggableOfTypeBefore(DatabaseRoot.DATABASE_ROOT_TYPE, root, logTip);
        }
        // "abnormal program termination", "blue screen of doom"
        // Something quite strange with the database: it is not empty, but no valid
        // root has found. We can't just reset the database and lose all the contents,
        // we should have a chance to investigate the case. So failing...
        // 
        // It's extremely likely the database was ciphered with different/unknown cipher parameters.
        log.close();
        throw new InvalidCipherParametersException();
    }
    // no roots found: the database is empty
    log.setHighAddress(logTip, 0);
    final ITree resultTree = getEmptyMetaTree(env);
    final long root;
    log.beginWrite();
    final LogTip createdTip;
    try {
        final long rootAddress = resultTree.getMutableCopy().save();
        root = log.write(DatabaseRoot.DATABASE_ROOT_TYPE, Loggable.NO_STRUCTURE_ID, DatabaseRoot.asByteIterable(rootAddress, EnvironmentImpl.META_TREE_ID));
        log.flush();
        createdTip = log.endWrite();
    } catch (Throwable t) {
        // rollback log state
        log.abortWrite();
        throw new ExodusException("Can't init meta tree in log", t);
    }
    return new Pair<>(new MetaTree(resultTree, root, createdTip), EnvironmentImpl.META_TREE_ID);
}
Also used : BTree(jetbrains.exodus.tree.btree.BTree) InvalidCipherParametersException(jetbrains.exodus.crypto.InvalidCipherParametersException) ExodusException(jetbrains.exodus.ExodusException) Pair(jetbrains.exodus.core.dataStructures.Pair)

Example 7 with Pair

use of jetbrains.exodus.core.dataStructures.Pair in project xodus by JetBrains.

the class ReadWriteTransaction method doCommit.

Iterable<ExpiredLoggableInfo>[] doCommit(@NotNull final MetaTree.Proto[] out) {
    final Set<Map.Entry<Integer, ITreeMutable>> entries = mutableTrees.entrySet();
    final Set<Map.Entry<Long, Pair<String, ITree>>> removedEntries = removedStores.entrySet();
    final int size = entries.size() + removedEntries.size();
    // noinspection unchecked
    final Iterable<ExpiredLoggableInfo>[] expiredLoggables = new Iterable[size + 1];
    int i = 0;
    final ITreeMutable metaTreeMutable = getMetaTree().tree.getMutableCopy();
    for (final Map.Entry<Long, Pair<String, ITree>> entry : removedEntries) {
        final Pair<String, ITree> value = entry.getValue();
        MetaTree.removeStore(metaTreeMutable, value.getFirst(), entry.getKey());
        expiredLoggables[i++] = TreeMetaInfo.getTreeLoggables(value.getSecond());
    }
    removedStores.clear();
    for (final Map.Entry<String, TreeMetaInfo> entry : createdStores.entrySet()) {
        MetaTree.addStore(metaTreeMutable, entry.getKey(), entry.getValue());
    }
    createdStores.clear();
    final Collection<ExpiredLoggableInfo> last;
    for (final Map.Entry<Integer, ITreeMutable> entry : entries) {
        final ITreeMutable treeMutable = entry.getValue();
        expiredLoggables[i++] = treeMutable.getExpiredLoggables();
        MetaTree.saveTree(metaTreeMutable, treeMutable);
    }
    clearImmutableTrees();
    mutableTrees.clear();
    expiredLoggables[i] = last = metaTreeMutable.getExpiredLoggables();
    out[0] = MetaTree.saveMetaTree(metaTreeMutable, getEnvironment(), last);
    return expiredLoggables;
}
Also used : TreeMetaInfo(jetbrains.exodus.tree.TreeMetaInfo) ITree(jetbrains.exodus.tree.ITree) ITreeMutable(jetbrains.exodus.tree.ITreeMutable) ExpiredLoggableInfo(jetbrains.exodus.log.ExpiredLoggableInfo) LongHashMap(jetbrains.exodus.core.dataStructures.hash.LongHashMap) Pair(jetbrains.exodus.core.dataStructures.Pair)

Example 8 with Pair

use of jetbrains.exodus.core.dataStructures.Pair in project xodus by JetBrains.

the class PersistentEntityStoreRefactorings method refactorMakePropTablesConsistent.

void refactorMakePropTablesConsistent() {
    store.executeInReadonlyTransaction(new StoreTransactionalExecutable() {

        @Override
        public void execute(@NotNull final StoreTransaction tx) {
            final PersistentStoreTransaction txn = (PersistentStoreTransaction) tx;
            for (final String entityType : store.getEntityTypes(txn)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Refactoring making props' tables consistent for [" + entityType + ']');
                }
                runReadonlyTransactionSafeForEntityType(entityType, new Runnable() {

                    @Override
                    public void run() {
                        final int entityTypeId = store.getEntityTypeId(txn, entityType, false);
                        final PropertiesTable propTable = store.getPropertiesTable(txn, entityTypeId);
                        final Transaction envTxn = txn.getEnvironmentTransaction();
                        final IntHashMap<LongHashMap<PropertyValue>> props = new IntHashMap<>();
                        final Cursor cursor = store.getPrimaryPropertyIndexCursor(txn, propTable);
                        final PropertyTypes propertyTypes = store.getPropertyTypes();
                        while (cursor.getNext()) {
                            final PropertyKey propKey = PropertyKey.entryToPropertyKey(cursor.getKey());
                            final PropertyValue propValue = propertyTypes.entryToPropertyValue(cursor.getValue());
                            final int propId = propKey.getPropertyId();
                            LongHashMap<PropertyValue> entitiesToValues = props.get(propId);
                            if (entitiesToValues == null) {
                                entitiesToValues = new LongHashMap<>();
                                props.put(propId, entitiesToValues);
                            }
                            entitiesToValues.put(propKey.getEntityLocalId(), propValue);
                        }
                        cursor.close();
                        final List<Pair<Integer, Pair<ByteIterable, ByteIterable>>> missingPairs = new ArrayList<>();
                        final IntHashMap<Set<Long>> allPropsMap = new IntHashMap<>();
                        for (final int propId : props.keySet()) {
                            final Store valueIndex = propTable.getValueIndex(txn, propId, false);
                            final Cursor valueCursor = valueIndex == null ? null : valueIndex.openCursor(envTxn);
                            final LongHashMap<PropertyValue> entitiesToValues = props.get(propId);
                            final Set<Long> localIdSet = entitiesToValues.keySet();
                            final TreeSet<Long> sortedLocalIdSet = new TreeSet<>(localIdSet);
                            allPropsMap.put(propId, sortedLocalIdSet);
                            final Long[] localIds = sortedLocalIdSet.toArray(new Long[entitiesToValues.size()]);
                            for (final long localId : localIds) {
                                final PropertyValue propValue = entitiesToValues.get(localId);
                                for (final ByteIterable secondaryKey : PropertiesTable.createSecondaryKeys(propertyTypes, PropertyTypes.propertyValueToEntry(propValue), propValue.getType())) {
                                    final ByteIterable secondaryValue = LongBinding.longToCompressedEntry(localId);
                                    if (valueCursor == null || !valueCursor.getSearchBoth(secondaryKey, secondaryValue)) {
                                        missingPairs.add(new Pair<>(propId, new Pair<>(secondaryKey, secondaryValue)));
                                    }
                                }
                            }
                            if (valueCursor != null) {
                                valueCursor.close();
                            }
                        }
                        if (!missingPairs.isEmpty()) {
                            store.executeInTransaction(new StoreTransactionalExecutable() {

                                @Override
                                public void execute(@NotNull final StoreTransaction tx) {
                                    final PersistentStoreTransaction txn = (PersistentStoreTransaction) tx;
                                    for (final Pair<Integer, Pair<ByteIterable, ByteIterable>> pair : missingPairs) {
                                        final Store valueIndex = propTable.getValueIndex(txn, pair.getFirst(), true);
                                        final Pair<ByteIterable, ByteIterable> missing = pair.getSecond();
                                        if (valueIndex == null) {
                                            throw new NullPointerException("Can't be");
                                        }
                                        valueIndex.put(txn.getEnvironmentTransaction(), missing.getFirst(), missing.getSecond());
                                    }
                                }
                            });
                            if (logger.isInfoEnabled()) {
                                logger.info(missingPairs.size() + " missing secondary keys found and fixed for [" + entityType + ']');
                            }
                        }
                        final List<Pair<Integer, Pair<ByteIterable, ByteIterable>>> phantomPairs = new ArrayList<>();
                        for (final Map.Entry<Integer, Store> entry : propTable.getValueIndices()) {
                            final int propId = entry.getKey();
                            final LongHashMap<PropertyValue> entitiesToValues = props.get(propId);
                            final Cursor c = entry.getValue().openCursor(envTxn);
                            while (c.getNext()) {
                                final ByteIterable keyEntry = c.getKey();
                                final ByteIterable valueEntry = c.getValue();
                                final PropertyValue propValue = entitiesToValues.get(LongBinding.compressedEntryToLong(valueEntry));
                                if (propValue != null) {
                                    final Comparable data = propValue.getData();
                                    final int typeId = propValue.getType().getTypeId();
                                    final Class<? extends Comparable> dataClass;
                                    final ComparableBinding objectBinding;
                                    if (typeId == ComparableValueType.COMPARABLE_SET_VALUE_TYPE) {
                                        // noinspection unchecked
                                        dataClass = ((ComparableSet) data).getItemClass();
                                        // noinspection ConstantConditions
                                        objectBinding = propertyTypes.getPropertyType(dataClass).getBinding();
                                    } else {
                                        dataClass = data.getClass();
                                        objectBinding = propValue.getBinding();
                                    }
                                    final Comparable value;
                                    try {
                                        value = objectBinding.entryToObject(keyEntry);
                                        if (dataClass.equals(value.getClass())) {
                                            if (typeId == ComparableValueType.COMPARABLE_SET_VALUE_TYPE) {
                                                // noinspection unchecked
                                                if (((ComparableSet) data).containsItem(value)) {
                                                    continue;
                                                }
                                            } else // noinspection unchecked
                                            if (PropertyTypes.toLowerCase(data).compareTo(value) == 0) {
                                                continue;
                                            }
                                        }
                                    } catch (Throwable t) {
                                        logger.error("Error reading property value index ", t);
                                        throwJVMError(t);
                                    }
                                }
                                phantomPairs.add(new Pair<>(propId, new Pair<>(keyEntry, valueEntry)));
                            }
                            c.close();
                        }
                        if (!phantomPairs.isEmpty()) {
                            store.executeInTransaction(new StoreTransactionalExecutable() {

                                @Override
                                public void execute(@NotNull final StoreTransaction tx) {
                                    final PersistentStoreTransaction txn = (PersistentStoreTransaction) tx;
                                    final Transaction envTxn = txn.getEnvironmentTransaction();
                                    for (final Pair<Integer, Pair<ByteIterable, ByteIterable>> pair : phantomPairs) {
                                        final Store valueIndex = propTable.getValueIndex(txn, pair.getFirst(), true);
                                        final Pair<ByteIterable, ByteIterable> phantom = pair.getSecond();
                                        if (valueIndex == null) {
                                            throw new NullPointerException("Can't be");
                                        }
                                        deletePair(valueIndex.openCursor(envTxn), phantom.getFirst(), phantom.getSecond());
                                    }
                                }
                            });
                            if (logger.isInfoEnabled()) {
                                logger.info(phantomPairs.size() + " phantom secondary keys found and fixed for [" + entityType + ']');
                            }
                        }
                        final List<Pair<Integer, Long>> phantomIds = new ArrayList<>();
                        final Cursor c = propTable.getAllPropsIndex().openCursor(envTxn);
                        while (c.getNext()) {
                            final int propId = IntegerBinding.compressedEntryToInt(c.getKey());
                            final long localId = LongBinding.compressedEntryToLong(c.getValue());
                            final Set<Long> localIds = allPropsMap.get(propId);
                            if (localIds == null || !localIds.remove(localId)) {
                                phantomIds.add(new Pair<>(propId, localId));
                            } else {
                                if (localIds.isEmpty()) {
                                    allPropsMap.remove(propId);
                                }
                            }
                        }
                        c.close();
                        if (!allPropsMap.isEmpty()) {
                            final int[] added = { 0 };
                            store.executeInTransaction(new StoreTransactionalExecutable() {

                                @Override
                                public void execute(@NotNull final StoreTransaction txn) {
                                    int count = 0;
                                    final Store allPropsIndex = propTable.getAllPropsIndex();
                                    final Transaction envTxn = ((PersistentStoreTransaction) txn).getEnvironmentTransaction();
                                    for (Map.Entry<Integer, Set<Long>> entry : allPropsMap.entrySet()) {
                                        final ArrayByteIterable keyEntry = IntegerBinding.intToCompressedEntry(entry.getKey());
                                        for (long localId : entry.getValue()) {
                                            allPropsIndex.put(envTxn, keyEntry, LongBinding.longToCompressedEntry(localId));
                                            ++count;
                                        }
                                    }
                                    added[0] = count;
                                }
                            });
                            if (logger.isInfoEnabled()) {
                                logger.info(added[0] + " missing id pairs found and fixed for [" + entityType + ']');
                            }
                        }
                        if (!phantomIds.isEmpty()) {
                            store.executeInTransaction(new StoreTransactionalExecutable() {

                                @Override
                                public void execute(@NotNull final StoreTransaction txn) {
                                    final Store allPropsIndex = propTable.getAllPropsIndex();
                                    final Transaction envTxn = ((PersistentStoreTransaction) txn).getEnvironmentTransaction();
                                    final Cursor c = allPropsIndex.openCursor(envTxn);
                                    for (final Pair<Integer, Long> phantom : phantomIds) {
                                        if (!c.getSearchBoth(IntegerBinding.intToCompressedEntry(phantom.getFirst()), LongBinding.longToCompressedEntry(phantom.getSecond()))) {
                                            throw new EntityStoreException("Can't be");
                                        }
                                        c.deleteCurrent();
                                    }
                                    c.close();
                                }
                            });
                            if (logger.isInfoEnabled()) {
                                logger.info(phantomIds.size() + " phantom id pairs found and fixed for [" + entityType + ']');
                            }
                        }
                    }
                });
            }
        }
    });
}
Also used : PersistentLong23TreeSet(jetbrains.exodus.core.dataStructures.persistent.PersistentLong23TreeSet) PersistentLongSet(jetbrains.exodus.core.dataStructures.persistent.PersistentLongSet) PersistentLong23TreeSet(jetbrains.exodus.core.dataStructures.persistent.PersistentLong23TreeSet) Pair(jetbrains.exodus.core.dataStructures.Pair) ArrayByteIterable(jetbrains.exodus.ArrayByteIterable) ByteIterable(jetbrains.exodus.ByteIterable) ArrayByteIterable(jetbrains.exodus.ArrayByteIterable)

Aggregations

Pair (jetbrains.exodus.core.dataStructures.Pair)8 ArrayByteIterable (jetbrains.exodus.ArrayByteIterable)2 ByteIterable (jetbrains.exodus.ByteIterable)2 LongHashMap (jetbrains.exodus.core.dataStructures.hash.LongHashMap)2 PersistentLongSet (jetbrains.exodus.core.dataStructures.persistent.PersistentLongSet)2 Nullable (org.jetbrains.annotations.Nullable)2 File (java.io.File)1 IOException (java.io.IOException)1 ExodusException (jetbrains.exodus.ExodusException)1 LongHashSet (jetbrains.exodus.core.dataStructures.hash.LongHashSet)1 PersistentLong23TreeSet (jetbrains.exodus.core.dataStructures.persistent.PersistentLong23TreeSet)1 InvalidCipherParametersException (jetbrains.exodus.crypto.InvalidCipherParametersException)1 FileDataReader (jetbrains.exodus.io.FileDataReader)1 FileDataWriter (jetbrains.exodus.io.FileDataWriter)1 CompressedUnsignedLongByteIterable (jetbrains.exodus.log.CompressedUnsignedLongByteIterable)1 ExpiredLoggableInfo (jetbrains.exodus.log.ExpiredLoggableInfo)1 ITree (jetbrains.exodus.tree.ITree)1 ITreeMutable (jetbrains.exodus.tree.ITreeMutable)1 TreeMetaInfo (jetbrains.exodus.tree.TreeMetaInfo)1 BTree (jetbrains.exodus.tree.btree.BTree)1