symmetric diff iterator: detect common paths
This commit is contained in:
parent
bb10c6fffa
commit
d2224af6b5
@ -8,9 +8,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type symmDiffIterator struct {
|
type symmDiffIterator struct {
|
||||||
a, b iterState // Nodes returned are those in b - a and a - b (keys only)
|
a, b iterState // Nodes returned are those in b - a and a - b (keys only)
|
||||||
yieldFromA bool // Whether next node comes from a
|
yieldFromA bool // Whether next node comes from a
|
||||||
count int // Number of nodes scanned on either trie
|
count int // Number of nodes scanned on either trie
|
||||||
|
eqPathIndex int // Count index of last pair of equal paths, to detect an updated key
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDifferenceIterator constructs a trie.NodeIterator that iterates over the exclusive elements in b that
|
// NewDifferenceIterator constructs a trie.NodeIterator that iterates over the exclusive elements in b that
|
||||||
@ -47,6 +48,12 @@ func (it *symmDiffIterator) FromA() bool {
|
|||||||
return it.yieldFromA
|
return it.yieldFromA
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommonPath returns true if a node with the current path exists in each sub-iterator - i.e. it
|
||||||
|
// represents an updated node.
|
||||||
|
func (it *symmDiffIterator) CommonPath() bool {
|
||||||
|
return it.count-it.eqPathIndex <= 1
|
||||||
|
}
|
||||||
|
|
||||||
func (it *symmDiffIterator) Hash() common.Hash {
|
func (it *symmDiffIterator) Hash() common.Hash {
|
||||||
return it.curr().Hash()
|
return it.curr().Hash()
|
||||||
}
|
}
|
||||||
@ -110,7 +117,12 @@ func (it *symmDiffIterator) seek() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch compareNodes(&it.a, &it.b) {
|
cmp := bytes.Compare(it.a.Path(), it.b.Path())
|
||||||
|
if cmp == 0 {
|
||||||
|
it.eqPathIndex = it.count
|
||||||
|
cmp = compareValues(&it.a, &it.b)
|
||||||
|
}
|
||||||
|
switch cmp {
|
||||||
case -1:
|
case -1:
|
||||||
it.yieldFromA = true
|
it.yieldFromA = true
|
||||||
return
|
return
|
||||||
@ -136,10 +148,7 @@ func (it *symmDiffIterator) Error() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compares nodes with equal paths by value
|
// Compares nodes with equal paths by value
|
||||||
func compareNodes(a, b trie.NodeIterator) int {
|
func compareValues(a, b trie.NodeIterator) int {
|
||||||
if cmp := bytes.Compare(a.Path(), b.Path()); cmp != 0 {
|
|
||||||
return cmp
|
|
||||||
}
|
|
||||||
if a.Leaf() && !b.Leaf() {
|
if a.Leaf() && !b.Leaf() {
|
||||||
return -1
|
return -1
|
||||||
} else if b.Leaf() && !a.Leaf() {
|
} else if b.Leaf() && !a.Leaf() {
|
||||||
|
@ -50,7 +50,26 @@ func TestSymmetricDifferenceIterator(t *testing.T) {
|
|||||||
for di.Next(true) {
|
for di.Next(true) {
|
||||||
t.Errorf("iterator should not yield any elements")
|
t.Errorf("iterator should not yield any elements")
|
||||||
}
|
}
|
||||||
assert.NotEqual(t, 0, count)
|
assert.Equal(t, 4, *count)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with one difference", func(t *testing.T) {
|
||||||
|
dba := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
||||||
|
triea := trie.NewEmpty(dba)
|
||||||
|
|
||||||
|
dbb := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
||||||
|
trieb := trie.NewEmpty(dbb)
|
||||||
|
trieb.MustUpdate([]byte("foo"), []byte("bar"))
|
||||||
|
|
||||||
|
di, count := utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
|
||||||
|
for di.Next(true) {
|
||||||
|
if di.Leaf() {
|
||||||
|
assert.Equal(t, []byte("foo"), di.LeafKey())
|
||||||
|
assert.Equal(t, []byte("bar"), di.LeafBlob())
|
||||||
|
assert.False(t, di.CommonPath())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Equal(t, 2, *count)
|
||||||
})
|
})
|
||||||
|
|
||||||
dba := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
dba := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
||||||
@ -66,6 +85,7 @@ func TestSymmetricDifferenceIterator(t *testing.T) {
|
|||||||
|
|
||||||
onlyA := make(map[string]string)
|
onlyA := make(map[string]string)
|
||||||
onlyB := make(map[string]string)
|
onlyB := make(map[string]string)
|
||||||
|
var deletions, creations []string
|
||||||
it, _ := utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
|
it, _ := utils.NewSymmetricDifferenceIterator(triea.NodeIterator(nil), trieb.NodeIterator(nil))
|
||||||
for it.Next(true) {
|
for it.Next(true) {
|
||||||
if !it.Leaf() {
|
if !it.Leaf() {
|
||||||
@ -74,8 +94,14 @@ func TestSymmetricDifferenceIterator(t *testing.T) {
|
|||||||
key, value := string(it.LeafKey()), string(it.LeafBlob())
|
key, value := string(it.LeafKey()), string(it.LeafBlob())
|
||||||
if it.FromA() {
|
if it.FromA() {
|
||||||
onlyA[key] = value
|
onlyA[key] = value
|
||||||
|
if !it.CommonPath() {
|
||||||
|
deletions = append(deletions, key)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
onlyB[key] = value
|
onlyB[key] = value
|
||||||
|
if !it.CommonPath() {
|
||||||
|
creations = append(creations, key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +118,17 @@ func TestSymmetricDifferenceIterator(t *testing.T) {
|
|||||||
"foos": "aa",
|
"foos": "aa",
|
||||||
"jars": "d",
|
"jars": "d",
|
||||||
}
|
}
|
||||||
|
expectedDeletions := []string{
|
||||||
|
"bard",
|
||||||
|
"food",
|
||||||
|
}
|
||||||
|
expectedCreations := []string{
|
||||||
|
"aardvark",
|
||||||
|
"foos",
|
||||||
|
"jars",
|
||||||
|
}
|
||||||
assert.Equal(t, expectedOnlyA, onlyA)
|
assert.Equal(t, expectedOnlyA, onlyA)
|
||||||
assert.Equal(t, expectedOnlyB, onlyB)
|
assert.Equal(t, expectedOnlyB, onlyB)
|
||||||
|
assert.Equal(t, expectedDeletions, deletions)
|
||||||
|
assert.Equal(t, expectedCreations, creations)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user