Skip to content

Commit

Permalink
More DLFS based refactoring and GUI updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Apr 17, 2024
1 parent 1bb0299 commit f5c484e
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 62 deletions.
6 changes: 3 additions & 3 deletions convex-core/src/main/java/convex/core/data/ACell.java
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ public void attachMemorySize(long memorySize) {
this.memorySize=memorySize;
assert (this.memorySize>0) : "Attempting to attach memory size "+memorySize+" to object of class "+Utils.getClassName(this);
} else {
assert (this.memorySize==memorySize) : "Attempting to attach memory size "+memorySize+" to object of class "+Utils.getClassName(this)+" which already has memorySize "+this.memorySize;
assert (this.memorySize==memorySize) : "Trying to change memory size to "+memorySize+" with object of class "+Utils.getClassName(this)+" which already has memorySize "+this.memorySize;
}
}

Expand All @@ -512,10 +512,10 @@ public void attachRef(Ref<?> ref) {
* complete Cell can be represented in a single encoding.
* @return true if completely encoded, false otherwise
*/
public boolean isCompletelyEncoded() {
boolean isCompletelyEncoded() {
if (memorySize==Format.FULL_EMBEDDED_MEMORY_SIZE) return true; // fast path for fully embedded
if (!isCanonical()) {
throw new Error("Checking whether a non-canonical cell is encoded. Not a good idea, any ref assumptions may be invalid: "+this.getType());
throw new Error("Checking whether a non-canonical cell is encoded. Not a good idea: any Ref assumptions may be invalid for "+this.getType());
}
int n=getRefCount();
for (int i=0; i<n; i++) {
Expand Down
10 changes: 10 additions & 0 deletions convex-core/src/main/java/convex/core/data/Cells.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ public static boolean isCVM(ACell a) {
return a.isCVMValue();
}

/**
* Checks if a Cell is completely encoded, i.e. has not external Refs
* @param a Cell to check
* @return True if completely encoded, false otherwise
*/
public static boolean isCompletelyEncoded(ACell a) {
if (a==null) return true;
return a.isCompletelyEncoded();
}

/**
* Checks if a Cell is a first class value
* @param a Cell to check
Expand Down
2 changes: 1 addition & 1 deletion convex-core/src/main/java/convex/dlfs/DLFS.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static DLFSProvider provider() {
return PROVIDER;
}

public static DLFileSystem createLocal() {
public static DLFSLocal createLocal() {
return DLFSLocal.create(provider());
}

Expand Down
8 changes: 8 additions & 0 deletions convex-core/src/main/java/convex/dlfs/DLFileSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import convex.core.data.Cells;
import convex.core.data.Hash;
import convex.core.data.prim.CVMLong;
import convex.core.util.Utils;
import convex.dlfs.impl.DLDirectoryStream;
import convex.dlfs.impl.DLFSFileAttributes;

Expand Down Expand Up @@ -86,6 +87,13 @@ public synchronized CVMLong updateTimestamp(long newTimestamp) {
}
return timestamp;
}

/**
* Updates the timestamp of the drive to the current system timestamp
*/
public synchronized CVMLong updateTimestamp() {
return updateTimestamp(Utils.getCurrentTimestamp());
}

@Override
public boolean isOpen() {
Expand Down
2 changes: 1 addition & 1 deletion convex-core/src/main/java/convex/dlfs/impl/DLFSLocal.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public DLFSLocal(DLFSProvider dlfsProvider, String uriPath, AVector<ACell> rootN
this.rootNode=rootNode;
}

public static DLFileSystem create(DLFSProvider provider) {
public static DLFSLocal create(DLFSProvider provider) {
return new DLFSLocal(provider,null,DLFSNode.createDirectory(CVMLong.ZERO));
}

Expand Down
104 changes: 58 additions & 46 deletions convex-core/src/main/java/etch/EtchStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,40 @@ public class EtchStore extends AStore {
* Etch file instance for the current store
*/
private Etch etch;

/**
* Etch file instance for GC destination
*/
private Etch target;

public EtchStore(Etch etch) {
this.etch = etch;
this.target=null;
this.target = null;
etch.setStore(this);
}

/**
* Starts a GC cycle. Creates a new Etch file for collection, and directs all new writes to
* the new store
* Starts a GC cycle. Creates a new Etch file for collection, and directs all
* new writes to the new store
*
* @throws IOException If an IO exception occurs
*/
public synchronized void startGC() throws IOException {
if (target!=null) throw new Error("Already collecting!");
File temp=new File(etch.getFile().getCanonicalPath()+"~");
target=Etch.create(temp);

if (target != null)
throw new Error("Already collecting!");
File temp = new File(etch.getFile().getCanonicalPath() + "~");
target = Etch.create(temp);

// copy across current root hash
target.setRootHash(etch.getRootHash());
}

private Etch getWriteEtch() {
if (target!=null) synchronized(this) {
if (target!=null) return target;
}
if (target != null)
synchronized (this) {
if (target != null)
return target;
}
return etch;
}

Expand All @@ -75,7 +79,7 @@ private Etch getWriteEtch() {
* @throws IOException If an IO error occurs
*/
public static EtchStore create(File file) throws IOException {
file=Utils.ensurePath(file);
file = Utils.ensurePath(file);
Etch etch = Etch.create(file);
return new EtchStore(etch);
}
Expand Down Expand Up @@ -114,19 +118,22 @@ public static EtchStore createTemp() {
public <T extends ACell> Ref<T> refForHash(Hash hash) {
try {
Ref<ACell> existing = (Ref<ACell>) refCache.getCell(hash);
if (existing!=null) return (Ref<T>) existing;

if (hash==Hash.NULL_HASH) return (Ref<T>) Ref.NULL_VALUE;
existing= readStoreRef(hash);
if (existing != null)
return (Ref<T>) existing;

if (hash == Hash.NULL_HASH)
return (Ref<T>) Ref.NULL_VALUE;
existing = readStoreRef(hash);
return (Ref<T>) existing;
} catch (IOException e) {
throw Utils.sneakyThrow(e);
}
}

public <T extends ACell> Ref<T> readStoreRef(Hash hash) throws IOException {
Ref<T> ref=etch.read(hash);
if (ref!=null) refCache.putCell(ref);
Ref<T> ref = etch.read(hash);
if (ref != null)
refCache.putCell(ref);
return ref;
}

Expand All @@ -145,17 +152,18 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume
boolean topLevel) {
// TODO: remove this?, probably dangerous if in different store
// first check if the Ref is already persisted to required level
//if (ref.getStatus() >= requiredStatus) {
// // we are done as long as not top level
// if (!topLevel) return ref;
//}
// if (ref.getStatus() >= requiredStatus) {
// // we are done as long as not top level
// if (!topLevel) return ref;
// }

// Get the value. If we are persisting, should be there!
ACell cell = ref.getValue();

// Quick handling for null
if (cell == null) return (Ref<T>) Ref.NULL_VALUE;

if (cell == null)
return (Ref<T>) Ref.NULL_VALUE;

// check store for existing ref first.
boolean embedded = cell.isEmbedded();
Hash hash = null;
Expand All @@ -170,16 +178,16 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume
}
}
}
if (requiredStatus<Ref.STORED) {

if (requiredStatus < Ref.STORED) {
if (topLevel || !embedded) {
addToCache(ref);
}
return ref;
}

// beyond STORED level, need to recursively persist child refs if they exist
if ((requiredStatus > Ref.STORED)&&(cell.getRefCount()>0)) {
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);
Expand All @@ -191,21 +199,21 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume

// perhaps need to update Ref
if (cell != newObject) {

ref = ref.withValue((T) newObject);
cell=newObject;
cell = newObject;
cell.attachRef(ref); // make sure we are using current ref within new cell
}
}

// Actually write top level an non-embedded cells only
if (topLevel || !embedded) {

// Do actual write to store
final Hash fHash = (hash != null) ? hash : ref.getHash();
if (log.isTraceEnabled()) {
log.trace( "Etch persisting at status=" + requiredStatus + " hash = 0x"
+ fHash.toHexString() + " ref of class " + Utils.getClassName(cell) + " with store " + this);
log.trace("Etch persisting at status=" + requiredStatus + " hash = 0x" + fHash.toHexString()
+ " ref of class " + Utils.getClassName(cell) + " with store " + this);
}

Ref<ACell> result;
Expand All @@ -214,10 +222,10 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume
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);
result = result.toSoft(this);
}

cell.attachRef(result);
Expand All @@ -228,12 +236,13 @@ public <T extends ACell> Ref<T> storeRef(Ref<T> ref, int requiredStatus, Consume

// call novelty handler if newly persisted non-embedded
if (noveltyHandler != null) {
if (!embedded) noveltyHandler.accept(result);
if (!embedded)
noveltyHandler.accept(result);
}
return (Ref<T>) result;
} else {
// no need to write, just tag updated status
ref= ref.withMinimumStatus(requiredStatus);
ref = ref.withMinimumStatus(requiredStatus);
cell.attachRef(ref);
return ref;
}
Expand Down Expand Up @@ -263,12 +272,14 @@ public void close() {

/**
* Ensure the store is fully persisted to disk
*
* @throws IOException If an IO error occurs
*/
public void flush() throws IOException {
public void flush() throws IOException {
etch.flush();
Etch target=this.target;
if (target!=null) target.flush();
Etch target = this.target;
if (target != null)
target.flush();
}

public File getFile() {
Expand All @@ -283,16 +294,17 @@ public Hash getRootHash() throws IOException {
@Override
public <T extends ACell> Ref<T> setRootData(T data) throws IOException {
// Ensure data if persisted at sufficient level
Ref<T> ref=storeTopRef(data.getRef(), Ref.PERSISTED,null);
Hash h=ref.getHash();
Etch etch=getWriteEtch();
Ref<T> ref = storeTopRef(data.getRef(), Ref.PERSISTED, null);
Hash h = ref.getHash();
Etch etch = getWriteEtch();
etch.setRootHash(h);
etch.writeDataLength(); // ensure data length updated for root data addition
return ref;
}

/**
* Gets the underlying Etch instance
*
* @return Etch instance
*/
public Etch getEtch() {
Expand Down
9 changes: 5 additions & 4 deletions convex-core/src/test/java/convex/core/TransactionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import convex.core.data.AVector;
import convex.core.data.Address;
import convex.core.data.Cells;
import convex.core.data.RecordTest;
import convex.core.data.SignedData;
import convex.core.data.Vectors;
Expand Down Expand Up @@ -70,7 +71,7 @@ public void testTransfer() {
assertEquals(AMT+expectedFees,balanceDrop);

// We expect a Transfer to be completely encoded
assertTrue(t1.isCompletelyEncoded());
assertTrue(Cells.isCompletelyEncoded(t1));

doTransactionTests(t1);
}
Expand Down Expand Up @@ -203,8 +204,8 @@ public void testCall() {
assertCVMEquals(7,rc2.getResult());


// We expect a short call to be completely encoded
assertTrue(t1.isCompletelyEncoded());
// We expect a short call transaction to be completely encoded
assertTrue(Cells.isCompletelyEncoded(t1));

doTransactionTests(t1);
doTransactionTests(t2);
Expand All @@ -218,7 +219,7 @@ public void testInvoke() {
assertEquals(CVMLong.create(7),ctx.getResult());

// We expect a short Invoke to be completely encoded
assertTrue(t1.isCompletelyEncoded());
assertTrue(Cells.isCompletelyEncoded(t1));

doTransactionTests(t1);
}
Expand Down
4 changes: 2 additions & 2 deletions convex-core/src/test/java/convex/store/StoresTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ public class StoresTest {
// non-emebdded single Cell
AString nv=Samples.NON_EMBEDDED_STRING;
assertFalse(nv.isEmbedded());
assertTrue(nv.isCompletelyEncoded());
assertTrue(Cells.isCompletelyEncoded(nv));

// small fully embedded cell
CVMLong ev=CVMLong.ONE;
assertTrue(ev.isEmbedded());
assertTrue(ev.isCompletelyEncoded());
assertTrue(Cells.isCompletelyEncoded(ev));

AVector<?> v=Vectors.of(Vectors.of(nv,ev),nv,ev);

Expand Down
3 changes: 2 additions & 1 deletion convex-core/src/test/java/examples/EncodingTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package examples;

import convex.core.data.AVector;
import convex.core.data.Cells;
import convex.core.data.Vectors;
import convex.core.data.prim.CVMLong;

Expand All @@ -14,7 +15,7 @@ public static void main(String... args) {
}

System.out.println(v.toString());
System.out.println("Complete encoded: "+v.isCompletelyEncoded());
System.out.println("Complete encoded: "+Cells.isCompletelyEncoded(v));
System.out.println("Embedded: "+v.isEmbedded());
System.out.println("Encoding Length: "+v.getEncodingLength());
}
Expand Down
Loading

0 comments on commit f5c484e

Please sign in to comment.