github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/storage/union_iter.go (about) 1 // Copyright 2022 zGraph Authors. All rights reserved. 2 // 3 // Copyright 2015 PingCAP, Inc. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package storage 18 19 import ( 20 "bytes" 21 22 "github.com/vescale/zgraph/storage/kv" 23 ) 24 25 // UnionIter is the SnapshotIter on an UnionStore. 26 type UnionIter struct { 27 dirtyIt kv.Iterator 28 snapshotIt kv.Iterator 29 30 dirtyValid bool 31 snapshotValid bool 32 33 curIsDirty bool 34 isValid bool 35 reverse bool 36 } 37 38 // NewUnionIter returns a union SnapshotIter for BufferStore. 39 func NewUnionIter(dirtyIt kv.Iterator, snapshotIt kv.Iterator, reverse bool) (*UnionIter, error) { 40 it := &UnionIter{ 41 dirtyIt: dirtyIt, 42 snapshotIt: snapshotIt, 43 dirtyValid: dirtyIt.Valid(), 44 snapshotValid: snapshotIt.Valid(), 45 reverse: reverse, 46 } 47 err := it.updateCur() 48 if err != nil { 49 return nil, err 50 } 51 return it, nil 52 } 53 54 // dirtyNext makes iter.dirtyIt go and update valid status. 55 func (iter *UnionIter) dirtyNext() error { 56 err := iter.dirtyIt.Next() 57 iter.dirtyValid = iter.dirtyIt.Valid() 58 return err 59 } 60 61 // snapshotNext makes iter.snapshotIt go and update valid status. 62 func (iter *UnionIter) snapshotNext() error { 63 err := iter.snapshotIt.Next() 64 iter.snapshotValid = iter.snapshotIt.Valid() 65 return err 66 } 67 68 func (iter *UnionIter) updateCur() error { 69 iter.isValid = true 70 for { 71 if !iter.dirtyValid && !iter.snapshotValid { 72 iter.isValid = false 73 break 74 } 75 76 if !iter.dirtyValid { 77 iter.curIsDirty = false 78 break 79 } 80 81 if !iter.snapshotValid { 82 iter.curIsDirty = true 83 // if delete it 84 if len(iter.dirtyIt.Value()) == 0 { 85 if err := iter.dirtyNext(); err != nil { 86 return err 87 } 88 continue 89 } 90 break 91 } 92 93 // both valid 94 if iter.snapshotValid && iter.dirtyValid { 95 snapshotKey := iter.snapshotIt.Key() 96 dirtyKey := iter.dirtyIt.Key() 97 cmp := bytes.Compare(dirtyKey, snapshotKey) 98 if iter.reverse { 99 cmp = -cmp 100 } 101 // if equal, means both have value 102 if cmp == 0 { 103 if len(iter.dirtyIt.Value()) == 0 { 104 // snapshot has a record, but txn says we have deleted it 105 // just go next 106 if err := iter.dirtyNext(); err != nil { 107 return err 108 } 109 if err := iter.snapshotNext(); err != nil { 110 return err 111 } 112 continue 113 } 114 // both go next 115 if err := iter.snapshotNext(); err != nil { 116 return err 117 } 118 iter.curIsDirty = true 119 break 120 } else if cmp > 0 { 121 // record from snapshot comes first 122 iter.curIsDirty = false 123 break 124 } else { 125 // record from dirty comes first 126 if len(iter.dirtyIt.Value()) == 0 { 127 // FIXME? delete a record not exists? 128 // jump over this deletion 129 if err := iter.dirtyNext(); err != nil { 130 return err 131 } 132 continue 133 } 134 iter.curIsDirty = true 135 break 136 } 137 } 138 } 139 return nil 140 } 141 142 // Next implements the Iterator Next interface. 143 func (iter *UnionIter) Next() error { 144 var err error 145 if !iter.curIsDirty { 146 err = iter.snapshotNext() 147 } else { 148 err = iter.dirtyNext() 149 } 150 if err != nil { 151 return err 152 } 153 err = iter.updateCur() 154 return err 155 } 156 157 // Value implements the Iterator Value interface. 158 // Multi columns 159 func (iter *UnionIter) Value() []byte { 160 if !iter.curIsDirty { 161 return iter.snapshotIt.Value() 162 } 163 return iter.dirtyIt.Value() 164 } 165 166 // Key implements the Iterator Key interface. 167 func (iter *UnionIter) Key() kv.Key { 168 if !iter.curIsDirty { 169 return iter.snapshotIt.Key() 170 } 171 return iter.dirtyIt.Key() 172 } 173 174 // Valid implements the Iterator Valid interface. 175 func (iter *UnionIter) Valid() bool { 176 return iter.isValid 177 } 178 179 // Close implements the Iterator Close interface. 180 func (iter *UnionIter) Close() { 181 if iter.snapshotIt != nil { 182 iter.snapshotIt.Close() 183 iter.snapshotIt = nil 184 } 185 if iter.dirtyIt != nil { 186 iter.dirtyIt.Close() 187 iter.dirtyIt = nil 188 } 189 }