github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/go-themis/mutation_cache.go (about) 1 package themis 2 3 import ( 4 "fmt" 5 "sort" 6 7 "github.com/insionng/yougam/libraries/juju/errors" 8 "github.com/insionng/yougam/libraries/ngaut/log" 9 "github.com/insionng/yougam/libraries/pingcap/go-hbase" 10 "github.com/insionng/yougam/libraries/pingcap/go-hbase/proto" 11 ) 12 13 type mutationValuePair struct { 14 typ hbase.Type 15 value []byte 16 } 17 18 func (mp *mutationValuePair) String() string { 19 return fmt.Sprintf("type: %d value: %s", mp.typ, mp.value) 20 } 21 22 type columnMutation struct { 23 *hbase.Column 24 *mutationValuePair 25 } 26 27 func getEntriesFromDel(p *hbase.Delete) ([]*columnMutation, error) { 28 errMsg := "must set at least one column for themis delete" 29 if len(p.FamilyQuals) == 0 { 30 return nil, errors.New(errMsg) 31 } 32 33 var ret []*columnMutation 34 for f, _ := range p.Families { 35 quilifiers := p.FamilyQuals[f] 36 if len(quilifiers) == 0 { 37 return nil, errors.New(errMsg) 38 } 39 for q, _ := range quilifiers { 40 mutation := &columnMutation{ 41 Column: &hbase.Column{ 42 Family: []byte(f), 43 Qual: []byte(q), 44 }, 45 mutationValuePair: &mutationValuePair{ 46 typ: hbase.TypeDeleteColumn, 47 }, 48 } 49 ret = append(ret, mutation) 50 } 51 } 52 return ret, nil 53 } 54 55 func getEntriesFromPut(p *hbase.Put) []*columnMutation { 56 var ret []*columnMutation 57 for i, f := range p.Families { 58 qualifiers := p.Qualifiers[i] 59 for j, q := range qualifiers { 60 mutation := &columnMutation{ 61 Column: &hbase.Column{ 62 Family: f, 63 Qual: q, 64 }, 65 mutationValuePair: &mutationValuePair{ 66 typ: hbase.TypePut, 67 value: p.Values[i][j], 68 }, 69 } 70 ret = append(ret, mutation) 71 } 72 } 73 return ret 74 } 75 76 func (cm *columnMutation) toCell() *proto.Cell { 77 ret := &proto.Cell{ 78 Family: cm.Family, 79 Qualifier: cm.Qual, 80 Value: cm.value, 81 } 82 if cm.typ == hbase.TypePut { // put 83 ret.CellType = proto.CellType_PUT.Enum() 84 } else if cm.typ == hbase.TypeMinimum { // onlyLock 85 ret.CellType = proto.CellType_MINIMUM.Enum() 86 } else { // delete, themis delete API only support delete column 87 ret.CellType = proto.CellType_DELETE_COLUMN.Enum() 88 } 89 return ret 90 } 91 92 type rowMutation struct { 93 tbl []byte 94 row []byte 95 // mutations := { 'cf:col' => mutationValuePair } 96 mutations map[string]*mutationValuePair 97 } 98 99 func (r *rowMutation) getColumns() []hbase.Column { 100 var ret []hbase.Column 101 for k, _ := range r.mutations { 102 c := &hbase.Column{} 103 // TODO: handle error, now just ignore 104 if err := c.ParseFromString(k); err != nil { 105 log.Warnf("parse from string error, column: %s, mutation: %s, error: %v", c, k, err) 106 } 107 ret = append(ret, *c) 108 } 109 return ret 110 } 111 112 func (r *rowMutation) getSize() int { 113 return len(r.mutations) 114 } 115 116 func (r *rowMutation) getType(c hbase.Column) hbase.Type { 117 p, ok := r.mutations[c.String()] 118 if !ok { 119 return hbase.TypeMinimum 120 } 121 return p.typ 122 } 123 124 func newRowMutation(tbl, row []byte) *rowMutation { 125 return &rowMutation{ 126 tbl: tbl, 127 row: row, 128 mutations: map[string]*mutationValuePair{}, 129 } 130 } 131 132 func (r *rowMutation) addMutation(c *hbase.Column, typ hbase.Type, val []byte, onlyLock bool) { 133 // 3 scene: put, delete, onlyLock 134 // if it is onlyLock scene, then has not data modify, when has contained the qualifier, can't replace exist value, 135 // becuase put or delete operation has add mutation 136 if onlyLock && r.mutations[c.String()] != nil { 137 return 138 } 139 140 r.mutations[c.String()] = &mutationValuePair{ 141 typ: typ, 142 value: val, 143 } 144 } 145 146 func (r *rowMutation) mutationList(withValue bool) []*columnMutation { 147 var ret []*columnMutation 148 var keys []string 149 for k, _ := range r.mutations { 150 keys = append(keys, k) 151 } 152 sort.Strings(keys) 153 for _, k := range keys { 154 v := &mutationValuePair{ 155 typ: r.mutations[k].typ, 156 } 157 if withValue { 158 v.value = r.mutations[k].value 159 } 160 c := &hbase.Column{} 161 // TODO: handle error, now just ignore 162 if err := c.ParseFromString(k); err != nil { 163 log.Warnf("parse from string error, column: %s, mutation: %s, error: %v", c, k, err) 164 } 165 ret = append(ret, &columnMutation{ 166 Column: c, 167 mutationValuePair: v, 168 }) 169 } 170 return ret 171 } 172 173 type columnMutationCache struct { 174 // mutations => {table => { rowKey => row mutations } } 175 mutations map[string]map[string]*rowMutation 176 } 177 178 func newColumnMutationCache() *columnMutationCache { 179 return &columnMutationCache{ 180 mutations: map[string]map[string]*rowMutation{}, 181 } 182 } 183 184 func (c *columnMutationCache) addMutation(tbl []byte, row []byte, col *hbase.Column, t hbase.Type, v []byte, onlyLock bool) { 185 tblRowMutations, ok := c.mutations[string(tbl)] 186 if !ok { 187 // create table mutation map 188 tblRowMutations = map[string]*rowMutation{} 189 c.mutations[string(tbl)] = tblRowMutations 190 } 191 192 rowMutations, ok := tblRowMutations[string(row)] 193 if !ok { 194 // create row mutation map 195 rowMutations = newRowMutation(tbl, row) 196 tblRowMutations[string(row)] = rowMutations 197 } 198 rowMutations.addMutation(col, t, v, onlyLock) 199 } 200 201 func (c *columnMutationCache) getMutation(cc *hbase.ColumnCoordinate) *mutationValuePair { 202 t, ok := c.mutations[string(cc.Table)] 203 if !ok { 204 return nil 205 } 206 rowMutation, ok := t[string(cc.Row)] 207 if !ok { 208 return nil 209 } 210 p, ok := rowMutation.mutations[cc.GetColumn().String()] 211 if !ok { 212 return nil 213 } 214 return p 215 } 216 217 func (c *columnMutationCache) getRowCount() int { 218 ret := 0 219 for _, v := range c.mutations { 220 ret += len(v) 221 } 222 return ret 223 } 224 225 func (c *columnMutationCache) getMutationCount() int { 226 ret := 0 227 for _, v := range c.mutations { 228 for _, vv := range v { 229 ret += len(vv.mutationList(false)) 230 } 231 } 232 return ret 233 }