Skip to content

Commit d385a78

Browse files
committed
Add demo class
1 parent a9a7062 commit d385a78

1 file changed

Lines changed: 173 additions & 0 deletions

File tree

  • convex-core/src/test/java/convex/lattice
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package convex.lattice;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
6+
import convex.core.data.ACell;
7+
import convex.core.data.AMap;
8+
import convex.core.data.Hash;
9+
import convex.core.data.Index;
10+
import convex.core.data.Maps;
11+
import convex.core.data.MapEntry;
12+
import convex.core.data.impl.LongBlob;
13+
import convex.core.data.AString;
14+
import convex.core.data.Strings;
15+
import convex.core.lang.RT;
16+
import convex.core.util.JSON;
17+
import convex.etch.EtchStore;
18+
import convex.lattice.cursor.Cursors;
19+
import convex.lattice.cursor.PathCursor;
20+
import convex.lattice.cursor.Root;
21+
22+
/**
23+
* Simple demonstration of using an EtchStore together with lattice cursors.
24+
* <p>
25+
* The demo:
26+
* <ul>
27+
* <li>Creates a temporary Etch database file.</li>
28+
* <li>Creates a root cursor whose value contains a {@code /db/users} path.</li>
29+
* <li>Populates 10,000 test user records under {@code /db/users} as an
30+
* {@link Index} mapping {@link Hash} user IDs to user records.</li>
31+
* <li>Persists the final cursor value as the Etch database root.</li>
32+
* </ul>
33+
*/
34+
public class Demo {
35+
36+
// Interned CVM Strings for well-known keys / paths
37+
private static final AString KEY_USER_ID = Strings.intern("user-id");
38+
private static final AString KEY_FAMILY = Strings.intern("family");
39+
private static final AString KEY_EMAIL = Strings.intern("email");
40+
private static final AString KEY_BIRTHDATE = Strings.intern("birthdate");
41+
private static final AString KEY_CREATED_AT = Strings.intern("created-at");
42+
private static final AString KEY_DB = Strings.intern("db");
43+
private static final AString KEY_USERS = Strings.intern("users");
44+
45+
/**
46+
* Run the demo.
47+
*
48+
* @param args Command-line arguments (ignored)
49+
* @throws IOException If an IO error occurs working with the Etch store
50+
*/
51+
public static void main(String[] args) throws IOException {
52+
long startTime = System.currentTimeMillis();
53+
System.out.println("Demo starting at " + startTime + " ms");
54+
55+
// 1. Create an EtchStore backed by a temporary file
56+
EtchStore store = EtchStore.createTemp("lattice-demo");
57+
System.out.println("Created EtchStore at: " + store.getFileName());
58+
59+
// 2. Create a root cursor with an initial structure containing /db/users
60+
// /db is a map; /db/users is an Index<LongBlob, ACell> that will hold user records.
61+
Index<LongBlob, ACell> emptyUsersIndex = Index.none();
62+
AMap<ACell, ACell> initialDb = Maps.of(
63+
KEY_USERS, emptyUsersIndex
64+
);
65+
AMap<ACell, ACell> initialRootMap = Maps.of(
66+
KEY_DB, initialDb
67+
);
68+
69+
Root<ACell> rootCursor = Cursors.create(RT.cvm(initialRootMap));
70+
71+
// 3. Create a cursor focused on the /db/users path
72+
PathCursor<Index<LongBlob, ACell>> usersCursor = new PathCursor<>(
73+
rootCursor,
74+
KEY_DB,
75+
KEY_USERS
76+
);
77+
78+
Index<LongBlob, ACell> snapshot=null;
79+
ArrayList<Index<LongBlob, ACell>> snapshots=new ArrayList<>();
80+
81+
82+
// 4. Populate 10,000 test user records:
83+
// Each record is a map with:
84+
// - user-id : Hash (the index key)
85+
// - family : family name (String)
86+
// - email : email address (String)
87+
// - birthdate: birth date (String)
88+
int nUsers = 10_000;
89+
for (int i = 0; i < nUsers; i++) {
90+
// Derive a deterministic userID LongBlob from the loop index
91+
LongBlob userId = LongBlob.create(i);
92+
93+
AMap<ACell, ACell> userRecord = createTestUser(userId, i);
94+
95+
// Update the /db/users index: userID -> userRecord
96+
usersCursor.updateAndGet(currentIndex -> {
97+
Index<LongBlob, ACell> idx = currentIndex;
98+
return idx.assoc(userId, userRecord);
99+
});
100+
if (i==nUsers/2) {
101+
snapshot=usersCursor.get();
102+
}
103+
snapshots.add(usersCursor.get());
104+
}
105+
106+
System.out.println("Users in snapshot: "+snapshot.count());
107+
108+
System.out.println("Added " + nUsers + " user records under /db/users");
109+
110+
// 5. Persist the cursor value to the Etch DB root
111+
ACell finalRootValue = rootCursor.get();
112+
store.setRootData(finalRootValue);
113+
store.flush();
114+
115+
System.out.println("Persisted root value to Etch store.");
116+
Hash rootHash = store.getRootHash();
117+
System.out.println("Root hash: " + rootHash);
118+
119+
// Keep a reference to the underlying file so we can reopen the store
120+
java.io.File etchFile = store.getFile();
121+
122+
store.close();
123+
124+
// 6. Reload the root value from the Etch database
125+
EtchStore reopenedStore = EtchStore.create(etchFile);
126+
Hash reopenedRootHash = reopenedStore.getRootHash();
127+
ACell reloadedRoot = reopenedStore.refForHash(reopenedRootHash).getValue();
128+
129+
// Recreate a cursor from the reloaded root value
130+
Root<ACell> reloadedRootCursor = Cursors.create(reloadedRoot);
131+
PathCursor<Index<LongBlob, ACell>> reloadedUsersCursor = new PathCursor<>(
132+
reloadedRootCursor,
133+
KEY_DB,
134+
KEY_USERS
135+
);
136+
137+
Index<LongBlob, ACell> reloadedUsersIndex = reloadedUsersCursor.get();
138+
if (reloadedUsersIndex != null && reloadedUsersIndex.count() > 0) {
139+
long lastIx = reloadedUsersIndex.count() - 1;
140+
141+
MapEntry<LongBlob, ACell> lastEntry = reloadedUsersIndex.entryAt(lastIx);
142+
System.out.println("Last user key : " + lastEntry.getKey());
143+
System.out.println("Last user value: " + JSON.toStringPretty(lastEntry.getValue()));
144+
} else {
145+
System.out.println("No users found after reload.");
146+
}
147+
148+
System.out.println("Total size: " + reloadedRootCursor.get().getMemorySize());
149+
150+
151+
reopenedStore.close();
152+
153+
long endTime = System.currentTimeMillis();
154+
long duration = endTime - startTime;
155+
System.out.println("Demo finished at " + endTime + " ms");
156+
System.out.println("Total execution time: " + duration + " ms");
157+
158+
// lattice.merge(rootCurstor,remoteCursorValue)
159+
}
160+
161+
private static AMap<ACell, ACell> createTestUser(LongBlob userId, int index) {
162+
long createdAt = System.currentTimeMillis();
163+
164+
return Maps.of(
165+
KEY_USER_ID, userId,
166+
KEY_FAMILY, Strings.create("User-" + index),
167+
KEY_EMAIL, Strings.create("user" + index + "@example.com"),
168+
KEY_BIRTHDATE, Strings.create("1970-01-01"),
169+
KEY_CREATED_AT, RT.cvm(createdAt)
170+
);
171+
}
172+
}
173+

0 commit comments

Comments
 (0)