nstream.persist.kv.KvNodePersistence Maven / Gradle / Ivy
Show all versions of nstream-persist-kv Show documentation
// Copyright 2015-2024 Nstream, inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nstream.persist.kv;
import java.nio.ByteBuffer;
import java.util.TreeMap;
import nstream.persist.api.PersistenceException;
import nstream.persist.api.cache.MapBackingStore;
import nstream.persist.api.cache.NodePersistenceApi;
import nstream.persist.api.cache.ValueBackingStore;
import nstream.persist.api.kv.IoResult;
import nstream.persist.api.kv.IterationStatus;
import nstream.persist.api.kv.KeyValueBuffers;
import nstream.persist.api.kv.KvStoreApi;
import nstream.persist.api.kv.MapIterator;
import nstream.persist.kv.state.StoreState;
import swim.codec.Binary;
import swim.collections.BTree;
import swim.recon.Recon;
import swim.recon.ReconParser;
import swim.structure.Item;
import swim.structure.Value;
/**
* Implements the core Swim store interface. The initial store instance created is the root. When the root instance is
* closed, the underlying database will be closed also, regardless of how many subsidiary stores have been opened.
*
* Each instance of this type has an associated path name (for the root, this path is empty).
*/
class KvNodePersistence implements NodePersistenceApi, AutoCloseable {
private final String node;
private final KvStoreApi store;
private final StoreState state;
/**
* Create a root store.
*
* @param store The underlying key-value store.
* @param state State store for the states of the lanes (shared between all children of the root).
*/
KvNodePersistence(final KvStoreApi store, String node, StoreState state) {
this.store = store;
this.node = node;
this.state = state;
}
private static Value parseFrom(ReconParser- parser, ByteBuffer buffer) {
final var after = parser.parseBlock(Binary.inputBuffer(buffer));
if (after.isDone()) {
return after.bind();
} else {
return Value.extant();
}
}
private static BTree
initMap(MapIterator it) throws PersistenceException {
final var parser = Recon.structureParser();
final TreeMap builder = new TreeMap<>();
final KeyValueBuffers buffers = new KeyValueBuffers(ByteBuffer.allocate(0), ByteBuffer.allocate(0));
while (it.hasCurrent()) {
IterationStatus status = null;
do {
if (status != null) {
if (status.keyOverflowed()) {
status.getKeyRequired().ifPresentOrElse(buffers::growKey, buffers::growKey);
}
if (status.valueOverflowed()) {
status.getValueRequired().ifPresentOrElse(buffers::growValue, buffers::growValue);
}
}
status = it.current(buffers);
} while (status.getResult() == IoResult.BufferOverflow);
final var key = parseFrom(parser, buffers.getKeyBuffer());
final var value = parseFrom(parser, buffers.getValueBuffer());
builder.put(key, value);
it.advance();
}
return BTree.from(builder);
}
@Override
public ValueBackingStore openValueStore(String lane) throws PersistenceException {
final var id = this.store.laneId(this.node, lane);
final var valueBuffer = this.store.getValue(id, null);
final Value value;
if (valueBuffer == null) {
value = Value.extant();
} else {
final var parser = Recon.structureParser().parseBlock(Binary.inputBuffer(valueBuffer));
if (parser.isDone()) {
value = parser.bind();
} else {
value = Value.extant();
}
}
return this.state.openValueState(id, value);
}
@Override
public MapBackingStore openMapStore(String lane) throws PersistenceException {
final var id = this.store.laneId(this.node, lane);
final BTree contents;
try (var iterator = this.store.getMap(id)) {
contents = initMap(iterator);
}
return this.state.openMapState(id, contents);
}
@Override
public void close() {
}
}