no.ssb.lds.api.persistence.flattened.DefaultFlattenedPersistence Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of linked-data-store-persistence-provider-api Show documentation
Show all versions of linked-data-store-persistence-provider-api Show documentation
LinkedDataStore Persistence Provider API
package no.ssb.lds.api.persistence.flattened;
import no.ssb.lds.api.persistence.PersistenceDeletePolicy;
import no.ssb.lds.api.persistence.PersistenceException;
import no.ssb.lds.api.persistence.Transaction;
import no.ssb.lds.api.persistence.TransactionFactory;
import no.ssb.lds.api.persistence.streaming.Fragment;
import no.ssb.lds.api.persistence.streaming.FragmentType;
import no.ssb.lds.api.persistence.streaming.Persistence;
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Flow;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
public class DefaultFlattenedPersistence implements FlattenedPersistence {
final Persistence persistence;
final int fragmentValueCapacityBytes;
public DefaultFlattenedPersistence(Persistence persistence, int fragmentValueCapacityBytes) {
this.persistence = persistence;
this.fragmentValueCapacityBytes = fragmentValueCapacityBytes;
}
@Override
public TransactionFactory transactionFactory() throws PersistenceException {
return persistence.transactionFactory();
}
@Override
public Transaction createTransaction(boolean readOnly) throws PersistenceException {
return persistence.createTransaction(readOnly);
}
@Override
public CompletableFuture createOrOverwrite(Transaction transaction, FlattenedDocument document) throws PersistenceException {
return persistence.createOrOverwrite(transaction, subscriber -> subscriber.onSubscribe(new Flow.Subscription() {
final AtomicLong budget = new AtomicLong();
final Iterator fragmentIterator = document.fragmentIterator();
final AtomicBoolean reEntryGuard = new AtomicBoolean(false);
@Override
public void request(long n) {
if (budget.getAndAdd(n) < 0) {
budget.getAndIncrement(); // return stolen budget
}
if (!reEntryGuard.compareAndSet(false, true)) {
return; // re-entry protection
}
try {
while (fragmentIterator.hasNext()) {
if (budget.getAndDecrement() > 0) {
subscriber.onNext(fragmentIterator.next());
} else {
return;// budget stolen, will be retured upon next request
}
}
// iterator exhausted
subscriber.onComplete();
} finally {
reEntryGuard.set(false);
}
}
@Override
public void cancel() {
// TODO stop fragmentIterator and signal subscriber
}
}));
}
public CompletableFuture read(Transaction transaction, ZonedDateTime snapshot, String namespace, String entity, String id) throws PersistenceException {
Flow.Publisher publisher = persistence.read(transaction, snapshot, namespace, entity, id);
CompletableFuture iteratorCompletableFuture = new CompletableFuture<>();
publisher.subscribe(new BufferedFragmentSubscriber(iteratorCompletableFuture, fragmentValueCapacityBytes, null, null, 1));
return iteratorCompletableFuture;
}
public CompletableFuture readVersions(Transaction transaction, ZonedDateTime snapshotFrom, ZonedDateTime snapshotTo, String namespace, String entity, String id, ZonedDateTime firstVersion, int limit) throws PersistenceException {
Flow.Publisher publisher = persistence.readVersions(transaction, snapshotFrom, snapshotTo, namespace, entity, id, firstVersion, limit);
CompletableFuture iteratorCompletableFuture = new CompletableFuture<>();
publisher.subscribe(new BufferedFragmentSubscriber(iteratorCompletableFuture, fragmentValueCapacityBytes, null, null, limit));
return iteratorCompletableFuture;
}
public CompletableFuture readAllVersions(Transaction transaction, String namespace, String entity, String id, ZonedDateTime firstVersion, int limit) throws PersistenceException {
Flow.Publisher publisher = persistence.readAllVersions(transaction, namespace, entity, id, firstVersion, Integer.MAX_VALUE);
CompletableFuture iteratorCompletableFuture = new CompletableFuture<>();
publisher.subscribe(new BufferedFragmentSubscriber(iteratorCompletableFuture, fragmentValueCapacityBytes, null, null, limit));
return iteratorCompletableFuture;
}
public CompletableFuture delete(Transaction transaction, String namespace, String entity, String id, ZonedDateTime version, PersistenceDeletePolicy policy) throws PersistenceException {
return persistence.delete(transaction, namespace, entity, id, version, policy);
}
public CompletableFuture deleteAllVersions(Transaction transaction, String namespace, String entity, String id, PersistenceDeletePolicy policy) throws PersistenceException {
return persistence.deleteAllVersions(transaction, namespace, entity, id, policy);
}
public CompletableFuture markDeleted(Transaction transaction, String namespace, String entity, String id, ZonedDateTime version, PersistenceDeletePolicy policy) throws PersistenceException {
return persistence.markDeleted(transaction, namespace, entity, id, version, policy);
}
public CompletableFuture findAll(Transaction transaction, ZonedDateTime snapshot, String namespace, String entity, String firstId, int limit) throws PersistenceException {
Flow.Publisher publisher = persistence.findAll(transaction, snapshot, namespace, entity, firstId, Integer.MAX_VALUE);
CompletableFuture iteratorCompletableFuture = new CompletableFuture<>();
publisher.subscribe(new BufferedFragmentSubscriber(iteratorCompletableFuture, fragmentValueCapacityBytes, null, null, limit));
return iteratorCompletableFuture;
}
public CompletableFuture find(Transaction transaction, ZonedDateTime snapshot, String namespace, String entity, String path, Object value, String firstId, int limit) throws PersistenceException {
// TODO support stronger typing of value
Map valueByOffset = FlattenedDocumentLeafNode.valueByOffset(FragmentType.STRING, fragmentValueCapacityBytes, (String) value);
byte[] bytesValue = valueByOffset.get(0);
Flow.Publisher publisher = persistence.find(transaction, snapshot, namespace, entity, path, bytesValue, firstId, Integer.MAX_VALUE);
CompletableFuture iteratorCompletableFuture = new CompletableFuture<>();
publisher.subscribe(new BufferedFragmentSubscriber(iteratorCompletableFuture, fragmentValueCapacityBytes, path, (String) value, limit));
return iteratorCompletableFuture;
}
public void close() throws PersistenceException {
persistence.close();
}
}