// 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" ) const ( стрХранилище = "Хранилище" ) // Хранилище -- главный тип плагина хранилища type Хранилище struct { ядро types.ИЯдро path string // Путь к хранилищу isWork *safe_bool.БезопБул // Признак открытой базы бд *leveldb.DB // Объект хранилища block sync.Mutex // Блокировка для безопасности потоков } // НовХранилище -- возвращает новое хранилище func НовХранилище(ядро types.ИЯдро, path string) (*Хранилище, error) { { // Прдусловия if ядро == nil { return nil, fmt.Errorf("НовХранилище: ядро == nil") } if path == "" { return nil, fmt.Errorf("НовХранилище: path == nil") } } сам := &Хранилище{ ядро: ядро, path: path, isWork: safe_bool.НовБезопБул(), } if err := сам.открыть(); err != nil { return nil, fmt.Errorf("НовХранилище: при открытии БД, err=\n\t%w", err) } if ош := ядро.Wg().Add(стрХранилище); ош != nil { return nil, fmt.Errorf("НовХранилище: при добавлении группы ожидания, ош=\n\t%v", ош) } _ = types.ИХранилище(сам) return сам, nil } // Уст -- добавляет в хранилище значение по ключу func (сам *Хранилище) Уст(ключ string, знач []byte) error { сам.block.Lock() defer сам.block.Unlock() if ключ == "" { return fmt.Errorf("Хранилище.Уст(): ключ пустой") } if знач == nil { return fmt.Errorf("Хранилище.Уст(): знач == nil") } if ош := сам.бд.Put([]byte(ключ), знач, nil); ош != nil { return fmt.Errorf("Хранилище.Уст(): при устнановке значения, ош=\n\t%w", ош) } return nil } // Получ -- возвращает значение по ключу func (sf *Хранилище) Получ(key string) ([]byte, error) { sf.block.Lock() defer sf.block.Unlock() value, err := sf.бд.Get([]byte(key), nil) if err != nil { return nil, fmt.Errorf("Хранилище.Get(): in get value, err=\n\t%w", err) } return value, nil } // Найти -- возвращает список ключей по префиксу func (sf *Хранилище) Найти(prefix string) ([]string, error) { sf.block.Lock() defer sf.block.Unlock() var keys []string slice := &util.Range{Start: []byte(prefix)} iter := sf.бд.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("Хранилище.Find(): in find keys, err=\n\t%w", err) } return keys, nil } // Удалить -- удаляет значение по ключу func (sf *Хранилище) Удалить(key string) error { sf.block.Lock() defer sf.block.Unlock() if err := sf.бд.Delete([]byte(key), nil); err != nil { return fmt.Errorf("Хранилище.Del(): in delete key, err=\n\t%w", err) } return nil } // открыть -- открывает хранилище func (сам *Хранилище) открыть() error { сам.block.Lock() defer сам.block.Unlock() бд, ош := leveldb.OpenFile(сам.path, nil) фнОткрыть := func() { сам.бд = бд сам.isWork.Уст() go сам.закрыть() } if ош == nil { фнОткрыть() return nil } log.Printf("Хранилище.открыть(): при открытии БД, ош=\n\t%v", ош) бд, ош = leveldb.RecoverFile(сам.path, nil) if ош != nil { return fmt.Errorf("Хранилище.открыть(): при попытке восстановлении БД, ош=\n\t%w", ош) } фнОткрыть() return nil } // закрыть -- закрывает хранилище по требованию func (sf *Хранилище) закрыть() { <-sf.ядро.Контекст().Done() sf.block.Lock() defer sf.block.Unlock() sf.isWork.Сброс() if err := sf.бд.Close(); err != nil { log.Printf("Хранилище.закрыть(): при закрытти БД, err=\n\t%v", err) return } ош := sf.ядро.Wg().Done(стрХранилище) if ош != nil { log.Printf("Хранилище.закрыть(): при удалении группы ожидания, ош=\n\t%v", ош) } }