diff --git a/client/app/config.go b/client/app/config.go index 7b80e50392..0dd055bad5 100644 --- a/client/app/config.go +++ b/client/app/config.go @@ -110,7 +110,7 @@ type CoreConfig struct { ExtensionModeFile string `long:"extension-mode-file" description:"path to a file that specifies options for running core as an extension."` - ArchiveSizeLimit uint64 `long:"archivesize" description:"the maximum number of orders to be archived before deleting the oldest"` + PruneArchive uint64 `long:"prunearchive" description:"prune that order archive to the specified number of most recent orders"` } // WebConfig encapsulates the configuration needed for the web server. @@ -219,7 +219,7 @@ func (cfg *Config) Core(log dex.Logger) *core.Config { NoAutoDBBackup: cfg.NoAutoDBBackup, ExtensionModeFile: cfg.ExtensionModeFile, TheOneHost: cfg.TheOneHost, - ArchiveSizeLimit: cfg.ArchiveSizeLimit, + PruneArchive: cfg.PruneArchive, } } @@ -230,9 +230,6 @@ var DefaultConfig = Config{ RPCConfig: RPCConfig{ CertHosts: []string{defaultTestnetHost, defaultSimnetHost, defaultMainnetHost}, }, - CoreConfig: CoreConfig{ - ArchiveSizeLimit: defaultArchiveSizeLimit, - }, } // ParseCLIConfig parses the command-line arguments into the provided struct diff --git a/client/core/core.go b/client/core/core.go index fdefc6f337..aa2b6c64d0 100644 --- a/client/core/core.go +++ b/client/core/core.go @@ -1462,9 +1462,9 @@ type Config struct { ExtensionModeFile string // TheOneHost will run core with only the specified server. TheOneHost string - // ArchiveSizeLimit is the maximum number of orders that will be archived - // before we start deleting the oldest. - ArchiveSizeLimit uint64 + // PruneArchive will prune the order archive to the specified number of + // orders. + PruneArchive uint64 } // locale is data associated with the currently selected language. @@ -1547,7 +1547,7 @@ func New(cfg *Config) (*Core, error) { } dbOpts := bolt.Opts{ BackupOnShutdown: !cfg.NoAutoDBBackup, - ArchiveSizeLimit: cfg.ArchiveSizeLimit, + PruneArchive: cfg.PruneArchive, } boltDB, err := bolt.NewDB(cfg.DBPath, cfg.Logger.SubLogger("DB"), dbOpts) if err != nil { diff --git a/client/db/bolt/db.go b/client/db/bolt/db.go index daecd5fa3d..b2898d4990 100644 --- a/client/db/bolt/db.go +++ b/client/db/bolt/db.go @@ -14,7 +14,6 @@ import ( "path/filepath" "sort" "strings" - "sync" "time" "decred.org/dcrdex/client/db" @@ -138,7 +137,7 @@ var ( // Opts is a set of options for the DB. type Opts struct { BackupOnShutdown bool // default is true - ArchiveSizeLimit uint64 + PruneArchive uint64 } var defaultOpts = Opts{ @@ -219,6 +218,11 @@ func NewDB(dbPath string, logger dex.Logger, opts ...Opts) (dexdb.DB, error) { return nil, err } + if bdb.opts.PruneArchive > 0 { + bdb.log.Info("Pruning the order archive") + bdb.pruneArchivedOrders(bdb.opts.PruneArchive) + } + bdb.log.Infof("Started database (version = %d, file = %s)", DBVersion, dbPath) return bdb, nil @@ -235,29 +239,8 @@ func (db *BoltDB) fileSize(path string) int64 { // Run waits for context cancellation and closes the database. func (db *BoltDB) Run(ctx context.Context) { - var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() - tick := time.After(time.Minute) - for { - select { - case <-tick: - case <-ctx.Done(): - return - } - if err := db.pruneArchivedOrders(); err != nil { - db.log.Errorf("Error cleaning archive: %v", err) - } - tick = time.After(time.Minute * 30) - } - }() - <-ctx.Done() // wait for shutdown to backup and compact - // Wait for archive cleaner to exit. - wg.Wait() - // Create a backup in the backups folder. if db.opts.BackupOnShutdown { db.log.Infof("Backing up database...") @@ -430,11 +413,7 @@ func (db *BoltDB) SetPrimaryCredentials(creds *dexdb.PrimaryCredentials) error { }) } -func (db *BoltDB) pruneArchivedOrders() error { - var archiveSizeLimit uint64 = 1000 - if db.opts.ArchiveSizeLimit != 0 { - archiveSizeLimit = db.opts.ArchiveSizeLimit - } +func (db *BoltDB) pruneArchivedOrders(prunedSize uint64) error { return db.Update(func(tx *bbolt.Tx) error { archivedOB := tx.Bucket(archivedOrdersBucket) @@ -462,11 +441,11 @@ func (db *BoltDB) pruneArchivedOrders() error { } nOrds := uint64(archivedOB.Stats().BucketN - 1 /* BucketN includes top bucket */) - if nOrds <= archiveSizeLimit { + if nOrds <= prunedSize { return nil } - toClear := int(nOrds - archiveSizeLimit) + toClear := int(nOrds - prunedSize) type orderStamp struct { oid []byte @@ -525,7 +504,7 @@ func (db *BoltDB) pruneArchivedOrders() error { } } - matchesToDelete := make([][]byte, 0, archiveSizeLimit /* just avoid some allocs if we can */) + matchesToDelete := make([][]byte, 0, prunedSize /* just avoid some allocs if we can */) archivedMatches := tx.Bucket(archivedMatchesBucket) if archivedMatches == nil { return errors.New("no archived match bucket") diff --git a/client/db/bolt/db_test.go b/client/db/bolt/db_test.go index b10c18e483..5c85b97a40 100644 --- a/client/db/bolt/db_test.go +++ b/client/db/bolt/db_test.go @@ -1629,8 +1629,8 @@ func TestPokes(t *testing.T) { func TestPruneArchivedOrders(t *testing.T) { const host = "blah" - const archiveSizeLimit = 5 - boltdb, shutdown := newTestDB(t, Opts{ArchiveSizeLimit: archiveSizeLimit}) + const prunedSize = 5 + boltdb, shutdown := newTestDB(t) defer shutdown() archivedOrdersN := func() (n int) { @@ -1663,27 +1663,27 @@ func TestPruneArchivedOrders(t *testing.T) { }) return oid } - for i := 0; i < archiveSizeLimit*2; i++ { + for i := 0; i < prunedSize*2; i++ { addOrder(0) } - if n := archivedOrdersN(); n != archiveSizeLimit*2 { - t.Fatalf("Expected %d archived orders after intitialization, saw %d", archiveSizeLimit*2, n) + if n := archivedOrdersN(); n != prunedSize*2 { + t.Fatalf("Expected %d archived orders after intitialization, saw %d", prunedSize*2, n) } - if err := boltdb.pruneArchivedOrders(); err != nil { + if err := boltdb.pruneArchivedOrders(prunedSize); err != nil { t.Fatalf("pruneArchivedOrders error: %v", err) } - if n := archivedOrdersN(); n != archiveSizeLimit { - t.Fatalf("Expected %d archived orders after first pruning, saw %d", archiveSizeLimit, n) + if n := archivedOrdersN(); n != prunedSize { + t.Fatalf("Expected %d archived orders after first pruning, saw %d", prunedSize, n) } // Make sure we pruned the first 5. if err := boltdb.View(func(tx *bbolt.Tx) error { bkt := tx.Bucket(archivedOrdersBucket) return bkt.ForEach(func(oidB, _ []byte) error { - if stamp := intCoder.Uint64(bkt.Bucket(oidB).Get(updateTimeKey)); stamp < archiveSizeLimit { + if stamp := intCoder.Uint64(bkt.Bucket(oidB).Get(updateTimeKey)); stamp < prunedSize { return fmt.Errorf("order stamp %d should have been pruned", stamp) } return nil @@ -1707,12 +1707,12 @@ func TestPruneArchivedOrders(t *testing.T) { t.Fatal(err) } - if err := boltdb.pruneArchivedOrders(); err != nil { + if err := boltdb.pruneArchivedOrders(prunedSize); err != nil { t.Fatalf("Error pruning orders when one has an active match: %v", err) } - if n := archivedOrdersN(); n != archiveSizeLimit { - t.Fatalf("Expected %d archived orders after pruning with active match order in place, saw %d", archiveSizeLimit, n) + if n := archivedOrdersN(); n != prunedSize { + t.Fatalf("Expected %d archived orders after pruning with active match order in place, saw %d", prunedSize, n) } // Our active match order should still be available @@ -1727,11 +1727,11 @@ func TestPruneArchivedOrders(t *testing.T) { } // Add an order to push the now retirable older order out addOrder(0) - if err := boltdb.pruneArchivedOrders(); err != nil { + if err := boltdb.pruneArchivedOrders(prunedSize); err != nil { t.Fatalf("Error pruning orders after retiring match: %v", err) } - if n := archivedOrdersN(); n != archiveSizeLimit { - t.Fatalf("Expected %d archived orders after pruning with retired match, saw %d", archiveSizeLimit, n) + if n := archivedOrdersN(); n != prunedSize { + t.Fatalf("Expected %d archived orders after pruning with retired match, saw %d", prunedSize, n) } // Match should not be archived any longer. metaID := m.MatchOrderUniqueID()