Skip to content

Commit

Permalink
Make Etch persistence throw checked IOExceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Aug 28, 2024
1 parent ea1b1a1 commit 9f51810
Show file tree
Hide file tree
Showing 29 changed files with 194 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package convex.benchmarks;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

Expand Down Expand Up @@ -53,7 +54,7 @@ public class BigBlockBenchmark {
}

@Benchmark
public void benchmark() throws BadSignatureException {
public void benchmark() throws BadSignatureException, IOException {
BlockResult br=state.applyBlock(block);
Cells.persist(br.getState());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,22 @@ public class EtchBenchmark {
static {
try {
store =EtchStore.createTemp();
for (int i=0; i<NUMVALS; i++) {
AVector<CVMLong> v=Vectors.of(0L,(long)i);
Ref<ACell> r=v.getRef();
refs[i]=r;
r.getHash();
store.storeTopRef(r, Ref.STORED, null);
}
} catch (IOException e) {
throw new Error(e);
}
for (int i=0; i<NUMVALS; i++) {
AVector<CVMLong> v=Vectors.of(0L,(long)i);
Ref<ACell> r=v.getRef();
refs[i]=r;
r.getHash();
store.storeTopRef(r, Ref.STORED, null);
}

System.out.println("Refs stored for testing");
}

@Benchmark
public void writeData() {
public void writeData() throws IOException {
AVector<CVMLong> v=Vectors.of(1L,nonce++);
store.storeTopRef(v.getRef(), Ref.STORED, null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package convex.benchmarks;

import java.io.IOException;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
Expand All @@ -25,7 +27,11 @@ public class SignatureBenchmark {

private static SignedData<ABlob> makeSigned() {
SignedData<ABlob> signed= KEYPAIR.signData(Blobs.fromHex("cafebabe"));
Cells.persist(signed);
try {
Cells.persist(signed);
} catch (IOException e) {
throw new Error(e);
}
return signed;
}

Expand Down
5 changes: 5 additions & 0 deletions convex-cli/src/main/java/convex/cli/etch/EtchWrite.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package convex.cli.etch;

import java.io.IOException;

import convex.cli.CLIError;
import convex.core.data.ACell;
import convex.core.data.Hash;
import convex.core.data.Ref;
Expand Down Expand Up @@ -34,6 +37,8 @@ public void run() {
Hash h=Ref.get(cell).getHash();
println(h.toString());
informSuccess("Data saved with hash: "+h);
} catch (IOException e) {
throw new CLIError("Unable to write to store",e);
} finally {
store.close();
}
Expand Down
13 changes: 9 additions & 4 deletions convex-core/src/main/java/convex/core/data/Cells.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package convex.core.data;

import java.io.IOException;
import java.lang.reflect.Array;
import java.util.function.Consumer;

Expand Down Expand Up @@ -126,8 +127,9 @@ public static boolean isValue(ACell a) {
* Persist a cell in the current store
* @param a Cell to persist
* @return Cell after persisting (may be the same Cell if no change in cell hierarchy)
* @throws IOException
*/
public static <T extends ACell> T persist(T a) {
public static <T extends ACell> T persist(T a) throws IOException {
return persist(a,Stores.current());
}

Expand All @@ -136,8 +138,9 @@ public static <T extends ACell> T persist(T a) {
* @param a Cell to persist
* @param store Store instance to persist in
* @return Cell after persisting (may be the same Cell if no change in cell hierarchy)
* @throws IOException
*/
public static <T extends ACell> T persist(T a, AStore store) {
public static <T extends ACell> T persist(T a, AStore store) throws IOException {
Ref<T> ref=Ref.get(a);
Ref<T> sref=store.storeTopRef(ref, Ref.PERSISTED, null);
return sref.getValue();
Expand All @@ -148,8 +151,9 @@ public static <T extends ACell> T persist(T a, AStore store) {
* @param a Cell to persist
* @param store Store instance to persist in
* @return Cell after persisting (may be the same Cell if no change in cell hierarchy)
* @throws IOException
*/
public static <T extends ACell> T store(T a, AStore store) {
public static <T extends ACell> T store(T a, AStore store) throws IOException {
Ref<T> ref=Ref.get(a);
Ref<T> sref=store.storeTopRef(ref, Ref.STORED, null);
return sref.getValue();
Expand All @@ -160,8 +164,9 @@ public static <T extends ACell> T store(T a, AStore store) {
* @param a Cell to announce
* @param noveltyHandler Handler for novelty values
* @return Cell after announcing (may be the same Cell if no change in cell hierarchy)
* @throws IOException
*/
public static <T extends ACell> T announce(T a, Consumer<Ref<ACell>> noveltyHandler) {
public static <T extends ACell> T announce(T a, Consumer<Ref<ACell>> noveltyHandler) throws IOException {
if (a==null) {
return null; // null is never "novelty"
};
Expand Down
13 changes: 9 additions & 4 deletions convex-core/src/main/java/convex/core/data/Ref.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package convex.core.data;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.function.Consumer;
Expand Down Expand Up @@ -404,11 +405,12 @@ public boolean isMarked() {
*
* @param noveltyHandler Novelty handler to call (may be null)
* @return the persisted Ref
* @throws IOException
* @throws MissingDataException If the Ref's value does not exist or has been
* garbage collected before being persisted
*/
@SuppressWarnings("unchecked")
public <R extends ACell> Ref<R> persist(Consumer<Ref<ACell>> noveltyHandler) {
public <R extends ACell> Ref<R> persist(Consumer<Ref<ACell>> noveltyHandler) throws IOException {
int status = getStatus();
if (status >= PERSISTED) return (Ref<R>) this; // already persisted in some form
AStore store=Stores.current();
Expand All @@ -423,8 +425,9 @@ public <R extends ACell> Ref<R> persist(Consumer<Ref<ACell>> noveltyHandler) {
*
* @throws MissingDataException if the Ref cannot be fully persisted.
* @return the persisted Ref
* @throws IOException
*/
public <R extends ACell> Ref<R> persist() {
public <R extends ACell> Ref<R> persist() throws IOException {
return persist(null);
}

Expand Down Expand Up @@ -531,8 +534,9 @@ public final boolean isEmbedded() {
* Status will be updated to STORED or higher.
*
* @return Ref with status of STORED or above
* @throws IOException
*/
public <R extends ACell> Ref<R> persistShallow() {
public <R extends ACell> Ref<R> persistShallow() throws IOException {
return persistShallow(null);
}

Expand All @@ -544,9 +548,10 @@ public <R extends ACell> Ref<R> persistShallow() {
*
* @param noveltyHandler Novelty handler to call (may be null)
* @return Ref with status of STORED or above
* @throws IOException
*/
@SuppressWarnings("unchecked")
public <R extends ACell> Ref<R> persistShallow(Consumer<Ref<ACell>> noveltyHandler) {
public <R extends ACell> Ref<R> persistShallow(Consumer<Ref<ACell>> noveltyHandler) throws IOException {
AStore store=Stores.current();
return (Ref<R>) store.storeTopRef((Ref<ACell>)this, Ref.STORED, noveltyHandler);
}
Expand Down
6 changes: 4 additions & 2 deletions convex-core/src/main/java/convex/core/store/AStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ public abstract class AStore implements Closeable {
* @param status Status to store at
* @param noveltyHandler Novelty Handler function for Novelty detected. May be null.
* @return The persisted Ref, of status STORED at minimum
* @throws IOException
*/
public abstract <T extends ACell> Ref<T> storeRef(Ref<T> ref, int status,Consumer<Ref<ACell>> noveltyHandler);
public abstract <T extends ACell> Ref<T> storeRef(Ref<T> ref, int status,Consumer<Ref<ACell>> noveltyHandler) throws IOException;

/**
* Stores a top level @Ref in long term storage as defined by this store implementation.
Expand All @@ -55,8 +56,9 @@ public abstract class AStore implements Closeable {
* @param status Status to store at
* @param noveltyHandler Novelty Handler function for Novelty detected. May be null.
* @return The persisted Ref, of status STORED at minimum
* @throws IOException
*/
public abstract <T extends ACell> Ref<T> storeTopRef(Ref<T> ref, int status,Consumer<Ref<ACell>> noveltyHandler);
public abstract <T extends ACell> Ref<T> storeTopRef(Ref<T> ref, int status,Consumer<Ref<ACell>> noveltyHandler) throws IOException;


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public <T extends ACell> Ref<T> persistRef(Ref<T> ref, Consumer<Ref<ACell>> nove

// need to do recursive persistence
cell = cell.updateRefs(r -> {
return r.persist(noveltyHandler);
return persistRef(r,noveltyHandler,requiredStatus,false);
});

ref=ref.withValue((T)cell);
Expand Down
37 changes: 19 additions & 18 deletions convex-core/src/main/java/convex/etch/EtchStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,18 @@ public <T extends ACell> Ref<T> readStoreRef(Hash hash) throws IOException {
}

@Override
public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int status, Consumer<Ref<ACell>> noveltyHandler) {
public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int status, Consumer<Ref<ACell>> noveltyHandler) throws IOException {
return storeRef(ref, status, noveltyHandler, false);
}

@Override
public <T extends ACell> Ref<T> storeTopRef(Ref<T> ref, int status, Consumer<Ref<ACell>> noveltyHandler) {
public <T extends ACell> Ref<T> storeTopRef(Ref<T> ref, int status, Consumer<Ref<ACell>> noveltyHandler) throws IOException {
return storeRef(ref, status, noveltyHandler, true);
}

@SuppressWarnings("unchecked")
public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consumer<Ref<ACell>> noveltyHandler,
boolean topLevel) {
boolean topLevel) throws IOException {

// Get the value. If we are persisting, should be there!
ACell cell = ref.getValue();
Expand Down Expand Up @@ -179,7 +179,11 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume
if ((requiredStatus > Ref.STORED) && (cell.getRefCount() > 0)) {
// TODO: probably slow to rebuild these all the time!
IRefFunction func = r -> {
return storeRef((Ref<ACell>) r, requiredStatus, noveltyHandler, false);
try {
return storeRef((Ref<ACell>) r, requiredStatus, noveltyHandler, false);
} catch (IOException e) {
throw Utils.sneakyThrow(e);
}
};

// need to do recursive persistence
Expand All @@ -206,23 +210,20 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume
}

Ref<ACell> result;
try {
// ensure status is set when we write to store
ref = ref.withMinimumStatus(requiredStatus);
cell.attachRef(ref); // make sure we are using current ref within cell
result = etch.write(fHash, (Ref<ACell>) ref);

if (!embedded) {
// Ensure we have soft Refpointing to this store
result = result.toSoft(this);
}

cell.attachRef(result);
addToCache(result); // cache for subsequent writes
} catch (IOException e) {
throw Utils.sneakyThrow(e);
// ensure status is set when we write to store
ref = ref.withMinimumStatus(requiredStatus);
cell.attachRef(ref); // make sure we are using current ref within cell
result = etch.write(fHash, (Ref<ACell>) ref);

if (!embedded) {
// Ensure we have soft Refpointing to this store
result = result.toSoft(this);
}

cell.attachRef(result);
addToCache(result); // cache for subsequent writes

// call novelty handler if newly persisted non-embedded
if (noveltyHandler != null) {
if (!embedded)
Expand Down
6 changes: 4 additions & 2 deletions convex-core/src/test/java/convex/comms/GenTestFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static org.junit.Assert.assertEquals;

import java.io.IOException;

import org.junit.runner.RunWith;

import com.pholser.junit.quickcheck.From;
Expand Down Expand Up @@ -35,7 +37,7 @@ public void messageRoundTrip(String str) throws BadFormatException {
}

@Property
public void primitiveRoundTrip(@From(PrimitiveGen.class) ACell prim) throws BadFormatException {
public void primitiveRoundTrip(@From(PrimitiveGen.class) ACell prim) throws BadFormatException, IOException {
Blob b = Format.encodedBlob(prim);
if (!Format.isEmbedded(prim)) {
// persist in case large
Expand All @@ -49,7 +51,7 @@ public void primitiveRoundTrip(@From(PrimitiveGen.class) ACell prim) throws BadF
}

@Property
public void dataRoundTrip(@From(ValueGen.class) ACell value) throws BadFormatException {
public void dataRoundTrip(@From(ValueGen.class) ACell value) throws BadFormatException, IOException {
Ref<ACell> pref = Ref.get(Cells.persist(value)); // ensure persisted
Blob b = Format.encodedBlob(value);
ACell o = Format.read(b);
Expand Down
6 changes: 4 additions & 2 deletions convex-core/src/test/java/convex/core/StateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;

import org.junit.jupiter.api.Test;

import convex.core.crypto.AKeyPair;
Expand Down Expand Up @@ -53,7 +55,7 @@ public void testInitialState() throws InvalidDataException {
}

@Test
public void testRoundTrip() throws BadFormatException {
public void testRoundTrip() throws BadFormatException, IOException {
State s = INIT_STATE;

assertEquals(0,s.getRef().getStatus());
Expand Down Expand Up @@ -97,7 +99,7 @@ public void testMultiCellTrip() throws BadFormatException {
}

@SuppressWarnings("unused")
@Test public void testStateRefs() {
@Test public void testStateRefs() throws IOException {
AKeyPair kp=AKeyPair.createSeeded(578587);
State s=Init.createState(Lists.of(kp.getAccountKey()));

Expand Down
4 changes: 3 additions & 1 deletion convex-core/src/test/java/convex/core/cpos/BeliefTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package convex.core.cpos;

import java.io.IOException;

import org.junit.jupiter.api.Test;

import convex.core.Belief;
Expand Down Expand Up @@ -30,7 +32,7 @@ public class BeliefTest {
}

@SuppressWarnings("unchecked")
@Test public void testBasicBelief() throws BadFormatException {
@Test public void testBasicBelief() throws BadFormatException, IOException {
Order o=Order.create();
for (int i=0; i<PEERS; i++) {
AKeyPair kp=kps[i];
Expand Down
5 changes: 3 additions & 2 deletions convex-core/src/test/java/convex/core/data/BlobsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Random;

Expand Down Expand Up @@ -389,7 +390,7 @@ public void testEncodingSize() {
}

@Test
public void testBigBlob() throws InvalidDataException, BadFormatException {
public void testBigBlob() throws InvalidDataException, BadFormatException, IOException {
BlobTree bb = Samples.BIG_BLOB_TREE;
long len = bb.count();

Expand Down Expand Up @@ -532,7 +533,7 @@ public void testBlobEncoding() throws BadFormatException {
* Test case from issue #357, credit @jcoultas
*/
@Test
public void testLongBlobBroken() throws BadFormatException {
public void testLongBlobBroken() throws BadFormatException, IOException {
ABlob value = Blob.fromHex("f".repeat(8194)); // 4KB + 1 byte
assertEquals(value,BlobTree.create(value)); // Check equality with canonical version

Expand Down
Loading

0 comments on commit 9f51810

Please sign in to comment.