-
Notifications
You must be signed in to change notification settings - Fork 2.2k
channeldb: add reject and channel caches #2847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Roasbeef
merged 16 commits into
lightningnetwork:master
from
cfromknecht:reject-and-channel-cache
Apr 3, 2019
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
f6d93c8
Revert "channeldb: convert all Update calls to use Batch"
cfromknecht e35f676
Revert "channeldb: convert concurrent channel state machine calls to …
cfromknecht 2f92749
Revert "channeldb: convert invoice settle/cancel calls to use Batch"
cfromknecht ac315fd
channeldb/db: remove unused buffer pool
cfromknecht ecbb786
channeldb/graph: add newChannelGraph constructor
cfromknecht 3c46cee
channeldb/db: init one ChannelGraph per channeldb.DB
cfromknecht af0ea35
channeldb/reject_cache: add rejectCache w/ randomized eviction
cfromknecht b20a254
channeldb/channel_cache: add channelCache w/ randomized eviction
cfromknecht ae3a00a
channeldb/graph+db: integrate reject and channel caches
cfromknecht baa968b
channeldb/options: add Options w/ functional modifiers
cfromknecht 6d3e081
channeldb: accept cache sizes in ChannelGraph
cfromknecht 5c8ba59
lncfg/interface: define Validator iface + variadic Validate
cfromknecht 7504d46
lncfg/caches: adds Caches sub config
cfromknecht 4336659
config: expose Caches subconfig
cfromknecht 63b15fd
lnd: pass CLI reject+channel cache sizes to channeldb Open
cfromknecht 5d98a94
channeldb: write chan updates through reject+channel cache
cfromknecht File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package channeldb | ||
|
||
// channelCache is an in-memory cache used to improve the performance of | ||
// ChanUpdatesInHorizon. It caches the chan info and edge policies for a | ||
// particular channel. | ||
type channelCache struct { | ||
n int | ||
channels map[uint64]ChannelEdge | ||
cfromknecht marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// newChannelCache creates a new channelCache with maximum capacity of n | ||
// channels. | ||
func newChannelCache(n int) *channelCache { | ||
return &channelCache{ | ||
n: n, | ||
channels: make(map[uint64]ChannelEdge), | ||
Roasbeef marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
// get returns the channel from the cache, if it exists. | ||
func (c *channelCache) get(chanid uint64) (ChannelEdge, bool) { | ||
channel, ok := c.channels[chanid] | ||
return channel, ok | ||
} | ||
|
||
// insert adds the entry to the channel cache. If an entry for chanid already | ||
// exists, it will be replaced with the new entry. If the entry doesn't exist, | ||
// it will be inserted to the cache, performing a random eviction if the cache | ||
// is at capacity. | ||
func (c *channelCache) insert(chanid uint64, channel ChannelEdge) { | ||
// If entry exists, replace it. | ||
if _, ok := c.channels[chanid]; ok { | ||
c.channels[chanid] = channel | ||
return | ||
} | ||
|
||
// Otherwise, evict an entry at random and insert. | ||
if len(c.channels) == c.n { | ||
for id := range c.channels { | ||
delete(c.channels, id) | ||
break | ||
} | ||
} | ||
c.channels[chanid] = channel | ||
} | ||
|
||
// remove deletes an edge for chanid from the cache, if it exists. | ||
func (c *channelCache) remove(chanid uint64) { | ||
delete(c.channels, chanid) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package channeldb | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
// TestChannelCache checks the behavior of the channelCache with respect to | ||
// insertion, eviction, and removal of cache entries. | ||
func TestChannelCache(t *testing.T) { | ||
const cacheSize = 100 | ||
|
||
// Create a new channel cache with the configured max size. | ||
c := newChannelCache(cacheSize) | ||
|
||
// As a sanity check, assert that querying the empty cache does not | ||
// return an entry. | ||
_, ok := c.get(0) | ||
if ok { | ||
t.Fatalf("channel cache should be empty") | ||
} | ||
|
||
// Now, fill up the cache entirely. | ||
for i := uint64(0); i < cacheSize; i++ { | ||
c.insert(i, channelForInt(i)) | ||
} | ||
|
||
// Assert that the cache has all of the entries just inserted, since no | ||
// eviction should occur until we try to surpass the max size. | ||
assertHasChanEntries(t, c, 0, cacheSize) | ||
|
||
// Now, insert a new element that causes the cache to evict an element. | ||
c.insert(cacheSize, channelForInt(cacheSize)) | ||
|
||
// Assert that the cache has this last entry, as the cache should evict | ||
// some prior element and not the newly inserted one. | ||
assertHasChanEntries(t, c, cacheSize, cacheSize) | ||
|
||
// Iterate over all inserted elements and construct a set of the evicted | ||
// elements. | ||
evicted := make(map[uint64]struct{}) | ||
for i := uint64(0); i < cacheSize+1; i++ { | ||
_, ok := c.get(i) | ||
if !ok { | ||
evicted[i] = struct{}{} | ||
} | ||
} | ||
|
||
// Assert that exactly one element has been evicted. | ||
numEvicted := len(evicted) | ||
if numEvicted != 1 { | ||
t.Fatalf("expected one evicted entry, got: %d", numEvicted) | ||
} | ||
|
||
// Remove the highest item which initially caused the eviction and | ||
// reinsert the element that was evicted prior. | ||
c.remove(cacheSize) | ||
for i := range evicted { | ||
c.insert(i, channelForInt(i)) | ||
} | ||
|
||
// Since the removal created an extra slot, the last insertion should | ||
// not have caused an eviction and the entries for all channels in the | ||
// original set that filled the cache should be present. | ||
assertHasChanEntries(t, c, 0, cacheSize) | ||
|
||
// Finally, reinsert the existing set back into the cache and test that | ||
// the cache still has all the entries. If the randomized eviction were | ||
// happening on inserts for existing cache items, we expect this to fail | ||
// with high probability. | ||
for i := uint64(0); i < cacheSize; i++ { | ||
c.insert(i, channelForInt(i)) | ||
} | ||
assertHasChanEntries(t, c, 0, cacheSize) | ||
|
||
} | ||
|
||
// assertHasEntries queries the edge cache for all channels in the range [start, | ||
// end), asserting that they exist and their value matches the entry produced by | ||
// entryForInt. | ||
func assertHasChanEntries(t *testing.T, c *channelCache, start, end uint64) { | ||
t.Helper() | ||
|
||
for i := start; i < end; i++ { | ||
entry, ok := c.get(i) | ||
if !ok { | ||
t.Fatalf("channel cache should contain chan %d", i) | ||
} | ||
|
||
expEntry := channelForInt(i) | ||
if !reflect.DeepEqual(entry, expEntry) { | ||
t.Fatalf("entry mismatch, want: %v, got: %v", | ||
expEntry, entry) | ||
} | ||
} | ||
} | ||
|
||
// channelForInt generates a unique ChannelEdge given an integer. | ||
func channelForInt(i uint64) ChannelEdge { | ||
return ChannelEdge{ | ||
Info: &ChannelEdgeInfo{ | ||
ChannelID: i, | ||
}, | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.