go.etcd.io/etcd@v3.3.27+incompatible/mvcc/backend/tx_buffer.go (about) 1 // Copyright 2017 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package backend 16 17 import ( 18 "bytes" 19 "sort" 20 ) 21 22 // txBuffer handles functionality shared between txWriteBuffer and txReadBuffer. 23 type txBuffer struct { 24 buckets map[string]*bucketBuffer 25 } 26 27 func (txb *txBuffer) reset() { 28 for k, v := range txb.buckets { 29 if v.used == 0 { 30 // demote 31 delete(txb.buckets, k) 32 } 33 v.used = 0 34 } 35 } 36 37 // txWriteBuffer buffers writes of pending updates that have not yet committed. 38 type txWriteBuffer struct { 39 txBuffer 40 seq bool 41 } 42 43 func (txw *txWriteBuffer) put(bucket, k, v []byte) { 44 txw.seq = false 45 txw.putSeq(bucket, k, v) 46 } 47 48 func (txw *txWriteBuffer) putSeq(bucket, k, v []byte) { 49 b, ok := txw.buckets[string(bucket)] 50 if !ok { 51 b = newBucketBuffer() 52 txw.buckets[string(bucket)] = b 53 } 54 b.add(k, v) 55 } 56 57 func (txw *txWriteBuffer) writeback(txr *txReadBuffer) { 58 for k, wb := range txw.buckets { 59 rb, ok := txr.buckets[k] 60 if !ok { 61 delete(txw.buckets, k) 62 txr.buckets[k] = wb 63 continue 64 } 65 if !txw.seq && wb.used > 1 { 66 // assume no duplicate keys 67 sort.Sort(wb) 68 } 69 rb.merge(wb) 70 } 71 txw.reset() 72 } 73 74 // txReadBuffer accesses buffered updates. 75 type txReadBuffer struct{ txBuffer } 76 77 func (txr *txReadBuffer) Range(bucketName, key, endKey []byte, limit int64) ([][]byte, [][]byte) { 78 if b := txr.buckets[string(bucketName)]; b != nil { 79 return b.Range(key, endKey, limit) 80 } 81 return nil, nil 82 } 83 84 func (txr *txReadBuffer) ForEach(bucketName []byte, visitor func(k, v []byte) error) error { 85 if b := txr.buckets[string(bucketName)]; b != nil { 86 return b.ForEach(visitor) 87 } 88 return nil 89 } 90 91 type kv struct { 92 key []byte 93 val []byte 94 } 95 96 // bucketBuffer buffers key-value pairs that are pending commit. 97 type bucketBuffer struct { 98 buf []kv 99 // used tracks number of elements in use so buf can be reused without reallocation. 100 used int 101 } 102 103 func newBucketBuffer() *bucketBuffer { 104 return &bucketBuffer{buf: make([]kv, 512), used: 0} 105 } 106 107 func (bb *bucketBuffer) Range(key, endKey []byte, limit int64) (keys [][]byte, vals [][]byte) { 108 f := func(i int) bool { return bytes.Compare(bb.buf[i].key, key) >= 0 } 109 idx := sort.Search(bb.used, f) 110 if idx < 0 { 111 return nil, nil 112 } 113 if len(endKey) == 0 { 114 if bytes.Equal(key, bb.buf[idx].key) { 115 keys = append(keys, bb.buf[idx].key) 116 vals = append(vals, bb.buf[idx].val) 117 } 118 return keys, vals 119 } 120 if bytes.Compare(endKey, bb.buf[idx].key) <= 0 { 121 return nil, nil 122 } 123 for i := idx; i < bb.used && int64(len(keys)) < limit; i++ { 124 if bytes.Compare(endKey, bb.buf[i].key) <= 0 { 125 break 126 } 127 keys = append(keys, bb.buf[i].key) 128 vals = append(vals, bb.buf[i].val) 129 } 130 return keys, vals 131 } 132 133 func (bb *bucketBuffer) ForEach(visitor func(k, v []byte) error) error { 134 for i := 0; i < bb.used; i++ { 135 if err := visitor(bb.buf[i].key, bb.buf[i].val); err != nil { 136 return err 137 } 138 } 139 return nil 140 } 141 142 func (bb *bucketBuffer) add(k, v []byte) { 143 bb.buf[bb.used].key, bb.buf[bb.used].val = k, v 144 bb.used++ 145 if bb.used == len(bb.buf) { 146 buf := make([]kv, (3*len(bb.buf))/2) 147 copy(buf, bb.buf) 148 bb.buf = buf 149 } 150 } 151 152 // merge merges data from bb into bbsrc. 153 func (bb *bucketBuffer) merge(bbsrc *bucketBuffer) { 154 for i := 0; i < bbsrc.used; i++ { 155 bb.add(bbsrc.buf[i].key, bbsrc.buf[i].val) 156 } 157 if bb.used == bbsrc.used { 158 return 159 } 160 if bytes.Compare(bb.buf[(bb.used-bbsrc.used)-1].key, bbsrc.buf[0].key) < 0 { 161 return 162 } 163 164 sort.Stable(bb) 165 166 // remove duplicates, using only newest update 167 widx := 0 168 for ridx := 1; ridx < bb.used; ridx++ { 169 if !bytes.Equal(bb.buf[ridx].key, bb.buf[widx].key) { 170 widx++ 171 } 172 bb.buf[widx] = bb.buf[ridx] 173 } 174 bb.used = widx + 1 175 } 176 177 func (bb *bucketBuffer) Len() int { return bb.used } 178 func (bb *bucketBuffer) Less(i, j int) bool { 179 return bytes.Compare(bb.buf[i].key, bb.buf[j].key) < 0 180 } 181 func (bb *bucketBuffer) Swap(i, j int) { bb.buf[i], bb.buf[j] = bb.buf[j], bb.buf[i] }