diff --git a/cached_raw.prof b/cached_raw.prof new file mode 100644 index 0000000..99f72d7 Binary files /dev/null and b/cached_raw.prof differ diff --git a/cpu.prof b/cpu.prof new file mode 100644 index 0000000..b1a9396 Binary files /dev/null and b/cpu.prof differ diff --git a/database/dbtest/benchmark.go b/database/dbtest/benchmark.go index 8e50145..6b5959a 100644 --- a/database/dbtest/benchmark.go +++ b/database/dbtest/benchmark.go @@ -16,15 +16,15 @@ import ( var ( // Benchmarks is a list of all database benchmarks Benchmarks = map[string]func(b *testing.B, db database.Database, keys, values [][]byte){ - "Get": BenchmarkGet, - "Put": BenchmarkPut, - "Delete": BenchmarkDelete, - "BatchPut": BenchmarkBatchPut, - "BatchDelete": BenchmarkBatchDelete, + // "Get": BenchmarkGet, + // "Put": BenchmarkPut, + // "Delete": BenchmarkDelete, + // // "BatchPut": BenchmarkBatchPut, + // // "BatchDelete": BenchmarkBatchDelete, "BatchWrite": BenchmarkBatchWrite, - "ParallelGet": BenchmarkParallelGet, - "ParallelPut": BenchmarkParallelPut, - "ParallelDelete": BenchmarkParallelDelete, + // "ParallelGet": BenchmarkParallelGet, + // "ParallelPut": BenchmarkParallelPut, + // "ParallelDelete": BenchmarkParallelDelete, } // BenchmarkSizes to use with each benchmark BenchmarkSizes = [][]int{ diff --git a/go.mod b/go.mod index 4714640..0170d2a 100644 --- a/go.mod +++ b/go.mod @@ -95,11 +95,13 @@ require ( github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect + github.com/dgraph-io/ristretto v0.2.0 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/frankban/quicktest v1.14.4 // indirect diff --git a/go.sum b/go.sum index db42149..b0a8838 100644 --- a/go.sum +++ b/go.sum @@ -162,6 +162,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= +github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= @@ -178,6 +180,8 @@ github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14 github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= diff --git a/leveldb.prof b/leveldb.prof new file mode 100644 index 0000000..7e016d3 Binary files /dev/null and b/leveldb.prof differ diff --git a/merkledb.prof b/merkledb.prof new file mode 100644 index 0000000..36813f8 Binary files /dev/null and b/merkledb.prof differ diff --git a/merkledb.test.exe b/merkledb.test.exe new file mode 100644 index 0000000..126f24c Binary files /dev/null and b/merkledb.test.exe differ diff --git a/x/merkledb/db_test.go b/x/merkledb/db_test.go index f470566..2223038 100644 --- a/x/merkledb/db_test.go +++ b/x/merkledb/db_test.go @@ -159,6 +159,37 @@ func Benchmark_MerkleDB_DBInterface(b *testing.B) { } } + +func Benchmark_MerkleDB_DBInterface_Timed(b *testing.B) { + totalTime := time.Duration(0) + for _, size := range dbtest.BenchmarkSizes { + keys, values := dbtest.SetupBenchmark(b, size[0], size[1], size[2]) + for _, bf := range validBranchFactors { + for name, bench := range dbtest.Benchmarks { + // Run the benchmark and track its time + b.Run(fmt.Sprintf("merkledb_%d_%d_pairs_%d_keys_%d_values_%s", bf, size[0], size[1], size[2], name), func(b *testing.B) { + db, err := getBasicDBWithBranchFactor(bf) + require.NoError(b, err) + b.Cleanup(func() { + db.Close() + }) + + // Record the start time for each individual benchmark + start := time.Now() + bench(b, db, keys, values) + // Calculate the time taken for the specific benchmark + duration := time.Since(start) + totalTime += duration + // Log the time taken for the specific benchmark + }) + } + } + } + // Log the total time taken for all benchmarks + fmt.Printf("Total time taken for all benchmarks: %v\n", totalTime) + b.Log("Total time taken for all benchmarks: ", totalTime) +} + // PASSES func Test_MerkleDB_DB_Load_Root_From_DB(t *testing.T) { require := require.New(t) diff --git a/x/merkledb/disk_manager.go b/x/merkledb/disk_manager.go index 722cb56..d302728 100644 --- a/x/merkledb/disk_manager.go +++ b/x/merkledb/disk_manager.go @@ -85,7 +85,7 @@ func newDiskManager(metaData []byte, dir string, fileName string) (*diskMgr, err } // start freelist - maxSize := 4096 * 4 * 4 + maxSize := 4096 * 4 * 4 * 4 f := newFreeList(maxSize) f.load(dir) @@ -119,8 +119,6 @@ func (dm *diskMgr) putBack(addr diskAddress) error { } func (dm *diskMgr) writeRoot(rootNode dbNode) (diskAddress, error) { - - // first check the size of rootNode without the disk address bytes := encodeDBNode_disk(&rootNode) freeSpace, ok := dm.free.get(int64(len(bytes)) + 16) @@ -190,6 +188,22 @@ func (dm *diskMgr) writeRoot(rootNode dbNode) (diskAddress, error) { } +func (dm *diskMgr) fetch(byteLength int64) (diskAddress, error) { + freeSpace, ok := dm.free.get(int64(byteLength)) + if !ok { + endOffset, err := dm.endOfFile() + if err != nil { + log.Fatalf("failed to get end of file: %v", err) + return diskAddress{}, err + } + return diskAddress{offset: endOffset, size: int64(byteLength)}, nil + } else { + return diskAddress{offset: freeSpace.offset, size: int64(byteLength)}, nil + } + + +} + // returning diskaddress that it wrote to // if we write to freelist: diskaddress would be the size of freespace // if we dont write to freelist: append bytes to end, return endoffset and size diff --git a/x/merkledb/freelist.go b/x/merkledb/freelist.go index 9b9404c..69fc3de 100644 --- a/x/merkledb/freelist.go +++ b/x/merkledb/freelist.go @@ -50,7 +50,12 @@ func (f *freeList) get(size int64) (diskAddress, bool) { return diskAddress{}, false }*/ bucket := f.bucketIndex(size) + + // first check whether or not the bucket would be out of bounds + if bucket >= len(f.buckets) { + return diskAddress{}, false + } if len(f.buckets[bucket]) > 0 { space := f.buckets[bucket][len(f.buckets[bucket])-1] f.buckets[bucket] = f.buckets[bucket][:len(f.buckets[bucket])-1] diff --git a/x/merkledb/helpers_test.go b/x/merkledb/helpers_test.go index 2e2550a..9872711 100644 --- a/x/merkledb/helpers_test.go +++ b/x/merkledb/helpers_test.go @@ -11,9 +11,16 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/maybe" + + + "github.com/ava-labs/avalanchego/database/leveldb" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/prometheus/client_golang/prometheus" + ) const disk = true func getBasicDB(tb testing.TB) (*merkleDB, error) { @@ -29,21 +36,24 @@ func getBasicDB(tb testing.TB) (*merkleDB, error) { } func getBasicDBWithBranchFactor(bf BranchFactor) (*merkleDB, error) { - config := newDefaultConfig() - config.BranchFactor = bf - t := &testing.T{} - dir := t.TempDir() - if disk{ - return getBasicDBWithBranchFactor_disk(bf,dir) - } - return newDatabase( - context.Background(), - memdb.New(), - config, - &mockMetrics{}, - ) -} + config := newDefaultConfig() + config.BranchFactor = bf + t := &testing.T{} + + folder := t.TempDir() + db, err := leveldb.New(folder, nil, logging.NoLog{}, prometheus.NewRegistry()) + require.NoError(t, err) + if disk { + return getBasicDBWithBranchFactor_disk(bf, folder) + } + return newDatabase( + context.Background(), + db, + config, + &mockMetrics{}, + ) +} // Writes []byte{i} -> []byte{i} for i in [0, 4] func writeBasicBatch(t *testing.T, db *merkleDB) { require := require.New(t) diff --git a/x/merkledb/key.go b/x/merkledb/key.go index dc4b070..02a6794 100644 --- a/x/merkledb/key.go +++ b/x/merkledb/key.go @@ -37,7 +37,7 @@ var ( BranchFactor2, BranchFactor4, BranchFactor16, - // BranchFactor256, + BranchFactor256, } ) diff --git a/x/merkledb/raw_disk.go b/x/merkledb/raw_disk.go index 308033c..5bd27b0 100644 --- a/x/merkledb/raw_disk.go +++ b/x/merkledb/raw_disk.go @@ -11,6 +11,10 @@ import ( "log" "sort" + // "github.com/hashicorp/golang-lru" + + "github.com/dgraph-io/ristretto" + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/utils/maybe" ) @@ -55,6 +59,7 @@ type rawDisk struct { dm *diskMgr config Config hasher Hasher + cache *ristretto.Cache } func newRawDisk(dir string, fileName string, hasher Hasher, config Config) (*rawDisk, error) { @@ -62,8 +67,13 @@ func newRawDisk(dir string, fileName string, hasher Hasher, config Config) (*raw if err != nil { return nil, err } + cache, _ := ristretto.NewCache(&ristretto.Config{ + NumCounters: 1e5, // Number of keys to track frequency (higher = better hit rate) + MaxCost: 1 << 30, // Maximum cost in bytes (adjust as needed) + BufferItems: 64, // Number of keys per eviction buffer + }) // correctly read rootId from the header - return &rawDisk{dm: dm, hasher: hasher, config: config}, nil + return &rawDisk{dm: dm, hasher: hasher, config: config, cache: cache}, nil } func (r *rawDisk) getShutdownType() ([]byte, error) { @@ -191,22 +201,27 @@ func (r *rawDisk) writeChanges(ctx context.Context, changes *changeSummary) erro return keys[i].length > keys[j].length }) - if len(keys) > 0 { - for i := 0; i < len(keys)-2; i += 2 { - pair := keys[i : i+2] - if pair[0].length < pair[1].length { - log.Printf("prev key shorter than next key") - } + totalLenBytes := 0 + for _, nodes := range changes.nodes { + if nodes.after != nil { + totalLenBytes += len(encodeDBNode_disk(&nodes.after.dbNode)) } } + totalLenBytes += 16 * (len(changes.nodes) - 1) - // Create a temporary map of remainingNodes to store the disk address and compressed key of the remainingNodes - childrenNodes := make(map[Key]diskAddress) + // fetch the available disk address for totallenbytes + totalDiskAddress, err := r.dm.fetch(int64(totalLenBytes)) + if err != nil { + return err + } - // ITERATES THROUGH ALL NODES EXCEPT THE ROOT - // STARTS WITH CHILDRENS THEN MOVES TO PARENTS - // EACH PARENT CHECKS THEIR CHILDREN'S KEY THEN ENSURES POINTERS PROPERLY WORK + // Start partitioning the data within the totaldiskaddress + // Start with longest keys (children), then move up the tree + // Start with the leaf nodes // Iterate through the keys + totalOffset := 0 + childrenNodes := make(map[Key]diskAddress) + totalBytes := make([]byte, 0) for _, k := range keys { // find the nodechange associated with the key nodeChange := changes.nodes[k] @@ -247,21 +262,145 @@ func (r *rawDisk) writeChanges(ctx context.Context, changes *changeSummary) erro return errors.New("regular node child disk address missing") } } - nodeBytes := encodeDBNode_disk(&nodeChange.after.dbNode) - diskAddr, err := r.dm.write(nodeBytes) - if err != nil { - return err - } - - // If there is not a node with the key in the map, create a new map with the key being the ch - if childrenNodes[k] == (diskAddress{}) { - // If the node is a leaf node, compress the key and store the disk address - key := Key{length: k.length, value: k.value} - childrenNodes[key] = diskAddr - + if nodeChange.after.hasValue() && changes.rootChange.after.HasValue() { + if nodeChange.after.key != changes.rootChange.after.Value().key { + + nodeBytes := encodeDBNode_disk(&nodeChange.after.dbNode) + diskAddr := diskAddress{totalDiskAddress.offset + int64(totalOffset), int64(len(nodeBytes))} + totalOffset += len(nodeBytes) + totalBytes = append(totalBytes, nodeBytes...) + if err != nil { + return err + } + + nodeChange.after.dbNode.diskAddr = diskAddr + if nodeChange.after.hasValue() { + compositeKey := fmt.Sprintf("%s:%d", nodeChange.after.key.value, nodeChange.after.key.length) + r.cache.Set(compositeKey, nodeChange.after.dbNode, nodeChange.after.dbNode.diskAddr.size) + } + // log.Print("Setting node in cache", nodeChange.after.dbNode.diskAddr) + // If there is not a node with the key in the map, create a new map with the key being the ch + if childrenNodes[k] == (diskAddress{}) { + // If the node is a leaf node, compress the key and store the disk address + key := Key{length: k.length, value: k.value} + childrenNodes[key] = diskAddr + } + } else { + // writing rootNode to header + rootNode := changes.rootChange.after.Value() + rootNodeBytes := encodeDBNode_disk(&rootNode.dbNode) + rootDiskAddr := diskAddress{totalDiskAddress.offset + int64(totalOffset), int64(len(rootNodeBytes))} + totalOffset += len(rootNodeBytes) + totalBytes = append(totalBytes, rootNodeBytes...) + if err != nil { + return err + } + + // iterate through cache and delete all nodes with same key value + // as the root node + changes.rootChange.after.Value().dbNode.diskAddr = rootDiskAddr + if changes.rootChange.after.HasValue() { + compositeKey := fmt.Sprintf("%s:%d", changes.rootChange.after.Value().key.value, changes.rootChange.after.Value().key.length) + r.cache.Set(compositeKey, changes.rootChange.after.Value().dbNode, changes.rootChange.after.Value().dbNode.diskAddr.size) + } + + // log.Print("Setting root node in cache", changes.rootChange.after.Value().dbNode.diskAddr) + // add function that would write the root node to the disk while also updating the disk address + if err != nil { + return err + } + rootDiskAddrBytes := rootDiskAddr.bytes() + r.dm.file.WriteAt(rootDiskAddrBytes[:], 1) + + rootKey := rootNode.key + rootKeyByteArray := encodeKey(rootKey) + + rootKeyDiskAddr, err := r.dm.write(rootKeyByteArray) + if err != nil { + return err + } + rootKeyDiskAddrBytes := rootKeyDiskAddr.bytes() + r.dm.file.WriteAt(rootKeyDiskAddrBytes[:], 17) + + // print the tree + // err = r.printTree(rootDiskAddr, changes) + if err != nil { + return err + } + changes.rootChange.after.Value().dbNode.diskAddr = rootDiskAddr + } } } + + // // Create a temporary map of remainingNodes to store the disk address and compressed key of the remainingNodes + // childrenNodes := make(map[Key]diskAddress) + + // // ITERATES THROUGH ALL NODES EXCEPT THE ROOT + // // STARTS WITH CHILDRENS THEN MOVES TO PARENTS + // // EACH PARENT CHECKS THEIR CHILDREN'S KEY THEN ENSURES POINTERS PROPERLY WORK + // // Iterate through the keys + // for _, k := range keys { + // // find the nodechange associated with the key + // nodeChange := changes.nodes[k] + // // filter through nodes that arent changed + // if nodeChange.after == nil { + // continue + // } + + // // Ensure root is not being written twice + // if changes.rootChange.after.HasValue() { + // if nodeChange.after.key == changes.rootChange.after.Value().key { + // continue + // } + // } + + // // Iterate through node's children + // for token, child := range nodeChange.after.children { + + // // Create the complete key (current key + compressed key of the child) + // completeKey := k.Extend(ToToken(token, BranchFactorToTokenSize[r.config.BranchFactor])) + // if child.compressedKey.length != 0 { + // completeKey = completeKey.Extend(child.compressedKey) + // } + + // // CASE WHERE NODES HAVE NOT BEEN WRITTEN TO DISK + // // Check whether or not there exists a value for the child in the map + // if childrenNodes[completeKey] != (diskAddress{}) { + // // If there is a value, set the disk address of the child to the value in the map + // child.diskAddr = childrenNodes[completeKey] + // } + // // IF THE CHILDREN ARE ALREADY WRITTEN TO DISK, THEY SHOULD HAVE A DISKADDRESS ASSOCIATED WITH THEM ALREADY + // // THEREFORE WE CAN SKIP THIS STEP + // } + // // check to ensure that all of its children have disk addresses + // for _, child := range nodeChange.after.children { + // // Check remainingNodes actually have disk addresses + // if child.diskAddr == (diskAddress{}) { + // return errors.New("regular node child disk address missing") + // } + // } + // nodeBytes := encodeDBNode_disk(&nodeChange.after.dbNode) + // diskAddr, err := r.dm.write(nodeBytes) + // if err != nil { + // return err + // } + + // nodeChange.after.dbNode.diskAddr = diskAddr + // if nodeChange.after.hasValue() { + // compositeKey := fmt.Sprintf("%s:%d", nodeChange.after.key.value, nodeChange.after.key.length) + // r.cache.Set(compositeKey, nodeChange.after.dbNode, nodeChange.after.dbNode.diskAddr.size) + // } + // // log.Print("Setting node in cache", nodeChange.after.dbNode.diskAddr) + // // If there is not a node with the key in the map, create a new map with the key being the ch + // if childrenNodes[k] == (diskAddress{}) { + // // If the node is a leaf node, compress the key and store the disk address + // key := Key{length: k.length, value: k.value} + // childrenNodes[key] = diskAddr + + // } + + // } if err := r.dm.file.Sync(); err != nil { return err } @@ -294,6 +433,19 @@ func (r *rawDisk) writeChanges(ctx context.Context, changes *changeSummary) erro rootNode := changes.rootChange.after.Value() rootNodeBytes := encodeDBNode_disk(&rootNode.dbNode) rootDiskAddr, err := r.dm.write(rootNodeBytes) + if err != nil { + return err + } + + // iterate through cache and delete all nodes with same key value + // as the root node + changes.rootChange.after.Value().dbNode.diskAddr = rootDiskAddr + if changes.rootChange.after.HasValue() { + compositeKey := fmt.Sprintf("%s:%d", changes.rootChange.after.Value().key.value, changes.rootChange.after.Value().key.length) + r.cache.Set(compositeKey, changes.rootChange.after.Value().dbNode, changes.rootChange.after.Value().dbNode.diskAddr.size) + } + + // log.Print("Setting root node in cache", changes.rootChange.after.Value().dbNode.diskAddr) // add function that would write the root node to the disk while also updating the disk address if err != nil { return err @@ -302,9 +454,9 @@ func (r *rawDisk) writeChanges(ctx context.Context, changes *changeSummary) erro r.dm.file.WriteAt(rootDiskAddrBytes[:], 1) rootKey := rootNode.key - rooyKeyByteArray := encodeKey(rootKey) + rootKeyByteArray := encodeKey(rootKey) - rootKeyDiskAddr, err := r.dm.write(rooyKeyByteArray) + rootKeyDiskAddr, err := r.dm.write(rootKeyByteArray) if err != nil { return err } @@ -330,18 +482,27 @@ func (r *rawDisk) writeChanges(ctx context.Context, changes *changeSummary) erro } if nodeChange.before != nil && nodeChange.after == nil { // make a new node that is the same as the old node but with has value set to false - tempdBNode := dbNode{} + tempDBNode := dbNode{} + // remove node from cache + if nodeChange.before.hasValue() { + compositeKey := fmt.Sprintf("%s:%d", nodeChange.before.key.value, nodeChange.before.key.length) + if val, _ := r.cache.Get(compositeKey); val != nil { + r.cache.Del(compositeKey) + } + } + // r.cache.Set(compositeKey, changes.rootChange.after.Value().dbNode, changes.rootChange.after.Value().dbNode.diskAddr.size) + nextBytes, err := r.dm.get(nodeChange.before.diskAddr) if err != nil { return err } - err = decodeDBNode_disk(nextBytes, &tempdBNode) + err = decodeDBNode_disk(nextBytes, &tempDBNode) if err != nil { return err } - tempdBNode.value = maybe.Nothing[[]byte]() + tempDBNode.value = maybe.Nothing[[]byte]() // write the new node to disk - nodeBytes := encodeDBNode_disk(&tempdBNode) + nodeBytes := encodeDBNode_disk(&tempDBNode) // write new node at the same disk address _, err = r.dm.file.WriteAt(nodeBytes, nodeChange.before.diskAddr.offset) if err != nil { @@ -358,6 +519,27 @@ func (r *rawDisk) Clear() error { } func (r *rawDisk) getNode(key Key, hasValue bool) (*node, error) { + // Add a flag to check if the cache was found + + if val, found := r.cache.Get(fmt.Sprintf("%s:%d", key.value, key.length)); found { + if val != nil { + // If the value is found, process normally + + // Assuming val is of type dbNode, create the return node + returnNode := &node{ + dbNode: val.(dbNode), + key: key, + valueDigest: val.(dbNode).value, + } + + // Set the disk address from the cache entry + returnNode.dbNode.diskAddr = val.(dbNode).diskAddr + + // You can then return the node if you wish + return returnNode, nil + } + } + // log.Printf("Getting node for key %v", key) metadata, err := r.dm.getHeader() if err != nil { @@ -405,31 +587,31 @@ func (r *rawDisk) getNode(key Key, hasValue bool) (*node, error) { } if !key.HasPrefix(currKey) { - // log.Printf("key %v %v, currkey %v %v", key.length, []byte(key.value), currKey.length, []byte(currKey.value)) - return nil, database.ErrNotFound //errors.New("Key doesn't match rootkey") + // log.Printf("key %v %v, currKey %v %v", key.length, []byte(key.value), currKey.length, []byte(currKey.value)) + return nil, database.ErrNotFound //errors.New("Key doesn't match rootKey") } - keylen := currKey.length // keeps track of where to start comparing prefixes in the key i.e. the length of key iterated so far + keyLen := currKey.length // keeps track of where to start comparing prefixes in the key i.e. the length of key iterated so far // tempDiskAddr := diskAddress{} // while the entire path hasn't been matched - for keylen < (key.length) { + for keyLen < (key.length) { // confirm that a child exists and grab its address before attempting to load it - // log.Printf("Token: %v", key.Token(keylen, tokenSize)) + // log.Printf("Token: %v", key.Token(keyLen, tokenSize)) // log.Printf("currentDbNode value %s", currentDbNode.value.Value()) // log.Printf("num of children %d", len(currentDbNode.children)) // for token, child := range currentDbNode.children { // log.Printf("Token: %v for Child: %x", (token), child.compressedKey.value) // } - // log.Printf("Checking key %x", key.Token(keylen, tokenSize)) - nextChildEntry, hasChild := currentDbNode.children[key.Token(keylen, tokenSize)] + // log.Printf("Checking key %x", key.Token(keyLen, tokenSize)) + nextChildEntry, hasChild := currentDbNode.children[key.Token(keyLen, tokenSize)] - keylen += tokenSize + keyLen += tokenSize if !hasChild { return nil, database.ErrNotFound } // log.Printf("nextChildEntry %v", nextChildEntry) - if !key.iteratedHasPrefix(nextChildEntry.compressedKey, keylen, tokenSize) { + if !key.iteratedHasPrefix(nextChildEntry.compressedKey, keyLen, tokenSize) { // there was no child along the path or the child that was there doesn't match the remaining path // return nil, errors.New("Key doesn't match an existing node") return nil, database.ErrNotFound @@ -437,10 +619,10 @@ func (r *rawDisk) getNode(key Key, hasValue bool) (*node, error) { } // get the next key from the current child - currKey := ToToken(key.Token(keylen-tokenSize, tokenSize), tokenSize) + currKey := ToToken(key.Token(keyLen-tokenSize, tokenSize), tokenSize) // log.Printf("currKey %x", currKey) currKey = currKey.Extend(nextChildEntry.compressedKey) - keylen += currKey.length - tokenSize + keyLen += currKey.length - tokenSize // grab the next node along the path nextBytes, err := r.dm.get(nextChildEntry.diskAddr) @@ -463,6 +645,8 @@ func (r *rawDisk) getNode(key Key, hasValue bool) (*node, error) { } returnNode.dbNode.diskAddr = currentDbNode.diskAddr + // log.Print("Found node in rawdisk", returnNode.dbNode.diskAddr, returnNode.key.value) + returnNode.setValueDigest(r.hasher) return returnNode, nil }