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);
}
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;
}
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 + ']');
}
}
}
});
}
}
});
}
Aggregations