2013-09-29 03:26:19 +04:00
|
|
|
package store
|
2013-09-03 22:30:42 +04:00
|
|
|
|
|
|
|
import (
|
2013-09-09 02:46:16 +04:00
|
|
|
"fmt"
|
2013-09-03 22:30:42 +04:00
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"time"
|
2013-09-14 01:10:40 +04:00
|
|
|
|
2013-09-29 03:26:19 +04:00
|
|
|
etcdErr "github.com/coreos/etcd/error"
|
2013-09-03 22:30:42 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2013-09-05 23:38:22 +04:00
|
|
|
Get = "get"
|
2013-09-07 16:54:58 +04:00
|
|
|
Create = "create"
|
|
|
|
Update = "update"
|
2013-09-05 23:38:22 +04:00
|
|
|
Delete = "delete"
|
|
|
|
TestAndSet = "testAndSet"
|
2013-09-30 09:06:18 +04:00
|
|
|
Expire = "expire"
|
2013-10-01 06:10:40 +04:00
|
|
|
UndefIndex = 0
|
|
|
|
UndefTerm = 0
|
2013-09-03 22:30:42 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
type Event struct {
|
2013-09-04 05:27:46 +04:00
|
|
|
Action string `json:"action"`
|
|
|
|
Key string `json:"key, omitempty"`
|
|
|
|
Dir bool `json:"dir,omitempty"`
|
|
|
|
PrevValue string `json:"prevValue,omitempty"`
|
|
|
|
Value string `json:"value,omitempty"`
|
2013-09-04 07:10:33 +04:00
|
|
|
KVPairs []KeyValuePair `json:"kvs,omitempty"`
|
2013-09-04 05:27:46 +04:00
|
|
|
Expiration *time.Time `json:"expiration,omitempty"`
|
|
|
|
TTL int64 `json:"ttl,omitempty"` // Time to live in second
|
2013-09-03 22:30:42 +04:00
|
|
|
// The command index of the raft machine when the command is executed
|
|
|
|
Index uint64 `json:"index"`
|
|
|
|
Term uint64 `json:"term"`
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:27:46 +04:00
|
|
|
// When user list a directory, we add all the node into key-value pair slice
|
|
|
|
type KeyValuePair struct {
|
2013-09-04 07:10:33 +04:00
|
|
|
Key string `json:"key, omitempty"`
|
|
|
|
Value string `json:"value,omitempty"`
|
|
|
|
Dir bool `json:"dir,omitempty"`
|
|
|
|
KVPairs []KeyValuePair `json:"kvs,omitempty"`
|
2013-09-04 05:27:46 +04:00
|
|
|
}
|
|
|
|
|
2013-09-09 07:13:28 +04:00
|
|
|
// interfaces for sorting
|
|
|
|
func (k KeyValuePair) Len() int {
|
|
|
|
return len(k.KVPairs)
|
2013-09-09 05:14:31 +04:00
|
|
|
}
|
|
|
|
|
2013-09-09 07:13:28 +04:00
|
|
|
func (k KeyValuePair) Less(i, j int) bool {
|
|
|
|
return k.KVPairs[i].Key < k.KVPairs[j].Key
|
2013-09-09 05:14:31 +04:00
|
|
|
}
|
|
|
|
|
2013-09-09 07:13:28 +04:00
|
|
|
func (k KeyValuePair) Swap(i, j int) {
|
|
|
|
k.KVPairs[i], k.KVPairs[j] = k.KVPairs[j], k.KVPairs[i]
|
2013-09-09 05:14:31 +04:00
|
|
|
}
|
|
|
|
|
2013-09-03 22:30:42 +04:00
|
|
|
func newEvent(action string, key string, index uint64, term uint64) *Event {
|
|
|
|
return &Event{
|
|
|
|
Action: action,
|
|
|
|
Key: key,
|
|
|
|
Index: index,
|
|
|
|
Term: term,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type eventQueue struct {
|
2013-09-14 01:10:40 +04:00
|
|
|
Events []*Event
|
|
|
|
Size int
|
|
|
|
Front int
|
|
|
|
Capacity int
|
2013-09-03 22:30:42 +04:00
|
|
|
}
|
|
|
|
|
2013-09-08 17:55:54 +04:00
|
|
|
func (eq *eventQueue) back() int {
|
2013-09-14 01:10:40 +04:00
|
|
|
return (eq.Front + eq.Size - 1 + eq.Capacity) % eq.Capacity
|
2013-09-08 17:55:54 +04:00
|
|
|
}
|
|
|
|
|
2013-09-05 07:36:14 +04:00
|
|
|
func (eq *eventQueue) insert(e *Event) {
|
2013-09-14 01:10:40 +04:00
|
|
|
index := (eq.back() + 1) % eq.Capacity
|
2013-09-08 17:55:54 +04:00
|
|
|
|
2013-09-14 01:10:40 +04:00
|
|
|
eq.Events[index] = e
|
2013-09-03 22:30:42 +04:00
|
|
|
|
2013-09-14 01:10:40 +04:00
|
|
|
if eq.Size == eq.Capacity { //dequeue
|
|
|
|
eq.Front = (index + 1) % eq.Capacity
|
2013-09-03 22:30:42 +04:00
|
|
|
} else {
|
2013-09-14 01:10:40 +04:00
|
|
|
eq.Size++
|
2013-09-03 22:30:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
type EventHistory struct {
|
|
|
|
Queue eventQueue
|
|
|
|
StartIndex uint64
|
2013-09-30 20:18:28 +04:00
|
|
|
LastIndex uint64
|
|
|
|
LastTerm uint64
|
2013-10-01 08:35:44 +04:00
|
|
|
DupCnt uint64 // help to compute the watching point with duplicated indexes in the queue
|
2013-09-03 22:30:42 +04:00
|
|
|
rwl sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func newEventHistory(capacity int) *EventHistory {
|
|
|
|
return &EventHistory{
|
|
|
|
Queue: eventQueue{
|
2013-09-14 01:10:40 +04:00
|
|
|
Capacity: capacity,
|
|
|
|
Events: make([]*Event, capacity),
|
2013-09-03 22:30:42 +04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// addEvent function adds event into the eventHistory
|
2013-09-30 20:18:28 +04:00
|
|
|
func (eh *EventHistory) addEvent(e *Event) *Event {
|
2013-09-03 22:30:42 +04:00
|
|
|
eh.rwl.Lock()
|
|
|
|
defer eh.rwl.Unlock()
|
|
|
|
|
2013-10-01 09:25:45 +04:00
|
|
|
var duped uint64
|
2013-10-01 06:10:40 +04:00
|
|
|
|
|
|
|
if e.Index == UndefIndex {
|
2013-09-30 20:18:28 +04:00
|
|
|
e.Index = eh.LastIndex
|
2013-10-01 08:35:44 +04:00
|
|
|
duped = 1
|
2013-09-30 20:18:28 +04:00
|
|
|
}
|
|
|
|
|
2013-10-01 06:10:40 +04:00
|
|
|
if e.Term == UndefTerm {
|
2013-09-30 20:18:28 +04:00
|
|
|
e.Term = eh.LastTerm
|
2013-10-01 08:35:44 +04:00
|
|
|
duped = 1
|
2013-09-30 20:18:28 +04:00
|
|
|
}
|
|
|
|
|
2013-09-05 07:36:14 +04:00
|
|
|
eh.Queue.insert(e)
|
|
|
|
|
2013-09-14 01:10:40 +04:00
|
|
|
eh.StartIndex = eh.Queue.Events[eh.Queue.Front].Index
|
2013-09-30 20:18:28 +04:00
|
|
|
|
|
|
|
eh.LastIndex = e.Index
|
|
|
|
eh.LastTerm = e.Term
|
2013-10-01 08:35:44 +04:00
|
|
|
eh.DupCnt += duped
|
2013-09-30 20:18:28 +04:00
|
|
|
|
|
|
|
return e
|
2013-09-03 22:30:42 +04:00
|
|
|
}
|
|
|
|
|
2013-09-08 17:55:54 +04:00
|
|
|
// scan function is enumerating events from the index in history and
|
|
|
|
// stops till the first point where the key has identified prefix
|
2013-09-03 22:30:42 +04:00
|
|
|
func (eh *EventHistory) scan(prefix string, index uint64) (*Event, error) {
|
|
|
|
eh.rwl.RLock()
|
|
|
|
defer eh.rwl.RUnlock()
|
|
|
|
|
2013-10-01 10:51:47 +04:00
|
|
|
start := index - eh.StartIndex
|
2013-09-03 22:30:42 +04:00
|
|
|
|
2013-09-08 17:55:54 +04:00
|
|
|
// the index should locate after the event history's StartIndex
|
|
|
|
if start < 0 {
|
2013-09-09 02:46:16 +04:00
|
|
|
return nil,
|
|
|
|
etcdErr.NewError(etcdErr.EcodeEventIndexCleared,
|
2013-10-01 10:51:47 +04:00
|
|
|
fmt.Sprintf("the requested history has been cleared [%v/%v]",
|
|
|
|
eh.StartIndex, index))
|
2013-09-03 22:30:42 +04:00
|
|
|
}
|
|
|
|
|
2013-10-01 10:51:47 +04:00
|
|
|
// the index should locate before the size of the queue minus the duplicate count
|
|
|
|
if start >= (uint64(eh.Queue.Size) - eh.DupCnt) { // future index
|
2013-09-03 22:30:42 +04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2013-09-14 01:10:40 +04:00
|
|
|
i := int((start + uint64(eh.Queue.Front)) % uint64(eh.Queue.Capacity))
|
2013-09-03 22:30:42 +04:00
|
|
|
|
|
|
|
for {
|
2013-09-14 01:10:40 +04:00
|
|
|
e := eh.Queue.Events[i]
|
2013-10-01 10:51:47 +04:00
|
|
|
if strings.HasPrefix(e.Key, prefix) && index <= e.Index { // make sure we bypass the smaller one
|
2013-09-03 22:30:42 +04:00
|
|
|
return e, nil
|
|
|
|
}
|
|
|
|
|
2013-09-14 01:10:40 +04:00
|
|
|
i = (i + 1) % eh.Queue.Capacity
|
2013-09-03 22:30:42 +04:00
|
|
|
|
2013-10-01 10:51:47 +04:00
|
|
|
if i == eh.Queue.back() { // find nothing, return and watch from current index
|
2013-09-03 22:30:42 +04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-29 04:41:02 +04:00
|
|
|
|
|
|
|
// clone will be protected by a stop-world lock
|
|
|
|
// do not need to obtain internal lock
|
|
|
|
func (eh *EventHistory) clone() *EventHistory {
|
|
|
|
clonedQueue := eventQueue{
|
|
|
|
Capacity: eh.Queue.Capacity,
|
|
|
|
Events: make([]*Event, eh.Queue.Capacity),
|
|
|
|
Size: eh.Queue.Size,
|
|
|
|
Front: eh.Queue.Front,
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, e := range eh.Queue.Events {
|
|
|
|
clonedQueue.Events[i] = e
|
|
|
|
}
|
|
|
|
|
|
|
|
return &EventHistory{
|
|
|
|
StartIndex: eh.StartIndex,
|
|
|
|
Queue: clonedQueue,
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|