Skip to content
This repository has been archived by the owner on Aug 19, 2022. It is now read-only.

Store-native TTL management #34

Merged
merged 12 commits into from
Sep 20, 2018
Merged

Store-native TTL management #34

merged 12 commits into from
Sep 20, 2018

Conversation

raulk
Copy link
Member

@raulk raulk commented Sep 13, 2018

This PR replaces the bespoke TTL manager with store-native TTL management.

Notes:

  • Entries are now expired by the DB without notifying us. To keep the cache consistent, we now store the invalidation timestamp, calculated as the earliest expiration out of all multiaddrs. Before we return a cached entry, we check it's expiration and remove it if it's expired, falling through to the DB to repopulate the entry afresh.

  • To support the UpdateAddrs() operation, which performs a conditional TTL update, we need to store the original TTL alongside the entry. Since the requirement is simple, I have not used anything fancy for sedes. I'm just packing the TTL (int64) + entry, by concatenating their byte strings.

  • Cache keys are now peer.ID, no longer stringing them.

  • Our friend badger doesn't support sub-second TTLs, so I've had to adjust the time-dependent TTL tests to use above-second resolutions.

  • Last but not least, previously we had two methods on the ttlManager to update the expiration: insertOrExtendTTL and setTTL:

    • The former inserted TTLs for new keys, or updated existing ones only to extend their TTL, it would never bring the expiration closer. This is now called ttlExtend mode.
    • The latter updated the TTL always. This is now called ttlOverride mode.

Both modes are represented by enum values.

@ghost ghost assigned raulk Sep 13, 2018
@ghost ghost added the status/in-progress In progress label Sep 13, 2018
@raulk raulk changed the title Store-native TTL management WIP Store-native TTL management Sep 13, 2018
@raulk raulk changed the base branch from txndatastore to master September 14, 2018 16:37
@raulk raulk changed the title WIP Store-native TTL management Store-native TTL management Sep 14, 2018
@raulk
Copy link
Member Author

raulk commented Sep 14, 2018

Benchmark comparison between master and this branch.

→ benchcmp txn.txt ttl.txt
benchmark                                                                 old ns/op     new ns/op     delta
BenchmarkBadgerDsPeerstore/AddAddrs-1Addrs-Caching-8                      125522        119486        -4.81%
BenchmarkBadgerDsPeerstore/AddAddrs-10Addrs-Caching-8                     262138        250963        -4.26%
BenchmarkBadgerDsPeerstore/AddAddrs-100Addrs-Caching-8                    760962        750596        -1.36%
BenchmarkBadgerDsPeerstore/SetAddrs-1Addrs-Caching-8                      116322        104276        -10.36%
BenchmarkBadgerDsPeerstore/SetAddrs-10Addrs-Caching-8                     251848        246731        -2.03%
BenchmarkBadgerDsPeerstore/SetAddrs-100Addrs-Caching-8                    797630        742194        -6.95%
BenchmarkBadgerDsPeerstore/GetAddrs-1Addrs-Caching-8                      2848          1694          -40.52%
BenchmarkBadgerDsPeerstore/GetAddrs-10Addrs-Caching-8                     2912          1765          -39.39%
BenchmarkBadgerDsPeerstore/GetAddrs-100Addrs-Caching-8                    3695          2140          -42.08%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Caching-8           806264        1119209       +38.81%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-10Addrs-Caching-8          3610875       3405595       -5.69%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-100Addrs-Caching-8         9733449       9621773       -1.15%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-1Addrs-Caching-8         5729764       6086530       +6.23%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-10Addrs-Caching-8        15502463      18584244      +19.88%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-100Addrs-Caching-8       135901828     160347525     +17.99%
BenchmarkBadgerDsPeerstore/AddAddrs-1Addrs-Cacheless-8                    117767        105665        -10.28%
BenchmarkBadgerDsPeerstore/AddAddrs-10Addrs-Cacheless-8                   253219        246950        -2.48%
BenchmarkBadgerDsPeerstore/AddAddrs-100Addrs-Cacheless-8                  760662        748213        -1.64%
BenchmarkBadgerDsPeerstore/SetAddrs-1Addrs-Cacheless-8                    121158        104135        -14.05%
BenchmarkBadgerDsPeerstore/SetAddrs-10Addrs-Cacheless-8                   293593        246731        -15.96%
BenchmarkBadgerDsPeerstore/SetAddrs-100Addrs-Cacheless-8                  758146        729168        -3.82%
BenchmarkBadgerDsPeerstore/GetAddrs-1Addrs-Cacheless-8                    30867         22391         -27.46%
BenchmarkBadgerDsPeerstore/GetAddrs-10Addrs-Cacheless-8                   82003         71262         -13.10%
BenchmarkBadgerDsPeerstore/GetAddrs-100Addrs-Cacheless-8                  253858        514980        +102.86%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Cacheless-8         1289891       1244353       -3.53%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-10Addrs-Cacheless-8        6629343       5758940       -13.13%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-100Addrs-Cacheless-8       13702590      12800675      -6.58%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-1Addrs-Cacheless-8       5578808       6106094       +9.45%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-10Addrs-Cacheless-8      15358239      18367850      +19.60%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-100Addrs-Cacheless-8     130995339     167926230     +28.19%

