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 }