Trie
+fixing the bug of loading Trie from the db +Tracing full tree improved - now it traverse the trie recursively from the root
This commit is contained in:
parent
da50b99394
commit
cee2e3cb20
|
@ -1,5 +1,7 @@
|
||||||
package org.ethereum.trie;
|
package org.ethereum.trie;
|
||||||
|
|
||||||
|
import org.ethereum.util.Value;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -14,7 +16,7 @@ public class CollectFullSetOfNodes implements Trie.ScanAction {
|
||||||
Set<byte[]> nodes = new HashSet<>();
|
Set<byte[]> nodes = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doOnNode(byte[] hash) {
|
public void doOnNode(byte[] hash, Value node) {
|
||||||
nodes.add(hash);
|
nodes.add(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.ethereum.trie;
|
package org.ethereum.trie;
|
||||||
|
|
||||||
|
import org.ethereum.util.Value;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -15,7 +17,7 @@ public class CountAllNodes implements Trie.ScanAction {
|
||||||
int counted = 0;
|
int counted = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doOnNode(byte[] hash) {
|
public void doOnNode(byte[] hash, Value node) {
|
||||||
++counted;
|
++counted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.ethereum.trie;
|
||||||
|
|
||||||
|
import org.ethereum.util.Value;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* www.ethereumJ.com
|
||||||
|
*
|
||||||
|
* @author: Roman Mandeleil
|
||||||
|
* Created on: 29/08/2014 10:46
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TraceAllNodes implements Trie.ScanAction {
|
||||||
|
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doOnNode(byte[] hash, Value node) {
|
||||||
|
|
||||||
|
output.append(Hex.toHexString(hash)).append(" ==> ").append(node.toString()).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOutput() {
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -504,40 +504,23 @@ public class Trie implements TrieFacade {
|
||||||
scanTree(val.asBytes(), scanAction);
|
scanTree(val.asBytes(), scanAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
scanAction.doOnNode(hash, node);
|
||||||
scanAction.doOnNode(hash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTrieDump(){
|
public String getTrieDump(){
|
||||||
|
|
||||||
Set<ByteArrayWrapper> keys = getCache().getNodes().keySet();
|
TraceAllNodes traceAction = new TraceAllNodes();
|
||||||
StringBuilder output = new StringBuilder();
|
this.scanTree(this.getRootHash(), traceAction);
|
||||||
|
|
||||||
Value rootVal = new Value(root);
|
String root = "root: " + Hex.toHexString(getRootHash()) + "\n";
|
||||||
if ( ! Arrays.equals(rootVal.asBytes() , this.getRootHash())){
|
|
||||||
|
|
||||||
output.append("root: ").append(Hex.toHexString( this.getRootHash() )).append(" => ").
|
return root + traceAction.getOutput();
|
||||||
append( rootVal.toString()).append("\n");
|
|
||||||
} else {
|
|
||||||
|
|
||||||
output.append("root: ").append(Hex.toHexString( this.getRootHash() )).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ByteArrayWrapper key : keys){
|
|
||||||
|
|
||||||
Node value = getCache().getNodes().get(key);
|
|
||||||
|
|
||||||
byte[] hash = HashUtil.sha3( value.getValue().encode() );
|
|
||||||
output.append(Hex.toHexString(hash)).append(" ==> ").append(value.getValue().toString()).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return output.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface ScanAction{
|
public interface ScanAction{
|
||||||
|
|
||||||
public void doOnNode(byte[] hash);
|
public void doOnNode(byte[] hash, Value node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,7 +680,7 @@ public class RLP {
|
||||||
}
|
}
|
||||||
int prefix = data[pos] & 0xFF;
|
int prefix = data[pos] & 0xFF;
|
||||||
if (prefix == OFFSET_SHORT_ITEM) {
|
if (prefix == OFFSET_SHORT_ITEM) {
|
||||||
return new DecodeResult(pos+1, new byte[0]); // means no length or 0
|
return new DecodeResult(pos+1, ""); // means no length or 0
|
||||||
} else if (prefix < OFFSET_SHORT_ITEM) {
|
} else if (prefix < OFFSET_SHORT_ITEM) {
|
||||||
return new DecodeResult(pos+1, new byte[] { data[pos] }); // byte is its own RLP encoding
|
return new DecodeResult(pos+1, new byte[] { data[pos] }); // byte is its own RLP encoding
|
||||||
} else if (prefix < OFFSET_LONG_ITEM) {
|
} else if (prefix < OFFSET_LONG_ITEM) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ public class TrieTest {
|
||||||
private static String dude = "dude";
|
private static String dude = "dude";
|
||||||
|
|
||||||
private MockDB mockDb = new MockDB();
|
private MockDB mockDb = new MockDB();
|
||||||
|
private MockDB mockDb_2 = new MockDB();
|
||||||
|
|
||||||
// ROOT: [ '\x16', A ]
|
// ROOT: [ '\x16', A ]
|
||||||
// A: [ '', '', '', '', B, '', '', '', C, '', '', '', '', '', '', '', '' ]
|
// A: [ '', '', '', '', B, '', '', '', C, '', '', '', '', '', '', '', '' ]
|
||||||
|
@ -57,6 +59,7 @@ public class TrieTest {
|
||||||
@After
|
@After
|
||||||
public void closeMockDb() throws IOException {
|
public void closeMockDb() throws IOException {
|
||||||
mockDb.close();
|
mockDb.close();
|
||||||
|
mockDb_2.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -566,6 +569,74 @@ public class TrieTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMasiveDetermenisticUpdate() throws IOException, URISyntaxException {
|
||||||
|
|
||||||
|
// should be root: 89bb4c4051774dd9039305bdad93b7fb61fcf2e6c0905d1acf2658b9c00b35c6
|
||||||
|
|
||||||
|
URL massiveUpload_1 = ClassLoader
|
||||||
|
.getSystemResource("trie/massive-upload.dmp");
|
||||||
|
|
||||||
|
File file = new File(massiveUpload_1.toURI());
|
||||||
|
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// *** Part - 1 ***
|
||||||
|
// 1. load the data from massive-upload.dmp
|
||||||
|
// which includes deletes/upadtes (100000 operations)
|
||||||
|
Trie trieSingle = new Trie(mockDb_2);
|
||||||
|
for (int i = 0; i < strData.size() ; ++i){
|
||||||
|
|
||||||
|
String[] keyVal= strData.get(i).split("=");
|
||||||
|
|
||||||
|
if (keyVal[0].equals("*"))
|
||||||
|
trieSingle.delete(keyVal[1].trim());
|
||||||
|
else
|
||||||
|
trieSingle.update(keyVal[0].trim(), keyVal[1].trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println( "root_1: => " + Hex.toHexString( trieSingle.getRootHash() ));
|
||||||
|
|
||||||
|
// *** Part - 2 ***
|
||||||
|
// pre. we use the same data from massive-upload.dmp
|
||||||
|
// which includes deletes/upadtes (100000 operations)
|
||||||
|
// 1. part of the data loaded
|
||||||
|
// 2. the trie cache sync to the db
|
||||||
|
// 3. the rest of the data loaded with part of the trie not in the cache
|
||||||
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10000; ++i){
|
||||||
|
|
||||||
|
String[] keyVal= strData.get(i).split("=");
|
||||||
|
|
||||||
|
if (keyVal[0].equals("*"))
|
||||||
|
trie.delete(keyVal[1].trim());
|
||||||
|
else
|
||||||
|
trie.update(keyVal[0].trim(), keyVal[1].trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
trie.cleanCacheGarbage();
|
||||||
|
trie.sync();
|
||||||
|
|
||||||
|
Trie trie2 = new Trie(mockDb, trie.getRootHash());
|
||||||
|
|
||||||
|
for (int i = 10000; i < strData.size(); ++i){
|
||||||
|
|
||||||
|
String[] keyVal= strData.get(i).split("=");
|
||||||
|
|
||||||
|
if (keyVal[0].equals("*"))
|
||||||
|
trie2.delete(keyVal[1].trim());
|
||||||
|
else
|
||||||
|
trie2.update(keyVal[0].trim(), keyVal[1].trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println( "root_2: => " + Hex.toHexString( trie2.getRootHash() ));
|
||||||
|
|
||||||
|
assertEquals(trieSingle.getRootHash(), trie2.getRootHash());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test // tests saving keys to the file //
|
@Test // tests saving keys to the file //
|
||||||
public void testMasiveUpdateFromDB(){
|
public void testMasiveUpdateFromDB(){
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue