github.com/jpetazzo/etcd@v0.2.1-0.20140113055439-97f1363afac5/store/event_history.go (about) 1 package store 2 3 import ( 4 "fmt" 5 "path" 6 "strings" 7 "sync" 8 9 etcdErr "github.com/coreos/etcd/error" 10 ) 11 12 type EventHistory struct { 13 Queue eventQueue 14 StartIndex uint64 15 LastIndex uint64 16 rwl sync.RWMutex 17 } 18 19 func newEventHistory(capacity int) *EventHistory { 20 return &EventHistory{ 21 Queue: eventQueue{ 22 Capacity: capacity, 23 Events: make([]*Event, capacity), 24 }, 25 } 26 } 27 28 // addEvent function adds event into the eventHistory 29 func (eh *EventHistory) addEvent(e *Event) *Event { 30 eh.rwl.Lock() 31 defer eh.rwl.Unlock() 32 33 eh.Queue.insert(e) 34 35 eh.LastIndex = e.Index() 36 37 eh.StartIndex = eh.Queue.Events[eh.Queue.Front].Index() 38 39 return e 40 } 41 42 // scan enumerates events from the index history and stops at the first point 43 // where the key matches. 44 func (eh *EventHistory) scan(key string, recursive bool, index uint64) (*Event, *etcdErr.Error) { 45 eh.rwl.RLock() 46 defer eh.rwl.RUnlock() 47 48 // index should be after the event history's StartIndex 49 if index < eh.StartIndex { 50 return nil, 51 etcdErr.NewError(etcdErr.EcodeEventIndexCleared, 52 fmt.Sprintf("the requested history has been cleared [%v/%v]", 53 eh.StartIndex, index), 0) 54 } 55 56 // the index should come before the size of the queue minus the duplicate count 57 if index > eh.LastIndex { // future index 58 return nil, nil 59 } 60 61 offset := index - eh.StartIndex 62 i := (eh.Queue.Front + int(offset)) % eh.Queue.Capacity 63 64 for { 65 e := eh.Queue.Events[i] 66 67 ok := (e.Node.Key == key) 68 69 if recursive { 70 // add tailing slash 71 key := path.Clean(key) 72 if key[len(key)-1] != '/' { 73 key = key + "/" 74 } 75 76 ok = ok || strings.HasPrefix(e.Node.Key, key) 77 } 78 79 if ok { 80 return e, nil 81 } 82 83 i = (i + 1) % eh.Queue.Capacity 84 85 if i == eh.Queue.Back { 86 return nil, nil 87 } 88 } 89 } 90 91 // clone will be protected by a stop-world lock 92 // do not need to obtain internal lock 93 func (eh *EventHistory) clone() *EventHistory { 94 clonedQueue := eventQueue{ 95 Capacity: eh.Queue.Capacity, 96 Events: make([]*Event, eh.Queue.Capacity), 97 Size: eh.Queue.Size, 98 Front: eh.Queue.Front, 99 Back: eh.Queue.Back, 100 } 101 102 for i, e := range eh.Queue.Events { 103 clonedQueue.Events[i] = e 104 } 105 106 return &EventHistory{ 107 StartIndex: eh.StartIndex, 108 Queue: clonedQueue, 109 LastIndex: eh.LastIndex, 110 } 111 112 }