mirror of
https://github.com/arnaucube/arbo.git
synced 2026-01-07 14:31:28 +01:00
Add AddBatch CaseB
CASE B: ALMOST CASE A, Almost empty Tree --> if Tree has numLeafs < minLeafsThreshold
==============================================================================
- Get the Leafs (key & value) (iterate the tree from the current root getting
the leafs)
- Create a new empty Tree
- Do CASE A for the new Tree, giving the already existing key&values (leafs)
from the original Tree + the new key&values to be added from the AddBatch call
R R
/ \ / \
A * / \
/ \ / \
B C * *
/ | / \
/ | / \
/ | / \
L: A B G D
/ \
/ \
/ \
C *
/ \
/ \
/ \
... ... (nLeafs < minLeafsThreshold)
This commit is contained in:
61
addbatch.go
61
addbatch.go
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
/*
|
||||
|
||||
|
||||
AddBatch design
|
||||
===============
|
||||
|
||||
@@ -18,7 +17,7 @@ CASE A: Empty Tree --> if tree is empty (root==0)
|
||||
- Build the full tree from bottom to top (from all the leaf to the root)
|
||||
|
||||
|
||||
CASE B: ALMOST CASE A, Almost empty Tree --> if Tree has numLeafs < numBuckets
|
||||
CASE B: ALMOST CASE A, Almost empty Tree --> if Tree has numLeafs < minLeafsThreshold
|
||||
==============================================================================
|
||||
- Get the Leafs (key & value) (iterate the tree from the current root getting
|
||||
the leafs)
|
||||
@@ -33,7 +32,7 @@ from the original Tree + the new key&values to be added from the AddBatch call
|
||||
B C
|
||||
|
||||
|
||||
CASE C: ALMOST CASE B --> if Tree has few Leafs (but numLeafs>=numBuckets)
|
||||
CASE C: ALMOST CASE B --> if Tree has few Leafs (but numLeafs>=minLeafsThreshold)
|
||||
==============================================================================
|
||||
- Use A, B, G, F as Roots of subtrees
|
||||
- Do CASE B for each subtree
|
||||
@@ -112,8 +111,8 @@ L: M1 * M2 * (where M1 and M2 are empty)
|
||||
Algorithm decision
|
||||
==================
|
||||
- if nLeafs==0 (root==0): CASE A
|
||||
- if nLeafs<nBuckets: CASE B
|
||||
- if nLeafs>=nBuckets && nLeafs < minLeafsThreshold: CASE C
|
||||
- if nLeafs<minLeafsThreshold: CASE B
|
||||
- if nLeafs>=minLeafsThreshold && (nLeafs/nBuckets) < minLeafsThreshold: CASE C
|
||||
- else: CASE D & CASE E
|
||||
|
||||
|
||||
@@ -148,14 +147,35 @@ func (t *Tree) AddBatchOpt(keys, values [][]byte) ([]int, error) {
|
||||
}
|
||||
|
||||
// if nLeafs==0 (root==0): CASE A
|
||||
e := make([]byte, t.hashFunction.Len())
|
||||
if bytes.Equal(t.root, e) {
|
||||
// CASE A
|
||||
if bytes.Equal(t.root, t.emptyHash) {
|
||||
// sort keys & values by path
|
||||
sortKvs(kvs)
|
||||
return t.buildTreeBottomUp(kvs)
|
||||
}
|
||||
|
||||
// if nLeafs<nBuckets: CASE B
|
||||
nLeafs, err := t.GetNLeafs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
minLeafsThreshold := uint64(100) // nolint:gomnd // TMP WIP
|
||||
if nLeafs < minLeafsThreshold {
|
||||
// get already existing keys
|
||||
aKs, aVs, err := t.getLeafs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aKvs, err := t.keysValuesToKvs(aKs, aVs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// add already existing key-values to the inputted key-values
|
||||
kvs = append(kvs, aKvs...)
|
||||
// proceed with CASE A
|
||||
sortKvs(kvs)
|
||||
return t.buildTreeBottomUp(kvs)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("UNIMPLEMENTED")
|
||||
}
|
||||
|
||||
@@ -209,6 +229,18 @@ func (t *Tree) keysValuesToKvs(ks, vs [][]byte) ([]kv, error) {
|
||||
return kvs, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (t *Tree) kvsToKeysValues(kvs []kv) ([][]byte, [][]byte) {
|
||||
ks := make([][]byte, len(kvs))
|
||||
vs := make([][]byte, len(kvs))
|
||||
for i := 0; i < len(kvs); i++ {
|
||||
ks[i] = kvs[i].k
|
||||
vs[i] = kvs[i].v
|
||||
}
|
||||
return ks, vs
|
||||
}
|
||||
*/
|
||||
|
||||
// keys & values must be sorted by path, and must be length multiple of 2
|
||||
// TODO return index of failed keyvaules
|
||||
func (t *Tree) buildTreeBottomUp(kvs []kv) ([]int, error) {
|
||||
@@ -254,3 +286,16 @@ func (t *Tree) upFromKeys(ks [][]byte) ([]byte, error) {
|
||||
}
|
||||
return t.upFromKeys(rKs)
|
||||
}
|
||||
|
||||
func (t *Tree) getLeafs() ([][]byte, [][]byte, error) {
|
||||
var ks, vs [][]byte
|
||||
err := t.Iterate(func(k, v []byte) {
|
||||
if v[0] != PrefixValueLeaf {
|
||||
return
|
||||
}
|
||||
leafK, leafV := readLeafValue(v)
|
||||
ks = append(ks, leafK)
|
||||
vs = append(vs, leafV)
|
||||
})
|
||||
return ks, vs, err
|
||||
}
|
||||
|
||||
@@ -49,3 +49,53 @@ func TestAddBatchCaseA(t *testing.T) {
|
||||
// check that both trees roots are equal
|
||||
c.Check(tree2.Root(), qt.DeepEquals, tree.Root())
|
||||
}
|
||||
|
||||
func TestAddBatchCaseB(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
nLeafs := 1024
|
||||
|
||||
tree, err := NewTree(memory.NewMemoryStorage(), 100, HashFunctionPoseidon)
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree.db.Close()
|
||||
|
||||
start := time.Now()
|
||||
for i := 0; i < nLeafs; i++ {
|
||||
k := BigIntToBytes(big.NewInt(int64(i)))
|
||||
v := BigIntToBytes(big.NewInt(int64(i * 2)))
|
||||
if err := tree.Add(k, v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
fmt.Println(time.Since(start))
|
||||
|
||||
tree2, err := NewTree(memory.NewMemoryStorage(), 100, HashFunctionPoseidon)
|
||||
c.Assert(err, qt.IsNil)
|
||||
defer tree2.db.Close()
|
||||
|
||||
// add the initial leafs to fill a bit the tree before calling the
|
||||
// AddBatch method
|
||||
for i := 0; i < 99; i++ { // TMP TODO use const minLeafsThreshold-1 once ready
|
||||
k := BigIntToBytes(big.NewInt(int64(i)))
|
||||
v := BigIntToBytes(big.NewInt(int64(i * 2)))
|
||||
if err := tree2.Add(k, v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var keys, values [][]byte
|
||||
for i := 99; i < nLeafs; i++ {
|
||||
k := BigIntToBytes(big.NewInt(int64(i)))
|
||||
v := BigIntToBytes(big.NewInt(int64(i * 2)))
|
||||
keys = append(keys, k)
|
||||
values = append(values, v)
|
||||
}
|
||||
start = time.Now()
|
||||
indexes, err := tree2.AddBatchOpt(keys, values)
|
||||
c.Assert(err, qt.IsNil)
|
||||
fmt.Println(time.Since(start))
|
||||
c.Check(len(indexes), qt.Equals, 0)
|
||||
|
||||
// check that both trees roots are equal
|
||||
c.Check(tree2.Root(), qt.DeepEquals, tree.Root())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user