diff --git a/erigon-lib/kv/mdbx/kv_mdbx.go b/erigon-lib/kv/mdbx/kv_mdbx.go index f3f7007da39..f553cc0b149 100644 --- a/erigon-lib/kv/mdbx/kv_mdbx.go +++ b/erigon-lib/kv/mdbx/kv_mdbx.go @@ -373,7 +373,7 @@ func (opts MdbxOpts) Open(ctx context.Context) (kv.RwDB, error) { } buckets := bucketSlice(db.buckets) - if err := db.openDBIs(buckets); err != nil { + if err := db.openDBIs(ctx, buckets); err != nil { return nil, err } @@ -478,26 +478,50 @@ func (db *MdbxKV) CHandle() unsafe.Pointer { // openDBIs - first trying to open existing DBI's in RO transaction // otherwise re-try by RW transaction // it allow open DB from another process - even if main process holding long RW transaction -func (db *MdbxKV) openDBIs(buckets []string) error { - if db.ReadOnly() || db.Accede() { - return db.View(context.Background(), func(tx kv.Tx) error { - for _, name := range buckets { - if db.buckets[name].IsDeprecated { - continue - } +func (db *MdbxKV) openDBIs(ctx context.Context, buckets []string) error { + nonDeprecatedBuckets := make([]string, 0, len(buckets)) + for _, name := range buckets { + if db.buckets[name].IsDeprecated { + continue + } + nonDeprecatedBuckets = append(nonDeprecatedBuckets, name) + } + + if db.ReadOnly() { // open or fail + return db.View(ctx, func(tx kv.Tx) error { + for _, name := range nonDeprecatedBuckets { if err := tx.(kv.BucketMigrator).CreateBucket(name); err != nil { return err } } - return tx.(*MdbxTx).Commit() // when open db as read-only, commit of this RO transaction is required + // when open db as read-only, commit of this RO transaction is required. + // it's weird - opening DBI on RO-db is "write/mutation operation" - which will be rolled-back if not committed. + return tx.(*MdbxTx).Commit() }) } - return db.Update(context.Background(), func(tx kv.RwTx) error { - for _, name := range buckets { - if db.buckets[name].IsDeprecated { - continue + if db.Accede() { // open or create + err := db.View(ctx, func(tx kv.Tx) error { + for _, name := range nonDeprecatedBuckets { + if err := tx.(kv.BucketMigrator).CreateBucket(name); err != nil { + return err + } } + // when open db as read-only, commit of this RO transaction is required. + // it's weird - opening DBI on RO-db is "write/mutation operation" - which will be rolled-back if not committed. + return tx.(*MdbxTx).Commit() + }) + if err == nil { // success + return nil + } + recoverable := !errors.Is(err, ErrTableDoesntExists) + if !recoverable { + return err + } + } + + return db.Update(ctx, func(tx kv.RwTx) error { + for _, name := range nonDeprecatedBuckets { if err := tx.(kv.BucketMigrator).CreateBucket(name); err != nil { return err } @@ -823,9 +847,8 @@ func (tx *MdbxTx) CreateBucket(name string) error { } dbi, err = tx.tx.OpenDBI(name, nativeFlags, nil, nil) - if err != nil { - return fmt.Errorf("db-talbe doesn't exists: %s, lable: %s, %w. Tip: try run `integration run_migrations` to create non-existing tables", name, tx.db.opts.label, err) + return fmt.Errorf("%w: %s, lable: %s, %w. Tip: try run `integration run_migrations`", ErrTableDoesntExists, name, tx.db.opts.label, err) } cnfCopy.DBI = kv.DBI(dbi) @@ -833,6 +856,8 @@ func (tx *MdbxTx) CreateBucket(name string) error { return nil } +var ErrTableDoesntExists = errors.New("table does not exist") + func (tx *MdbxTx) dropEvenIfBucketIsNotDeprecated(name string) error { dbi := tx.db.buckets[name].DBI // if bucket was not open on db start, then it's may be deprecated diff --git a/eth/integrity/e3_ef_files.go b/eth/integrity/e3_ef_files.go index 6103acfa9d7..516330cb572 100644 --- a/eth/integrity/e3_ef_files.go +++ b/eth/integrity/e3_ef_files.go @@ -21,18 +21,13 @@ import ( "time" "github.com/erigontech/erigon-lib/kv" - "github.com/erigontech/erigon-lib/kv/temporal" "github.com/erigontech/erigon-lib/state" "golang.org/x/sync/errgroup" ) -func E3EfFiles(ctx context.Context, chainDB kv.RwDB, agg *state.Aggregator, failFast bool, fromStep uint64) error { +func E3EfFiles(ctx context.Context, db kv.TemporalRwDB, failFast bool, fromStep uint64) error { logEvery := time.NewTicker(20 * time.Second) defer logEvery.Stop() - db, err := temporal.New(chainDB, agg) - if err != nil { - return err - } g := &errgroup.Group{} for _, idx := range []kv.InvertedIdx{kv.AccountsHistoryIdx, kv.StorageHistoryIdx, kv.CodeHistoryIdx, kv.CommitmentHistoryIdx, kv.ReceiptHistoryIdx, kv.LogTopicIdx, kv.LogAddrIdx, kv.TracesFromIdx, kv.TracesToIdx} { idx := idx diff --git a/eth/integrity/e3_history_no_system_txs.go b/eth/integrity/e3_history_no_system_txs.go index 511433b966d..15c9934a39f 100644 --- a/eth/integrity/e3_history_no_system_txs.go +++ b/eth/integrity/e3_history_no_system_txs.go @@ -28,7 +28,6 @@ import ( "github.com/erigontech/erigon-lib/kv" "github.com/erigontech/erigon-lib/kv/order" "github.com/erigontech/erigon-lib/kv/rawdbv3" - "github.com/erigontech/erigon-lib/kv/temporal" "github.com/erigontech/erigon-lib/log/v3" "github.com/erigontech/erigon-lib/state" "github.com/erigontech/erigon/turbo/services" @@ -36,14 +35,11 @@ import ( ) // E3 History - usually don't have anything attributed to 1-st system txs (except genesis) -func E3HistoryNoSystemTxs(ctx context.Context, chainDB kv.RwDB, blockReader services.FullBlockReader, agg *state.Aggregator) error { +func E3HistoryNoSystemTxs(ctx context.Context, db kv.TemporalRwDB, blockReader services.FullBlockReader) error { count := atomic.Uint64{} logEvery := time.NewTicker(20 * time.Second) defer logEvery.Stop() - db, err := temporal.New(chainDB, agg) - if err != nil { - return err - } + agg := db.(state.HasAgg).Agg().(*state.Aggregator) g := &errgroup.Group{} for j := 0; j < 256; j++ { j := j diff --git a/turbo/app/snapshots_cmd.go b/turbo/app/snapshots_cmd.go index 9bf8d1a15f9..20b05aabf7c 100644 --- a/turbo/app/snapshots_cmd.go +++ b/turbo/app/snapshots_cmd.go @@ -572,11 +572,11 @@ func doIntegrity(cliCtx *cli.Context) error { return err } case integrity.InvertedIndex: - if err := integrity.E3EfFiles(ctx, db, agg, failFast, fromStep); err != nil { + if err := integrity.E3EfFiles(ctx, db, failFast, fromStep); err != nil { return err } case integrity.HistoryNoSystemTxs: - if err := integrity.E3HistoryNoSystemTxs(ctx, db, blockReader, agg); err != nil { + if err := integrity.E3HistoryNoSystemTxs(ctx, db, blockReader); err != nil { return err } case integrity.BorEvents: