kstore_kv.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // package kstore_kv -- локальное быстрое key-value хранилище ядра.
  2. package kstore_kv
  3. import (
  4. "os"
  5. "sync"
  6. "time"
  7. "github.com/dgraph-io/badger/v4"
  8. "gitp78su.ipnodns.ru/svi/kern/v4/lev0"
  9. "gitp78su.ipnodns.ru/svi/kern/v4/lev1"
  10. "gitp78su.ipnodns.ru/svi/kern/v4/lev1/log_buf"
  11. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kern_ctx"
  12. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kern_ent/stream_name"
  13. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/kspec"
  14. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/lsi/store_ent"
  15. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/lsi/store_ent/rec_key"
  16. "gitp78su.ipnodns.ru/svi/kern/v4/lev2/lsi/store_spec"
  17. )
  18. var (
  19. storeStreamName = stream_name.NewAStreamName("kstore_kv") // Имя потока для ожидателя потоков
  20. )
  21. // kStoreKv -- локальное хранилище ядра.
  22. type kStoreKv struct {
  23. sync.RWMutex
  24. kCtx *kern_ctx.KernCtx
  25. lCtx *lev1.LocalCtx
  26. log *lev1.LogBuf
  27. wg kspec.IKernelWg
  28. storePath *lev0.LTxt
  29. db *badger.DB
  30. isWork *lev0.MSafeBool
  31. }
  32. var (
  33. kernStore *kStoreKv // Глобальный объект
  34. block sync.Mutex
  35. )
  36. // GetKernelStore -- возвращает новое локальное хранилище ядра.
  37. func GetKernelStore() store_spec.IKernelStoreKv {
  38. block.Lock()
  39. defer block.Unlock()
  40. if kernStore != nil {
  41. kernStore.log.Debug("GetKernelStore()")
  42. return kernStore
  43. }
  44. kCtx := kern_ctx.GetKernCtx()
  45. param := &log_buf.LogBufParam{
  46. Prefix_: lev0.LetTxt("kStoreKv"),
  47. IsTerm_: lev0.MutSafeBool(true),
  48. }
  49. log := lev1.NewLogBuf(param)
  50. sf := &kStoreKv{
  51. kCtx: kCtx,
  52. lCtx: lev1.NewLocalCtx(kCtx.SelfCtx()),
  53. wg: kCtx.Wg(),
  54. isWork: lev0.MutSafeBool(true),
  55. log: log,
  56. }
  57. sf.open()
  58. kernStore = sf
  59. kCtx.Set(lev0.LetTxt("kernStoreKV"), kernStore, "fast KV store on Badger")
  60. return kernStore
  61. }
  62. // Log -- возвращает локальный лог.
  63. func (sf *kStoreKv) Log() *lev1.LogBuf {
  64. return sf.log
  65. }
  66. // Set -- устанавливает значение по ключу.
  67. func (sf *kStoreKv) Set(rec store_ent.IRecKvFix) *lev0.Result[lev0.Bool] {
  68. sf.Lock()
  69. defer sf.Unlock()
  70. key := rec.Key()
  71. sf.log.Debug("Set(): key='%v'", key.Get())
  72. fnSet := func(txn *badger.Txn) error {
  73. err := txn.Set(key.Byte(), rec.Val().Byte())
  74. return err
  75. }
  76. err := sf.db.Update(fnSet)
  77. if err != nil {
  78. err := lev0.LetErr("Set(): key=%v, err=\n\t%w", key, err)
  79. sf.log.Err(err)
  80. return lev0.ResErr[lev0.Bool](err)
  81. }
  82. return lev0.ResOk(lev0.Bool(true))
  83. }
  84. // Get -- возвращает значение по ключу.
  85. func (sf *kStoreKv) Get(key store_ent.IStoreKeyFix) *lev0.Result[[]byte] {
  86. sf.RLock()
  87. defer sf.RUnlock()
  88. sf.log.Debug("Get(): key='%v'", key)
  89. var binVal []byte
  90. fnGet := func(txn *badger.Txn) error {
  91. item, err := txn.Get(key.Byte())
  92. if err != nil {
  93. return err
  94. }
  95. binVal, err = item.ValueCopy(binVal)
  96. return err
  97. }
  98. err := sf.db.View(fnGet)
  99. if err != nil {
  100. err := lev0.LetErr("Get(): key=%v, err=\n\t%v", key, err)
  101. sf.log.Err(err)
  102. return lev0.ResErr[[]byte](err)
  103. }
  104. return lev0.ResOk(binVal)
  105. }
  106. // ByPrefix -- фильтрует ключи по префиксу.
  107. func (sf *kStoreKv) ByPrefix(prefix store_ent.IStoreKeyFix) *lev0.Result[[]store_ent.AStoreKey] {
  108. var (
  109. binKey []byte
  110. lstKey = []store_ent.AStoreKey{}
  111. )
  112. // fnValue := func(v []byte) error {
  113. // fmt.Printf("key=%s, value=%s\n", key, v)
  114. // return nil
  115. // }
  116. fnPrefix := func(txn *badger.Txn) error {
  117. it := txn.NewIterator(badger.DefaultIteratorOptions)
  118. defer it.Close()
  119. binPref := prefix.Byte()
  120. for it.Seek(binPref); it.ValidForPrefix(binPref); it.Next() {
  121. item := it.Item()
  122. binKey = item.Key()
  123. // err := item.Value(fnValue)
  124. // if err != nil {
  125. // return err
  126. // }
  127. lstKey = append(lstKey, rec_key.ARecKey(binKey))
  128. }
  129. return nil
  130. }
  131. err := sf.db.View(fnPrefix)
  132. if err != nil {
  133. err := lev0.LetErr("ByPrefix(): in find, err=\n\t%w", err)
  134. return lev0.ResErr[[]store_ent.AStoreKey](err)
  135. }
  136. return lev0.ResOk(lstKey)
  137. }
  138. // Delete -- удалить ключ из хранилища.
  139. func (sf *kStoreKv) Delete(key store_ent.IStoreKeyFix) *lev0.Result[lev0.Bool] {
  140. sf.Lock()
  141. defer sf.Unlock()
  142. sf.log.Debug("Delete(): key='%v'", key)
  143. fnDelete := func(txn *badger.Txn) error {
  144. err := txn.Delete(key.Byte())
  145. return err
  146. }
  147. err := sf.db.Update(fnDelete)
  148. if err != nil {
  149. err := lev0.LetErr("Delete(): key=%v, err=\n\t%w", key, err)
  150. sf.log.Err(err)
  151. return lev0.ResErr[lev0.Bool](err)
  152. }
  153. return lev0.ResOk(lev0.Bool(true))
  154. }
  155. // Открывает базу при создании.
  156. func (sf *kStoreKv) open() {
  157. sf.Lock()
  158. defer sf.Unlock()
  159. sf.log.Debug("open()")
  160. strPath := os.Getenv("LOCAL_STORE_PATH")
  161. lev0.If(strPath == "").Hassert("open(): env LOCAL_STORE_PATH not set")
  162. pwd, err := os.Getwd()
  163. lev0.If(err != nil).Hassert("open(): in get PWD, err=\n\t%v", err)
  164. sf.storePath = lev0.LetTxt(pwd + strPath + "/db_local")
  165. err = os.MkdirAll(sf.storePath.String(), 0750)
  166. lev0.If(err != nil).Hassert("open(): in make dir %v, err=\n\t%v", sf.storePath, err)
  167. sf.db, err = badger.Open(badger.DefaultOptions(sf.storePath.String()))
  168. lev0.If(err != nil).Hassert("open(): in open DB %v, err=\n\t%v", sf.storePath, err)
  169. sf.wg.Add(storeStreamName)
  170. sf.isWork.Set()
  171. go sf.close()
  172. go sf.clean()
  173. }
  174. // Выполняет периодическую сборку мусора в файле.
  175. func (sf *kStoreKv) clean() {
  176. chRun := make(chan lev0.Num, 2)
  177. defer close(chRun)
  178. fnClean := func() {
  179. sf.Lock()
  180. defer sf.Unlock()
  181. _ = sf.db.RunValueLogGC(0.7)
  182. }
  183. chRun <- 1
  184. for {
  185. select {
  186. case <-sf.kCtx.SelfCtx().Done(): // надо прекратить работу
  187. return
  188. case <-chRun: // Пора поработать
  189. fnClean()
  190. }
  191. time.Sleep(time.Second * 1)
  192. }
  193. }
  194. // Ожидает последнего потока под отдельной блокировкой.
  195. func (sf *kStoreKv) wait(chWait chan lev0.Num) {
  196. for {
  197. time.Sleep(time.Millisecond * 5)
  198. if sf.wg.Len() <= 1 {
  199. break
  200. }
  201. }
  202. close(chWait)
  203. }
  204. // Ожидает закрытия контекста ядра, закрывает хранилище.
  205. func (sf *kStoreKv) close() {
  206. sf.kCtx.Wait()
  207. sf.Lock()
  208. defer sf.Unlock()
  209. if !sf.isWork.Get() {
  210. return
  211. }
  212. chWait := make(chan lev0.Num, 2)
  213. go sf.wait(chWait)
  214. <-chWait
  215. sf.isWork.Reset()
  216. err := sf.db.Close()
  217. lev0.If(err != nil).Assert("kStoreKv.close(): in close DB, err=\n\t%v", err)
  218. sf.wg.Done(storeStreamName)
  219. sf.log.Debug("close(): done")
  220. }