use of io.pravega.client.tables.impl.TableSegmentKeyVersion in project pravega by pravega.
the class SegmentHelper method updateTableEntries.
public CompletableFuture<List<TableSegmentKeyVersion>> updateTableEntries(final String tableName, final PravegaNodeUri uri, final List<TableSegmentEntry> entries, String delegationToken, final long clientRequestId) {
final WireCommandType type = WireCommandType.UPDATE_TABLE_ENTRIES;
List<Map.Entry<WireCommands.TableKey, WireCommands.TableValue>> wireCommandEntries = entries.stream().map(te -> {
final WireCommands.TableKey key = convertToWireCommand(te.getKey());
final WireCommands.TableValue value = new WireCommands.TableValue(te.getValue());
return new AbstractMap.SimpleImmutableEntry<>(key, value);
}).collect(Collectors.toList());
RawClient connection = new RawClient(uri, connectionPool);
final long requestId = connection.getFlow().asLong();
WireCommands.UpdateTableEntries request = new WireCommands.UpdateTableEntries(requestId, tableName, delegationToken, new WireCommands.TableEntries(wireCommandEntries), WireCommands.NULL_TABLE_SEGMENT_OFFSET);
return sendRequest(connection, clientRequestId, request).thenApply(rpl -> {
handleReply(clientRequestId, rpl, connection, tableName, WireCommands.UpdateTableEntries.class, type);
return ((WireCommands.TableEntriesUpdated) rpl).getUpdatedVersions().stream().map(TableSegmentKeyVersion::from).collect(Collectors.toList());
});
}
use of io.pravega.client.tables.impl.TableSegmentKeyVersion in project pravega by pravega.
the class SegmentHelper method removeTableKeys.
/**
* This method sends a WireCommand to remove table keys.
*
* @param tableName Qualified table name.
* @param keys List of {@link TableSegmentKey}s to be removed. Only if all the elements in the list has version
* as {@link TableSegmentKeyVersion#NO_VERSION} then an unconditional update/removal is performed.
* Else an atomic conditional update (removal) is performed.
* @param delegationToken The token to be presented to the Segment Store.
* @param clientRequestId Request id.
* @return A CompletableFuture that will complete normally when the provided keys are deleted.
* If the operation failed, the future will be failed with the causing exception. If the exception can be
* retried then the future will be failed with {@link WireCommandFailedException}.
*/
public CompletableFuture<Void> removeTableKeys(final String tableName, final List<TableSegmentKey> keys, String delegationToken, final long clientRequestId) {
final Controller.NodeUri uri = getTableUri(tableName);
final WireCommandType type = WireCommandType.REMOVE_TABLE_KEYS;
List<WireCommands.TableKey> keyList = keys.stream().map(x -> {
WireCommands.TableKey key = convertToWireCommand(x);
return key;
}).collect(Collectors.toList());
RawClient connection = new RawClient(ModelHelper.encode(uri), connectionPool);
final long requestId = connection.getFlow().asLong();
WireCommands.RemoveTableKeys request = new WireCommands.RemoveTableKeys(requestId, tableName, delegationToken, keyList, WireCommands.NULL_TABLE_SEGMENT_OFFSET);
return sendRequest(connection, clientRequestId, request).thenAccept(rpl -> handleReply(clientRequestId, rpl, connection, tableName, WireCommands.RemoveTableKeys.class, type));
}
use of io.pravega.client.tables.impl.TableSegmentKeyVersion in project pravega by pravega.
the class SegmentHelperMock method getSegmentHelperMockForTables.
public static SegmentHelper getSegmentHelperMockForTables(ScheduledExecutorService executor) {
SegmentHelper helper = getSegmentHelperMock();
final Object lock = new Object();
final Map<String, Map<ByteBuffer, TableSegmentEntry>> mapOfTables = new HashMap<>();
final Map<String, Map<ByteBuffer, Long>> mapOfTablesPosition = new HashMap<>();
// region create table
doAnswer(x -> {
String tableName = x.getArgument(0);
return CompletableFuture.runAsync(() -> {
synchronized (lock) {
mapOfTables.putIfAbsent(tableName, new HashMap<>());
mapOfTablesPosition.putIfAbsent(tableName, new HashMap<>());
}
}, executor);
}).when(helper).createTableSegment(anyString(), anyString(), anyLong(), anyBoolean(), anyInt(), anyLong());
// endregion
// region delete table
doAnswer(x -> {
String tableName = x.getArgument(0);
Boolean mustBeEmpty = x.getArgument(1);
final WireCommandType type = WireCommandType.DELETE_TABLE_SEGMENT;
return CompletableFuture.supplyAsync(() -> {
synchronized (lock) {
if (!mapOfTables.containsKey(tableName)) {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.SegmentDoesNotExist);
}
boolean empty = Optional.ofNullable(mapOfTables.get(tableName)).orElse(Collections.emptyMap()).isEmpty();
if (!mustBeEmpty || empty) {
mapOfTables.remove(tableName);
mapOfTablesPosition.remove(tableName);
return null;
} else {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.TableSegmentNotEmpty);
}
}
}, executor);
}).when(helper).deleteTableSegment(anyString(), anyBoolean(), anyString(), anyLong());
// endregion
// region update keys
doAnswer(x -> {
final WireCommandType type = WireCommandType.UPDATE_TABLE_ENTRIES;
String tableName = x.getArgument(0);
List<TableSegmentEntry> entries = x.getArgument(1);
return CompletableFuture.supplyAsync(() -> {
synchronized (lock) {
Map<ByteBuffer, TableSegmentEntry> table = mapOfTables.get(tableName);
Map<ByteBuffer, Long> tablePos = mapOfTablesPosition.get(tableName);
if (table == null) {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.SegmentDoesNotExist);
} else {
List<TableSegmentKeyVersion> resultList = new LinkedList<>();
entries.forEach(entry -> {
ByteBuffer key = entry.getKey().getKey().copy().nioBuffer();
byte[] value = entry.getValue().copy().array();
TableSegmentEntry existingEntry = table.get(key);
if (existingEntry == null) {
if (entry.getKey().getVersion().equals(TableSegmentKeyVersion.NOT_EXISTS)) {
TableSegmentEntry newEntry = TableSegmentEntry.versioned(key.array(), value, 0);
table.put(key, newEntry);
tablePos.put(key, System.nanoTime());
resultList.add(newEntry.getKey().getVersion());
} else {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.TableKeyDoesNotExist);
}
} else if (existingEntry.getKey().getVersion().equals(entry.getKey().getVersion())) {
TableSegmentKeyVersion newVersion = TableSegmentKeyVersion.from(existingEntry.getKey().getVersion().getSegmentVersion() + 1);
TableSegmentEntry newEntry = TableSegmentEntry.versioned(key.array(), value, newVersion.getSegmentVersion());
table.put(key, newEntry);
tablePos.put(key, System.nanoTime());
resultList.add(newVersion);
} else {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.TableKeyBadVersion);
}
});
return resultList;
}
}
}, executor);
}).when(helper).updateTableEntries(anyString(), any(), anyString(), anyLong());
// endregion
// region remove keys
doAnswer(x -> {
final WireCommandType type = WireCommandType.REMOVE_TABLE_KEYS;
String tableName = x.getArgument(0);
List<TableSegmentKey> keys = x.getArgument(1);
return CompletableFuture.runAsync(() -> {
synchronized (lock) {
Map<ByteBuffer, TableSegmentEntry> table = mapOfTables.get(tableName);
Map<ByteBuffer, Long> tablePos = mapOfTablesPosition.get(tableName);
if (table == null) {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.SegmentDoesNotExist);
} else {
keys.forEach(rawKey -> {
ByteBuffer key = rawKey.getKey().copy().nioBuffer();
TableSegmentEntry existingEntry = table.get(key);
if (existingEntry != null) {
if (existingEntry.getKey().getVersion().equals(rawKey.getVersion()) || rawKey.getVersion() == null || rawKey.getVersion().equals(TableSegmentKeyVersion.NO_VERSION)) {
table.remove(key);
tablePos.remove(key);
} else {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.TableKeyBadVersion);
}
}
});
}
}
}, executor);
}).when(helper).removeTableKeys(anyString(), any(), anyString(), anyLong());
// endregion
// region read keys
doAnswer(x -> {
final WireCommandType type = WireCommandType.READ_TABLE;
String tableName = x.getArgument(0);
List<TableSegmentKey> requestKeys = x.getArgument(1);
return CompletableFuture.supplyAsync(() -> {
synchronized (lock) {
Map<ByteBuffer, TableSegmentEntry> table = mapOfTables.get(tableName);
if (table == null) {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.SegmentDoesNotExist);
} else {
List<TableSegmentEntry> resultList = new LinkedList<>();
requestKeys.forEach(requestKey -> {
ByteBuffer key = requestKey.getKey().copy().nioBuffer();
TableSegmentEntry existingEntry = table.get(key);
if (existingEntry == null) {
resultList.add(TableSegmentEntry.notExists(key.array(), new byte[0]));
} else if (existingEntry.getKey().getVersion().equals(requestKey.getVersion()) || requestKey.getVersion() == null || requestKey.getVersion().equals(TableSegmentKeyVersion.NO_VERSION)) {
resultList.add(duplicate(existingEntry));
} else {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.TableKeyBadVersion);
}
});
return resultList;
}
}
}, executor);
}).when(helper).readTable(anyString(), any(), anyString(), anyLong());
// endregion
// region readTableKeys
doAnswer(x -> {
String tableName = x.getArgument(0);
int limit = x.getArgument(1);
HashTableIteratorItem.State state = x.getArgument(2);
final WireCommandType type = WireCommandType.READ_TABLE;
return CompletableFuture.supplyAsync(() -> {
synchronized (lock) {
Map<ByteBuffer, TableSegmentEntry> table = mapOfTables.get(tableName);
Map<ByteBuffer, Long> tablePos = mapOfTablesPosition.get(tableName);
if (table == null) {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.SegmentDoesNotExist);
} else {
long floor;
if (state.equals(HashTableIteratorItem.State.EMPTY)) {
floor = 0L;
} else {
floor = new ByteArraySegment(state.toBytes()).getLong(0);
}
AtomicLong token = new AtomicLong(floor);
List<TableSegmentKey> list = tablePos.entrySet().stream().sorted(Comparator.comparingLong(Map.Entry::getValue)).filter(c -> c.getValue() > floor).map(r -> {
token.set(r.getValue());
return duplicate(table.get(r.getKey()).getKey());
}).limit(limit).collect(Collectors.toList());
byte[] continuationToken = new byte[Long.BYTES];
BitConverter.writeLong(continuationToken, 0, token.get());
HashTableIteratorItem.State newState = HashTableIteratorItem.State.fromBytes(Unpooled.wrappedBuffer(continuationToken));
return new HashTableIteratorItem<>(newState, list);
}
}
}, executor);
}).when(helper).readTableKeys(anyString(), anyInt(), any(), anyString(), anyLong());
// endregion
// region readTableEntries
doAnswer(x -> {
String tableName = x.getArgument(0);
int limit = x.getArgument(1);
HashTableIteratorItem.State state = x.getArgument(2);
final WireCommandType type = WireCommandType.READ_TABLE;
return CompletableFuture.supplyAsync(() -> {
synchronized (lock) {
Map<ByteBuffer, TableSegmentEntry> table = mapOfTables.get(tableName);
Map<ByteBuffer, Long> tablePos = mapOfTablesPosition.get(tableName);
if (table == null) {
throw new WireCommandFailedException(type, WireCommandFailedException.Reason.SegmentDoesNotExist);
} else {
long floor;
if (state.equals(HashTableIteratorItem.State.EMPTY)) {
floor = 0L;
} else {
floor = new ByteArraySegment(state.toBytes()).getLong(0);
}
AtomicLong token = new AtomicLong(floor);
List<TableSegmentEntry> list = tablePos.entrySet().stream().sorted(Comparator.comparingLong(Map.Entry::getValue)).filter(c -> c.getValue() > floor).map(r -> {
token.set(r.getValue());
return duplicate(table.get(r.getKey()));
}).limit(limit).collect(Collectors.toList());
byte[] continuationToken = new byte[Long.BYTES];
BitConverter.writeLong(continuationToken, 0, token.get());
HashTableIteratorItem.State newState = HashTableIteratorItem.State.fromBytes(Unpooled.wrappedBuffer(continuationToken));
return new HashTableIteratorItem<>(newState, list);
}
}
}, executor);
}).when(helper).readTableEntries(anyString(), anyInt(), any(), anyString(), anyLong());
// endregion
return helper;
}
use of io.pravega.client.tables.impl.TableSegmentKeyVersion in project pravega by pravega.
the class ControllerMetadataUpdateEntryCommand method execute.
@Override
public void execute() throws Exception {
ensureArgCount(4);
final String tableName = getArg(0);
final String key = getArg(1);
final String newValueFile = getArg(3);
final String segmentStoreHost = getArg(2);
@Cleanup CuratorFramework zkClient = createZKClient();
@Cleanup AdminSegmentHelper adminSegmentHelper = instantiateAdminSegmentHelper(zkClient);
ControllerMetadataSerializer serializer = new ControllerMetadataSerializer(tableName, key);
ControllerMetadataJsonSerializer jsonSerializer = new ControllerMetadataJsonSerializer();
String jsonValue;
try {
jsonValue = new String(Files.readAllBytes(Paths.get(newValueFile)));
} catch (NoSuchFileException e) {
output("File with new value does not exist: %s", newValueFile);
return;
}
ByteBuffer updatedValue = serializer.serialize(jsonSerializer.fromJson(jsonValue, serializer.getMetadataClass()));
TableSegmentEntry currentEntry = getTableEntry(tableName, key, segmentStoreHost, adminSegmentHelper);
if (currentEntry == null) {
return;
}
long currentVersion = currentEntry.getKey().getVersion().getSegmentVersion();
TableSegmentKeyVersion newVersion = updateTableEntry(tableName, key, updatedValue, currentVersion, segmentStoreHost, adminSegmentHelper);
if (newVersion == null) {
return;
}
output("Successfully updated the key %s in table %s with version %s", key, tableName, newVersion.getSegmentVersion());
}
use of io.pravega.client.tables.impl.TableSegmentKeyVersion in project pravega by pravega.
the class ControllerMetadataCommand method updateTableEntry.
/**
* Method to update entry corresponding to the provided key in the table.
*
* @param tableName The name of the table.
* @param key The key.
* @param value The new value.
* @param version The expected update version.
* @param segmentStoreHost The address of the segment store instance.
* @param adminSegmentHelper An instance of {@link AdminSegmentHelper}.
* @return The new key version after the update takes place successfully.
*/
TableSegmentKeyVersion updateTableEntry(String tableName, String key, ByteBuffer value, long version, String segmentStoreHost, AdminSegmentHelper adminSegmentHelper) {
ByteArraySegment serializedKey = new ByteArraySegment(KEY_SERIALIZER.serialize(key));
ByteArraySegment serializedValue = new ByteArraySegment(value);
TableSegmentEntry updatedEntry = TableSegmentEntry.versioned(serializedKey.getCopy(), serializedValue.getCopy(), version);
List<TableSegmentKeyVersion> keyVersions = completeSafely(adminSegmentHelper.updateTableEntries(tableName, new PravegaNodeUri(segmentStoreHost, getServiceConfig().getAdminGatewayPort()), Collections.singletonList(updatedEntry), authHelper.retrieveMasterToken(), 0L), tableName, key);
if (keyVersions == null) {
return null;
}
return keyVersions.get(0);
}
Aggregations