Commit 4a2f5db4 by lancet

heavy refactoring of vault, still WIP

parent c68ad926
......@@ -97,8 +97,7 @@ func main() {
flag.Parse()
listenStr := fmt.Sprintf("%s:%d", *hostF, *portF)
router := new(web.Svc)
storage := new(vault.Store)
storage.Init(*ttlF)
storage := vault.Store{30}
routing := []web.Route{
{URL: "/storage/{id}", Methods: []string{"GET"}, Handler: router.GetValue},
{URL: "/storage/{id}/{value}", Methods: []string{"PUT", "POST"}, Handler: router.SetValue},
......
package vault
import (
"errors"
"time"
)
// Init - инициализация хранилища
func (store *Store) Init(ttl uint64) error {
if store.ttl != 0 {
return errors.New("Already up")
}
if ttl < 1 {
return errors.New("Wrong TTL")
}
store.ttl = ttl
store.Exchange = make(chan Message)
store.flat = make(map[string]*node)
// Создаём достаточное количество узлов-филлеров, чтобы механизм
// устаревания не начал уничтожать записи преждевременно.
var i uint64
for i = 0; i < ttl; i++ {
store.addNode("", "", false)
}
go store.control() // запускаем управление хранилищем
go store.cleaner() // запускаем устаревание записей
return nil
}
// cleaner - уничтожаем устаревшие ключи
func (store *Store) cleaner() {
reply := make(chan Message)
for {
msg := Message{Action: "POP", Reply: reply}
store.Exchange <- msg
store.exchange <- msg
got := <-reply
if got.Error == true {
time.Sleep(1 * time.Second)
......@@ -50,14 +24,22 @@ func (store *Store) control() {
select {
case <-tick:
store.addNode("", "", false)
case request := <-store.Exchange:
for {
err := store.popNode()
if err != nil {
break
}
}
case request := <-store.exchange:
reply := Message{}
switch request.Action {
/*
case "POP": // внутренний метод, часть механизма устаревания. Недоступен клиентам.
err := store.popNode()
if err != nil {
reply.Error = true
}
*/
case "SET":
err := store.setNode(request.Key, request.Value)
reply.Key = request.Key
......
......@@ -21,7 +21,9 @@ type node struct {
// Store - корневая структура для хранения данных
type Store struct {
Exchange chan Message // Небуферизованный канал для синхронизации доступа
TTL uint64 // Публично доступный TTL для инициализации
isInit bool // Признак выполненной инициализации
exchange chan Message // Небуферизованный канал для синхронизации доступа
ttl uint64 // Время жизни узла, сек
head *node // Голова, выходит первым
tail *node // Добавлен последним
......
/* Методы, доступные внешним сущностям. */
package vault
import (
"errors"
)
// GetValue - получить значение ключа из хранилища
func (store *Store) GetValue(key string) (string, error) {
reply := make(chan Message)
msg := Message{Action: "GET", Reply: reply, Key: key}
store.exchange <- msg
resp := <-reply
if resp.Error != true {
return resp.Value, nil
}
return "", errors.New("No such key")
}
// SetValue - установить/обновить значение ключа
func (store *Store) SetValue(key, value string) error {
reply := make(chan Message)
msg := Message{Action: "SET", Reply: reply, Key: key, Value: value}
store.exchange <- msg
resp := <-reply
if resp.Error != true {
return nil
}
return errors.New("Cannot set value")
}
// DelValue - удалить ключ из хранилища
func (store *Store) DelValue(key string) error {
reply := make(chan Message)
msg := Message{Action: "DEL", Reply: reply, Key: key}
store.exchange <- msg
resp := <-reply
if resp.Error != true {
return nil
}
return errors.New("There was no such key")
}
......@@ -4,8 +4,37 @@ import (
"errors"
)
// init - инициализация хранилища с заданным TTL
func (store *Store) init() {
if store.isInit == true {
return
}
if store.TTL < 1 {
store.TTL = 30
}
store.ttl = store.TTL
store.exchange = make(chan Message)
store.flat = make(map[string]*node)
// Создаём достаточное количество узлов-филлеров, чтобы механизм
// устаревания не начал уничтожать записи преждевременно.
var i uint64
for i = 0; i < store.ttl; i++ {
store.addNode("", "", false)
}
go store.control() // запускаем управление хранилищем
//go store.cleaner() // запускаем устаревание записей
store.isInit = true
}
// addNode - добавляем новый узел в хвост очереди.
func (store *Store) addNode(key, value string, kind bool) {
func (store *Store) addNode(key, value string, kind bool) error {
if store.isInit == false {
store.init()
}
var prev *node
if store.tail != nil {
prev = store.tail
......@@ -20,12 +49,16 @@ func (store *Store) addNode(key, value string, kind bool) {
if kind == true {
store.flat[key] = store.tail
}
return nil
}
// setNode - собираемся добавить новый узел.
// Если ключа ещё нет - просто добавляем в хвост.
// Если ключ есть - переносим в хвост.
func (store *Store) setNode(key, value string) error {
if store.isInit == false {
store.init()
}
if _, ok := store.flat[key]; ok == false {
store.addNode(key, value, true)
return nil
......@@ -39,6 +72,9 @@ func (store *Store) setNode(key, value string) error {
// Если Kind == 0 - то возвращаем ошибку.
// При ошибке устаревание приостанавливается на секунду.
func (store *Store) popNode() error {
if store.isInit == false {
store.init()
}
var err error
if store.head == nil {
return errors.New("No nodes")
......@@ -58,6 +94,9 @@ func (store *Store) popNode() error {
// getNode - получить значение ключа, или ошибку, если такого нет.
func (store *Store) getNode(key string) (string, error) {
if store.isInit == false {
store.init()
}
if v, ok := store.flat[key]; ok != false {
return v.Value, nil
}
......@@ -67,6 +106,9 @@ func (store *Store) getNode(key string) (string, error) {
// delNode - удалить узел с указанным ключом.
// Если такого ключа не было - вернуть ошибку.
func (store *Store) delNode(key string) error {
if store.isInit == false {
store.init()
}
if _, ok := store.flat[key]; ok == false {
return errors.New("No such key")
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment