Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
dc3c3fb1
Commit
dc3c3fb1
authored
Oct 12, 2018
by
lash
Committed by
Anton Evangelatov
Oct 12, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
swarm/storage: Add accessCnt for GC (#17845)
parent
862d6f2f
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
358 additions
and
143 deletions
+358
-143
ldbstore.go
swarm/storage/ldbstore.go
+182
-100
ldbstore_test.go
swarm/storage/ldbstore_test.go
+176
-43
No files found.
swarm/storage/ldbstore.go
View file @
dc3c3fb1
This diff is collapsed.
Click to expand it.
swarm/storage/ldbstore_test.go
View file @
dc3c3fb1
...
@@ -22,6 +22,8 @@ import (
...
@@ -22,6 +22,8 @@ import (
"fmt"
"fmt"
"io/ioutil"
"io/ioutil"
"os"
"os"
"strconv"
"strings"
"testing"
"testing"
"time"
"time"
...
@@ -297,27 +299,73 @@ func TestLDBStoreWithoutCollectGarbage(t *testing.T) {
...
@@ -297,27 +299,73 @@ func TestLDBStoreWithoutCollectGarbage(t *testing.T) {
}
}
// TestLDBStoreCollectGarbage tests that we can put more chunks than LevelDB's capacity, and
// TestLDBStoreCollectGarbage tests that we can put more chunks than LevelDB's capacity, and
// retrieve only some of them, because garbage collection must have cleared some of them
// retrieve only some of them, because garbage collection must have partially cleared the store
// Also tests that we can delete chunks and that we can trigger garbage collection
func
TestLDBStoreCollectGarbage
(
t
*
testing
.
T
)
{
func
TestLDBStoreCollectGarbage
(
t
*
testing
.
T
)
{
capacity
:=
500
n
:=
2000
// below max ronud
cap
:=
defaultMaxGCRound
/
2
t
.
Run
(
fmt
.
Sprintf
(
"A/%d/%d"
,
cap
,
cap
*
4
),
testLDBStoreCollectGarbage
)
t
.
Run
(
fmt
.
Sprintf
(
"B/%d/%d"
,
cap
,
cap
*
4
),
testLDBStoreRemoveThenCollectGarbage
)
// at max round
cap
=
defaultMaxGCRound
t
.
Run
(
fmt
.
Sprintf
(
"A/%d/%d"
,
cap
,
cap
*
4
),
testLDBStoreCollectGarbage
)
t
.
Run
(
fmt
.
Sprintf
(
"B/%d/%d"
,
cap
,
cap
*
4
),
testLDBStoreRemoveThenCollectGarbage
)
// more than max around, not on threshold
cap
=
defaultMaxGCRound
*
1.1
t
.
Run
(
fmt
.
Sprintf
(
"A/%d/%d"
,
cap
,
cap
*
4
),
testLDBStoreCollectGarbage
)
t
.
Run
(
fmt
.
Sprintf
(
"B/%d/%d"
,
cap
,
cap
*
4
),
testLDBStoreRemoveThenCollectGarbage
)
}
func
testLDBStoreCollectGarbage
(
t
*
testing
.
T
)
{
params
:=
strings
.
Split
(
t
.
Name
(),
"/"
)
capacity
,
err
:=
strconv
.
Atoi
(
params
[
2
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
n
,
err
:=
strconv
.
Atoi
(
params
[
3
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ldb
,
cleanup
:=
newLDBStore
(
t
)
ldb
,
cleanup
:=
newLDBStore
(
t
)
ldb
.
setCapacity
(
uint64
(
capacity
))
ldb
.
setCapacity
(
uint64
(
capacity
))
defer
cleanup
()
defer
cleanup
()
chunks
,
err
:=
mputRandomChunks
(
ldb
,
n
,
int64
(
ch
.
DefaultSize
))
// retrieve the gc round target count for the db capacity
if
err
!=
nil
{
ldb
.
startGC
(
capacity
)
t
.
Fatal
(
err
.
Error
())
roundTarget
:=
ldb
.
gc
.
target
}
log
.
Info
(
"ldbstore"
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
// split put counts to gc target count threshold, and wait for gc to finish in between
var
allChunks
[]
Chunk
remaining
:=
n
for
remaining
>
0
{
var
putCount
int
if
remaining
<
roundTarget
{
putCount
=
remaining
}
else
{
putCount
=
roundTarget
}
remaining
-=
putCount
chunks
,
err
:=
mputRandomChunks
(
ldb
,
putCount
,
int64
(
ch
.
DefaultSize
))
if
err
!=
nil
{
t
.
Fatal
(
err
.
Error
())
}
allChunks
=
append
(
allChunks
,
chunks
...
)
log
.
Debug
(
"ldbstore"
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
,
"cap"
,
capacity
,
"n"
,
n
)
// wait for garbage collection to kick in on the responsible actor
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Second
*
10
)
time
.
Sleep
(
1
*
time
.
Second
)
defer
cancel
()
waitGc
(
ctx
,
ldb
)
}
// attempt gets on all put chunks
var
missing
int
var
missing
int
for
_
,
ch
:=
range
c
hunks
{
for
_
,
ch
:=
range
allC
hunks
{
ret
,
err
:=
ldb
.
Get
(
context
.
Background
(),
ch
.
Address
())
ret
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
ch
.
Address
())
if
err
==
ErrChunkNotFound
||
err
==
ldberrors
.
ErrNotFound
{
if
err
==
ErrChunkNotFound
||
err
==
ldberrors
.
ErrNotFound
{
missing
++
missing
++
continue
continue
...
@@ -333,8 +381,10 @@ func TestLDBStoreCollectGarbage(t *testing.T) {
...
@@ -333,8 +381,10 @@ func TestLDBStoreCollectGarbage(t *testing.T) {
log
.
Trace
(
"got back chunk"
,
"chunk"
,
ret
)
log
.
Trace
(
"got back chunk"
,
"chunk"
,
ret
)
}
}
if
missing
<
n
-
capacity
{
// all surplus chunks should be missing
t
.
Fatalf
(
"gc failure: expected to miss %v chunks, but only %v are actually missing"
,
n
-
capacity
,
missing
)
expectMissing
:=
roundTarget
+
(((
n
-
capacity
)
/
roundTarget
)
*
roundTarget
)
if
missing
!=
expectMissing
{
t
.
Fatalf
(
"gc failure: expected to miss %v chunks, but only %v are actually missing"
,
expectMissing
,
missing
)
}
}
log
.
Info
(
"ldbstore"
,
"total"
,
n
,
"missing"
,
missing
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
log
.
Info
(
"ldbstore"
,
"total"
,
n
,
"missing"
,
missing
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
...
@@ -367,7 +417,6 @@ func TestLDBStoreAddRemove(t *testing.T) {
...
@@ -367,7 +417,6 @@ func TestLDBStoreAddRemove(t *testing.T) {
if
i
%
2
==
0
{
if
i
%
2
==
0
{
// expect even chunks to be missing
// expect even chunks to be missing
if
err
==
nil
{
if
err
==
nil
{
// if err != ErrChunkNotFound {
t
.
Fatal
(
"expected chunk to be missing, but got no error"
)
t
.
Fatal
(
"expected chunk to be missing, but got no error"
)
}
}
}
else
{
}
else
{
...
@@ -383,30 +432,48 @@ func TestLDBStoreAddRemove(t *testing.T) {
...
@@ -383,30 +432,48 @@ func TestLDBStoreAddRemove(t *testing.T) {
}
}
}
}
// TestLDBStoreRemoveThenCollectGarbage tests that we can delete chunks and that we can trigger garbage collection
func
testLDBStoreRemoveThenCollectGarbage
(
t
*
testing
.
T
)
{
func
TestLDBStoreRemoveThenCollectGarbage
(
t
*
testing
.
T
)
{
capacity
:=
11
params
:=
strings
.
Split
(
t
.
Name
(),
"/"
)
surplus
:=
4
capacity
,
err
:=
strconv
.
Atoi
(
params
[
2
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
n
,
err
:=
strconv
.
Atoi
(
params
[
3
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ldb
,
cleanup
:=
newLDBStore
(
t
)
ldb
,
cleanup
:=
newLDBStore
(
t
)
defer
cleanup
()
ldb
.
setCapacity
(
uint64
(
capacity
))
ldb
.
setCapacity
(
uint64
(
capacity
))
n
:=
capacity
// put capacity count number of chunks
chunks
:=
make
([]
Chunk
,
n
)
chunks
:=
[]
Chunk
{}
for
i
:=
0
;
i
<
n
;
i
++
{
for
i
:=
0
;
i
<
n
+
surplus
;
i
++
{
c
:=
GenerateRandomChunk
(
ch
.
DefaultSize
)
c
:=
GenerateRandomChunk
(
ch
.
DefaultSize
)
chunks
=
append
(
chunks
,
c
)
chunks
[
i
]
=
c
log
.
Trace
(
"generate random chunk"
,
"idx"
,
i
,
"chunk"
,
c
)
log
.
Trace
(
"generate random chunk"
,
"idx"
,
i
,
"chunk"
,
c
)
}
}
for
i
:=
0
;
i
<
n
;
i
++
{
for
i
:=
0
;
i
<
n
;
i
++
{
ldb
.
Put
(
context
.
TODO
(),
chunks
[
i
])
err
:=
ldb
.
Put
(
context
.
TODO
(),
chunks
[
i
])
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
}
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Second
*
10
)
defer
cancel
()
waitGc
(
ctx
,
ldb
)
// delete all chunks
// delete all chunks
// (only count the ones actually deleted, the rest will have been gc'd)
deletes
:=
0
for
i
:=
0
;
i
<
n
;
i
++
{
for
i
:=
0
;
i
<
n
;
i
++
{
ldb
.
Delete
(
chunks
[
i
]
.
Address
())
if
ldb
.
Delete
(
chunks
[
i
]
.
Address
())
==
nil
{
deletes
++
}
}
}
log
.
Info
(
"ldbstore"
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
log
.
Info
(
"ldbstore"
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
...
@@ -415,37 +482,49 @@ func TestLDBStoreRemoveThenCollectGarbage(t *testing.T) {
...
@@ -415,37 +482,49 @@ func TestLDBStoreRemoveThenCollectGarbage(t *testing.T) {
t
.
Fatalf
(
"ldb.entrCnt expected 0 got %v"
,
ldb
.
entryCnt
)
t
.
Fatalf
(
"ldb.entrCnt expected 0 got %v"
,
ldb
.
entryCnt
)
}
}
expAccessCnt
:=
uint64
(
n
*
2
)
// the manual deletes will have increased accesscnt, so we need to add this when we verify the current count
expAccessCnt
:=
uint64
(
n
)
if
ldb
.
accessCnt
!=
expAccessCnt
{
if
ldb
.
accessCnt
!=
expAccessCnt
{
t
.
Fatalf
(
"ldb.accessCnt expected %v got %v"
,
expAccessCnt
,
ldb
.
entry
Cnt
)
t
.
Fatalf
(
"ldb.accessCnt expected %v got %v"
,
expAccessCnt
,
ldb
.
access
Cnt
)
}
}
cleanup
()
// retrieve the gc round target count for the db capacity
ldb
.
startGC
(
capacity
)
roundTarget
:=
ldb
.
gc
.
target
ldb
,
cleanup
=
newLDBStore
(
t
)
remaining
:=
n
capacity
=
10
var
puts
int
ldb
.
setCapacity
(
uint64
(
capacity
))
for
remaining
>
0
{
defer
cleanup
()
var
putCount
int
if
remaining
<
roundTarget
{
n
=
capacity
+
surplus
putCount
=
remaining
}
else
{
putCount
=
roundTarget
}
remaining
-=
putCount
for
putCount
>
0
{
ldb
.
Put
(
context
.
TODO
(),
chunks
[
puts
])
log
.
Debug
(
"ldbstore"
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
,
"cap"
,
capacity
,
"n"
,
n
,
"puts"
,
puts
,
"remaining"
,
remaining
,
"roundtarget"
,
roundTarget
)
puts
++
putCount
--
}
for
i
:=
0
;
i
<
n
;
i
++
{
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Second
*
10
)
ldb
.
Put
(
context
.
TODO
(),
chunks
[
i
])
defer
cancel
()
waitGc
(
ctx
,
ldb
)
}
}
// wait for garbage collection
time
.
Sleep
(
1
*
time
.
Second
)
// expect first surplus chunks to be missing, because they have the smallest access value
// expect first surplus chunks to be missing, because they have the smallest access value
for
i
:=
0
;
i
<
surplus
;
i
++
{
expectMissing
:=
roundTarget
+
(((
n
-
capacity
)
/
roundTarget
)
*
roundTarget
)
for
i
:=
0
;
i
<
expectMissing
;
i
++
{
_
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
chunks
[
i
]
.
Address
())
_
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
chunks
[
i
]
.
Address
())
if
err
==
nil
{
if
err
==
nil
{
t
.
Fatal
(
"expected surplus chunk to be missing, but got no error"
)
t
.
Fatal
f
(
"expected surplus chunk %d to be missing, but got no error"
,
i
)
}
}
}
}
// expect last chunks to be present, as they have the largest access value
// expect last chunks to be present, as they have the largest access value
for
i
:=
surplus
;
i
<
surplus
+
capacity
;
i
++
{
for
i
:=
expectMissing
;
i
<
n
;
i
++
{
ret
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
chunks
[
i
]
.
Address
())
ret
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
chunks
[
i
]
.
Address
())
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"chunk %v: expected no error, but got %s"
,
i
,
err
)
t
.
Fatalf
(
"chunk %v: expected no error, but got %s"
,
i
,
err
)
...
@@ -455,3 +534,57 @@ func TestLDBStoreRemoveThenCollectGarbage(t *testing.T) {
...
@@ -455,3 +534,57 @@ func TestLDBStoreRemoveThenCollectGarbage(t *testing.T) {
}
}
}
}
}
}
// TestLDBStoreCollectGarbageAccessUnlikeIndex tests garbage collection where accesscount differs from indexcount
func
TestLDBStoreCollectGarbageAccessUnlikeIndex
(
t
*
testing
.
T
)
{
capacity
:=
defaultMaxGCRound
*
2
n
:=
capacity
-
1
ldb
,
cleanup
:=
newLDBStore
(
t
)
ldb
.
setCapacity
(
uint64
(
capacity
))
defer
cleanup
()
chunks
,
err
:=
mputRandomChunks
(
ldb
,
n
,
int64
(
ch
.
DefaultSize
))
if
err
!=
nil
{
t
.
Fatal
(
err
.
Error
())
}
log
.
Info
(
"ldbstore"
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
// set first added capacity/2 chunks to highest accesscount
for
i
:=
0
;
i
<
capacity
/
2
;
i
++
{
_
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
chunks
[
i
]
.
Address
())
if
err
!=
nil
{
t
.
Fatalf
(
"fail add chunk #%d - %s: %v"
,
i
,
chunks
[
i
]
.
Address
(),
err
)
}
}
_
,
err
=
mputRandomChunks
(
ldb
,
2
,
int64
(
ch
.
DefaultSize
))
if
err
!=
nil
{
t
.
Fatal
(
err
.
Error
())
}
// wait for garbage collection to kick in on the responsible actor
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Second
*
10
)
defer
cancel
()
waitGc
(
ctx
,
ldb
)
var
missing
int
for
i
,
ch
:=
range
chunks
[
2
:
capacity
/
2
]
{
ret
,
err
:=
ldb
.
Get
(
context
.
TODO
(),
ch
.
Address
())
if
err
==
ErrChunkNotFound
||
err
==
ldberrors
.
ErrNotFound
{
t
.
Fatalf
(
"fail find chunk #%d - %s: %v"
,
i
,
ch
.
Address
(),
err
)
}
if
!
bytes
.
Equal
(
ret
.
Data
(),
ch
.
Data
())
{
t
.
Fatal
(
"expected to get the same data back, but got smth else"
)
}
log
.
Trace
(
"got back chunk"
,
"chunk"
,
ret
)
}
log
.
Info
(
"ldbstore"
,
"total"
,
n
,
"missing"
,
missing
,
"entrycnt"
,
ldb
.
entryCnt
,
"accesscnt"
,
ldb
.
accessCnt
)
}
func
waitGc
(
ctx
context
.
Context
,
ldb
*
LDBStore
)
{
<-
ldb
.
gc
.
runC
ldb
.
gc
.
runC
<-
struct
{}{}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment