Commit 4a2f5db4 by lancet

heavy refactoring of vault, still WIP

parent c68ad926
...@@ -97,8 +97,7 @@ func main() { ...@@ -97,8 +97,7 @@ func main() {
flag.Parse() flag.Parse()
listenStr := fmt.Sprintf("%s:%d", *hostF, *portF) listenStr := fmt.Sprintf("%s:%d", *hostF, *portF)
router := new(web.Svc) router := new(web.Svc)
storage := new(vault.Store) storage := vault.Store{30}
storage.Init(*ttlF)
routing := []web.Route{ routing := []web.Route{
{URL: "/storage/{id}", Methods: []string{"GET"}, Handler: router.GetValue}, {URL: "/storage/{id}", Methods: []string{"GET"}, Handler: router.GetValue},
{URL: "/storage/{id}/{value}", Methods: []string{"PUT", "POST"}, Handler: router.SetValue}, {URL: "/storage/{id}/{value}", Methods: []string{"PUT", "POST"}, Handler: router.SetValue},
......
package vault package vault
import ( import (
"errors"
"time" "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 - уничтожаем устаревшие ключи // cleaner - уничтожаем устаревшие ключи
func (store *Store) cleaner() { func (store *Store) cleaner() {
reply := make(chan Message) reply := make(chan Message)
for { for {
msg := Message{Action: "POP", Reply: reply} msg := Message{Action: "POP", Reply: reply}
store.Exchange <- msg store.exchange <- msg
got := <-reply got := <-reply
if got.Error == true { if got.Error == true {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
...@@ -50,14 +24,22 @@ func (store *Store) control() { ...@@ -50,14 +24,22 @@ func (store *Store) control() {
select { select {
case <-tick: case <-tick:
store.addNode("", "", false) store.addNode("", "", false)
case request := <-store.Exchange: for {
err := store.popNode()
if err != nil {
break
}
}
case request := <-store.exchange:
reply := Message{} reply := Message{}
switch request.Action { switch request.Action {
/*
case "POP": // внутренний метод, часть механизма устаревания. Недоступен клиентам. case "POP": // внутренний метод, часть механизма устаревания. Недоступен клиентам.
err := store.popNode() err := store.popNode()
if err != nil { if err != nil {
reply.Error = true reply.Error = true
} }
*/
case "SET": case "SET":
err := store.setNode(request.Key, request.Value) err := store.setNode(request.Key, request.Value)
reply.Key = request.Key reply.Key = request.Key
......
...@@ -21,7 +21,9 @@ type node struct { ...@@ -21,7 +21,9 @@ type node struct {
// Store - корневая структура для хранения данных // Store - корневая структура для хранения данных
type Store struct { type Store struct {
Exchange chan Message // Небуферизованный канал для синхронизации доступа TTL uint64 // Публично доступный TTL для инициализации
isInit bool // Признак выполненной инициализации
exchange chan Message // Небуферизованный канал для синхронизации доступа
ttl uint64 // Время жизни узла, сек ttl uint64 // Время жизни узла, сек
head *node // Голова, выходит первым head *node // Голова, выходит первым
tail *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 ( ...@@ -4,8 +4,37 @@ import (
"errors" "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 - добавляем новый узел в хвост очереди. // 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 var prev *node
if store.tail != nil { if store.tail != nil {
prev = store.tail prev = store.tail
...@@ -20,12 +49,16 @@ func (store *Store) addNode(key, value string, kind bool) { ...@@ -20,12 +49,16 @@ func (store *Store) addNode(key, value string, kind bool) {
if kind == true { if kind == true {
store.flat[key] = store.tail store.flat[key] = store.tail
} }
return nil
} }
// setNode - собираемся добавить новый узел. // setNode - собираемся добавить новый узел.
// Если ключа ещё нет - просто добавляем в хвост. // Если ключа ещё нет - просто добавляем в хвост.
// Если ключ есть - переносим в хвост. // Если ключ есть - переносим в хвост.
func (store *Store) setNode(key, value string) error { func (store *Store) setNode(key, value string) error {
if store.isInit == false {
store.init()
}
if _, ok := store.flat[key]; ok == false { if _, ok := store.flat[key]; ok == false {
store.addNode(key, value, true) store.addNode(key, value, true)
return nil return nil
...@@ -39,6 +72,9 @@ func (store *Store) setNode(key, value string) error { ...@@ -39,6 +72,9 @@ func (store *Store) setNode(key, value string) error {
// Если Kind == 0 - то возвращаем ошибку. // Если Kind == 0 - то возвращаем ошибку.
// При ошибке устаревание приостанавливается на секунду. // При ошибке устаревание приостанавливается на секунду.
func (store *Store) popNode() error { func (store *Store) popNode() error {
if store.isInit == false {
store.init()
}
var err error var err error
if store.head == nil { if store.head == nil {
return errors.New("No nodes") return errors.New("No nodes")
...@@ -58,6 +94,9 @@ func (store *Store) popNode() error { ...@@ -58,6 +94,9 @@ func (store *Store) popNode() error {
// getNode - получить значение ключа, или ошибку, если такого нет. // getNode - получить значение ключа, или ошибку, если такого нет.
func (store *Store) getNode(key string) (string, error) { func (store *Store) getNode(key string) (string, error) {
if store.isInit == false {
store.init()
}
if v, ok := store.flat[key]; ok != false { if v, ok := store.flat[key]; ok != false {
return v.Value, nil return v.Value, nil
} }
...@@ -67,6 +106,9 @@ func (store *Store) getNode(key string) (string, error) { ...@@ -67,6 +106,9 @@ func (store *Store) getNode(key string) (string, error) {
// delNode - удалить узел с указанным ключом. // delNode - удалить узел с указанным ключом.
// Если такого ключа не было - вернуть ошибку. // Если такого ключа не было - вернуть ошибку.
func (store *Store) delNode(key string) error { func (store *Store) delNode(key string) error {
if store.isInit == false {
store.init()
}
if _, ok := store.flat[key]; ok == false { if _, ok := store.flat[key]; ok == false {
return errors.New("No such key") 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