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  }