// package store -- главный тип плагина хранилища package store import ( "fmt" "sync" "wartank/pkg/components/kernel/logger" "wartank/pkg/components/safe_bool" "wartank/pkg/types" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" ) const ( стрХранилище = "Хранилище" ) // Хранилище -- главный тип плагина хранилища type Хранилище struct { ядро types.ИЯдро genm string // Путь к хранилищу isWork *safe_bool.БезопБул // Признак открытой базы бд *leveldb.DB // Объект хранилища блок sync.Mutex // Блокировка для безопасности потоков лог types.ИЛоггер } // НовХранилище -- возвращает новое хранилище func НовХранилище(ядро types.ИЯдро, путь string) (*Хранилище, error) { лог := logger.НовЛоггер("Хранилище") лог.Инфо("НовХранилище()\n") лог.Проверить(ядро != nil, "НовХранилище(): ИЯдро == nil\n") лог.Проверить(путь != "", "НовХранилище(): путь пустой\n") сам := &Хранилище{ ядро: ядро, genm: путь, isWork: safe_bool.НовБезопБул(), лог: лог, } сам.открыть() if ош := ядро.Wg().Add(стрХранилище); ош != nil { return nil, fmt.Errorf("НовХранилище: при добавлении группы ожидания, ош=\n\t%v", ош) } _ = types.ИХранилище(сам) return сам, nil } // Уст -- добавляет в хранилище значение по ключу func (сам *Хранилище) Уст(ключ string, знач []byte) error { сам.блок.Lock() defer сам.блок.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 *Хранилище) Получ(ключ string) ([]byte, error) { sf.блок.Lock() defer sf.блок.Unlock() value, err := sf.бд.Get([]byte(ключ), 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.блок.Lock() defer sf.блок.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.блок.Lock() defer sf.блок.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 (сам *Хранилище) открыть() { сам.блок.Lock() defer сам.блок.Unlock() бд, ош := leveldb.OpenFile(сам.genm, nil) фнОткрыть := func() { сам.бд = бд сам.isWork.Уст() go сам.закрыть() } if ош == nil { фнОткрыть() return } сам.лог.Внимание("Хранилище.открыть(): при открытии БД, ош=\n\t%v\n", ош) бд, ош = leveldb.RecoverFile(сам.genm, nil) сам.лог.Проверить(ош == nil, "Хранилище.открыть(): при восстановлении БД, ош=\n\t%v\n", ош) фнОткрыть() } // закрыть -- закрывает хранилище по требованию func (сам *Хранилище) закрыть() { <-сам.ядро.Контекст().Done() сам.блок.Lock() defer сам.блок.Unlock() сам.isWork.Сброс() err := сам.бд.Close() сам.лог.Проверить(err == nil, "Хранилище.закрыть(): при закрытии БД, err=\n\t%v\n", err) ош := сам.ядро.Wg().Done(стрХранилище) сам.лог.Проверить(ош == nil, "Хранилище.закрыть(): при удалении группы ожидания, ош=\n\t%v\n", ош) }