benchmark                                                                 old allocs     new allocs     delta
BenchmarkBadgerDsPeerstore/AddAddrs-1Addrs-Caching-8                      138            124            -10.14%
BenchmarkBadgerDsPeerstore/AddAddrs-10Addrs-Caching-8                     677            673            -0.59%
BenchmarkBadgerDsPeerstore/AddAddrs-100Addrs-Caching-8                    6099           6092           -0.11%
BenchmarkBadgerDsPeerstore/SetAddrs-1Addrs-Caching-8                      127            124            -2.36%
BenchmarkBadgerDsPeerstore/SetAddrs-10Addrs-Caching-8                     677            673            -0.59%
BenchmarkBadgerDsPeerstore/SetAddrs-100Addrs-Caching-8                    6099           6092           -0.11%
BenchmarkBadgerDsPeerstore/GetAddrs-1Addrs-Caching-8                      11             7              -36.36%
BenchmarkBadgerDsPeerstore/GetAddrs-10Addrs-Caching-8                     11             7              -36.36%
BenchmarkBadgerDsPeerstore/GetAddrs-100Addrs-Caching-8                    11             7              -36.36%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Caching-8           3497           5450           +55.85%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-10Addrs-Caching-8          23009          23771          +3.31%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-100Addrs-Caching-8         77939          77388          -0.71%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-1Addrs-Caching-8         39135          39136          +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-10Addrs-Caching-8        170120         170121         +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-100Addrs-Caching-8       1610125        1610119        -0.00%
BenchmarkBadgerDsPeerstore/AddAddrs-1Addrs-Cacheless-8                    127            124            -2.36%
BenchmarkBadgerDsPeerstore/AddAddrs-10Addrs-Cacheless-8                   677            673            -0.59%
BenchmarkBadgerDsPeerstore/AddAddrs-100Addrs-Cacheless-8                  6099           6092           -0.11%
BenchmarkBadgerDsPeerstore/SetAddrs-1Addrs-Cacheless-8                    127            124            -2.36%
BenchmarkBadgerDsPeerstore/SetAddrs-10Addrs-Cacheless-8                   677            673            -0.59%
BenchmarkBadgerDsPeerstore/SetAddrs-100Addrs-Cacheless-8                  6099           6092           -0.11%
BenchmarkBadgerDsPeerstore/GetAddrs-1Addrs-Cacheless-8                    112            77             -31.25%
BenchmarkBadgerDsPeerstore/GetAddrs-10Addrs-Cacheless-8                   477            379            -20.55%
BenchmarkBadgerDsPeerstore/GetAddrs-100Addrs-Cacheless-8                  1380           1772           +28.41%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Cacheless-8         6648           6658           +0.15%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-10Addrs-Cacheless-8        44489          44378          -0.25%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-100Addrs-Cacheless-8       110894         107717         -2.86%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-1Addrs-Cacheless-8       39135          39135          +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-10Addrs-Cacheless-8      170120         170120         +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-100Addrs-Cacheless-8     1610119        1610122        +0.00%

