| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- // 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("ядро")
- }
|