use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method checkRebuild.
private CompletableFuture<Void> checkRebuild(@Nullable UserVersionChecker userVersionChecker, @Nonnull RecordMetaDataProto.DataStoreInfo.Builder info, @Nonnull RecordMetaData metaData) {
final List<CompletableFuture<Void>> work = new LinkedList<>();
final int oldFormatVersion = info.getFormatVersion();
if (oldFormatVersion != formatVersion) {
info.setFormatVersion(formatVersion);
// attempting to read data, i.e., before we update any indexes.
if ((oldFormatVersion >= MIN_FORMAT_VERSION && oldFormatVersion < SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION && formatVersion >= SAVE_UNSPLIT_WITH_SUFFIX_FORMAT_VERSION && !metaData.isSplitLongRecords())) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(KeyValueLogMessage.of("unsplit records stored at old format", LogMessageKeys.OLD_VERSION, oldFormatVersion, LogMessageKeys.NEW_VERSION, formatVersion, subspaceProvider.logKey(), subspaceProvider.toString(context)));
}
info.setOmitUnsplitRecordSuffix(true);
omitUnsplitRecordSuffix = true;
}
if (oldFormatVersion >= MIN_FORMAT_VERSION && oldFormatVersion < SAVE_VERSION_WITH_RECORD_FORMAT_VERSION && metaData.isStoreRecordVersions() && !useOldVersionFormat()) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(KeyValueLogMessage.of("migrating record versions to new format"), LogMessageKeys.OLD_VERSION, oldFormatVersion, LogMessageKeys.NEW_VERSION, formatVersion, subspaceProvider.logKey(), subspaceProvider.toString(context));
}
addConvertRecordVersions(work);
}
}
final boolean newStore = oldFormatVersion == 0;
final int oldMetaDataVersion = newStore ? -1 : info.getMetaDataversion();
final int newMetaDataVersion = metaData.getVersion();
final boolean metaDataVersionChanged = oldMetaDataVersion != newMetaDataVersion;
if (metaDataVersionChanged) {
// Clear the version table if we are no longer storing record versions.
if (!metaData.isStoreRecordVersions()) {
final Transaction tr = ensureContextActive();
tr.clear(getSubspace().subspace(Tuple.from(RECORD_VERSION_KEY)).range());
}
info.setMetaDataversion(newMetaDataVersion);
}
final boolean rebuildRecordCounts = checkPossiblyRebuildRecordCounts(metaData, info, work, oldFormatVersion);
// Done if we just needed to update format version (which might trigger record count rebuild).
if (!metaDataVersionChanged) {
return work.isEmpty() ? AsyncUtil.DONE : AsyncUtil.whenReady(work.get(0));
}
// Remove former indexes.
for (FormerIndex formerIndex : metaData.getFormerIndexesSince(oldMetaDataVersion)) {
removeFormerIndex(formerIndex);
}
return checkRebuildIndexes(userVersionChecker, info, oldFormatVersion, metaData, oldMetaDataVersion, rebuildRecordCounts, work);
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method updateIndexState.
// Actually (1) writes the index state to the database and (2) updates the cached state with the new state
private void updateIndexState(@Nonnull String indexName, byte[] indexKey, @Nonnull IndexState indexState) {
if (recordStoreStateRef.get() == null) {
throw uninitializedStoreException("cannot update index state on an uninitialized store");
}
// This is generally called by someone who should already have a write lock, but adding them here
// defensively shouldn't cause problems.
beginRecordStoreStateWrite();
try {
context.setDirtyStoreState(true);
if (isStateCacheableInternal()) {
// The cache contains index state information, so updates to this information must also
// update the meta-data version stamp or instances might cache state index states.
context.setMetaDataVersionStamp();
}
Transaction tr = context.ensureActive();
if (IndexState.READABLE.equals(indexState)) {
tr.clear(indexKey);
} else {
tr.set(indexKey, Tuple.from(indexState.code()).pack());
}
recordStoreStateRef.updateAndGet(state -> {
// See beginRecordStoreStateRead() on why setting state is done in updateAndGet().
state.setState(indexName, indexState);
return state;
});
} finally {
endRecordStoreStateWrite();
}
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method rebuildIndex.
@Nonnull
// Resource usage for indexBuilder is too complicated for rule.
@SuppressWarnings("squid:S2095")
public CompletableFuture<Void> rebuildIndex(@Nonnull final Index index, @Nullable final Collection<RecordType> recordTypes, @Nonnull RebuildIndexReason reason) {
final boolean newStore = reason == RebuildIndexReason.NEW_STORE;
if (newStore ? LOGGER.isDebugEnabled() : LOGGER.isInfoEnabled()) {
final KeyValueLogMessage msg = KeyValueLogMessage.build("rebuilding index", LogMessageKeys.INDEX_NAME, index.getName(), LogMessageKeys.INDEX_VERSION, index.getLastModifiedVersion(), LogMessageKeys.REASON, reason.name(), subspaceProvider.logKey(), subspaceProvider.toString(context), LogMessageKeys.SUBSPACE_KEY, index.getSubspaceKey());
if (newStore) {
LOGGER.debug(msg.toString());
} else {
LOGGER.info(msg.toString());
}
}
long startTime = System.nanoTime();
OnlineIndexer indexBuilder = OnlineIndexer.newBuilder().setRecordStore(this).setIndex(index).setRecordTypes(recordTypes).build();
CompletableFuture<Void> future = indexBuilder.rebuildIndexAsync(this).thenCompose(vignore -> markIndexReadable(index)).handle((b, t) -> {
if (t != null) {
logExceptionAsWarn(KeyValueLogMessage.build("rebuilding index failed", LogMessageKeys.INDEX_NAME, index.getName(), LogMessageKeys.INDEX_VERSION, index.getLastModifiedVersion(), LogMessageKeys.REASON, reason.name(), subspaceProvider.logKey(), subspaceProvider.toString(context), LogMessageKeys.SUBSPACE_KEY, index.getSubspaceKey()), t);
}
// Only call method that builds in the current transaction, so never any pending work,
// so it would work to close before returning future, which would look better to SonarQube.
// But this is better if close ever does more.
indexBuilder.close();
return null;
});
return context.instrument(FDBStoreTimer.Events.REBUILD_INDEX, future, startTime);
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method markIndexNotReadable.
@Nonnull
private CompletableFuture<Boolean> markIndexNotReadable(@Nonnull String indexName, @Nonnull IndexState indexState) {
if (recordStoreStateRef.get() == null) {
return preloadRecordStoreStateAsync().thenCompose(vignore -> markIndexNotReadable(indexName, indexState));
}
addIndexStateReadConflict(indexName);
beginRecordStoreStateWrite();
boolean haveFuture = false;
try {
// A read is done before the write in order to avoid having unnecessary
// updates cause spurious not_committed errors.
byte[] indexKey = indexStateSubspace().pack(indexName);
Transaction tr = context.ensureActive();
CompletableFuture<Boolean> future = tr.get(indexKey).thenCompose(previous -> {
if (previous == null) {
RangeSet indexRangeSet = new RangeSet(indexRangeSubspace(getRecordMetaData().getIndex(indexName)));
return indexRangeSet.isEmpty(tr).thenCompose(isEmpty -> {
if (isEmpty) {
// that the index was completely built (if the range set was empty, i.e., cleared)
return indexRangeSet.insertRange(tr, null, null);
} else {
return AsyncUtil.READY_FALSE;
}
}).thenApply(ignore -> {
updateIndexState(indexName, indexKey, indexState);
return true;
});
} else if (!Tuple.fromBytes(previous).get(0).equals(indexState.code())) {
updateIndexState(indexName, indexKey, indexState);
return AsyncUtil.READY_TRUE;
} else {
return AsyncUtil.READY_FALSE;
}
}).whenComplete((b, t) -> endRecordStoreStateWrite());
haveFuture = true;
return future;
} finally {
if (!haveFuture) {
endRecordStoreStateWrite();
}
}
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class FDBRecordStore method deleteAllRecords.
@Override
public void deleteAllRecords() {
preloadCache.invalidateAll();
Transaction tr = ensureContextActive();
// Clear out all data except for the store header key and the index state space.
// Those two subspaces are determined by the configuration of the record store rather then
// the records.
Range indexStateRange = indexStateSubspace().range();
tr.clear(recordsSubspace().getKey(), indexStateRange.begin);
tr.clear(indexStateRange.end, getSubspace().range().end);
}
Aggregations