store.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // package store -- хранилище на диске
  2. package store
  3. import (
  4. "fmt"
  5. "log"
  6. "os"
  7. "strings"
  8. "sync"
  9. "github.com/syndtr/goleveldb/leveldb"
  10. "github.com/syndtr/goleveldb/leveldb/util"
  11. "git.p78su.freemyip.com/svi/gostore/pkg/types"
  12. )
  13. // StoreDisk -- хранилище на диске
  14. type Store struct {
  15. serv types.IServCtx
  16. db *leveldb.DB
  17. isWork bool
  18. block sync.RWMutex
  19. }
  20. var IsBad_ = false // Для тестов
  21. // NewStore -- возвращает новое хранилище на диске
  22. func NewStore(serv types.IServCtx) (types.IStore, error) {
  23. if IsBad_ {
  24. return nil, fmt.Errorf("NewStore(): IsBad_==true")
  25. }
  26. if serv == nil {
  27. return nil, fmt.Errorf("NewStore(): IServCtx==nil")
  28. }
  29. err := os.MkdirAll("./store", 0750)
  30. if err != nil {
  31. return nil, fmt.Errorf("NewStore(): in create dir, err=\n\t%w", err)
  32. }
  33. db, err := leveldb.OpenFile("./store/db", nil)
  34. if err != nil {
  35. if !strings.Contains(err.Error(), "leveldb: manifest corrupted") {
  36. return nil, fmt.Errorf("NewStore(): in create IStoreDisk, err=\n\t%w", err)
  37. }
  38. db, err = leveldb.RecoverFile("./store/db", nil)
  39. if err != nil {
  40. return nil, fmt.Errorf("NewStore(): in recovery DB, err=\n\t%w", err)
  41. }
  42. }
  43. sf := &Store{
  44. serv: serv,
  45. db: db,
  46. }
  47. sf.serv.Wg().Add(1)
  48. sf.isWork = true
  49. go sf.close()
  50. return sf, nil
  51. }
  52. // Проверка на нерабочую схему
  53. func (sf *Store) isClosed() bool {
  54. sf.block.RLock()
  55. defer sf.block.RUnlock()
  56. return !sf.isWork
  57. }
  58. // Put -- размещает в хранилище ключ и значение
  59. func (sf *Store) Put(key string, val []byte) error {
  60. if sf.isClosed() {
  61. return fmt.Errorf("Store.Put(): store is closed")
  62. }
  63. if key == "" {
  64. return fmt.Errorf("Store.Put(): key is empty")
  65. }
  66. err := sf.db.Put([]byte(key), val, nil)
  67. if err != nil {
  68. return fmt.Errorf("Store.Put(): key=%q\terr=\n\t%w", key, err)
  69. }
  70. return nil
  71. }
  72. // Get -- возвращает значение ключа
  73. func (sf *Store) Get(key string) ([]byte, error) {
  74. if sf.isClosed() {
  75. return nil, fmt.Errorf("Store.Get(): store is closed")
  76. }
  77. val, err := sf.db.Get([]byte(key), nil)
  78. if err != nil {
  79. return nil, fmt.Errorf("Store.Get(): key=%q\terr=\n\t%w", key, err)
  80. }
  81. return val, nil
  82. }
  83. // Find -- ищет ключи по префиксу
  84. func (sf *Store) Find(prefixKey string) ([]string, error) {
  85. if sf.isClosed() {
  86. return nil, fmt.Errorf("Store.Find(): store is closed")
  87. }
  88. lstKey := []string{}
  89. iter := sf.db.NewIterator(util.BytesPrefix([]byte(prefixKey)), nil)
  90. for iter.Next() {
  91. key := iter.Key()
  92. lstKey = append(lstKey, string(key))
  93. }
  94. iter.Release()
  95. err := iter.Error()
  96. if err != nil {
  97. return nil, fmt.Errorf("Store.Find(): preefixKey=%q\terr=\n\t%w", prefixKey, err)
  98. }
  99. return lstKey, nil
  100. }
  101. // Del -- удаление ключа из базы
  102. func (sf *Store) Del(key string) error {
  103. if sf.isClosed() {
  104. return fmt.Errorf("Store.Del(): store is closed")
  105. }
  106. err := sf.db.Delete([]byte(key), nil)
  107. if err != nil {
  108. return fmt.Errorf("Store.Del(): key=%q\terr=\n\t%w", key, err)
  109. }
  110. return nil
  111. }
  112. // Ожидание закрытия приложения
  113. func (sf *Store) close() {
  114. <-sf.serv.Ctx().Done()
  115. sf.block.Lock()
  116. defer sf.block.Unlock()
  117. if !sf.isWork {
  118. return
  119. }
  120. sf.isWork = false
  121. err := sf.db.Close()
  122. if err != nil {
  123. log.Printf("Store.close(): err=\n\t%v\n", err)
  124. }
  125. sf.serv.Wg().Done()
  126. }