123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- // package store -- хранилище на диске
- package store
- import (
- "fmt"
- "log"
- "os"
- "strings"
- "sync"
- "github.com/syndtr/goleveldb/leveldb"
- "github.com/syndtr/goleveldb/leveldb/util"
- "git.p78su.freemyip.com/svi/gostore/pkg/types"
- )
- // StoreDisk -- хранилище на диске
- type Store struct {
- serv types.IService
- db *leveldb.DB
- isWork bool
- block sync.RWMutex
- }
- var IsBad_ = false // Для тестов
- // NewStore -- возвращает новое хранилище на диске
- func NewStore(serv types.IService) (*Store, error) {
- if IsBad_ {
- return nil, fmt.Errorf("NewStore(): IsBad_==true")
- }
- if serv == nil {
- return nil, fmt.Errorf("NewStore(): IService==nil")
- }
- _ = os.MkdirAll("./store/db", 0750)
- db, err := leveldb.OpenFile("./store/db", nil)
- if err != nil {
- if !strings.Contains(err.Error(), "leveldb: manifest corrupted") {
- return nil, fmt.Errorf("NewStore(): in create IStoreDisk, err=\n\t%w", err)
- }
- db, err = leveldb.RecoverFile("./stor/db", nil)
- if err != nil {
- return nil, fmt.Errorf("NewStore(): in recovery DB, err=\n\t%w", err)
- }
- }
- sf := &Store{
- serv: serv,
- db: db,
- }
- sf.serv.Wg().Add(1)
- sf.isWork = true
- go sf.close()
- return sf, nil
- }
- // Проверка на нерабочую схему
- func (sf *Store) isClosed() bool {
- sf.block.RLock()
- defer sf.block.RUnlock()
- return !sf.isWork
- }
- // Put -- размещает в хранилище ключ и значение
- func (sf *Store) Put(key string, val []byte) error {
- if sf.isClosed() {
- return fmt.Errorf("Store.Put(): store is closed")
- }
- if key == "" {
- return fmt.Errorf("Store.Put(): key is empty")
- }
- err := sf.db.Put([]byte(key), val, nil)
- if err != nil {
- return fmt.Errorf("Store.Put(): key=%q\terr=\n\t%w", key, err)
- }
- return nil
- }
- // Get -- возвращает значение ключа
- func (sf *Store) Get(key string) ([]byte, error) {
- if sf.isClosed() {
- return nil, fmt.Errorf("Store.Get(): store is closed")
- }
- val, err := sf.db.Get([]byte(key), nil)
- if err != nil {
- return nil, fmt.Errorf("Store.Get(): key=%q\terr=\n\t%w", key, err)
- }
- return val, nil
- }
- // Find -- ищет ключи по префиксу
- func (sf *Store) Find(prefixKey string) ([]string, error) {
- if sf.isClosed() {
- return nil, fmt.Errorf("Store.Find(): store is closed")
- }
- lstKey := []string{}
- iter := sf.db.NewIterator(util.BytesPrefix([]byte(prefixKey)), nil)
- for iter.Next() {
- key := iter.Key()
- lstKey = append(lstKey, string(key))
- }
- iter.Release()
- err := iter.Error()
- if err != nil {
- return nil, fmt.Errorf("Store.Find(): preefixKey=%q\terr=\n\t%w", prefixKey, err)
- }
- return lstKey, nil
- }
- // Del -- удаление ключа из базы
- func (sf *Store) Del(key string) error {
- if sf.isClosed() {
- return fmt.Errorf("Store.Del(): store is closed")
- }
- err := sf.db.Delete([]byte(key), nil)
- if err != nil {
- return fmt.Errorf("Store.Del(): key=%q\terr=\n\t%w", key, err)
- }
- return nil
- }
- // Ожидание закрытия приложения
- func (sf *Store) close() {
- <-sf.serv.Ctx().Done()
- sf.block.Lock()
- defer sf.block.Unlock()
- if !sf.isWork {
- return
- }
- sf.isWork = false
- err := sf.db.Close()
- if err != nil {
- log.Printf("Store.close(): err=\n\t%v\n", err)
- }
- sf.serv.Wg().Done()
- }
|