benchmark                                                                 old bytes     new bytes     delta
BenchmarkBadgerDsPeerstore/AddAddrs-1Addrs-Caching-8                      10786         9944          -7.81%
BenchmarkBadgerDsPeerstore/AddAddrs-10Addrs-Caching-8                     34326         33667         -1.92%
BenchmarkBadgerDsPeerstore/AddAddrs-100Addrs-Caching-8                    278240        273577        -1.68%
BenchmarkBadgerDsPeerstore/SetAddrs-1Addrs-Caching-8                      10164         9943          -2.17%
BenchmarkBadgerDsPeerstore/SetAddrs-10Addrs-Caching-8                     34323         33667         -1.91%
BenchmarkBadgerDsPeerstore/SetAddrs-100Addrs-Caching-8                    278269        273561        -1.69%
BenchmarkBadgerDsPeerstore/GetAddrs-1Addrs-Caching-8                      464           272           -41.38%
BenchmarkBadgerDsPeerstore/GetAddrs-10Addrs-Caching-8                     608           416           -31.58%
BenchmarkBadgerDsPeerstore/GetAddrs-100Addrs-Caching-8                    2240          2048          -8.57%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Caching-8           120265        182528        +51.77%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-10Addrs-Caching-8          752611        777324        +3.28%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-100Addrs-Caching-8         2600536       2589311       -0.43%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-1Addrs-Caching-8         2684315       2684482       +0.01%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-10Addrs-Caching-8        7321860       7321976       +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-100Addrs-Caching-8       62042404      62041576      -0.00%
BenchmarkBadgerDsPeerstore/AddAddrs-1Addrs-Cacheless-8                    10164         9943          -2.17%
BenchmarkBadgerDsPeerstore/AddAddrs-10Addrs-Cacheless-8                   34330         33668         -1.93%
BenchmarkBadgerDsPeerstore/AddAddrs-100Addrs-Cacheless-8                  278238        273548        -1.69%
BenchmarkBadgerDsPeerstore/SetAddrs-1Addrs-Cacheless-8                    10164         9943          -2.17%
BenchmarkBadgerDsPeerstore/SetAddrs-10Addrs-Cacheless-8                   34325         33668         -1.91%
BenchmarkBadgerDsPeerstore/SetAddrs-100Addrs-Cacheless-8                  278226        273566        -1.67%
BenchmarkBadgerDsPeerstore/GetAddrs-1Addrs-Cacheless-8                    6360          4679          -26.43%
BenchmarkBadgerDsPeerstore/GetAddrs-10Addrs-Cacheless-8                   24985         20777         -16.84%
BenchmarkBadgerDsPeerstore/GetAddrs-100Addrs-Cacheless-8                  75801         89835         +18.51%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Cacheless-8         233188        233330        +0.06%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-10Addrs-Cacheless-8        1453068       1449961       -0.21%
BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-100Addrs-Cacheless-8       3677443       3582483       -2.58%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-1Addrs-Cacheless-8       2684390       2684395       +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-10Addrs-Cacheless-8      7321831       7321852       +0.00%
BenchmarkBadgerDsPeerstore/Get1000PeersWithAddrs-100Addrs-Cacheless-8     62041620      62041938      +0.00%

@raulk
Copy link
Member Author

raulk commented Sep 14, 2018

Comments:

  • TTLs + iterators + deleted keys seem to cause badger to hiccup inconsistently. It evaluates the expiry and logical delete on every visit to a key. The effect of this overhead can be observed in the benchmarks for Get1000Addrs and AddGetClearAddrs.

  • Due to compaction policies, logical deletes, DB GC and badger's prefetch, it is very difficult to get consistent performance metrics in short-lived benchmarks. The order of the keys also plays a part, as badger is an LSM tree. There are some wild one-off fluctuations quite often, e.g.:

BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Caching-8         	    3000	    748832 ns/op	  115649 B/op	    3360 allocs/op

