@ -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  
			
		
	
		
			
				
					}