in core/src/main/java/com/jetbrains/youtrackdb/internal/core/storage/impl/local/AbstractStorage.java [477:681]
public final void open(final ContextConfiguration contextConfiguration) {
try {
stateLock.readLock().lock();
try {
if (status == STATUS.OPEN || isInError()) {
// ALREADY OPENED: THIS IS THE CASE WHEN A STORAGE INSTANCE IS
// REUSED
sessionCount.incrementAndGet();
return;
}
} finally {
stateLock.readLock().unlock();
}
checkPageSizeAndRelatedParametersInGlobalConfiguration(name);
try {
stateLock.writeLock().lock();
try {
if (status == STATUS.MIGRATION) {
try {
// Yes this look inverted but is correct.
stateLock.writeLock().unlock();
migration.await();
} finally {
stateLock.writeLock().lock();
}
}
if (status == STATUS.OPEN || isInError())
// ALREADY OPENED: THIS IS THE CASE WHEN A STORAGE INSTANCE IS
// REUSED
{
return;
}
if (status != STATUS.CLOSED) {
throw new StorageException(name,
"Storage " + name + " is in wrong state " + status + " and can not be opened.");
}
if (!exists()) {
throw new StorageDoesNotExistException(name,
"Cannot open the storage '" + name + "' because it does not exist in path: " + url);
}
readIv();
initWalAndDiskCache(contextConfiguration);
transaction = new ThreadLocal<>();
final var startupMetadata = checkIfStorageDirty();
final var lastTxId = startupMetadata.lastTxId;
if (lastTxId > 0) {
idGen.setStartId(lastTxId + 1);
} else {
idGen.setStartId(0);
}
atomicOperationsTable =
new AtomicOperationsTable(
contextConfiguration.getValueAsInteger(
GlobalConfiguration.STORAGE_ATOMIC_OPERATIONS_TABLE_COMPACTION_LIMIT),
idGen.getLastId() + 1);
atomicOperationsManager = new AtomicOperationsManager(this, atomicOperationsTable);
recoverIfNeeded();
atomicOperationsManager.executeInsideAtomicOperation(
null,
atomicOperation -> {
if (CollectionBasedStorageConfiguration.exists(writeCache)) {
configuration = new CollectionBasedStorageConfiguration(this);
((CollectionBasedStorageConfiguration) configuration)
.load(contextConfiguration, atomicOperation);
// otherwise delayed to disk based storage to convert old format to new format.
}
initConfiguration(contextConfiguration, atomicOperation);
});
atomicOperationsManager.executeInsideAtomicOperation(
null,
(atomicOperation) -> {
var uuid = configuration.getUuid();
if (uuid == null) {
uuid = UUID.randomUUID().toString();
configuration.setUuid(atomicOperation, uuid);
}
this.uuid = UUID.fromString(uuid);
});
checkPageSizeAndRelatedParameters();
componentsFactory = new CurrentStorageComponentsFactory(configuration);
linkCollectionsBTreeManager.load();
atomicOperationsManager.executeInsideAtomicOperation(null, this::openCollections);
openIndexes();
atomicOperationsManager.executeInsideAtomicOperation(
null,
(atomicOperation) -> {
final var cs = configuration.getConflictStrategy();
if (cs != null) {
// SET THE CONFLICT STORAGE STRATEGY FROM THE LOADED CONFIGURATION
doSetConflictStrategy(
YouTrackDBEnginesManager.instance().getRecordConflictStrategy()
.getStrategy(cs),
atomicOperation);
}
if (lastMetadata == null) {
lastMetadata = startupMetadata.txMetadata;
}
});
status = STATUS.MIGRATION;
} finally {
stateLock.writeLock().unlock();
}
// we need to use read lock to allow for example correctly truncate WAL during data
// processing
// all operations are prohibited on storage because of usage of special status.
stateLock.readLock().lock();
try {
if (status != STATUS.MIGRATION) {
LogManager.instance()
.error(
this,
"Unexpected storage status %s, process of creation of storage is aborted",
null,
status.name());
return;
}
//migration goes here, for future use
} finally {
stateLock.readLock().unlock();
}
stateLock.writeLock().lock();
try {
if (status != STATUS.MIGRATION) {
LogManager.instance()
.error(
this,
"Unexpected storage status %s, process of creation of storage is aborted",
null,
status.name());
return;
}
atomicOperationsManager.executeInsideAtomicOperation(null, this::checkRidBagsPresence);
status = STATUS.OPEN;
migration.countDown();
} finally {
stateLock.writeLock().unlock();
}
} catch (final RuntimeException e) {
try {
if (writeCache != null) {
readCache.closeStorage(writeCache);
}
} catch (final Exception ee) {
// ignore
}
try {
if (writeAheadLog != null) {
writeAheadLog.close();
}
} catch (final Exception ee) {
// ignore
}
try {
postCloseSteps(false, true, idGen.getLastId());
} catch (final Exception ee) {
// ignore
}
status = STATUS.CLOSED;
throw e;
}
} catch (final RuntimeException ee) {
throw logAndPrepareForRethrow(ee);
} catch (final Error ee) {
throw logAndPrepareForRethrow(ee);
} catch (final Throwable t) {
throw logAndPrepareForRethrow(t);
} finally {
if (status == STATUS.OPEN) {
sessionCount.incrementAndGet();
}
}
final var additionalArgs = new Object[]{getURL(), YouTrackDBConstants.getVersion()};
LogManager.instance()
.info(this, "Storage '%s' is opened under YouTrackDB distribution : %s", additionalArgs);
}