Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
lancet
/
kvcache
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
0060028b
authored
Aug 26, 2019
by
lancet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
some text and cleanups
parent
a4de484c
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
45 additions
and
3 deletions
+45
-3
main.go
+42
-0
vault/control.go
+3
-3
No files found.
main.go
View file @
0060028b
...
@@ -35,6 +35,48 @@ package main
...
@@ -35,6 +35,48 @@ package main
curl -X DELETE http://localhost:8881/storage/mykey
curl -X DELETE http://localhost:8881/storage/mykey
удалит ключ "mykey" и вернёт код 200 с текстом "OK", либо вернёт код 400
удалит ключ "mykey" и вернёт код 200 с текстом "OK", либо вернёт код 400
с текстом "FAILURE", если такого ключа в хранилище нет.
с текстом "FAILURE", если такого ключа в хранилище нет.
Механика хранилища.
Хранилище организовано в виде связанного списка, работающего в качестве очереди.
Для ускорения выборки существует ассоциативный массив (map), со ссылками по
ключам на узлы данных с соответсвующими значениями (оверхед, но выигрыш в
скорости тем больше, чем больше записей в хранилище).
Узлы бывают двух типов: узел данных и "филлер".
Механизм устаревания последовательно извлекает узлы из головы очереди.
Если извлечён узел данных - то он отбрасывается в связи с устареванием.
Если извлечён "филлер", то механизм устаревания "засыпает" на секунду.
Каждую секунду в хвост очереди автоматически добавляется новый филлер.
При создании новой записи создаётся узел данных и добавляется в хвост очереди.
При обновлении существующей записи, её узел данных уничтожается и
создаётся заново в хвосте очереди (эффективней было бы просто править
ссылки, но это усложняет и запутывает код, при том, что не требуется в
данной задаче).
Таким образом, из хранилища каждую секунду удаляются записи, устаревшие на
данный момент.
Для синхронизации доступа использованы небуферизованные каналы, поэтому с
собственно хранилищем в каждый момент времени работает не более одной
процедуры, все операции с данными строго последовательные, конкурентный
доступ исключён.
Есть интересная потенциальная проблема, связанная с тем, что добавление
"филлеров" и их потребление механизмом устаревания могут происходить с
разной скоростью, что приведёт либо к постепенному неконтролируемому
нарастанию числа "филлеров", либо наоборот, к их исчерпанию и
преждевременному устареванию узлов данных.
Эта потенциальная проблема решается дополнительным механизмом контроля,
который я не стал включать в данную реализацию, поскольку указанная
проблема может возникнуть только через достаточно большое время,
заведомо превосходящее время демонстрации данного приложения.
*/
*/
import
(
import
(
...
...
vault/control.go
View file @
0060028b
...
@@ -18,10 +18,13 @@ func (store *Store) Init(ttl uint64) error {
...
@@ -18,10 +18,13 @@ func (store *Store) Init(ttl uint64) error {
store
.
Exchange
=
make
(
chan
Message
)
store
.
Exchange
=
make
(
chan
Message
)
store
.
flat
=
make
(
map
[
string
]
*
node
)
store
.
flat
=
make
(
map
[
string
]
*
node
)
// Создаём достаточное количество узлов-филлеров, чтобы механизм
// устаревания не начал уничтожать записи преждевременно.
var
i
uint64
var
i
uint64
for
i
=
0
;
i
<
ttl
;
i
++
{
for
i
=
0
;
i
<
ttl
;
i
++
{
store
.
addNode
(
""
,
""
,
false
)
store
.
addNode
(
""
,
""
,
false
)
}
}
go
store
.
control
()
// запускаем управление хранилищем
go
store
.
control
()
// запускаем управление хранилищем
go
store
.
cleaner
()
// запускаем устаревание записей
go
store
.
cleaner
()
// запускаем устаревание записей
return
nil
return
nil
...
@@ -35,7 +38,6 @@ func (store *Store) cleaner() {
...
@@ -35,7 +38,6 @@ func (store *Store) cleaner() {
store
.
Exchange
<-
msg
store
.
Exchange
<-
msg
got
:=
<-
reply
got
:=
<-
reply
if
got
.
Error
==
true
{
if
got
.
Error
==
true
{
//fmt.Print("Cleaner sleeps.\n")
time
.
Sleep
(
1
*
time
.
Second
)
time
.
Sleep
(
1
*
time
.
Second
)
}
}
}
}
...
@@ -47,10 +49,8 @@ func (store *Store) control() {
...
@@ -47,10 +49,8 @@ func (store *Store) control() {
for
{
for
{
select
{
select
{
case
<-
tick
:
case
<-
tick
:
//fmt.Print("Got time tick\n")
store
.
addNode
(
""
,
""
,
false
)
store
.
addNode
(
""
,
""
,
false
)
case
request
:=
<-
store
.
Exchange
:
case
request
:=
<-
store
.
Exchange
:
//fmt.Print("Got request: ", request.Action, "\n")
reply
:=
Message
{}
reply
:=
Message
{}
switch
request
.
Action
{
switch
request
.
Action
{
case
"POP"
:
// внутренний метод, часть механизма устаревания. Недоступен клиентам.
case
"POP"
:
// внутренний метод, часть механизма устаревания. Недоступен клиентам.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment