github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/kv/union_iter.go (about) 1 // Copyright 2015 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package kv 15 16 import "github.com/insionng/yougam/libraries/ngaut/log" 17 18 // UnionIter is the iterator on an UnionStore. 19 type UnionIter struct { 20 dirtyIt Iterator 21 snapshotIt Iterator 22 23 dirtyValid bool 24 snapshotValid bool 25 26 curIsDirty bool 27 isValid bool 28 reverse bool 29 } 30 31 func newUnionIter(dirtyIt Iterator, snapshotIt Iterator, reverse bool) *UnionIter { 32 it := &UnionIter{ 33 dirtyIt: dirtyIt, 34 snapshotIt: snapshotIt, 35 dirtyValid: dirtyIt.Valid(), 36 snapshotValid: snapshotIt.Valid(), 37 reverse: reverse, 38 } 39 it.updateCur() 40 return it 41 } 42 43 // Go next and update valid status. 44 func (iter *UnionIter) dirtyNext() { 45 iter.dirtyIt.Next() 46 iter.dirtyValid = iter.dirtyIt.Valid() 47 } 48 49 // Go next and update valid status. 50 func (iter *UnionIter) snapshotNext() { 51 iter.snapshotIt.Next() 52 iter.snapshotValid = iter.snapshotIt.Valid() 53 } 54 55 func (iter *UnionIter) updateCur() { 56 iter.isValid = true 57 for { 58 if !iter.dirtyValid && !iter.snapshotValid { 59 iter.isValid = false 60 return 61 } 62 63 if !iter.dirtyValid { 64 iter.curIsDirty = false 65 return 66 } 67 68 if !iter.snapshotValid { 69 iter.curIsDirty = true 70 // if delete it 71 if len(iter.dirtyIt.Value()) == 0 { 72 iter.dirtyNext() 73 continue 74 } 75 break 76 } 77 78 // both valid 79 if iter.snapshotValid && iter.dirtyValid { 80 snapshotKey := iter.snapshotIt.Key() 81 dirtyKey := iter.dirtyIt.Key() 82 cmp := dirtyKey.Cmp(snapshotKey) 83 if iter.reverse { 84 cmp = -cmp 85 } 86 // if equal, means both have value 87 if cmp == 0 { 88 if len(iter.dirtyIt.Value()) == 0 { 89 // snapshot has a record, but txn says we have deleted it 90 // just go next 91 iter.dirtyNext() 92 iter.snapshotNext() 93 continue 94 } 95 // both go next 96 iter.snapshotNext() 97 iter.curIsDirty = true 98 break 99 } else if cmp > 0 { 100 // record from snapshot comes first 101 iter.curIsDirty = false 102 break 103 } else { 104 // record from dirty comes first 105 if len(iter.dirtyIt.Value()) == 0 { 106 log.Warnf("[kv] delete a record not exists? k = %q", iter.dirtyIt.Key()) 107 // jump over this deletion 108 iter.dirtyNext() 109 continue 110 } 111 iter.curIsDirty = true 112 break 113 } 114 } 115 } 116 } 117 118 // Next implements the Iterator Next interface. 119 func (iter *UnionIter) Next() error { 120 if !iter.curIsDirty { 121 iter.snapshotNext() 122 } else { 123 iter.dirtyNext() 124 } 125 iter.updateCur() 126 return nil 127 } 128 129 // Value implements the Iterator Value interface. 130 // Multi columns 131 func (iter *UnionIter) Value() []byte { 132 if !iter.curIsDirty { 133 return iter.snapshotIt.Value() 134 } 135 return iter.dirtyIt.Value() 136 } 137 138 // Key implements the Iterator Key interface. 139 func (iter *UnionIter) Key() Key { 140 if !iter.curIsDirty { 141 return iter.snapshotIt.Key() 142 } 143 return iter.dirtyIt.Key() 144 } 145 146 // Valid implements the Iterator Valid interface. 147 func (iter *UnionIter) Valid() bool { 148 return iter.isValid 149 } 150 151 // Close implements the Iterator Close interface. 152 func (iter *UnionIter) Close() { 153 if iter.snapshotIt != nil { 154 iter.snapshotIt.Close() 155 iter.snapshotIt = nil 156 } 157 if iter.dirtyIt != nil { 158 iter.dirtyIt.Close() 159 iter.dirtyIt = nil 160 } 161 }