main.mx raw

   1  package main
   2  
   3  import (
   4  	"fmt"
   5  	"git.smesh.lol/iskradb/lattice"
   6  )
   7  
   8  func main() {
   9  	testInMemory()
  10  	fmt.Printf("\n--- disk-backed test ---\n")
  11  	testDisk()
  12  	fmt.Printf("\n--- transfer test ---\n")
  13  	testTransfer()
  14  }
  15  
  16  func testInMemory() {
  17  	t := lattice.NewTree(64)
  18  	fmt.Printf("iskradb: %d nodes, %d records\n", t.NodeCount(), t.RecordCount())
  19  
  20  	key := lattice.HashKey([]byte("hello"))
  21  	fmt.Printf("hash(hello) = %x\n", key)
  22  
  23  	p1 := lattice.MakeTritPath(1, 2, 1)
  24  	p2 := lattice.MakeTritPath(1, 2, 3)
  25  	fmt.Printf("p1 depth=%d branch=%d\n", p1.Depth(), p1.Branch())
  26  	fmt.Printf("distance(p1,p2)=%d\n", lattice.Distance(p1, p2))
  27  	lca := lattice.LCA(p1, p2)
  28  	fmt.Printf("lca depth=%d\n", lca.Depth())
  29  	resolved := lattice.Resolve(p1, 2)
  30  	fmt.Printf("resolve(p1,2) depth=%d\n", resolved.Depth())
  31  
  32  	words := []string{"cat", "dog", "run", "jump", "big", "small", "eat", "fly", "red", "hot"}
  33  	for _, w := range words {
  34  		var rec lattice.Record
  35  		rec.SetInline([]byte(w))
  36  		t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec)
  37  	}
  38  	fmt.Printf("after insert: %d nodes, %d records\n", t.NodeCount(), t.RecordCount())
  39  
  40  	r := t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("dog")))
  41  	if r != nil {
  42  		fmt.Printf("lookup(dog) = %s\n", r.InlineData())
  43  	}
  44  
  45  	var nRec, vRec, mRec lattice.Record
  46  	nRec.SetInline([]byte("bird"))
  47  	vRec.SetInline([]byte("flies"))
  48  	mRec.SetInline([]byte("high"))
  49  	t.InsertTriple(
  50  		lattice.HashKey([]byte("bird")),
  51  		lattice.HashKey([]byte("flies")),
  52  		lattice.HashKey([]byte("high")),
  53  		nRec, vRec, mRec,
  54  	)
  55  
  56  	birdRI := t.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("bird")))
  57  	if birdRI != lattice.NullRec {
  58  		fmt.Printf("cross-walk: ")
  59  		t.CrossWalk(birdRI, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool {
  60  			if r != nil && r.IsInline() {
  61  				fmt.Printf("%s ", r.InlineData())
  62  			}
  63  			return true
  64  		})
  65  		fmt.Printf("\n")
  66  	}
  67  }
  68  
  69  func testDisk() {
  70  	dbPath := "/tmp/iskra_disk.db"
  71  
  72  	// phase 1: create, insert, flush, close
  73  	t, err := lattice.Create(dbPath)
  74  	if err != nil {
  75  		fmt.Printf("create error: %s\n", err)
  76  		return
  77  	}
  78  	for i := 0; i < 100; i++ {
  79  		w := fmt.Sprintf("word%04d", i)
  80  		var rec lattice.Record
  81  		rec.SetInline([]byte(w))
  82  		t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec)
  83  	}
  84  	// insert some triples
  85  	for i := 0; i < 10; i++ {
  86  		noun := fmt.Sprintf("noun%d", i)
  87  		verb := fmt.Sprintf("verb%d", i)
  88  		mod := fmt.Sprintf("mod%d", i)
  89  		var nRec, vRec, mRec lattice.Record
  90  		nRec.SetInline([]byte(noun))
  91  		vRec.SetInline([]byte(verb))
  92  		mRec.SetInline([]byte(mod))
  93  		t.InsertTriple(
  94  			lattice.HashKey([]byte(noun)),
  95  			lattice.HashKey([]byte(verb)),
  96  			lattice.HashKey([]byte(mod)),
  97  			nRec, vRec, mRec,
  98  		)
  99  	}
 100  	fmt.Printf("created: %d nodes, %d records\n", t.NodeCount(), t.RecordCount())
 101  	err = t.Close()
 102  	if err != nil {
 103  		fmt.Printf("close error: %s\n", err)
 104  		return
 105  	}
 106  
 107  	// phase 2: reopen, verify lookups
 108  	t, err = lattice.Open(dbPath)
 109  	if err != nil {
 110  		fmt.Printf("open error: %s\n", err)
 111  		return
 112  	}
 113  	found := 0
 114  	for i := 0; i < 100; i++ {
 115  		w := fmt.Sprintf("word%04d", i)
 116  		r := t.Lookup(lattice.Bnoun, lattice.HashKey([]byte(w)))
 117  		if r != nil && r.IsInline() && string(r.InlineData()) == w {
 118  			found++
 119  		}
 120  	}
 121  	fmt.Printf("reopened: %d/100 words found\n", found)
 122  
 123  	n5ri := t.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("noun5")))
 124  	if n5ri != lattice.NullRec {
 125  		fmt.Printf("triple walk noun5: ")
 126  		t.CrossWalk(n5ri, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool {
 127  			if r != nil && r.IsInline() {
 128  				fmt.Printf("%s ", r.InlineData())
 129  			}
 130  			return true
 131  		})
 132  		fmt.Printf("\n")
 133  	}
 134  
 135  	// phase 3: insert more, delete some, close
 136  	for i := 100; i < 110; i++ {
 137  		w := fmt.Sprintf("word%04d", i)
 138  		var rec lattice.Record
 139  		rec.SetInline([]byte(w))
 140  		t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec)
 141  	}
 142  	for i := 0; i < 5; i++ {
 143  		w := fmt.Sprintf("word%04d", i)
 144  		t.Delete(lattice.Bnoun, lattice.HashKey([]byte(w)))
 145  	}
 146  	fmt.Printf("after mutations: %d nodes, freeCount=%d\n", t.NodeCount(), t.FreeCount)
 147  	err = t.Close()
 148  	if err != nil {
 149  		fmt.Printf("close error: %s\n", err)
 150  		return
 151  	}
 152  
 153  	// phase 4: reopen, verify state
 154  	t, err = lattice.Open(dbPath)
 155  	if err != nil {
 156  		fmt.Printf("open error: %s\n", err)
 157  		return
 158  	}
 159  	// deleted words should be gone
 160  	r := t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("word0000")))
 161  	if r == nil {
 162  		fmt.Printf("word0000 after delete+reopen: NOT FOUND (correct)\n")
 163  	} else {
 164  		fmt.Printf("word0000 after delete+reopen: FOUND (BUG)\n")
 165  	}
 166  	// new words should be present
 167  	r = t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("word0105")))
 168  	if r != nil && r.IsInline() {
 169  		fmt.Printf("word0105 after reopen: %s\n", r.InlineData())
 170  	} else {
 171  		fmt.Printf("word0105 after reopen: NOT FOUND (BUG)\n")
 172  	}
 173  
 174  	// compact and verify
 175  	reclaimed := t.Compact()
 176  	fmt.Printf("compacted: reclaimed=%d, now %d nodes\n", reclaimed, t.NodeCount())
 177  	r = t.Lookup(lattice.Bnoun, lattice.HashKey([]byte("word0050")))
 178  	if r != nil && r.IsInline() {
 179  		fmt.Printf("post-compact lookup(word0050) = %s\n", r.InlineData())
 180  	}
 181  
 182  	err = t.Close()
 183  	if err != nil {
 184  		fmt.Printf("final close error: %s\n", err)
 185  	}
 186  	fmt.Printf("disk test complete\n")
 187  }
 188  
 189  func testTransfer() {
 190  	t := lattice.NewTree(256)
 191  	for i := 0; i < 50; i++ {
 192  		w := fmt.Sprintf("n%d", i)
 193  		var rec lattice.Record
 194  		rec.SetInline([]byte(w))
 195  		t.Insert(lattice.Bnoun, lattice.HashKey([]byte(w)), rec)
 196  	}
 197  	for i := 0; i < 10; i++ {
 198  		noun := fmt.Sprintf("t_noun%d", i)
 199  		verb := fmt.Sprintf("t_verb%d", i)
 200  		mod := fmt.Sprintf("t_mod%d", i)
 201  		var nRec, vRec, mRec lattice.Record
 202  		nRec.SetInline([]byte(noun))
 203  		vRec.SetInline([]byte(verb))
 204  		mRec.SetInline([]byte(mod))
 205  		t.InsertTriple(
 206  			lattice.HashKey([]byte(noun)),
 207  			lattice.HashKey([]byte(verb)),
 208  			lattice.HashKey([]byte(mod)),
 209  			nRec, vRec, mRec,
 210  		)
 211  	}
 212  	fmt.Printf("source: %d nodes, %d records\n", t.NodeCount(), t.RecordCount())
 213  
 214  	// 1. ExtractBranch - noun branch only
 215  	sl := t.ExtractBranch(lattice.Bnoun)
 216  	fmt.Printf("extract branch noun: %d nodes, %d records\n", sl.Tree.NodeCount(), sl.Tree.RecordCount())
 217  	r := sl.Tree.Lookup(lattice.Bnoun, lattice.HashKey([]byte("n25")))
 218  	if r != nil && r.IsInline() {
 219  		fmt.Printf("  lookup(n25) = %s\n", r.InlineData())
 220  	} else {
 221  		fmt.Printf("  lookup(n25) = NOT FOUND (BUG)\n")
 222  	}
 223  
 224  	// 2. ExtractLinked - follow cross-branch links from t_noun5
 225  	n5ri := t.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5")))
 226  	linked := t.ExtractLinked(n5ri)
 227  	fmt.Printf("extract linked t_noun5: %d records\n", linked.Tree.RecordCount())
 228  	lri := linked.Tree.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5")))
 229  	if lri != lattice.NullRec {
 230  		fmt.Printf("  cross-walk: ")
 231  		linked.Tree.CrossWalk(lri, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool {
 232  			if r != nil && r.IsInline() {
 233  				fmt.Printf("%s ", r.InlineData())
 234  			}
 235  			return true
 236  		})
 237  		fmt.Printf("\n")
 238  	} else {
 239  		fmt.Printf("  t_noun5 NOT FOUND in extract (BUG)\n")
 240  	}
 241  
 242  	// 3. SaveFile/LoadFile round-trip
 243  	slPath := "/tmp/iskra_sub.iskr"
 244  	err := linked.SaveFile(slPath)
 245  	if err != nil {
 246  		fmt.Printf("  save error: %s\n", err)
 247  		return
 248  	}
 249  	loaded, err := lattice.LoadSubLattice(slPath)
 250  	if err != nil {
 251  		fmt.Printf("  load error: %s\n", err)
 252  		return
 253  	}
 254  	loadedRI := loaded.Tree.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5")))
 255  	if loadedRI != lattice.NullRec {
 256  		fmt.Printf("  round-trip cross-walk: ")
 257  		loaded.Tree.CrossWalk(loadedRI, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool {
 258  			if r != nil && r.IsInline() {
 259  				fmt.Printf("%s ", r.InlineData())
 260  			}
 261  			return true
 262  		})
 263  		fmt.Printf("\n")
 264  	} else {
 265  		fmt.Printf("  round-trip t_noun5 NOT FOUND (BUG)\n")
 266  	}
 267  
 268  	// 4. Graft into fresh tree
 269  	dst := lattice.NewTree(64)
 270  	grafted := dst.Graft(linked)
 271  	fmt.Printf("graft into empty: inserted=%d, records=%d\n", grafted, dst.RecordCount())
 272  	gri := dst.LookupRecIdx(lattice.Bnoun, lattice.HashKey([]byte("t_noun5")))
 273  	if gri != lattice.NullRec {
 274  		fmt.Printf("  graft cross-walk: ")
 275  		dst.CrossWalk(gri, lattice.PatNounVerbMod, func(ri uint32, r *lattice.Record) bool {
 276  			if r != nil && r.IsInline() {
 277  				fmt.Printf("%s ", r.InlineData())
 278  			}
 279  			return true
 280  		})
 281  		fmt.Printf("\n")
 282  	} else {
 283  		fmt.Printf("  graft t_noun5 NOT FOUND (BUG)\n")
 284  	}
 285  
 286  	// 5. Graft with overlap - dedup test
 287  	beforeRecs := dst.RecordCount()
 288  	deduped := dst.Graft(linked)
 289  	fmt.Printf("graft overlap: inserted=%d (should be 0), records before=%d after=%d\n",
 290  		deduped, beforeRecs, dst.RecordCount())
 291  	if dst.RecordCount() == beforeRecs {
 292  		fmt.Printf("  dedup: correct\n")
 293  	} else {
 294  		fmt.Printf("  dedup: FAILED - records grew (BUG)\n")
 295  	}
 296  }
 297