Skip to content

Commit 2fc421a

Browse files
Merge pull request #25 from coinbase/patrick/upgrade-sdk-go
Update rosetta-sdk-go + mmap files
2 parents f4fe50f + 6d2c1ba commit 2fc421a

File tree

8 files changed

+71
-42
lines changed

8 files changed

+71
-42
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,9 @@ _If you cloned the repository, you can run `make run-testnet-offline`._
8585

8686
## System Requirements
8787
`rosetta-bitcoin` has been tested on an [AWS c5.2xlarge instance](https://aws.amazon.com/ec2/instance-types/c5).
88-
This instance type has 8 vCPU and 16 GB of RAM. If you use a computer with less than 16 GB of RAM,
89-
it is possible that `rosetta-bitcoin` will exit with an OOM error.
88+
This instance type has 8 vCPU and 16 GB of RAM.
9089

91-
### Recommended OS Settings
90+
### Network Settings
9291
To increase the load `rosetta-bitcoin` can handle, it is recommended to tune your OS
9392
settings to allow for more connections. On a linux-based OS, you can run the following
9493
commands ([source](http://www.tweaked.io/guide/kernel)):
@@ -106,6 +105,14 @@ enabling it._
106105
You should also modify your open file settings to `100000`. This can be done on a linux-based OS
107106
with the command: `ulimit -n 100000`.
108107

108+
### Memory-Mapped Files
109+
`rosetta-bitcoin` uses [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file) to
110+
persist data in the `indexer`. As a result, you **must** run `rosetta-bitcoin` on a 64-bit
111+
architecture (the virtual address space easily exceeds 100s of GBs).
112+
113+
If you receive a kernel OOM, you may need to increase the allocated size of swap space
114+
on your OS. There is a great tutorial for how to do this on Linux [here](https://linuxize.com/post/create-a-linux-swap-file/).
115+
109116
## Architecture
110117
`rosetta-bitcoin` uses the `syncer`, `storage`, `parser`, and `server` package
111118
from [`rosetta-sdk-go`](https://github.com/coinbase/rosetta-sdk-go) instead

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.13
55
require (
66
github.com/btcsuite/btcd v0.21.0-beta
77
github.com/btcsuite/btcutil v1.0.2
8-
github.com/coinbase/rosetta-sdk-go v0.4.8
8+
github.com/coinbase/rosetta-sdk-go v0.5.5
99
github.com/dgraph-io/badger/v2 v2.2007.2
1010
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
1111
github.com/stretchr/testify v1.6.1

go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ github.com/coinbase/rosetta-sdk-go v0.4.7 h1:5KFc0CgLMkKamX++hYUFvE58a5/tCn0wSqp
7373
github.com/coinbase/rosetta-sdk-go v0.4.7/go.mod h1:8d4iN4VSGvLUzl+jRQlvYSLyS9TeY0QZebneWouizqU=
7474
github.com/coinbase/rosetta-sdk-go v0.4.8 h1:+E1TM4q1c5/x/jE9FPI1IZIbNvUWy4tRRgDPLnKzUV4=
7575
github.com/coinbase/rosetta-sdk-go v0.4.8/go.mod h1:8d4iN4VSGvLUzl+jRQlvYSLyS9TeY0QZebneWouizqU=
76+
github.com/coinbase/rosetta-sdk-go v0.5.4 h1:pM18LK2ci8zZwIu+uETmP6BXHqZbQGXRulwQCjYudg4=
77+
github.com/coinbase/rosetta-sdk-go v0.5.4/go.mod h1:QVVeKHWFNb0NyzEY06LxXMAylJkYa7n+Hk03pORr0ws=
78+
github.com/coinbase/rosetta-sdk-go v0.5.5 h1:Z61/VUO89BDVl1m6Zj0e6OWMl5GnVevj4z79Eh3sSL0=
79+
github.com/coinbase/rosetta-sdk-go v0.5.5/go.mod h1:JRO4BJjhWAI7nYGwzYZWFgYfCTsQOvdZB7tGyN6kEtE=
7680
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
7781
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
7882
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -116,6 +120,7 @@ github.com/ethereum/go-ethereum v1.9.21 h1:8qRlhzrItnmUGdVlBzZLI2Tb46S0RdSNjFwIC
116120
github.com/ethereum/go-ethereum v1.9.21/go.mod h1:RXAVzbGrSGmDkDnHymruTAIEjUR3E4TX0EOpaj702sI=
117121
github.com/ethereum/go-ethereum v1.9.22 h1:/Fea9n2EWJuNJ9oahMq9luqjRBcbW7QWdThbcJl13ek=
118122
github.com/ethereum/go-ethereum v1.9.22/go.mod h1:FQjK3ZwD8C5DYn7ukTmFee36rq1dOMESiUfXr5RUc1w=
123+
github.com/ethereum/go-ethereum v1.9.23/go.mod h1:JIfVb6esrqALTExdz9hRYvrP0xBDf6wCncIu1hNwHpM=
119124
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
120125
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
121126
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
@@ -314,6 +319,8 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
314319
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
315320
github.com/tidwall/sjson v1.1.1 h1:7h1vk049Jnd5EH9NyzNiEuwYW4b5qgreBbqRC19AS3U=
316321
github.com/tidwall/sjson v1.1.1/go.mod h1:yvVuSnpEQv5cYIrO+AT6kw4QVfd5SDZoGIS7/5+fZFs=
322+
github.com/tidwall/sjson v1.1.2 h1:NC5okI+tQ8OG/oyzchvwXXxRxCV/FVdhODbPKkQ25jQ=
323+
github.com/tidwall/sjson v1.1.2/go.mod h1:SEzaDwxiPzKzNfUEO4HbYF/m4UCSJDsGgNqsS1LvdoY=
317324
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
318325
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
319326
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=

indexer/indexer.go

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,10 @@ import (
3131
"github.com/coinbase/rosetta-sdk-go/types"
3232
sdkUtils "github.com/coinbase/rosetta-sdk-go/utils"
3333
"github.com/dgraph-io/badger/v2"
34+
"github.com/dgraph-io/badger/v2/options"
3435
)
3536

3637
const (
37-
// DefaultIndexCacheSize is the default size of the indexer cache. The larger
38-
// the index cache size, the better the performance.
39-
DefaultIndexCacheSize = 5 << 30 // 5 GB
40-
4138
// indexPlaceholder is provided to the syncer
4239
// to indicate we should both start from the
4340
// last synced block and that we should sync
@@ -56,10 +53,6 @@ const (
5653
// this is the estimated memory overhead for each
5754
// block fetched by the indexer.
5855
sizeMultiplier = 15
59-
60-
// Other BadgerDB options overrides
61-
defaultBlockSize = 1 << 20 // use large blocks so less table indexes (1 MB)
62-
defaultValueThreshold = 0 // put almost everything in value logs (only use table for key)
6356
)
6457

6558
var (
@@ -114,23 +107,51 @@ func (i *Indexer) CloseDatabase(ctx context.Context) {
114107
}
115108

116109
// defaultBadgerOptions returns a set of badger.Options optimized
117-
// for running a Rosetta implementation. After extensive research
118-
// and profiling, we determined that the bottleneck to high RPC
119-
// load was fetching table indexes from disk on an index cache miss.
120-
// Thus, we increased the default block size to be much larger than
121-
// the Badger default so we have a lot less indexes to store. We also
122-
// ensure all values are stored in value log files (as to minimize
123-
// table bloat at the cost of some performance).
110+
// for running a Rosetta implementation.
124111
func defaultBadgerOptions(
125-
path string,
126-
indexCacheSize int64,
112+
dir string,
127113
) badger.Options {
128-
defaultOps := storage.DefaultBadgerOptions(path)
129-
defaultOps.BlockSize = defaultBlockSize
130-
defaultOps.ValueThreshold = defaultValueThreshold
131-
defaultOps.IndexCacheSize = indexCacheSize
114+
opts := badger.DefaultOptions(dir)
115+
116+
// By default, we do not compress the table at all. Doing so can
117+
// significantly increase memory usage.
118+
opts.Compression = options.None
119+
120+
// Load tables into memory and memory map value logs.
121+
opts.TableLoadingMode = options.MemoryMap
122+
opts.ValueLogLoadingMode = options.MemoryMap
123+
124+
// Use an extended table size for larger commits.
125+
opts.MaxTableSize = storage.DefaultMaxTableSize
126+
127+
// Smaller value log sizes means smaller contiguous memory allocations
128+
// and less RAM usage on cleanup.
129+
opts.ValueLogFileSize = storage.DefaultLogValueSize
130+
131+
// To allow writes at a faster speed, we create a new memtable as soon as
132+
// an existing memtable is filled up. This option determines how many
133+
// memtables should be kept in memory.
134+
opts.NumMemtables = 1
135+
136+
// Don't keep multiple memtables in memory. With larger
137+
// memtable size, this explodes memory usage.
138+
opts.NumLevelZeroTables = 1
139+
opts.NumLevelZeroTablesStall = 2
140+
141+
// This option will have a significant effect the memory. If the level is kept
142+
// in-memory, read are faster but the tables will be kept in memory. By default,
143+
// this is set to false.
144+
opts.KeepL0InMemory = false
145+
146+
// We don't compact L0 on close as this can greatly delay shutdown time.
147+
opts.CompactL0OnClose = false
148+
149+
// LoadBloomsOnOpen=false will improve the db startup speed. This is also
150+
// a waste to enable with a limited index cache size (as many of the loaded bloom
151+
// filters will be immediately discarded from the cache).
152+
opts.LoadBloomsOnOpen = false
132153

133-
return defaultOps
154+
return opts
134155
}
135156

136157
// Initialize returns a new Indexer.
@@ -139,15 +160,13 @@ func Initialize(
139160
cancel context.CancelFunc,
140161
config *configuration.Configuration,
141162
client Client,
142-
indexCacheSize int64,
143163
) (*Indexer, error) {
144164
localStore, err := storage.NewBadgerStorage(
145165
ctx,
146166
config.IndexerPath,
147167
storage.WithCompressorEntries(config.Compressors),
148168
storage.WithCustomSettings(defaultBadgerOptions(
149169
config.IndexerPath,
150-
indexCacheSize,
151170
)),
152171
)
153172
if err != nil {

indexer/indexer_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func TestIndexer_Pruning(t *testing.T) {
7272
IndexerPath: newDir,
7373
}
7474

75-
i, err := Initialize(ctx, cancel, cfg, mockClient, storage.TinyIndexCacheSize)
75+
i, err := Initialize(ctx, cancel, cfg, mockClient)
7676
assert.NoError(t, err)
7777

7878
// Waiting for bitcoind...
@@ -232,7 +232,7 @@ func TestIndexer_Transactions(t *testing.T) {
232232
IndexerPath: newDir,
233233
}
234234

235-
i, err := Initialize(ctx, cancel, cfg, mockClient, storage.TinyIndexCacheSize)
235+
i, err := Initialize(ctx, cancel, cfg, mockClient)
236236
assert.NoError(t, err)
237237

238238
// Sync to 1000
@@ -450,7 +450,7 @@ func TestIndexer_Reorg(t *testing.T) {
450450
IndexerPath: newDir,
451451
}
452452

453-
i, err := Initialize(ctx, cancel, cfg, mockClient, storage.TinyIndexCacheSize)
453+
i, err := Initialize(ctx, cancel, cfg, mockClient)
454454
assert.NoError(t, err)
455455

456456
// Sync to 1000
@@ -692,7 +692,7 @@ func TestIndexer_HeaderReorg(t *testing.T) {
692692
IndexerPath: newDir,
693693
}
694694

695-
i, err := Initialize(ctx, cancel, cfg, mockClient, storage.TinyIndexCacheSize)
695+
i, err := Initialize(ctx, cancel, cfg, mockClient)
696696
assert.NoError(t, err)
697697

698698
// Sync to 1000

main.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ const (
5151
// idleTimeout is the maximum amount of time to wait for the
5252
// next request when keep-alives are enabled.
5353
idleTimeout = 30 * time.Second
54-
55-
// maxHeapUsage is the size of the heap in MB before we manually
56-
// trigger garbage collection.
57-
maxHeapUsage = 8500 // ~8.5 GB
5854
)
5955

6056
var (
@@ -99,7 +95,6 @@ func startOnlineDependencies(
9995
cancel,
10096
cfg,
10197
client,
102-
indexer.DefaultIndexCacheSize,
10398
)
10499
if err != nil {
105100
return nil, nil, fmt.Errorf("%w: unable to initialize indexer", err)
@@ -143,7 +138,7 @@ func main() {
143138
g, ctx := errgroup.WithContext(ctx)
144139

145140
g.Go(func() error {
146-
return utils.MonitorMemoryUsage(ctx, maxHeapUsage)
141+
return utils.MonitorMemoryUsage(ctx, -1)
147142
})
148143

149144
var i *indexer.Indexer
@@ -161,6 +156,7 @@ func main() {
161156
bitcoin.OperationTypes,
162157
false,
163158
[]*types.NetworkIdentifier{cfg.Network},
159+
nil,
164160
)
165161
if err != nil {
166162
logger.Fatalw("unable to create new server asserter", "error", err)

services/network_service_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import (
2727
)
2828

2929
var (
30-
middlewareVersion = "0.0.3"
30+
middlewareVersion = "0.0.4"
3131
defaultNetworkOptions = &types.NetworkOptionsResponse{
3232
Version: &types.Version{
33-
RosettaVersion: "1.4.4",
33+
RosettaVersion: "1.4.5",
3434
NodeVersion: "0.20.1",
3535
MiddlewareVersion: &middlewareVersion,
3636
},

services/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525
const (
2626
// RosettaVersion is the version of the
2727
// Rosetta Specification we are using.
28-
RosettaVersion = "1.4.4"
28+
RosettaVersion = "1.4.5"
2929

3030
// NodeVersion is the version of
3131
// bitcoin core we are using.
@@ -38,7 +38,7 @@ var (
3838
// variable instead of a constant because
3939
// we typically need the pointer of this
4040
// value.
41-
MiddlewareVersion = "0.0.3"
41+
MiddlewareVersion = "0.0.4"
4242
)
4343

4444
// Client is used by the servicers to get Peer information

0 commit comments

Comments
 (0)