package content import ( "fmt" "github.com/dgraph-io/badger/v3" "time" ) type Database struct { handle *badger.DB closeChannel chan bool gcTicker *time.Ticker } func OpenDatabase(path string) (*Database, error) { opts := badger.DefaultOptions(path) opts.IndexCacheSize = 256 << 20 //256 MiB, TODO check relative to keys db, err := badger.Open(opts) if err != nil { return nil, err } database := &Database{ handle: db, gcTicker: time.NewTicker(time.Minute * 5), closeChannel: make(chan bool), } go func() { defer database.gcTicker.Stop() for { select { case <-database.gcTicker.C: for database.handle.RunValueLogGC(0.5) == nil { } case <-database.closeChannel: return } } }() return database, nil } func (db *Database) GetEntry(key HashIdentifier) *Entry { var entry *Entry err := db.handle.View(func(txn *badger.Txn) error { var err error entry, err = db.getChain(txn, key) return err }) if err != nil { return nil } return entry } func (db *Database) SetAlias(alias *Alias) error { return db.handle.Update(func(txn *badger.Txn) error { return txn.Set(alias.Key.Encode(), alias.Encode()) }) } func (db *Database) SetEntry(entry *Entry) error { return db.handle.Update(func(txn *badger.Txn) error { b, err := entry.Encode() if err != nil { return err } return txn.Set(entry.Key.Encode(), b) }) } func (db *Database) RemoveEntry(key *HashIdentifier) error { return db.handle.Update(func(txn *badger.Txn) error { return txn.Delete(key.Encode()) }) } func (db *Database) getChain(txn *badger.Txn, key HashIdentifier) (*Entry, error) { item, err := txn.Get(key.Encode()) if err != nil { return nil, err } var entry *Entry err = item.Value(func(val []byte) error { if key.IsKey() { entry = DecodeEntry(key, val) return nil } else { alias := DecodeAlias(key, val) if alias == nil { return fmt.Errorf("could not decode alias %x", key.Encode()) } entry, err = db.getChain(txn, alias.Identifier) return err } }) return entry, err } func (db *Database) Close() error { db.closeChannel <- true return db.handle.Close() }