use of io.deephaven.web.client.api.TableData in project deephaven-core by deephaven.
the class TableViewportSubscription method snapshot.
@JsMethod
public Promise<TableData> snapshot(JsRangeSet rows, Column[] columns) {
// TODO #1039 slice rows and drop columns
return copy.then(table -> {
final ClientTableState state = table.state();
String[] columnTypes = Arrays.stream(state.getTableDef().getColumns()).map(ColumnDefinition::getType).toArray(String[]::new);
final BitSet columnBitset = table.lastVisibleState().makeBitset(columns);
return Callbacks.<TableSnapshot, String>promise(this, callback -> {
WorkerConnection connection = table.getConnection();
BiDiStream<FlightData, FlightData> stream = connection.<FlightData, FlightData>streamFactory().create(headers -> connection.flightServiceClient().doExchange(headers), (first, headers) -> connection.browserFlightServiceClient().openDoExchange(first, headers), (next, headers, c) -> connection.browserFlightServiceClient().nextDoExchange(next, headers, c::apply), new FlightData());
Builder doGetRequest = new Builder(1024);
double columnsOffset = BarrageSubscriptionRequest.createColumnsVector(doGetRequest, makeUint8ArrayFromBitset(columnBitset));
double viewportOffset = BarrageSubscriptionRequest.createViewportVector(doGetRequest, serializeRanges(Collections.singleton(rows.getRange())));
double serializationOptionsOffset = BarrageSnapshotOptions.createBarrageSnapshotOptions(doGetRequest, ColumnConversionMode.Stringify, true, 0);
double tableTicketOffset = BarrageSubscriptionRequest.createTicketVector(doGetRequest, state.getHandle().getTicket());
BarrageSnapshotRequest.startBarrageSnapshotRequest(doGetRequest);
BarrageSnapshotRequest.addTicket(doGetRequest, tableTicketOffset);
BarrageSnapshotRequest.addColumns(doGetRequest, columnsOffset);
BarrageSnapshotRequest.addSnapshotOptions(doGetRequest, serializationOptionsOffset);
BarrageSnapshotRequest.addViewport(doGetRequest, viewportOffset);
doGetRequest.finish(BarrageSnapshotRequest.endBarrageSnapshotRequest(doGetRequest));
FlightData request = new FlightData();
request.setAppMetadata(BarrageUtils.wrapMessage(doGetRequest, BarrageMessageType.BarrageSnapshotRequest));
stream.send(request);
stream.end();
stream.onData(flightData -> {
Message message = Message.getRootAsMessage(new ByteBuffer(flightData.getDataHeader_asU8()));
if (message.headerType() == MessageHeader.Schema) {
// ignore for now, we'll handle this later
return;
}
assert message.headerType() == MessageHeader.RecordBatch;
RecordBatch header = message.header(new RecordBatch());
Uint8Array appMetadataBytes = flightData.getAppMetadata_asU8();
BarrageUpdateMetadata update = null;
if (appMetadataBytes.length != 0) {
BarrageMessageWrapper barrageMessageWrapper = BarrageMessageWrapper.getRootAsBarrageMessageWrapper(new io.deephaven.javascript.proto.dhinternal.flatbuffers.ByteBuffer(appMetadataBytes));
update = BarrageUpdateMetadata.getRootAsBarrageUpdateMetadata(new ByteBuffer(new Uint8Array(barrageMessageWrapper.msgPayloadArray())));
}
TableSnapshot snapshot = BarrageUtils.createSnapshot(header, BarrageUtils.typedArrayToLittleEndianByteBuffer(flightData.getDataBody_asU8()), update, true, columnTypes);
callback.onSuccess(snapshot);
});
stream.onStatus(status -> {
if (!status.isOk()) {
callback.onFailure(status.getDetails());
}
});
}).then(defer()).then(snapshot -> {
SubscriptionTableData pretendSubscription = new SubscriptionTableData(Js.uncheckedCast(columns), state.getRowFormatColumn() == null ? NO_ROW_FORMAT_COLUMN : state.getRowFormatColumn().getIndex(), null);
TableData data = pretendSubscription.handleSnapshot(snapshot);
return Promise.resolve(data);
}).then(defer());
});
}
use of io.deephaven.web.client.api.TableData in project deephaven-core by deephaven.
the class ChartData method update.
public void update(Object eventDetail) {
assert eventDetail instanceof UpdateEventData : "update() can only take table subscription event instances";
UpdateEventData tableData = (UpdateEventData) eventDetail;
Iterator<Range> addedIterator = tableData.getAdded().getRange().rangeIterator();
Iterator<Range> removedIterator = tableData.getRemoved().getRange().rangeIterator();
Iterator<Range> modifiedIterator = tableData.getModified().getRange().rangeIterator();
Range nextAdded = addedIterator.hasNext() ? addedIterator.next() : null;
Range nextRemoved = removedIterator.hasNext() ? removedIterator.next() : null;
Range nextModified = modifiedIterator.hasNext() ? modifiedIterator.next() : null;
int i = 0;
// not useful for adding/modifying data, but fast and easy to use when removing rows
JsArray<Any>[] allColumns;
if (nextRemoved != null) {
// noinspection unchecked
allColumns = cachedData.values().stream().flatMap(m -> m.values().stream()).toArray(JsArray[]::new);
} else {
allColumns = null;
}
while (nextAdded != null || nextRemoved != null || nextModified != null) {
if (i >= indexes.length) {
// Note that this is the first case we'll hit on initial snapshot
assert nextRemoved == null;
assert nextModified == null;
while (nextAdded != null) {
insertDataRange(tableData, nextAdded, i);
// increment i past these new items so our offset is correct if there is a next block
i += nextAdded.size();
// not bothering with i or lastIndexSeen since we will break after this while loop
nextAdded = addedIterator.hasNext() ? addedIterator.next() : null;
}
break;
}
long nextIndex = indexes[i];
// index, while the other two start at the current index
if (nextAdded != null && nextAdded.getFirst() < nextIndex) {
// the whole range should be there if any is
assert nextAdded.getLast() < nextIndex;
// update the index array and insert the actual data into our mapped columns
insertDataRange(tableData, nextAdded, i);
// increment i past these new items, so that our "next" is actually next
i += nextAdded.size();
nextAdded = addedIterator.hasNext() ? addedIterator.next() : null;
} else if (nextModified != null && nextModified.getFirst() == nextIndex) {
// somehow being asked to update an item which wasn't
assert nextModified.getLast() >= nextIndex;
// the updated block is contiguous, make sure there are at least that many items to tweak
assert indexes.length - i >= nextModified.size();
replaceDataRange(tableData, nextModified, i);
// advance i past this section, since no other change can happen to these rows
i += nextModified.size();
nextModified = modifiedIterator.hasNext() ? modifiedIterator.next() : null;
} else if (nextRemoved != null && nextRemoved.getFirst() == nextIndex) {
// somehow being asked to remove an item which wasn't present
assert nextRemoved.getLast() >= nextIndex;
// the block being removed is contiguous, so make sure there are at least that many and splice them out
assert indexes.length - i >= nextRemoved.size();
// splice out the indexes
asArray(indexes).splice(i, (int) nextRemoved.size());
// splice out the data itself
assert allColumns != null;
for (JsArray<Any> column : allColumns) {
column.splice(i, (int) nextRemoved.size());
}
// don't in/decrement i, we'll just keep going
nextRemoved = removedIterator.hasNext() ? removedIterator.next() : null;
} else {
// no match, keep reading
i++;
}
}
if (JsSettings.isDevMode()) {
assert ((UpdateEventData) eventDetail).getRows().length == indexes.length;
assert cachedData.values().stream().flatMap(m -> m.values().stream()).allMatch(arr -> arr.length == indexes.length);
assert cachedData.values().stream().flatMap(m -> m.values().stream()).allMatch(arr -> arr.reduce((Object val, Any p1, int p2, JsArray<Any> p3) -> ((Integer) val) + 1, 0) == indexes.length);
JsRangeSet fullIndex = tableData.getFullIndex();
PrimitiveIterator.OfLong iter = fullIndex.getRange().indexIterator();
for (int j = 0; j < indexes.length; j++) {
assert indexes[j] == iter.nextLong();
}
}
}
Aggregations