Skip to content

Commit

Permalink
run once at startup
Browse files Browse the repository at this point in the history
  • Loading branch information
buck54321 committed Oct 6, 2024
1 parent 82831b9 commit 71ce774
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 55 deletions.
7 changes: 2 additions & 5 deletions client/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,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.
Expand Down Expand Up @@ -216,7 +216,7 @@ func (cfg *Config) Core(log dex.Logger) *core.Config {
NoAutoWalletLock: cfg.NoAutoWalletLock,
NoAutoDBBackup: cfg.NoAutoDBBackup,
ExtensionModeFile: cfg.ExtensionModeFile,
ArchiveSizeLimit: cfg.ArchiveSizeLimit,
PruneArchive: cfg.PruneArchive,
}
}

Expand All @@ -227,9 +227,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
Expand Down
8 changes: 4 additions & 4 deletions client/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1433,9 +1433,9 @@ type Config struct {
// for running core in extension mode, which gives the caller options for
// e.g. limiting the ability to configure wallets.
ExtensionModeFile 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.
Expand Down Expand Up @@ -1518,7 +1518,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 {
Expand Down
41 changes: 10 additions & 31 deletions client/db/bolt/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"path/filepath"
"sort"
"strings"
"sync"
"time"

"decred.org/dcrdex/client/db"
Expand Down Expand Up @@ -139,7 +138,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{
Expand Down Expand Up @@ -220,6 +219,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
Expand All @@ -236,29 +240,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...")
Expand Down Expand Up @@ -431,11 +414,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)
Expand Down Expand Up @@ -463,11 +442,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
Expand Down Expand Up @@ -526,7 +505,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")
Expand Down
30 changes: 15 additions & 15 deletions client/db/bolt/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1615,8 +1615,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) {
Expand Down Expand Up @@ -1649,27 +1649,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
Expand All @@ -1693,12 +1693,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
Expand All @@ -1713,11 +1713,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()
Expand Down

0 comments on commit 71ce774

Please sign in to comment.