vs.

BenchmarkBadgerDsPeerstore/AddGetAndClearAddrs-1Addrs-Caching-8         	    5000	   1076499 ns/op	  181482 B/op	    5417 allocs/op

I've memprofiled this. Iterator + deletes + expiries + order of random values in that execution + compaction + prefetch = wild fluctuations in benchmarks. I might play around with disabling compaction in tests to get consistent readings, but there's nothing I can do about removing prefetch – as that is an iterator-specific property, and our go-datastore API doesn't give us access to that.

@raulk raulk requested a review from bigs September 14, 2018 17:27
@raulk
Copy link
Member Author

raulk commented Sep 14, 2018

@bigs – this should be ready for review ;-)

@raulk
Copy link
Member Author

raulk commented Sep 14, 2018

benchmp between baseline (prior to refactorings) and this PR here:

#31 (comment)

Copy link
Contributor

@bigs bigs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's just refactor that serialized type, beyond that it looks great.

@@ -60,7 +82,7 @@ func NewAddrBook(ctx context.Context, ds ds.TxnDatastore, opts Options) (*dsAddr

// Stop will signal the TTL manager to stop and block until it returns.
func (mgr *dsAddrBook) Stop() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we delete this? it's not part of the interface, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, not part of the interface, which is an omission IMHO.

// Attempt to add the key.
if err = txn.Put(key, addrs[i].Bytes()); err != nil {
// format: bytes(ttl) || bytes(multiaddr)
value := append(ttlB, addrs[i].Bytes()...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make a record type, i.e.

type AddrRecord struct {
  Addrs []ma.Multiaddr
  TTL time.Duration
}

and either hand write serializer/deserializer or use gob (simplest). that way we can isolate serialization/deserialization

if existed[i] {
switch mode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the enum is so nice :D like this

@bigs
Copy link
Contributor

bigs commented Sep 18, 2018

Closes libp2p/go-libp2p#1702

@raulk
Copy link
Member Author

raulk commented Sep 18, 2018

Removed the no-op Stop() – good catch!

Introduced a struct to represent the persisted value. Brings allocs and bytes slightly up in benchmarks, but no significant slowdown in time – as expected.

@bigs I think you meant to say #28 in your previous comment ;-)

@@ -57,14 +57,14 @@
},
{
"author": "magik6k",
"hash": "QmUCfrikzKVGAfpE31RPwPd32fu1DYxSG7HTGCadba5Wza",
"hash": "QmaiEBFgkgB1wjrPRxru5PyXPEkx58WuMjXNaR1Q9QNRjn",
"name": "go-ds-badger",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

depending on badger directly this far down is a bit weird. Especially since its not something we are tied to at this point (and may move away from)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just used in tests to create test instances -- not in production code. Any other way you can think of?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Java, this dependency would be in test scope in maven or gradle. No such thing in Go / gx AFAIK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a gx thing. go get by default won't download test dependency packages. The -t flag is required to download test deps.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How difficult would it be to add basic ttl support to the in-memory datastore. It doesn't have to be fancy, it could literally be a:

  1. Check on read.
  2. Sweep every N minutes.

Copy link
Member Author

@raulk raulk Sep 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the datastore not the peerstore, right? It would be pretty straightforward, I'll work on it!

Eventually (when KeyBook and PeerMetadata are migrated to use the datastore), it may make sense to remove the in-memory implementation of the peerstore, and have the constructor delegate to a map-based datastore peerstore.

That's almost a tongue twister!

@bigs
Copy link
Contributor

bigs commented Sep 18, 2018 via email

@raulk
Copy link
Member Author

raulk commented Sep 19, 2018

@bigs what are you referring to with the last comment?

@bigs
Copy link
Contributor

bigs commented Sep 19, 2018 via email

Copy link
Contributor

@bigs bigs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@raulk raulk merged commit 6f9a3c2 into master Sep 20, 2018
@ghost ghost removed the status/in-progress In progress label Sep 20, 2018
@raulk raulk deleted the ttldatastore branch September 20, 2018 13:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants