package peergos.shared.storage;
import peergos.shared.cbor.*;
import peergos.shared.crypto.asymmetric.*;
import peergos.shared.io.ipfs.multihash.*;
import peergos.shared.util.*;
import java.util.*;
import java.util.concurrent.*;
public class CachingStorage implements ContentAddressedStorage {
private final ContentAddressedStorage target;
private final LRUCache<Multihash, byte[]> cache;
private final LRUCache<Multihash, CompletableFuture<Optional<CborObject>>> pending;
private final int maxValueSize;
public CachingStorage(ContentAddressedStorage target, int cacheSize, int maxValueSize) {
this.target = target;
this.cache = new LRUCache<>(cacheSize);
this.maxValueSize = maxValueSize;
this.pending = new LRUCache<>(100);
}
@Override
public CompletableFuture<List<Multihash>> put(PublicSigningKey writer, List<byte[]> blocks) {
return target.put(writer, blocks);
}
@Override
public CompletableFuture<Optional<CborObject>> get(Multihash key) {
if (cache.containsKey(key))
return CompletableFuture.completedFuture(Optional.of(CborObject.fromByteArray(cache.get(key))));
if (pending.containsKey(key))
return pending.get(key);
CompletableFuture<Optional<CborObject>> pipe = new CompletableFuture<>();
pending.put(key, pipe);
return target.get(key).thenApply(cborOpt -> {
if (cborOpt.isPresent()) {
byte[] value = cborOpt.get().toByteArray();
if (value.length > 0 && value.length < maxValueSize)
cache.put(key, value);
}
pending.remove(key);
pipe.complete(cborOpt);
return cborOpt;
});
}
@Override
public CompletableFuture<List<Multihash>> recursivePin(Multihash h) {
return target.recursivePin(h);
}
@Override
public CompletableFuture<List<Multihash>> recursiveUnpin(Multihash h) {
return target.recursiveUnpin(h);
}
@Override
public CompletableFuture<List<Multihash>> getLinks(Multihash root) {
return target.getLinks(root);
}
@Override
public CompletableFuture<Optional<Integer>> getSize(Multihash block) {
return target.getSize(block);
}
}