use of org.infinispan.container.versioning.EntryVersion in project infinispan by infinispan.
the class ScatteredPreloadManager method initTopologyId.
private void initTopologyId() {
int preloadedTopologyId = scatteredVersionManager.getPreloadedTopologyId();
if (isFullyPreloaded()) {
// We don't have to do the preload, already done
if (preloadedTopologyId > 0) {
clusterTopologyManager.setInitialCacheTopologyId(cache.wired().getName(), preloadedTopologyId + 1);
}
return;
}
// An alternative (not implemented) approach is storing the max versions as a part of the persisted global state
// in ScatteredConsistentHash, but that works only for the orderly shutdown.
// TODO: implement start after shutdown
AtomicInteger maxTopologyId = new AtomicInteger(preloadedTopologyId);
Publisher<MarshallableEntry<Object, Object>> publisher = persistenceManager.publishEntries(false, true);
CompletionStage<Void> stage = Flowable.fromPublisher(publisher).doOnNext(me -> {
Metadata metadata = me.getMetadata();
EntryVersion entryVersion = metadata.version();
if (entryVersion instanceof SimpleClusteredVersion) {
int entryTopologyId = ((SimpleClusteredVersion) entryVersion).getTopologyId();
if (maxTopologyId.get() < entryTopologyId) {
maxTopologyId.updateAndGet(current -> Math.max(current, entryTopologyId));
}
}
}).ignoreElements().toCompletionStage(null);
CompletionStages.join(stage);
if (maxTopologyId.get() > 0) {
clusterTopologyManager.setInitialCacheTopologyId(cache.wired().getName(), maxTopologyId.get() + 1);
}
}
use of org.infinispan.container.versioning.EntryVersion in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method handleWriteOnOriginPrimary.
private Object handleWriteOnOriginPrimary(InvocationContext ctx, DataWriteCommand command, Object rv, RepeatableReadEntry cacheEntry, Object seenValue, EntryVersion seenVersion, CacheTopology cacheTopology, DistributionInfo info) {
if (!command.isSuccessful()) {
if (log.isTraceEnabled())
log.tracef("Skipping the replication of the command as it did not succeed on primary owner (%s).", command);
return rv;
}
// increment the version
EntryVersion nextVersion = svm.incrementVersion(info.segmentId());
Metadata metadata = addVersion(cacheEntry.getMetadata(), nextVersion);
cacheEntry.setMetadata(metadata);
CompletionStage<Void> stage;
if (command.loadType() != DONT_LOAD) {
stage = commitSingleEntryIfNoChange(cacheEntry, ctx, command);
} else {
stage = commitSingleEntryIfNewer(cacheEntry, ctx, command);
}
// When replicating to backup, we'll add skip ownership check since we're now on primary owner
// and we have already committed the entry, reading the return value. If we got OTE from remote
// site and the command would be retried, we could fail to do the retry/return wrong value.
WriteCommand backupCommand;
long flags = command.getFlagsBitSet() | FlagBitSets.SKIP_OWNERSHIP_CHECK;
if (cacheEntry.isRemoved()) {
backupCommand = cf.buildRemoveCommand(command.getKey(), null, info.segmentId(), flags);
((RemoveCommand) backupCommand).setMetadata(cacheEntry.getMetadata());
} else {
backupCommand = cf.buildPutKeyValueCommand(command.getKey(), cacheEntry.getValue(), info.segmentId(), cacheEntry.getMetadata(), flags);
}
backupCommand.setTopologyId(command.getTopologyId());
Address backup = getNextMember(cacheTopology);
if (backup != null) {
// error responses throw exceptions from JGroupsTransport
CompletionStage<?> rpcFuture = rpcManager.invokeCommand(backup, backupCommand, SingleResponseCollector.validOnly(), rpcManager.getSyncRpcOptions());
rpcFuture.thenRun(() -> {
if (cacheEntry.isCommitted() && !command.hasAnyFlag(FlagBitSets.PUT_FOR_STATE_TRANSFER)) {
scheduleKeyInvalidation(command.getKey(), cacheEntry.getMetadata().version(), cacheEntry.isRemoved());
}
});
rpcFuture = completeSingleWriteOnPrimaryOriginator(command, backup, rpcFuture);
// Exception responses are thrown anyway and we don't expect any return values
return delayedValue(CompletionStages.allOf(stage.toCompletableFuture(), rpcFuture.toCompletableFuture()), rv);
} else {
return delayedValue(stage, rv);
}
}
use of org.infinispan.container.versioning.EntryVersion in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method updateEntryIfNoChange.
private boolean updateEntryIfNoChange(RepeatableReadEntry entry) {
// We cannot delegate the dataContainer.compute() to entry.commit() as we need to reliably
// retrieve previous value and metadata, but the entry API does not provide these.
dataContainer.compute(entry.getKey(), (key, oldEntry, factory) -> {
// newMetadata is null in case of local-mode write on non-primary owners
Metadata newMetadata = entry.getMetadata();
if (oldEntry == null) {
if (entry.getOldValue() != null) {
if (log.isTraceEnabled()) {
log.trace("Non-null value in context, not committing");
}
throw new ConcurrentChangeException();
}
if (entry.getValue() == null && newMetadata == null) {
if (log.isTraceEnabled()) {
log.trace("No previous record and this is a removal, not committing anything.");
}
return null;
} else {
if (log.isTraceEnabled()) {
log.trace("Committing new entry " + entry);
}
entry.setCommitted();
return factory.create(entry);
}
}
Metadata oldMetadata = oldEntry.getMetadata();
EntryVersion oldVersion = oldMetadata == null ? null : oldMetadata.version();
Metadata seenMetadata = entry.getOldMetadata();
EntryVersion seenVersion = seenMetadata == null ? null : seenMetadata.version();
if (oldVersion == null) {
if (seenVersion != null) {
if (log.isTraceEnabled()) {
log.tracef("Current version is null but seen version is %s, throwing", seenVersion);
}
throw new ConcurrentChangeException();
}
} else if (seenVersion == null) {
if (oldEntry.canExpire() && oldEntry.isExpired(timeService.wallClockTime())) {
if (log.isTraceEnabled()) {
log.trace("Current entry is expired and therefore we haven't seen it");
}
} else {
if (log.isTraceEnabled()) {
log.tracef("Current version is %s but seen version is null, throwing", oldVersion);
}
throw new ConcurrentChangeException();
}
} else if (seenVersion.compareTo(oldVersion) != InequalVersionComparisonResult.EQUAL) {
if (log.isTraceEnabled()) {
log.tracef("Current version is %s but seen version is %s, throwing", oldVersion, seenVersion);
}
throw new ConcurrentChangeException();
}
InequalVersionComparisonResult comparisonResult;
if (oldVersion == null || newMetadata == null || newMetadata.version() == null || (comparisonResult = oldMetadata.version().compareTo(newMetadata.version())) == InequalVersionComparisonResult.BEFORE || (oldMetadata instanceof RemoteMetadata && comparisonResult == InequalVersionComparisonResult.EQUAL)) {
if (log.isTraceEnabled()) {
log.tracef("Committing entry %s, replaced %s", entry, oldEntry);
}
entry.setCommitted();
if (entry.getValue() != null || newMetadata != null) {
return factory.create(entry);
} else {
return null;
}
} else {
if (log.isTraceEnabled()) {
log.tracef("Not committing %s, current entry is %s", entry, oldEntry);
}
return oldEntry;
}
});
return entry.isCommitted();
}
use of org.infinispan.container.versioning.EntryVersion in project infinispan by infinispan.
the class EntryEventListener method writeVersion.
private void writeVersion(CacheEntryEvent<?, ?> event, StructuredEventBuilder writer) throws IOException, InterruptedException {
if (event.getMetadata() != null) {
EntryVersion version = event.getMetadata().version();
if (version != null) {
byte[] versionBytes = persistenceMarshaller.objectToByteBuffer(version);
writer.setEntryVersion(versionBytes);
}
}
}
use of org.infinispan.container.versioning.EntryVersion in project infinispan by infinispan.
the class MetadataUtils method extractVersion.
public static long extractVersion(CacheEntry ce) {
if (ce == null)
return -1;
EntryVersion entryVersion = ce.getMetadata().version();
long version = 0;
if (entryVersion != null) {
if (entryVersion instanceof NumericVersion) {
version = NumericVersion.class.cast(entryVersion).getVersion();
}
if (entryVersion instanceof SimpleClusteredVersion) {
version = SimpleClusteredVersion.class.cast(entryVersion).getVersion();
}
}
return version;
}
Aggregations