index.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package storage
  2. import (
  3. "log"
  4. "sync"
  5. "github.com/coreos/etcd/Godeps/_workspace/src/github.com/google/btree"
  6. )
  7. type index interface {
  8. Get(key []byte, atIndex uint64) (index uint64, err error)
  9. Put(key []byte, index uint64)
  10. Tombstone(key []byte, index uint64) error
  11. Compact(index uint64) map[uint64]struct{}
  12. }
  13. type treeIndex struct {
  14. sync.RWMutex
  15. tree *btree.BTree
  16. }
  17. func newTreeIndex() index {
  18. return &treeIndex{
  19. tree: btree.New(32),
  20. }
  21. }
  22. func (ti *treeIndex) Put(key []byte, index uint64) {
  23. keyi := &keyIndex{key: key}
  24. ti.Lock()
  25. defer ti.Unlock()
  26. item := ti.tree.Get(keyi)
  27. if item == nil {
  28. keyi.put(index)
  29. ti.tree.ReplaceOrInsert(keyi)
  30. return
  31. }
  32. okeyi := item.(*keyIndex)
  33. okeyi.put(index)
  34. }
  35. func (ti *treeIndex) Get(key []byte, atIndex uint64) (index uint64, err error) {
  36. keyi := &keyIndex{key: key}
  37. ti.RLock()
  38. defer ti.RUnlock()
  39. item := ti.tree.Get(keyi)
  40. if item == nil {
  41. return 0, ErrIndexNotFound
  42. }
  43. keyi = item.(*keyIndex)
  44. return keyi.get(atIndex)
  45. }
  46. func (ti *treeIndex) Tombstone(key []byte, index uint64) error {
  47. keyi := &keyIndex{key: key}
  48. ti.Lock()
  49. defer ti.Unlock()
  50. item := ti.tree.Get(keyi)
  51. if item == nil {
  52. return ErrIndexNotFound
  53. }
  54. ki := item.(*keyIndex)
  55. ki.tombstone(index)
  56. return nil
  57. }
  58. func (ti *treeIndex) Compact(index uint64) map[uint64]struct{} {
  59. available := make(map[uint64]struct{})
  60. emptyki := make([]*keyIndex, 0)
  61. log.Printf("store.index: compact %d", index)
  62. // TODO: do not hold the lock for long time?
  63. // This is probably OK. Compacting 10M keys takes O(10ms).
  64. ti.Lock()
  65. defer ti.Unlock()
  66. ti.tree.Ascend(compactIndex(index, available, &emptyki))
  67. for _, ki := range emptyki {
  68. item := ti.tree.Delete(ki)
  69. if item == nil {
  70. log.Panic("store.index: unexpected delete failure during compaction")
  71. }
  72. }
  73. return available
  74. }
  75. func compactIndex(index uint64, available map[uint64]struct{}, emptyki *[]*keyIndex) func(i btree.Item) bool {
  76. return func(i btree.Item) bool {
  77. keyi := i.(*keyIndex)
  78. keyi.compact(index, available)
  79. if keyi.isEmpty() {
  80. *emptyki = append(*emptyki, keyi)
  81. }
  82. return true
  83. }
  84. }