// package store -- главный тип плагина хранилища package store import ( "fmt" "log" "sync" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" "wartank/pkg/components/safe_bool" "wartank/pkg/types" ) // Store -- главный тип плагина хранилища type Store struct { ядро types.ИЯдро path string // Путь к хранилищу isWork *safe_bool.БезопБул // Признак открытой базы db *leveldb.DB // Объект хранилища block sync.Mutex // Блокировка для безопасности потоков } // NewStore -- возвращает новое хранилище func NewStore(ядро types.ИЯдро, path string) (*Store, error) { { // Прдусловия if ядро == nil { return nil, fmt.Errorf("NewStore: ядро == nil") } if path == "" { return nil, fmt.Errorf("NewStore: path == nil") } } sf := &Store{ ядро: ядро, path: path, isWork: safe_bool.НовБезопБул(), } if err := sf.open(); err != nil { return nil, fmt.Errorf("NewStore: in open db, err=\n\t%w", err) } ядро.Wg().Add("ядро") return sf, nil } // Put -- добавляет в хранилище значение по ключу func (sf *Store) Put(key string, value []byte) error { sf.block.Lock() defer sf.block.Unlock() if key == "" { return fmt.Errorf("Store.Put(): key is empty") } if value == nil { return fmt.Errorf("Store.Put(): value == nil") } if err := sf.db.Put([]byte(key), value, nil); err != nil { return fmt.Errorf("Store.Put(): in put value, err=\n\t%w", err) } return nil } // Get -- возвращает значение по ключу func (sf *Store) Get(key string) ([]byte, error) { sf.block.Lock() defer sf.block.Unlock() value, err := sf.db.Get([]byte(key), nil) if err != nil { return nil, fmt.Errorf("Store.Get(): in get value, err=\n\t%w", err) } return value, nil } // Find -- возвращает список ключей по префиксу func (sf *Store) Find(prefix string) ([]string, error) { sf.block.Lock() defer sf.block.Unlock() var keys []string slice := &util.Range{Start: []byte(prefix)} iter := sf.db.NewIterator(slice, nil) for iter.Next() { key := string(iter.Key()) keys = append(keys, key) } iter.Release() if err := iter.Error(); err != nil { return nil, fmt.Errorf("Store.Find(): in find keys, err=\n\t%w", err) } return keys, nil } // Del -- удаляет значение по ключу func (sf *Store) Del(key string) error { sf.block.Lock() defer sf.block.Unlock() if err := sf.db.Delete([]byte(key), nil); err != nil { return fmt.Errorf("Store.Del(): in delete key, err=\n\t%w", err) } return nil } // open -- открывает хранилище func (sf *Store) open() error { sf.block.Lock() defer sf.block.Unlock() db, err := leveldb.OpenFile(sf.path, nil) fnOpen := func() { sf.db = db sf.isWork.Уст() go sf.close() } if err == nil { fnOpen() return nil } log.Printf("Store.open(): try restore db, in open err=\n\t%v", err) db, err = leveldb.RecoverFile(sf.path, nil) if err != nil { return fmt.Errorf("Store.open(): in recover db, err=\n\t%w", err) } fnOpen() return nil } // close -- закрывает хранилище по требованию func (sf *Store) close() { <-sf.ядро.CtxApp().Done() sf.block.Lock() defer sf.block.Unlock() sf.isWork.Сброс() if err := sf.db.Close(); err != nil { log.Printf("Store.close(): in close db, err=\n\t%v", err) return } sf.ядро.Wg().Done("ядро") }