use of org.rocksdb.Transaction in project pulsar by apache.
the class RocksdbMetadataStore method storeDelete.
@Override
protected CompletableFuture<Void> storeDelete(String path, Optional<Long> expectedVersion) {
if (log.isDebugEnabled()) {
log.debug("storeDelete.path={},instanceId={}", path, instanceId);
}
try {
dbStateLock.readLock().lock();
if (state == State.CLOSED) {
throw new MetadataStoreException.AlreadyClosedException("");
}
try (Transaction transaction = db.beginTransaction(optionSync)) {
byte[] pathBytes = toBytes(path);
byte[] oldValueData = transaction.getForUpdate(optionDontCache, pathBytes, false);
MetaValue metaValue = MetaValue.parse(oldValueData);
if (metaValue == null) {
throw new MetadataStoreException.NotFoundException(String.format("path %s not found.", path));
}
if (expectedVersion.isPresent() && !expectedVersion.get().equals(metaValue.getVersion())) {
throw new MetadataStoreException.BadVersionException(String.format("Version mismatch, actual=%s, expect=%s", metaValue.getVersion(), expectedVersion.get()));
}
transaction.delete(pathBytes);
transaction.commit();
receivedNotification(new Notification(NotificationType.Deleted, path));
notifyParentChildrenChanged(path);
return CompletableFuture.completedFuture(null);
}
} catch (Throwable e) {
return FutureUtil.failedFuture(MetadataStoreException.wrap(e));
} finally {
dbStateLock.readLock().unlock();
}
}
use of org.rocksdb.Transaction in project FarPlaneTwo by PorkStudios.
the class RocksStorage method markAllDirty.
@Override
@SneakyThrows(RocksDBException.class)
public Stream<POS> markAllDirty(@NonNull Stream<POS> positionsIn, long dirtyTimestamp) {
// we'll buffer all the positions, lock all of them at once, compare each one and then commit as many as needed. the logic here is identical to
// RocksTileHandle#markDirty(long), but in bulk, and since RocksTileHandle doesn't cache anything internally, we don't need to get any instances
// of RocksTileHandle or do any additional synchronization.
List<POS> positions = positionsIn.distinct().collect(Collectors.toList());
int length = positions.size();
if (length == 0) {
// nothing to do!
return Stream.empty();
}
try (Transaction txn = this.db.beginTransaction(WRITE_OPTIONS)) {
// convert positions to key bytes
byte[][] allKeyBytes = positions.stream().map(POS::toBytes).toArray(byte[][]::new);
byte[][] get;
{
// double up the keys and column families to pass them to multiGetForUpdate
int doubleLength = multiplyExact(length, 2);
ColumnFamilyHandle[] handles = new ColumnFamilyHandle[doubleLength];
byte[][] keys = new byte[doubleLength][];
for (int i = 0; i < doubleLength; ) {
byte[] keyBytes = allKeyBytes[i >> 1];
handles[i] = this.cfTileTimestamp;
keys[i++] = keyBytes;
handles[i] = this.cfTileDirtyTimestamp;
keys[i++] = keyBytes;
}
// obtain an exclusive lock on both timestamp keys to ensure coherency
final int MAX_BATCH_SIZE = 65536;
if (keys.length <= MAX_BATCH_SIZE) {
get = txn.multiGetForUpdate(READ_OPTIONS, Arrays.asList(handles), keys);
} else {
// workaround for https://github.com/facebook/rocksdb/issues/9006
get = new byte[keys.length][];
for (int i = 0; i < keys.length; ) {
int batchSize = min(keys.length - i, MAX_BATCH_SIZE);
byte[][] tmp = txn.multiGetForUpdate(READ_OPTIONS, Arrays.asList(handles).subList(i, i + batchSize), Arrays.copyOfRange(keys, i, i + batchSize));
System.arraycopy(tmp, 0, get, i, batchSize);
i += batchSize;
}
}
}
// iterate through positions, updating the dirty timestamps as needed
List<POS> out = new ArrayList<>(length);
byte[] dirtyTimestampArray = new byte[Long.BYTES];
for (int i = 0; i < length; i++) {
byte[] timestampBytes = get[(i << 1) + 0];
long timestamp = timestampBytes != null ? // timestamp for this tile exists, extract it from the byte array
readLongLE(timestampBytes) : TIMESTAMP_BLANK;
byte[] dirtyTimestampBytes = get[(i << 1) + 1];
long existingDirtyTimestamp = dirtyTimestampBytes != null ? // dirty timestamp for this tile exists, extract it from the byte array
readLongLE(dirtyTimestampBytes) : TIMESTAMP_BLANK;
if (// the tile doesn't exist, so we can't mark it as dirty
timestamp == TIMESTAMP_BLANK || dirtyTimestamp <= timestamp || dirtyTimestamp <= existingDirtyTimestamp) {
// skip this position
continue;
}
// store new dirty timestamp in db
writeLongLE(dirtyTimestampArray, 0, dirtyTimestamp);
txn.put(this.cfTileDirtyTimestamp, allKeyBytes[i], dirtyTimestampArray);
// save the position to return it as part of the result stream
out.add(positions.get(i));
}
if (!out.isEmpty()) {
// non-empty list indicates that at least some positions were modified, so we should commit the transaction
txn.commit();
this.listeners.forEach(listener -> listener.tilesDirty(out.stream()));
return out.stream();
} else {
// no positions were modified...
return Stream.empty();
}
}
}
use of org.rocksdb.Transaction in project FarPlaneTwo by PorkStudios.
the class RocksTileHandle method clearDirty.
@Override
@SneakyThrows(RocksDBException.class)
public boolean clearDirty() {
try (Transaction txn = this.storage.db.beginTransaction(WRITE_OPTIONS)) {
byte[] keyBytes = this.pos.toBytes();
if (txn.getForUpdate(READ_OPTIONS, this.storage.cfTileDirtyTimestamp, keyBytes, true) == null) {
// exit without committing the transaction
return false;
}
// store new dirty timestamp in db
txn.delete(this.storage.cfTileDirtyTimestamp, keyBytes);
// commit transaction and report that a change was made
txn.commit();
return true;
}
}
Aggregations