github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/badgerdb/badger.go (about)

     1  package badgerdb
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"log"
     7  	"time"
     8  
     9  	"github.com/bingoohuang/gg/pkg/osx"
    10  	"github.com/dgraph-io/badger/v3"
    11  )
    12  
    13  type Badger struct {
    14  	DB *badger.DB
    15  }
    16  
    17  func WithInMemory(v bool) OpenOptionsFn { return func(o *OpenOptions) { o.InMemory = v } }
    18  func WithPath(v string) OpenOptionsFn   { return func(o *OpenOptions) { o.Path = v } }
    19  
    20  func Open(fns ...OpenOptionsFn) (*Badger, error) {
    21  	db, err := badger.Open(OpenOptionsFns(fns).Create().Apply())
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  
    26  	return &Badger{DB: db}, nil
    27  }
    28  
    29  func (b *Badger) Close() error { return b.DB.Close() }
    30  
    31  func WithStart(v []byte) WalkOptionsFn  { return func(o *WalkOptions) { o.Start = v } }
    32  func WithMax(v int) WalkOptionsFn       { return func(o *WalkOptions) { o.Max = v } }
    33  func WithPrefix(v []byte) WalkOptionsFn { return func(o *WalkOptions) { o.Prefix = v } }
    34  func WithReverse(v bool) WalkOptionsFn  { return func(o *WalkOptions) { o.Reverse = v } }
    35  func WithOnlyKeys(v bool) WalkOptionsFn { return func(o *WalkOptions) { o.OnlyKeys = v } }
    36  
    37  func (b *Badger) Walk(f func(k, v []byte) error, fns ...WalkOptionsFn) error {
    38  	wo := WalkOptionsFns(fns).Create()
    39  	return b.DB.View(func(txn *badger.Txn) error {
    40  		it := txn.NewIterator(wo.NewIteratorOptions())
    41  		defer it.Close()
    42  
    43  		for wo.Seek(it); wo.Valid(it); it.Next() {
    44  			if k, v, err := wo.ParseKv(it.Item()); err != nil {
    45  				return err
    46  			} else if err = f(k, v); err != nil {
    47  				return err
    48  			}
    49  		}
    50  		return nil
    51  	})
    52  }
    53  
    54  func (b *Badger) Get(k []byte) (val []byte, er error) {
    55  	er = b.DB.View(func(txn *badger.Txn) error {
    56  		item, err := txn.Get(k)
    57  		if errors.Is(err, badger.ErrKeyNotFound) {
    58  			return nil
    59  		}
    60  
    61  		val, err = item.ValueCopy(nil)
    62  		return err
    63  	})
    64  
    65  	return
    66  }
    67  
    68  func WithTTL(v time.Duration) SetOptionsFn { return func(o *SetOptions) { o.TTL = v } }
    69  func WithMeta(v byte) SetOptionsFn         { return func(o *SetOptions) { o.Meta = v } }
    70  
    71  func (b *Badger) Set(k, v []byte, fns ...SetOptionsFn) error {
    72  	e := badger.NewEntry(k, v)
    73  	SetOptionsFns(fns).Create().Apply(e)
    74  	return b.DB.Update(func(txn *badger.Txn) error { return txn.SetEntry(e) })
    75  }
    76  
    77  type OpenOptions struct {
    78  	InMemory bool
    79  	Path     string
    80  }
    81  
    82  func (o OpenOptions) Apply() badger.Options {
    83  	if o.InMemory {
    84  		options := badger.DefaultOptions("").WithInMemory(true)
    85  		options.Logger = nil
    86  		return options
    87  	}
    88  
    89  	path := o.Path
    90  	if path == "" {
    91  		dir, err := ioutil.TempDir("", "badgerdb")
    92  		if err != nil {
    93  			panic(err)
    94  		}
    95  		path = dir
    96  		log.Printf("badgerdb created at %s", path)
    97  	} else {
    98  		path = osx.ExpandHome(path)
    99  	}
   100  
   101  	options := badger.DefaultOptions(path)
   102  	options.Logger = nil
   103  	return options
   104  }
   105  
   106  type (
   107  	OpenOptionsFn  func(*OpenOptions)
   108  	OpenOptionsFns []OpenOptionsFn
   109  )
   110  
   111  func (fns OpenOptionsFns) Create() *OpenOptions {
   112  	o := &OpenOptions{}
   113  	for _, f := range fns {
   114  		f(o)
   115  	}
   116  	return o
   117  }
   118  
   119  type SetOptions struct {
   120  	TTL  time.Duration
   121  	Meta byte
   122  }
   123  
   124  func (o SetOptions) Apply(e *badger.Entry) {
   125  	if o.TTL > 0 {
   126  		e.WithTTL(o.TTL)
   127  	}
   128  
   129  	e.WithMeta(o.Meta)
   130  }
   131  
   132  type (
   133  	SetOptionsFn  func(*SetOptions)
   134  	SetOptionsFns []SetOptionsFn
   135  )
   136  
   137  func (fns SetOptionsFns) Create() *SetOptions {
   138  	o := &SetOptions{}
   139  	for _, f := range fns {
   140  		f(o)
   141  	}
   142  	return o
   143  }
   144  
   145  type WalkOptions struct {
   146  	Start    []byte
   147  	Max      int
   148  	OnlyKeys bool
   149  	Reverse  bool
   150  	Prefix   []byte
   151  
   152  	Num int
   153  }
   154  
   155  func (o *WalkOptions) NewIteratorOptions() badger.IteratorOptions {
   156  	opts := badger.DefaultIteratorOptions
   157  	opts.PrefetchSize = 10
   158  	opts.PrefetchValues = !o.OnlyKeys
   159  	opts.Reverse = o.Reverse
   160  	opts.Prefix = o.Prefix
   161  
   162  	return opts
   163  }
   164  
   165  func (o *WalkOptions) Seek(it *badger.Iterator) {
   166  	if len(o.Prefix) > 0 {
   167  		it.Seek(o.Prefix)
   168  		return
   169  	}
   170  
   171  	it.Seek(o.Start)
   172  }
   173  
   174  func (o *WalkOptions) Valid(it *badger.Iterator) bool {
   175  	b := it.ValidForPrefix(o.Prefix) && (o.Max <= 0 || o.Num < o.Max)
   176  	if b {
   177  		o.Num++
   178  	}
   179  
   180  	return b
   181  }
   182  
   183  func (o *WalkOptions) ParseKv(item *badger.Item) (k, v []byte, err error) {
   184  	if o.OnlyKeys {
   185  		return item.Key(), nil, nil
   186  	}
   187  
   188  	v, err = item.ValueCopy(nil)
   189  	return item.Key(), v, err
   190  }
   191  
   192  type WalkOptionsFn func(*WalkOptions)
   193  
   194  type WalkOptionsFns []WalkOptionsFn
   195  
   196  func (fns WalkOptionsFns) Create() *WalkOptions {
   197  	o := &WalkOptions{}
   198  	for _, fn := range fns {
   199  		fn(o)
   200  	}
   201  
   202  	return o
   203  }