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
4800c943
Commit
4800c943
authored
May 06, 2015
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
eth/downloader: prioritize block fetch based on chain position, cap memory use
parent
97c37356
Changes
11
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
798 additions
and
273 deletions
+798
-273
Godeps.json
Godeps/Godeps.json
+4
-0
example_test.go
...n/karalabe/cookiejar.v2/collections/prque/example_test.go
+44
-0
prque.go
...gopkg.in/karalabe/cookiejar.v2/collections/prque/prque.go
+75
-0
prque_test.go
....in/karalabe/cookiejar.v2/collections/prque/prque_test.go
+110
-0
sstack.go
...opkg.in/karalabe/cookiejar.v2/collections/prque/sstack.go
+103
-0
sstack_test.go
...in/karalabe/cookiejar.v2/collections/prque/sstack_test.go
+93
-0
downloader.go
eth/downloader/downloader.go
+70
-120
downloader_test.go
eth/downloader/downloader_test.go
+2
-2
peer.go
eth/downloader/peer.go
+7
-8
queue.go
eth/downloader/queue.go
+282
-134
queue_test.go
eth/downloader/queue_test.go
+8
-9
No files found.
Godeps/Godeps.json
View file @
4800c943
...
...
@@ -98,6 +98,10 @@
"Comment"
:
"v0.1.0-3-g27c4092"
,
"Rev"
:
"27c40922c40b43fe04554d8223a402af3ea333f3"
},
{
"ImportPath"
:
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
,
"Rev"
:
"cf5d8079df7c4501217638e1e3a6e43f94822548"
},
{
"ImportPath"
:
"gopkg.in/qml.v1/cdata"
,
"Rev"
:
"1116cb9cd8dee23f8d444ded354eb53122739f99"
...
...
Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/example_test.go
0 → 100644
View file @
4800c943
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// The toolbox is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// Alternatively, the CookieJar toolbox may be used in accordance with the terms
// and conditions contained in a signed written agreement between you and the
// author(s).
package
prque_test
import
(
"fmt"
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
)
// Insert some data into a priority queue and pop them out in prioritized order.
func
Example_usage
()
{
// Define some data to push into the priority queue
prio
:=
[]
float32
{
77.7
,
22.2
,
44.4
,
55.5
,
11.1
,
88.8
,
33.3
,
99.9
,
0.0
,
66.6
}
data
:=
[]
string
{
"zero"
,
"one"
,
"two"
,
"three"
,
"four"
,
"five"
,
"six"
,
"seven"
,
"eight"
,
"nine"
}
// Create the priority queue and insert the prioritized data
pq
:=
prque
.
New
()
for
i
:=
0
;
i
<
len
(
data
);
i
++
{
pq
.
Push
(
data
[
i
],
prio
[
i
])
}
// Pop out the data and print them
for
!
pq
.
Empty
()
{
val
,
prio
:=
pq
.
Pop
()
fmt
.
Printf
(
"%.1f:%s "
,
prio
,
val
)
}
// Output:
// 99.9:seven 88.8:five 77.7:zero 66.6:nine 55.5:three 44.4:two 33.3:six 22.2:one 11.1:four 0.0:eight
}
Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque.go
0 → 100644
View file @
4800c943
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// The toolbox is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// Alternatively, the CookieJar toolbox may be used in accordance with the terms
// and conditions contained in a signed written agreement between you and the
// author(s).
// Package prque implements a priority queue data structure supporting arbitrary
// value types and float priorities.
//
// The reasoning behind using floats for the priorities vs. ints or interfaces
// was larger flexibility without sacrificing too much performance or code
// complexity.
//
// If you would like to use a min-priority queue, simply negate the priorities.
//
// Internally the queue is based on the standard heap package working on a
// sortable version of the block based stack.
package
prque
import
(
"container/heap"
)
// Priority queue data structure.
type
Prque
struct
{
cont
*
sstack
}
// Creates a new priority queue.
func
New
()
*
Prque
{
return
&
Prque
{
newSstack
()}
}
// Pushes a value with a given priority into the queue, expanding if necessary.
func
(
p
*
Prque
)
Push
(
data
interface
{},
priority
float32
)
{
heap
.
Push
(
p
.
cont
,
&
item
{
data
,
priority
})
}
// Pops the value with the greates priority off the stack and returns it.
// Currently no shrinking is done.
func
(
p
*
Prque
)
Pop
()
(
interface
{},
float32
)
{
item
:=
heap
.
Pop
(
p
.
cont
)
.
(
*
item
)
return
item
.
value
,
item
.
priority
}
// Pops only the item from the queue, dropping the associated priority value.
func
(
p
*
Prque
)
PopItem
()
interface
{}
{
return
heap
.
Pop
(
p
.
cont
)
.
(
*
item
)
.
value
}
// Checks whether the priority queue is empty.
func
(
p
*
Prque
)
Empty
()
bool
{
return
p
.
cont
.
Len
()
==
0
}
// Returns the number of element in the priority queue.
func
(
p
*
Prque
)
Size
()
int
{
return
p
.
cont
.
Len
()
}
// Clears the contents of the priority queue.
func
(
p
*
Prque
)
Reset
()
{
p
.
cont
.
Reset
()
}
Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/prque_test.go
0 → 100644
View file @
4800c943
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// The toolbox is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// Alternatively, the CookieJar toolbox may be used in accordance with the terms
// and conditions contained in a signed written agreement between you and the
// author(s).
package
prque
import
(
"math/rand"
"testing"
)
func
TestPrque
(
t
*
testing
.
T
)
{
// Generate a batch of random data and a specific priority order
size
:=
16
*
blockSize
prio
:=
rand
.
Perm
(
size
)
data
:=
make
([]
int
,
size
)
for
i
:=
0
;
i
<
size
;
i
++
{
data
[
i
]
=
rand
.
Int
()
}
queue
:=
New
()
for
rep
:=
0
;
rep
<
2
;
rep
++
{
// Fill a priority queue with the above data
for
i
:=
0
;
i
<
size
;
i
++
{
queue
.
Push
(
data
[
i
],
float32
(
prio
[
i
]))
if
queue
.
Size
()
!=
i
+
1
{
t
.
Errorf
(
"queue size mismatch: have %v, want %v."
,
queue
.
Size
(),
i
+
1
)
}
}
// Create a map the values to the priorities for easier verification
dict
:=
make
(
map
[
float32
]
int
)
for
i
:=
0
;
i
<
size
;
i
++
{
dict
[
float32
(
prio
[
i
])]
=
data
[
i
]
}
// Pop out the elements in priority order and verify them
prevPrio
:=
float32
(
size
+
1
)
for
!
queue
.
Empty
()
{
val
,
prio
:=
queue
.
Pop
()
if
prio
>
prevPrio
{
t
.
Errorf
(
"invalid priority order: %v after %v."
,
prio
,
prevPrio
)
}
prevPrio
=
prio
if
val
!=
dict
[
prio
]
{
t
.
Errorf
(
"push/pop mismatch: have %v, want %v."
,
val
,
dict
[
prio
])
}
delete
(
dict
,
prio
)
}
}
}
func
TestReset
(
t
*
testing
.
T
)
{
// Fill the queue with some random data
size
:=
16
*
blockSize
queue
:=
New
()
for
i
:=
0
;
i
<
size
;
i
++
{
queue
.
Push
(
rand
.
Int
(),
rand
.
Float32
())
}
// Reset and ensure it's empty
queue
.
Reset
()
if
!
queue
.
Empty
()
{
t
.
Errorf
(
"priority queue not empty after reset: %v"
,
queue
)
}
}
func
BenchmarkPush
(
b
*
testing
.
B
)
{
// Create some initial data
data
:=
make
([]
int
,
b
.
N
)
prio
:=
make
([]
float32
,
b
.
N
)
for
i
:=
0
;
i
<
len
(
data
);
i
++
{
data
[
i
]
=
rand
.
Int
()
prio
[
i
]
=
rand
.
Float32
()
}
// Execute the benchmark
b
.
ResetTimer
()
queue
:=
New
()
for
i
:=
0
;
i
<
len
(
data
);
i
++
{
queue
.
Push
(
data
[
i
],
prio
[
i
])
}
}
func
BenchmarkPop
(
b
*
testing
.
B
)
{
// Create some initial data
data
:=
make
([]
int
,
b
.
N
)
prio
:=
make
([]
float32
,
b
.
N
)
for
i
:=
0
;
i
<
len
(
data
);
i
++
{
data
[
i
]
=
rand
.
Int
()
prio
[
i
]
=
rand
.
Float32
()
}
queue
:=
New
()
for
i
:=
0
;
i
<
len
(
data
);
i
++
{
queue
.
Push
(
data
[
i
],
prio
[
i
])
}
// Execute the benchmark
b
.
ResetTimer
()
for
!
queue
.
Empty
()
{
queue
.
Pop
()
}
}
Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack.go
0 → 100644
View file @
4800c943
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// The toolbox is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// Alternatively, the CookieJar toolbox may be used in accordance with the terms
// and conditions contained in a signed written agreement between you and the
// author(s).
package
prque
// The size of a block of data
const
blockSize
=
4096
// A prioritized item in the sorted stack.
type
item
struct
{
value
interface
{}
priority
float32
}
// Internal sortable stack data structure. Implements the Push and Pop ops for
// the stack (heap) functionality and the Len, Less and Swap methods for the
// sortability requirements of the heaps.
type
sstack
struct
{
size
int
capacity
int
offset
int
blocks
[][]
*
item
active
[]
*
item
}
// Creates a new, empty stack.
func
newSstack
()
*
sstack
{
result
:=
new
(
sstack
)
result
.
active
=
make
([]
*
item
,
blockSize
)
result
.
blocks
=
[][]
*
item
{
result
.
active
}
result
.
capacity
=
blockSize
return
result
}
// Pushes a value onto the stack, expanding it if necessary. Required by
// heap.Interface.
func
(
s
*
sstack
)
Push
(
data
interface
{})
{
if
s
.
size
==
s
.
capacity
{
s
.
active
=
make
([]
*
item
,
blockSize
)
s
.
blocks
=
append
(
s
.
blocks
,
s
.
active
)
s
.
capacity
+=
blockSize
s
.
offset
=
0
}
else
if
s
.
offset
==
blockSize
{
s
.
active
=
s
.
blocks
[
s
.
size
/
blockSize
]
s
.
offset
=
0
}
s
.
active
[
s
.
offset
]
=
data
.
(
*
item
)
s
.
offset
++
s
.
size
++
}
// Pops a value off the stack and returns it. Currently no shrinking is done.
// Required by heap.Interface.
func
(
s
*
sstack
)
Pop
()
(
res
interface
{})
{
s
.
size
--
s
.
offset
--
if
s
.
offset
<
0
{
s
.
offset
=
blockSize
-
1
s
.
active
=
s
.
blocks
[
s
.
size
/
blockSize
]
}
res
,
s
.
active
[
s
.
offset
]
=
s
.
active
[
s
.
offset
],
nil
return
}
// Returns the length of the stack. Required by sort.Interface.
func
(
s
*
sstack
)
Len
()
int
{
return
s
.
size
}
// Compares the priority of two elements of the stack (higher is first).
// Required by sort.Interface.
func
(
s
*
sstack
)
Less
(
i
,
j
int
)
bool
{
return
s
.
blocks
[
i
/
blockSize
][
i
%
blockSize
]
.
priority
>
s
.
blocks
[
j
/
blockSize
][
j
%
blockSize
]
.
priority
}
// Swapts two elements in the stack. Required by sort.Interface.
func
(
s
*
sstack
)
Swap
(
i
,
j
int
)
{
ib
,
io
,
jb
,
jo
:=
i
/
blockSize
,
i
%
blockSize
,
j
/
blockSize
,
j
%
blockSize
s
.
blocks
[
ib
][
io
],
s
.
blocks
[
jb
][
jo
]
=
s
.
blocks
[
jb
][
jo
],
s
.
blocks
[
ib
][
io
]
}
// Resets the stack, effectively clearing its contents.
func
(
s
*
sstack
)
Reset
()
{
s
.
size
=
0
s
.
offset
=
0
s
.
active
=
s
.
blocks
[
0
]
s
.
capacity
=
blockSize
}
Godeps/_workspace/src/gopkg.in/karalabe/cookiejar.v2/collections/prque/sstack_test.go
0 → 100644
View file @
4800c943
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// The toolbox is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// Alternatively, the CookieJar toolbox may be used in accordance with the terms
// and conditions contained in a signed written agreement between you and the
// author(s).
package
prque
import
(
"math/rand"
"sort"
"testing"
)
func
TestSstack
(
t
*
testing
.
T
)
{
// Create some initial data
size
:=
16
*
blockSize
data
:=
make
([]
*
item
,
size
)
for
i
:=
0
;
i
<
size
;
i
++
{
data
[
i
]
=
&
item
{
rand
.
Int
(),
rand
.
Float32
()}
}
stack
:=
newSstack
()
for
rep
:=
0
;
rep
<
2
;
rep
++
{
// Push all the data into the stack, pop out every second
secs
:=
[]
*
item
{}
for
i
:=
0
;
i
<
size
;
i
++
{
stack
.
Push
(
data
[
i
])
if
i
%
2
==
0
{
secs
=
append
(
secs
,
stack
.
Pop
()
.
(
*
item
))
}
}
rest
:=
[]
*
item
{}
for
stack
.
Len
()
>
0
{
rest
=
append
(
rest
,
stack
.
Pop
()
.
(
*
item
))
}
// Make sure the contents of the resulting slices are ok
for
i
:=
0
;
i
<
size
;
i
++
{
if
i
%
2
==
0
&&
data
[
i
]
!=
secs
[
i
/
2
]
{
t
.
Errorf
(
"push/pop mismatch: have %v, want %v."
,
secs
[
i
/
2
],
data
[
i
])
}
if
i
%
2
==
1
&&
data
[
i
]
!=
rest
[
len
(
rest
)
-
i
/
2
-
1
]
{
t
.
Errorf
(
"push/pop mismatch: have %v, want %v."
,
rest
[
len
(
rest
)
-
i
/
2
-
1
],
data
[
i
])
}
}
}
}
func
TestSstackSort
(
t
*
testing
.
T
)
{
// Create some initial data
size
:=
16
*
blockSize
data
:=
make
([]
*
item
,
size
)
for
i
:=
0
;
i
<
size
;
i
++
{
data
[
i
]
=
&
item
{
rand
.
Int
(),
float32
(
i
)}
}
// Push all the data into the stack
stack
:=
newSstack
()
for
_
,
val
:=
range
data
{
stack
.
Push
(
val
)
}
// Sort and pop the stack contents (should reverse the order)
sort
.
Sort
(
stack
)
for
_
,
val
:=
range
data
{
out
:=
stack
.
Pop
()
if
out
!=
val
{
t
.
Errorf
(
"push/pop mismatch after sort: have %v, want %v."
,
out
,
val
)
}
}
}
func
TestSstackReset
(
t
*
testing
.
T
)
{
// Push some stuff onto the stack
size
:=
16
*
blockSize
stack
:=
newSstack
()
for
i
:=
0
;
i
<
size
;
i
++
{
stack
.
Push
(
&
item
{
i
,
float32
(
i
)})
}
// Clear and verify
stack
.
Reset
()
if
stack
.
Len
()
!=
0
{
t
.
Errorf
(
"stack not empty after reset: %v"
,
stack
)
}
}
eth/downloader/downloader.go
View file @
4800c943
This diff is collapsed.
Click to expand it.
eth/downloader/downloader_test.go
View file @
4800c943
...
...
@@ -128,7 +128,7 @@ func TestDownload(t *testing.T) {
t
.
Error
(
"download error"
,
err
)
}
inqueue
:=
len
(
tester
.
downloader
.
queue
.
block
s
)
inqueue
:=
len
(
tester
.
downloader
.
queue
.
block
Cache
)
if
inqueue
!=
targetBlocks
{
t
.
Error
(
"expected"
,
targetBlocks
,
"have"
,
inqueue
)
}
...
...
@@ -151,7 +151,7 @@ func TestMissing(t *testing.T) {
t
.
Error
(
"download error"
,
err
)
}
inqueue
:=
len
(
tester
.
downloader
.
queue
.
block
s
)
inqueue
:=
len
(
tester
.
downloader
.
queue
.
block
Cache
)
if
inqueue
!=
targetBlocks
{
t
.
Error
(
"expected"
,
targetBlocks
,
"have"
,
inqueue
)
}
...
...
eth/downloader/peer.go
View file @
4800c943
...
...
@@ -78,7 +78,7 @@ func newPeer(id string, hash common.Hash, getHashes hashFetcherFn, getBlocks blo
}
// fetch a chunk using the peer
func
(
p
*
peer
)
fetch
(
chunk
*
chunk
)
error
{
func
(
p
*
peer
)
fetch
(
request
*
fetchRequest
)
error
{
p
.
mu
.
Lock
()
defer
p
.
mu
.
Unlock
()
...
...
@@ -88,13 +88,12 @@ func (p *peer) fetch(chunk *chunk) error {
// set working state
p
.
state
=
workingState
// convert the set to a fetchable slice
hashes
,
i
:=
make
([]
common
.
Hash
,
chunk
.
hashes
.
Size
()),
0
chunk
.
hashes
.
Each
(
func
(
v
interface
{})
bool
{
hashes
[
i
]
=
v
.
(
common
.
Hash
)
i
++
return
true
})
// Convert the hash set to a fetchable slice
hashes
:=
make
([]
common
.
Hash
,
0
,
len
(
request
.
Hashes
))
for
hash
,
_
:=
range
request
.
Hashes
{
hashes
=
append
(
hashes
,
hash
)
}
p
.
getBlocks
(
hashes
)
return
nil
...
...
eth/downloader/queue.go
View file @
4800c943
This diff is collapsed.
Click to expand it.
eth/downloader/queue_test.go
View file @
4800c943
...
...
@@ -32,31 +32,30 @@ func createBlocksFromHashSet(hashes *set.Set) []*types.Block {
}
func
TestChunking
(
t
*
testing
.
T
)
{
queue
:=
new
q
ueue
()
queue
:=
new
Q
ueue
()
peer1
:=
newPeer
(
"peer1"
,
common
.
Hash
{},
nil
,
nil
)
peer2
:=
newPeer
(
"peer2"
,
common
.
Hash
{},
nil
,
nil
)
// 99 + 1 (1 == known genesis hash)
hashes
:=
createHashes
(
0
,
99
)
hashSet
:=
createHashSet
(
hashes
)
queue
.
put
(
hashSet
)
queue
.
Insert
(
hashes
)
chunk1
:=
queue
.
get
(
peer1
,
99
)
chunk1
:=
queue
.
Reserve
(
peer1
,
99
)
if
chunk1
==
nil
{
t
.
Errorf
(
"chunk1 is nil"
)
t
.
FailNow
()
}
chunk2
:=
queue
.
get
(
peer2
,
99
)
chunk2
:=
queue
.
Reserve
(
peer2
,
99
)
if
chunk2
==
nil
{
t
.
Errorf
(
"chunk2 is nil"
)
t
.
FailNow
()
}
if
chunk1
.
hashes
.
Size
(
)
!=
99
{
t
.
Error
(
"expected chunk1 hashes to be 99, got"
,
chunk1
.
hashes
.
Size
(
))
if
len
(
chunk1
.
Hashes
)
!=
99
{
t
.
Error
(
"expected chunk1 hashes to be 99, got"
,
len
(
chunk1
.
Hashes
))
}
if
chunk2
.
hashes
.
Size
(
)
!=
1
{
t
.
Error
(
"expected chunk1 hashes to be 1, got"
,
chunk2
.
hashes
.
Size
(
))
if
len
(
chunk2
.
Hashes
)
!=
1
{
t
.
Error
(
"expected chunk1 hashes to be 1, got"
,
len
(
chunk2
.
Hashes
))
}
}
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