package main import ( "fmt" "git.smesh.lol/iskradb/lattice" ) func main() { testInMemory() fmt.Printf("\n--- disk-backed test ---\n") testDisk() fmt.Printf("\n--- transfer test ---\n") testTransfer() } func testInMemory() { t := lattice.NewTree(64) fmt.Printf("iskradb: %d nodes, %d records\n", t.NodeCount(), t.RecordCount()) key := lattice.HashKey([]byte("hello")) fmt.Printf("hash(hello) = %x\n", key) p1 := lattice.MakeTritPath(1, 2, 1) p2 := lattice.MakeTritPath(1, 2, 3) fmt.Printf("p1 depth=%d branch=%d\n", p1.Depth(), p1.Branch()) fmt.Printf("distance(p1,p2)=%d\n", lattice.Distance(p1, p2)) lca := lattice.LCA(p1, p2) fmt.Printf("lca depth=%d\n", lca.Depth()) resolved := lattice.Resolve(p1, 2) fmt.Printf("resolve(p1,2) depth=%d\n", resolved.Depth()) words := []string{"cat", "dog", "run", "jump", "big", "small", "eat", "fly", "red", "hot"} for _, w := range words { var rec lattice.Record rec.SetInline([]byte(w)) t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec) } fmt.Printf("after insert: %d nodes, %d records\n", t.NodeCount(), t.RecordCount()) r := t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("dog"))) if r != nil { fmt.Printf("lookup(dog) = %s\n", r.InlineData()) } var nRec, vRec, mRec lattice.Record nRec.SetInline([]byte("bird")) vRec.SetInline([]byte("flies")) mRec.SetInline([]byte("high")) t.InsertTriple( lattice.HashKey([]byte("bird")), lattice.HashKey([]byte("flies")), lattice.HashKey([]byte("high")), nRec, vRec, mRec, ) birdRI := t.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("bird"))) if birdRI != lattice.NullRec { fmt.Printf("cross-walk: ") t.CrossWalk(birdRI, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool { if r != nil && r.IsInline() { fmt.Printf("%s ", r.InlineData()) } return true }) fmt.Printf("\n") } } func testDisk() { dbPath := "/tmp/iskra_disk.db" // phase 1: create, insert, flush, close t, err := lattice.Create(dbPath) if err != nil { fmt.Printf("create error: %s\n", err) return } for i := 0; i < 100; i++ { w := fmt.Sprintf("word%04d", i) var rec lattice.Record rec.SetInline([]byte(w)) t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec) } // insert some triples for i := 0; i < 10; i++ { noun := fmt.Sprintf("noun%d", i) verb := fmt.Sprintf("verb%d", i) mod := fmt.Sprintf("mod%d", i) var nRec, vRec, mRec lattice.Record nRec.SetInline([]byte(noun)) vRec.SetInline([]byte(verb)) mRec.SetInline([]byte(mod)) t.InsertTriple( lattice.HashKey([]byte(noun)), lattice.HashKey([]byte(verb)), lattice.HashKey([]byte(mod)), nRec, vRec, mRec, ) } fmt.Printf("created: %d nodes, %d records\n", t.NodeCount(), t.RecordCount()) err = t.Close() if err != nil { fmt.Printf("close error: %s\n", err) return } // phase 2: reopen, verify lookups t, err = lattice.Open(dbPath) if err != nil { fmt.Printf("open error: %s\n", err) return } found := 0 for i := 0; i < 100; i++ { w := fmt.Sprintf("word%04d", i) r := t.Lookup(lattice.Bnoun, lattice.HashKey([]byte(w))) if r != nil && r.IsInline() && string(r.InlineData()) == w { found++ } } fmt.Printf("reopened: %d/100 words found\n", found) n5ri := t.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("noun5"))) if n5ri != lattice.NullRec { fmt.Printf("triple walk noun5: ") t.CrossWalk(n5ri, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool { if r != nil && r.IsInline() { fmt.Printf("%s ", r.InlineData()) } return true }) fmt.Printf("\n") } // phase 3: insert more, delete some, close for i := 100; i < 110; i++ { w := fmt.Sprintf("word%04d", i) var rec lattice.Record rec.SetInline([]byte(w)) t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec) } for i := 0; i < 5; i++ { w := fmt.Sprintf("word%04d", i) t.Delete(lattice.Bnoun, lattice.HashKey([]byte(w))) } fmt.Printf("after mutations: %d nodes, freeCount=%d\n", t.NodeCount(), t.FreeCount) err = t.Close() if err != nil { fmt.Printf("close error: %s\n", err) return } // phase 4: reopen, verify state t, err = lattice.Open(dbPath) if err != nil { fmt.Printf("open error: %s\n", err) return } // deleted words should be gone r := t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("word0000"))) if r == nil { fmt.Printf("word0000 after delete+reopen: NOT FOUND (correct)\n") } else { fmt.Printf("word0000 after delete+reopen: FOUND (BUG)\n") } // new words should be present r = t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("word0105"))) if r != nil && r.IsInline() { fmt.Printf("word0105 after reopen: %s\n", r.InlineData()) } else { fmt.Printf("word0105 after reopen: NOT FOUND (BUG)\n") } // compact and verify reclaimed := t.Compact() fmt.Printf("compacted: reclaimed=%d, now %d nodes\n", reclaimed, t.NodeCount()) r = t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("word0050"))) if r != nil && r.IsInline() { fmt.Printf("post-compact lookup(word0050) = %s\n", r.InlineData()) } err = t.Close() if err != nil { fmt.Printf("final close error: %s\n", err) } fmt.Printf("disk test complete\n") } func testTransfer() { t := lattice.NewTree(256) for i := 0; i < 50; i++ { w := fmt.Sprintf("n%d", i) var rec lattice.Record rec.SetInline([]byte(w)) t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec) } for i := 0; i < 10; i++ { noun := fmt.Sprintf("t_noun%d", i) verb := fmt.Sprintf("t_verb%d", i) mod := fmt.Sprintf("t_mod%d", i) var nRec, vRec, mRec lattice.Record nRec.SetInline([]byte(noun)) vRec.SetInline([]byte(verb)) mRec.SetInline([]byte(mod)) t.InsertTriple( lattice.HashKey([]byte(noun)), lattice.HashKey([]byte(verb)), lattice.HashKey([]byte(mod)), nRec, vRec, mRec, ) } fmt.Printf("source: %d nodes, %d records\n", t.NodeCount(), t.RecordCount()) // 1. ExtractBranch - noun branch only sl := t.ExtractBranch(lattice.Bnoun) fmt.Printf("extract branch noun: %d nodes, %d records\n", sl.Tree.NodeCount(), sl.Tree.RecordCount()) r := sl.Tree.Lookup(lattice.Bnoun, lattice.HashKey([]byte("n25"))) if r != nil && r.IsInline() { fmt.Printf(" lookup(n25) = %s\n", r.InlineData()) } else { fmt.Printf(" lookup(n25) = NOT FOUND (BUG)\n") } // 2. ExtractLinked - follow cross-branch links from t_noun5 n5ri := t.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5"))) linked := t.ExtractLinked(n5ri) fmt.Printf("extract linked t_noun5: %d records\n", linked.Tree.RecordCount()) lri := linked.Tree.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5"))) if lri != lattice.NullRec { fmt.Printf(" cross-walk: ") linked.Tree.CrossWalk(lri, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool { if r != nil && r.IsInline() { fmt.Printf("%s ", r.InlineData()) } return true }) fmt.Printf("\n") } else { fmt.Printf(" t_noun5 NOT FOUND in extract (BUG)\n") } // 3. SaveFile/LoadFile round-trip slPath := "/tmp/iskra_sub.iskr" err := linked.SaveFile(slPath) if err != nil { fmt.Printf(" save error: %s\n", err) return } loaded, err := lattice.LoadSubLattice(slPath) if err != nil { fmt.Printf(" load error: %s\n", err) return } loadedRI := loaded.Tree.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5"))) if loadedRI != lattice.NullRec { fmt.Printf(" round-trip cross-walk: ") loaded.Tree.CrossWalk(loadedRI, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool { if r != nil && r.IsInline() { fmt.Printf("%s ", r.InlineData()) } return true }) fmt.Printf("\n") } else { fmt.Printf(" round-trip t_noun5 NOT FOUND (BUG)\n") } // 4. Graft into fresh tree dst := lattice.NewTree(64) grafted := dst.Graft(linked) fmt.Printf("graft into empty: inserted=%d, records=%d\n", grafted, dst.RecordCount()) gri := dst.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5"))) if gri != lattice.NullRec { fmt.Printf(" graft cross-walk: ") dst.CrossWalk(gri, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool { if r != nil && r.IsInline() { fmt.Printf("%s ", r.InlineData()) } return true }) fmt.Printf("\n") } else { fmt.Printf(" graft t_noun5 NOT FOUND (BUG)\n") } // 5. Graft with overlap - dedup test beforeRecs := dst.RecordCount() deduped := dst.Graft(linked) fmt.Printf("graft overlap: inserted=%d (should be 0), records before=%d after=%d\n", deduped, beforeRecs, dst.RecordCount()) if dst.RecordCount() == beforeRecs { fmt.Printf(" dedup: correct\n") } else { fmt.Printf(" dedup: FAILED - records grew (BUG)\n") } }