Skip to content

Commit 75e354e

Browse files
authored
Merge pull request #357 from uprendis/feature/seamless-migration
Allow to preserve legacy DBs layout, use leveldb-only layout by default
2 parents efe49f1 + c481d0f commit 75e354e

File tree

8 files changed

+670
-178
lines changed

8 files changed

+670
-178
lines changed

cmd/opera/launcher/config.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ var (
111111
Name: "exitwhensynced.epoch",
112112
Usage: "Exits after synchronisation reaches the required epoch",
113113
}
114+
115+
DBMigrationModeFlag = cli.StringFlag{
116+
Name: "db.migration.mode",
117+
Usage: "MultiDB migration mode ('reformat' or 'rebuild')",
118+
}
119+
DBPresetFlag = cli.StringFlag{
120+
Name: "db.preset",
121+
Usage: "DBs layout preset ('pbl-1' or 'ldb-1' or 'legacy-ldb' or 'legacy-pbl')",
122+
}
114123
)
115124

116125
type GenesisTemplate struct {
@@ -336,6 +345,28 @@ func gossipStoreConfigWithFlags(ctx *cli.Context, src gossip.StoreConfig) (gossi
336345
return cfg, nil
337346
}
338347

348+
func setDBConfig(ctx *cli.Context, cfg integration.DBsConfig, cacheRatio cachescale.Func) integration.DBsConfig {
349+
if ctx.GlobalIsSet(DBPresetFlag.Name) {
350+
preset := ctx.GlobalString(DBPresetFlag.Name)
351+
switch preset {
352+
case "pbl-1":
353+
cfg = integration.Pbl1DBsConfig(cacheRatio.U64, uint64(utils.MakeDatabaseHandles()))
354+
case "ldb-1":
355+
cfg = integration.Ldb1DBsConfig(cacheRatio.U64, uint64(utils.MakeDatabaseHandles()))
356+
case "legacy-ldb":
357+
cfg = integration.LdbLegacyDBsConfig(cacheRatio.U64, uint64(utils.MakeDatabaseHandles()))
358+
case "legacy-pbl":
359+
cfg = integration.PblLegacyDBsConfig(cacheRatio.U64, uint64(utils.MakeDatabaseHandles()))
360+
default:
361+
utils.Fatalf("--%s must be 'pbl-1', 'ldb-1', 'legacy-pbl' or 'legacy-ldb'", DBPresetFlag.Name)
362+
}
363+
}
364+
if ctx.GlobalIsSet(DBMigrationModeFlag.Name) {
365+
cfg.MigrationMode = ctx.GlobalString(DBMigrationModeFlag.Name)
366+
}
367+
return cfg
368+
}
369+
339370
func nodeConfigWithFlags(ctx *cli.Context, cfg node.Config) node.Config {
340371
utils.SetNodeConfig(ctx, &cfg)
341372

@@ -411,6 +442,7 @@ func mayMakeAllConfigs(ctx *cli.Context) (*config, error) {
411442
return nil, err
412443
}
413444
cfg.Node = nodeConfigWithFlags(ctx, cfg.Node)
445+
cfg.DBs = setDBConfig(ctx, cfg.DBs, cacheRatio)
414446

415447
err = setValidator(ctx, &cfg.Emitter)
416448
if err != nil {

cmd/opera/launcher/launcher.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ func initFlags() {
122122
validatorPasswordFlag,
123123
SyncModeFlag,
124124
GCModeFlag,
125+
DBPresetFlag,
126+
DBMigrationModeFlag,
125127
}
126128
legacyRpcFlags = []cli.Flag{
127129
utils.NoUSBFlag,

gossip/c_block_callbacks.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ var (
4949
snapshotStorageReadTimer = metrics.GetOrRegisterTimer("chain/snapshot/storage/reads", nil)
5050
snapshotCommitTimer = metrics.GetOrRegisterTimer("chain/snapshot/commits", nil)
5151

52-
blockInsertTimer = metrics.GetOrRegisterTimer("chain/inserts", nil)
53-
blockExecutionTimer = metrics.GetOrRegisterTimer("chain/execution", nil)
54-
blockWriteTimer = metrics.GetOrRegisterTimer("chain/write", nil)
52+
blockInsertTimer = metrics.GetOrRegisterTimer("chain/inserts", nil)
53+
blockExecutionTimer = metrics.GetOrRegisterTimer("chain/execution", nil)
54+
blockWriteTimer = metrics.GetOrRegisterTimer("chain/write", nil)
5555
)
5656

5757
type ExtendedTxPosition struct {

integration/assembly.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,17 @@ func makeEngine(chaindataDir string, g *genesis.Genesis, genesisProc bool, cfg C
242242
// MakeEngine makes consensus engine from config.
243243
func MakeEngine(chaindataDir string, g *genesis.Genesis, cfg Configs) (*abft.Lachesis, *vecmt.Index, *gossip.Store, *abft.Store, gossip.BlockProc, func() error) {
244244
// Legacy DBs migrate
245+
if cfg.DBs.MigrationMode != "reformat" && cfg.DBs.MigrationMode != "rebuild" && cfg.DBs.MigrationMode != "" {
246+
utils.Fatalf("MigrationMode must be 'reformat' or 'rebuild'")
247+
}
245248
if !isEmpty(path.Join(chaindataDir, "gossip")) {
246249
MakeDBDirs(chaindataDir)
247250
genesisProducers, _ := SupportedDBs(chaindataDir, cfg.DBs.GenesisCache)
248251
dbs, err := MakeDirectMultiProducer(genesisProducers, cfg.DBs.Routing)
249252
if err != nil {
250253
utils.Fatalf("Failed to make engine: %v", err)
251254
}
252-
err = migrateLegacyDBs(chaindataDir, dbs)
255+
err = migrateLegacyDBs(chaindataDir, dbs, cfg.DBs.MigrationMode, cfg.DBs.Routing)
253256
_ = dbs.Close()
254257
if err != nil {
255258
utils.Fatalf("Failed to migrate state: %v", err)

integration/db.go

Lines changed: 4 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ import (
1818
"github.com/Fantom-foundation/lachesis-base/utils/fmtfilter"
1919
"github.com/ethereum/go-ethereum/cmd/utils"
2020
"github.com/ethereum/go-ethereum/log"
21-
"github.com/syndtr/goleveldb/leveldb/opt"
2221

2322
"github.com/Fantom-foundation/go-opera/gossip"
2423
"github.com/Fantom-foundation/go-opera/utils/dbutil/asyncflushproducer"
2524
)
2625

2726
type DBsConfig struct {
28-
Routing RoutingConfig
29-
RuntimeCache DBsCacheConfig
30-
GenesisCache DBsCacheConfig
27+
Routing RoutingConfig
28+
RuntimeCache DBsCacheConfig
29+
GenesisCache DBsCacheConfig
30+
MigrationMode string
3131
}
3232

3333
type DBCacheConfig struct {
@@ -39,76 +39,6 @@ type DBsCacheConfig struct {
3939
Table map[string]DBCacheConfig
4040
}
4141

42-
func DefaultDBsConfig(scale func(uint64) uint64, fdlimit uint64) DBsConfig {
43-
return DBsConfig{
44-
Routing: DefaultRoutingConfig(),
45-
RuntimeCache: DefaultRuntimeDBsCacheConfig(scale, fdlimit),
46-
GenesisCache: DefaultGenesisDBsCacheConfig(scale, fdlimit),
47-
}
48-
}
49-
50-
func DefaultRuntimeDBsCacheConfig(scale func(uint64) uint64, fdlimit uint64) DBsCacheConfig {
51-
return DBsCacheConfig{
52-
Table: map[string]DBCacheConfig{
53-
"evm-data": {
54-
Cache: scale(242 * opt.MiB),
55-
Fdlimit: fdlimit*242/700 + 1,
56-
},
57-
"evm-logs": {
58-
Cache: scale(110 * opt.MiB),
59-
Fdlimit: fdlimit*110/700 + 1,
60-
},
61-
"main": {
62-
Cache: scale(186 * opt.MiB),
63-
Fdlimit: fdlimit*186/700 + 1,
64-
},
65-
"events": {
66-
Cache: scale(87 * opt.MiB),
67-
Fdlimit: fdlimit*87/700 + 1,
68-
},
69-
"epoch-%d": {
70-
Cache: scale(75 * opt.MiB),
71-
Fdlimit: fdlimit*75/700 + 1,
72-
},
73-
"": {
74-
Cache: 64 * opt.MiB,
75-
Fdlimit: fdlimit/100 + 1,
76-
},
77-
},
78-
}
79-
}
80-
81-
func DefaultGenesisDBsCacheConfig(scale func(uint64) uint64, fdlimit uint64) DBsCacheConfig {
82-
return DBsCacheConfig{
83-
Table: map[string]DBCacheConfig{
84-
"main": {
85-
Cache: scale(1024 * opt.MiB),
86-
Fdlimit: fdlimit*1024/3072 + 1,
87-
},
88-
"evm-data": {
89-
Cache: scale(1024 * opt.MiB),
90-
Fdlimit: fdlimit*1024/3072 + 1,
91-
},
92-
"evm-logs": {
93-
Cache: scale(1024 * opt.MiB),
94-
Fdlimit: fdlimit*1024/3072 + 1,
95-
},
96-
"events": {
97-
Cache: scale(1 * opt.MiB),
98-
Fdlimit: fdlimit*1/3072 + 1,
99-
},
100-
"epoch-%d": {
101-
Cache: scale(1 * opt.MiB),
102-
Fdlimit: fdlimit*1/3072 + 1,
103-
},
104-
"": {
105-
Cache: 16 * opt.MiB,
106-
Fdlimit: fdlimit/100 + 1,
107-
},
108-
},
109-
}
110-
}
111-
11242
func SupportedDBs(chaindataDir string, cfg DBsCacheConfig) (map[multidb.TypeName]kvdb.IterableDBProducer, map[multidb.TypeName]kvdb.FullDBProducer) {
11343
if chaindataDir == "inmemory" || chaindataDir == "" {
11444
chaindataDir, _ = ioutil.TempDir("", "opera-tmp")

integration/legacy_migrate.go

Lines changed: 108 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,20 @@ func translateGossipPrefix(p byte) byte {
186186
return p
187187
}
188188

189-
func migrateLegacyDBs(chaindataDir string, dbs kvdb.FlushableDBProducer) error {
190-
if !isEmpty(path.Join(chaindataDir, "gossip")) {
189+
func equalRoutingConfig(a, b RoutingConfig) bool {
190+
if len(a.Table) != len(b.Table) {
191+
return false
192+
}
193+
for k, v := range a.Table {
194+
if b.Table[k] != v {
195+
return false
196+
}
197+
}
198+
return true
199+
}
200+
201+
func migrateLegacyDBs(chaindataDir string, dbs kvdb.FlushableDBProducer, mode string, layout RoutingConfig) error {
202+
{ // didn't erase the brackets to avoid massive code changes
191203
// migrate DB layout
192204
cacheFn, err := dbCacheFdlimit(DBsCacheConfig{
193205
Table: map[string]DBCacheConfig{
@@ -201,10 +213,13 @@ func migrateLegacyDBs(chaindataDir string, dbs kvdb.FlushableDBProducer) error {
201213
return err
202214
}
203215
var oldDBs kvdb.IterableDBProducer
216+
var oldDBsType string
204217
if fileExists(path.Join(chaindataDir, "gossip", "LOG")) {
205218
oldDBs = leveldb.NewProducer(chaindataDir, cacheFn)
219+
oldDBsType = "ldb"
206220
} else {
207221
oldDBs = pebble.NewProducer(chaindataDir, cacheFn)
222+
oldDBsType = "pbl"
208223
}
209224
openOldDB := func(name string) kvdb.Store {
210225
db, err := oldDBs.OpenDB(name)
@@ -221,67 +236,106 @@ func migrateLegacyDBs(chaindataDir string, dbs kvdb.FlushableDBProducer) error {
221236
return db
222237
}
223238

224-
// move lachesis, lachesis-%d and gossip-%d DBs
225-
for _, name := range oldDBs.Names() {
226-
if strings.HasPrefix(name, "lachesis") || strings.HasPrefix(name, "gossip-") {
227-
mustTransform(transformTask{
228-
openSrc: func() kvdb.Store {
229-
return skipkeys.Wrap(openOldDB(name), MetadataPrefix)
230-
},
231-
openDst: func() kvdb.Store {
232-
return openNewDB(name)
233-
},
234-
name: name,
235-
dir: chaindataDir,
236-
})
239+
switch mode {
240+
case "rebuild":
241+
// move lachesis, lachesis-%d and gossip-%d DBs
242+
for _, name := range oldDBs.Names() {
243+
if strings.HasPrefix(name, "lachesis") || strings.HasPrefix(name, "gossip-") {
244+
mustTransform(transformTask{
245+
openSrc: func() kvdb.Store {
246+
return skipkeys.Wrap(openOldDB(name), MetadataPrefix)
247+
},
248+
openDst: func() kvdb.Store {
249+
return openNewDB(name)
250+
},
251+
name: name,
252+
dir: chaindataDir,
253+
})
254+
}
237255
}
238-
}
239256

240-
// move gossip DB
241-
242-
// move logs
243-
mustTransform(transformTask{
244-
openSrc: func() kvdb.Store {
245-
return newClosableTable(openOldDB("gossip"), []byte("Lr"))
246-
},
247-
openDst: func() kvdb.Store {
248-
return openNewDB("evm-logs/r")
249-
},
250-
name: "gossip/Lr",
251-
dir: chaindataDir,
252-
})
253-
mustTransform(transformTask{
254-
openSrc: func() kvdb.Store {
255-
return newClosableTable(openOldDB("gossip"), []byte("Lt"))
256-
},
257-
openDst: func() kvdb.Store {
258-
return openNewDB("evm-logs/t")
259-
},
260-
name: "gossip/Lt",
261-
dir: chaindataDir,
262-
})
257+
// move gossip DB
263258

264-
// skip 0 prefix, as it contains flushID
265-
for b := 1; b <= 0xff; b++ {
266-
if b == int('L') {
267-
// logs are already moved above
268-
continue
269-
}
259+
// move logs
270260
mustTransform(transformTask{
271261
openSrc: func() kvdb.Store {
272-
return newClosableTable(openOldDB("gossip"), []byte{byte(b)})
262+
return newClosableTable(openOldDB("gossip"), []byte("Lr"))
273263
},
274264
openDst: func() kvdb.Store {
275-
if b == int('M') || b == int('r') || b == int('x') || b == int('X') {
276-
return openNewDB("evm/" + string([]byte{byte(b)}))
277-
} else {
278-
return openNewDB("gossip/" + string([]byte{translateGossipPrefix(byte(b))}))
279-
}
265+
return openNewDB("evm-logs/r")
266+
},
267+
name: "gossip/Lr",
268+
dir: chaindataDir,
269+
})
270+
mustTransform(transformTask{
271+
openSrc: func() kvdb.Store {
272+
return newClosableTable(openOldDB("gossip"), []byte("Lt"))
273+
},
274+
openDst: func() kvdb.Store {
275+
return openNewDB("evm-logs/t")
280276
},
281-
name: fmt.Sprintf("gossip/%c", rune(b)),
282-
dir: chaindataDir,
283-
dropSrc: b == 0xff,
277+
name: "gossip/Lt",
278+
dir: chaindataDir,
284279
})
280+
281+
// skip 0 prefix, as it contains flushID
282+
for b := 1; b <= 0xff; b++ {
283+
if b == int('L') {
284+
// logs are already moved above
285+
continue
286+
}
287+
mustTransform(transformTask{
288+
openSrc: func() kvdb.Store {
289+
return newClosableTable(openOldDB("gossip"), []byte{byte(b)})
290+
},
291+
openDst: func() kvdb.Store {
292+
if b == int('M') || b == int('r') || b == int('x') || b == int('X') {
293+
return openNewDB("evm/" + string([]byte{byte(b)}))
294+
} else {
295+
return openNewDB("gossip/" + string([]byte{translateGossipPrefix(byte(b))}))
296+
}
297+
},
298+
name: fmt.Sprintf("gossip/%c", rune(b)),
299+
dir: chaindataDir,
300+
dropSrc: b == 0xff,
301+
})
302+
}
303+
case "reformat":
304+
if oldDBsType == "ldb" {
305+
if !equalRoutingConfig(layout, LdbLegacyRoutingConfig()) {
306+
return errors.New("reformatting DBs: missing --db.preset=legacy-ldb flag")
307+
}
308+
err = os.Rename(path.Join(chaindataDir, "gossip"), path.Join(chaindataDir, "leveldb-fsh", "main"))
309+
if err != nil {
310+
return err
311+
}
312+
for _, name := range oldDBs.Names() {
313+
if strings.HasPrefix(name, "lachesis") || strings.HasPrefix(name, "gossip-") {
314+
err = os.Rename(path.Join(chaindataDir, name), path.Join(chaindataDir, "leveldb-fsh", name))
315+
if err != nil {
316+
return err
317+
}
318+
}
319+
}
320+
} else {
321+
if !equalRoutingConfig(layout, PblLegacyRoutingConfig()) {
322+
return errors.New("reformatting DBs: missing --db.preset=legacy-pbl flag")
323+
}
324+
err = os.Rename(path.Join(chaindataDir, "gossip"), path.Join(chaindataDir, "pebble-fsh", "main"))
325+
if err != nil {
326+
return err
327+
}
328+
for _, name := range oldDBs.Names() {
329+
if strings.HasPrefix(name, "lachesis") || strings.HasPrefix(name, "gossip-") {
330+
err = os.Rename(path.Join(chaindataDir, name), path.Join(chaindataDir, "pebble-fsh", name))
331+
if err != nil {
332+
return err
333+
}
334+
}
335+
}
336+
}
337+
default:
338+
return errors.New("missing --db.migration.mode flag")
285339
}
286340
}
287341

0 commit comments

Comments
 (0)