1 module neton.store.EventHistory;
2 
3 import neton.store.Event;
4 import neton.store.EventQueue;
5 import core.sync.mutex;
6 import hunt.logging;
7 import std.algorithm.searching;
8 
9 class EventHistory {
10     Mutex _mtx;
11 	EventQueue _queue;
12 	ulong      _startIndex ;
13 	ulong      _lastIndex ;
14 
15 
16     this(int capacity)
17     {
18         _mtx = new Mutex;
19         _queue = new EventQueue(capacity);
20     }
21 
22 
23     // addEvent function adds event into the eventHistory
24     Event addEvent(Event e) {
25         synchronized( _mtx )
26         {
27             _queue.insert(e);
28             _lastIndex = e.Index();
29 
30             _startIndex = _queue.getIndex(_queue.front());
31         }
32         
33         return e;
34     }
35 
36 
37     // scan enumerates events from the index history and stops at the first point
38     // where the key matches.
39     Event scan(string key, bool recursive,ulong index)  {
40         logInfo("scan key from eventHistory : ",key,"  index :",index," histiry lastindex :",_lastIndex);
41         synchronized( _mtx )
42         {
43              // index should be after the event history's StartIndex
44             if (index < _startIndex ){
45                 logError("the requested history has been cleared");
46                 return null;
47             }
48 
49             // the index should come before the size of the queue minus the duplicate count
50             if (index > _lastIndex) { // future index
51                 return null;
52             }
53 
54             auto offset = index - _startIndex;
55             auto i = (_queue.front() + cast(int)(offset)) % _queue.capacity();
56 
57             while(1) {
58                 auto e = _queue.event(i);
59                  logInfo("compare event from eventHistory : ",e.node().key);
60                 if (!e.refresh) {
61                     auto ok = (e.node().key == key);
62 
63                     if (recursive) {
64                         // add tailing slash
65                         auto nkey = key;
66                         if (nkey[nkey.length-1] != '/') {
67                             nkey = nkey ~ "/";
68                         }
69 
70                         ok = ok || startsWith(e.node().key, nkey);
71                     }
72 
73                     if ((e.action == EventAction.Delete || e.action == EventAction.Expire) && e.prevNode() !is null && e.prevNode().dir()) {
74                         ok = ok || startsWith(key, e.prevNode().key);
75                     }
76 
77                     if (ok ){
78                         logInfo("find event from eventHistory : ",key);
79                         return e ;
80                     }
81                 }
82 
83                 i = (i + 1) % _queue.capacity;
84 
85                 if (i == _queue.back) {
86                     logInfo("not find event from eventHistory : ",key);
87                     return null;
88                 }
89             }      
90         }
91        // return null;
92     }
93 
94 }
95 
96 
97