Add PutMany, currently only for bbolt and hashmap storage backends

This commit is contained in:
Daniel 2020-04-09 14:22:22 +02:00
parent 35ab2be6a0
commit e0f96d5188
10 changed files with 246 additions and 12 deletions

View file

@ -170,10 +170,19 @@ func (i *Interface) InsertValue(key string, attribute string, value interface{})
}
// Put saves a record to the database.
func (i *Interface) Put(r record.Record) error {
_, db, err := i.getRecord(r.DatabaseName(), r.DatabaseKey(), true, true)
if err != nil && err != ErrNotFound {
return err
func (i *Interface) Put(r record.Record) (err error) {
// get record or only database
var db *Controller
if !i.options.Internal || !i.options.Local {
_, db, err = i.getRecord(r.DatabaseName(), r.DatabaseKey(), true, true)
if err != nil && err != ErrNotFound {
return err
}
} else {
db, err = getController(r.DatabaseKey())
if err != nil {
return err
}
}
r.Lock()
@ -186,24 +195,100 @@ func (i *Interface) Put(r record.Record) error {
}
// PutNew saves a record to the database as a new record (ie. with new timestamps).
func (i *Interface) PutNew(r record.Record) error {
_, db, err := i.getRecord(r.DatabaseName(), r.DatabaseKey(), true, true)
if err != nil && err != ErrNotFound {
return err
func (i *Interface) PutNew(r record.Record) (err error) {
// get record or only database
var db *Controller
if !i.options.Internal || !i.options.Local {
_, db, err = i.getRecord(r.DatabaseName(), r.DatabaseKey(), true, true)
if err != nil && err != ErrNotFound {
return err
}
} else {
db, err = getController(r.DatabaseKey())
if err != nil {
return err
}
}
r.Lock()
defer r.Unlock()
if r.Meta() == nil {
r.CreateMeta()
if r.Meta() != nil {
r.Meta().Reset()
}
r.Meta().Reset()
i.options.Apply(r)
i.updateCache(r)
return db.Put(r)
}
// PutMany stores many records in the database. Warning: This is nearly a direct database access and omits many things:
// - Record locking
// - Hooks
// - Subscriptions
// - Caching
func (i *Interface) PutMany(dbName string) (put func(record.Record) error) {
interfaceBatch := make(chan record.Record, 100)
// permission check
if !i.options.Internal || !i.options.Local {
return func(r record.Record) error {
return ErrPermissionDenied
}
}
// get database
db, err := getController(dbName)
if err != nil {
return func(r record.Record) error {
return err
}
}
// start database access
dbBatch, errCh := db.PutMany()
// interface options proxy
go func() {
for {
select {
case r := <-interfaceBatch:
// finished?
if r == nil {
close(dbBatch) // signify that we are finished
return
}
// apply options
i.options.Apply(r)
// pass along
dbBatch <- r
case <-time.After(1 * time.Second):
// bail out
errCh <- errors.New("timeout: putmany unused for too long")
close(dbBatch) // signify that we are finished
return
}
}
}()
return func(r record.Record) error {
if r == nil {
interfaceBatch <- nil // signify that we are finished
// do not close, as this fn could be called again with nil.
return <-errCh
}
if r.DatabaseName() != dbName {
return errors.New("record out of database scope")
}
select {
case interfaceBatch <- r:
return nil
case err := <-errCh:
return err
}
}
}
// SetAbsoluteExpiry sets an absolute record expiry.
func (i *Interface) SetAbsoluteExpiry(key string, time int64) error {
r, db, err := i.getRecord(getDBFromKey, key, true, true)