github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/utils/dbutil/autocompact/compacter.go (about) 1 package autocompact 2 3 import ( 4 "bytes" 5 "errors" 6 7 "github.com/unicornultrafoundation/go-u2u/common" 8 ) 9 10 type ContainerI interface { 11 Add(key []byte, size uint64) 12 Merge(c ContainerI) 13 Error() error 14 Reset() 15 Size() uint64 16 Ranges() []Range 17 } 18 19 type Range struct { 20 minKey []byte 21 maxKey []byte 22 } 23 24 // MonotonicContainer implements tracking of compaction ranges in cases when keys are inserted as series of monotonic ranges 25 type MonotonicContainer struct { 26 forward bool 27 ranges []Range 28 size uint64 29 err error 30 } 31 32 type DevnullContainer struct{} 33 34 func (d DevnullContainer) Add(key []byte, size uint64) {} 35 36 func (d DevnullContainer) Merge(c ContainerI) {} 37 38 func (d DevnullContainer) Error() error { 39 return nil 40 } 41 42 func (d DevnullContainer) Reset() { 43 44 } 45 46 func (d DevnullContainer) Size() uint64 { 47 return 0 48 } 49 50 func (d DevnullContainer) Ranges() []Range { 51 return []Range{} 52 } 53 54 func NewForwardCont() ContainerI { 55 return &MonotonicContainer{ 56 forward: true, 57 } 58 } 59 60 func NewBackwardsCont() ContainerI { 61 return &MonotonicContainer{ 62 forward: false, 63 } 64 } 65 66 func NewDevnullCont() ContainerI { 67 return DevnullContainer{} 68 } 69 70 func (m *MonotonicContainer) addRange(key []byte) { 71 m.ranges = append(m.ranges, Range{ 72 minKey: common.CopyBytes(key), 73 maxKey: common.CopyBytes(key), 74 }) 75 } 76 77 func (m *MonotonicContainer) Add(key []byte, size uint64) { 78 m.size += size 79 if len(m.ranges) == 0 { 80 m.addRange(key) 81 } 82 // extend the last range if it's a monotonic addition or start new range otherwise 83 l := len(m.ranges) - 1 84 if m.forward { 85 if bytes.Compare(key, m.ranges[l].maxKey) >= 0 { 86 m.ranges[l].maxKey = common.CopyBytes(key) 87 } else { 88 m.addRange(key) 89 } 90 } else { 91 if bytes.Compare(key, m.ranges[l].minKey) <= 0 { 92 m.ranges[l].minKey = common.CopyBytes(key) 93 } else { 94 m.addRange(key) 95 } 96 } 97 } 98 99 func (m *MonotonicContainer) Merge(c ContainerI) { 100 if err := c.Error(); err != nil { 101 m.err = err 102 } 103 104 for _, r := range c.Ranges() { 105 if m.forward { 106 m.Add(r.minKey, 0) 107 m.Add(r.maxKey, 0) 108 } else { 109 m.Add(r.maxKey, 0) 110 m.Add(r.minKey, 0) 111 } 112 } 113 m.size += c.Size() 114 } 115 116 func (m *MonotonicContainer) Error() error { 117 if m.err != nil { 118 return m.err 119 } 120 if len(m.ranges) > 2 { 121 return errors.New("too many compaction ranges, it's likely that dataset isn't monotonic enough") 122 } 123 return nil 124 } 125 126 func (m *MonotonicContainer) Reset() { 127 m.ranges = nil 128 m.size = 0 129 } 130 131 func (m *MonotonicContainer) Size() uint64 { 132 return m.size 133 } 134 135 func (m *MonotonicContainer) Ranges() []Range { 136 return m.ranges 137 }