github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/structure/hash.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 structure 15 16 import ( 17 "bytes" 18 "encoding/binary" 19 "strconv" 20 21 "github.com/insionng/yougam/libraries/juju/errors" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 24 ) 25 26 // HashPair is the pair for (field, value) in a hash. 27 type HashPair struct { 28 Field []byte 29 Value []byte 30 } 31 32 type hashMeta struct { 33 FieldCount int64 34 } 35 36 func (meta hashMeta) Value() []byte { 37 buf := make([]byte, 8) 38 binary.BigEndian.PutUint64(buf[0:8], uint64(meta.FieldCount)) 39 return buf 40 } 41 42 func (meta hashMeta) IsEmpty() bool { 43 return meta.FieldCount <= 0 44 } 45 46 // HSet sets the string value of a hash field. 47 func (t *TxStructure) HSet(key []byte, field []byte, value []byte) error { 48 return t.updateHash(key, field, func([]byte) ([]byte, error) { 49 return value, nil 50 }) 51 } 52 53 // HGet gets the value of a hash field. 54 func (t *TxStructure) HGet(key []byte, field []byte) ([]byte, error) { 55 dataKey := t.encodeHashDataKey(key, field) 56 value, err := t.txn.Get(dataKey) 57 if terror.ErrorEqual(err, kv.ErrNotExist) { 58 err = nil 59 } 60 return value, errors.Trace(err) 61 } 62 63 // HInc increments the integer value of a hash field, by step, returns 64 // the value after the increment. 65 func (t *TxStructure) HInc(key []byte, field []byte, step int64) (int64, error) { 66 base := int64(0) 67 err := t.updateHash(key, field, func(oldValue []byte) ([]byte, error) { 68 if oldValue != nil { 69 var err error 70 base, err = strconv.ParseInt(string(oldValue), 10, 64) 71 if err != nil { 72 return nil, errors.Trace(err) 73 } 74 } 75 base += step 76 return []byte(strconv.FormatInt(base, 10)), nil 77 }) 78 79 return base, errors.Trace(err) 80 } 81 82 // HGetInt64 gets int64 value of a hash field. 83 func (t *TxStructure) HGetInt64(key []byte, field []byte) (int64, error) { 84 value, err := t.HGet(key, field) 85 if err != nil || value == nil { 86 return 0, errors.Trace(err) 87 } 88 89 var n int64 90 n, err = strconv.ParseInt(string(value), 10, 64) 91 return n, errors.Trace(err) 92 } 93 94 func (t *TxStructure) updateHash(key []byte, field []byte, fn func(oldValue []byte) ([]byte, error)) error { 95 dataKey := t.encodeHashDataKey(key, field) 96 oldValue, err := t.loadHashValue(dataKey) 97 if err != nil { 98 return errors.Trace(err) 99 } 100 101 newValue, err := fn(oldValue) 102 if err != nil { 103 return errors.Trace(err) 104 } 105 106 // Check if new value is equal to old value. 107 if bytes.Equal(oldValue, newValue) { 108 return nil 109 } 110 111 if err = t.txn.Set(dataKey, newValue); err != nil { 112 return errors.Trace(err) 113 } 114 115 metaKey := t.encodeHashMetaKey(key) 116 meta, err := t.loadHashMeta(metaKey) 117 if err != nil { 118 return errors.Trace(err) 119 } 120 121 if oldValue == nil { 122 meta.FieldCount++ 123 if err = t.txn.Set(metaKey, meta.Value()); err != nil { 124 return errors.Trace(err) 125 } 126 } 127 128 return nil 129 } 130 131 // HLen gets the number of fields in a hash. 132 func (t *TxStructure) HLen(key []byte) (int64, error) { 133 metaKey := t.encodeHashMetaKey(key) 134 meta, err := t.loadHashMeta(metaKey) 135 if err != nil { 136 return 0, errors.Trace(err) 137 } 138 return meta.FieldCount, nil 139 } 140 141 // HDel deletes one or more hash fields. 142 func (t *TxStructure) HDel(key []byte, fields ...[]byte) error { 143 metaKey := t.encodeHashMetaKey(key) 144 meta, err := t.loadHashMeta(metaKey) 145 if err != nil || meta.IsEmpty() { 146 return errors.Trace(err) 147 } 148 149 var value []byte 150 for _, field := range fields { 151 dataKey := t.encodeHashDataKey(key, field) 152 153 value, err = t.loadHashValue(dataKey) 154 if err != nil { 155 return errors.Trace(err) 156 } 157 158 if value != nil { 159 if err = t.txn.Delete(dataKey); err != nil { 160 return errors.Trace(err) 161 } 162 163 meta.FieldCount-- 164 } 165 } 166 167 if meta.IsEmpty() { 168 err = t.txn.Delete(metaKey) 169 } else { 170 err = t.txn.Set(metaKey, meta.Value()) 171 } 172 173 return errors.Trace(err) 174 } 175 176 // HKeys gets all the fields in a hash. 177 func (t *TxStructure) HKeys(key []byte) ([][]byte, error) { 178 var keys [][]byte 179 err := t.iterateHash(key, func(field []byte, value []byte) error { 180 keys = append(keys, append([]byte{}, field...)) 181 return nil 182 }) 183 184 return keys, errors.Trace(err) 185 } 186 187 // HGetAll gets all the fields and values in a hash. 188 func (t *TxStructure) HGetAll(key []byte) ([]HashPair, error) { 189 var res []HashPair 190 err := t.iterateHash(key, func(field []byte, value []byte) error { 191 pair := HashPair{ 192 Field: append([]byte{}, field...), 193 Value: append([]byte{}, value...), 194 } 195 res = append(res, pair) 196 return nil 197 }) 198 199 return res, errors.Trace(err) 200 } 201 202 // HClear removes the hash value of the key. 203 func (t *TxStructure) HClear(key []byte) error { 204 metaKey := t.encodeHashMetaKey(key) 205 meta, err := t.loadHashMeta(metaKey) 206 if err != nil || meta.IsEmpty() { 207 return errors.Trace(err) 208 } 209 210 err = t.iterateHash(key, func(field []byte, value []byte) error { 211 k := t.encodeHashDataKey(key, field) 212 return errors.Trace(t.txn.Delete(k)) 213 }) 214 215 if err != nil { 216 return errors.Trace(err) 217 } 218 219 return errors.Trace(t.txn.Delete(metaKey)) 220 } 221 222 func (t *TxStructure) iterateHash(key []byte, fn func(k []byte, v []byte) error) error { 223 dataPrefix := t.hashDataKeyPrefix(key) 224 it, err := t.txn.Seek(dataPrefix) 225 if err != nil { 226 return errors.Trace(err) 227 } 228 229 var field []byte 230 231 for it.Valid() { 232 if !it.Key().HasPrefix(dataPrefix) { 233 break 234 } 235 236 _, field, err = t.decodeHashDataKey(it.Key()) 237 if err != nil { 238 return errors.Trace(err) 239 } 240 241 if err = fn(field, it.Value()); err != nil { 242 return errors.Trace(err) 243 } 244 245 err = it.Next() 246 if err != nil { 247 return errors.Trace(err) 248 } 249 } 250 251 return nil 252 } 253 254 func (t *TxStructure) loadHashMeta(metaKey []byte) (hashMeta, error) { 255 v, err := t.txn.Get(metaKey) 256 if terror.ErrorEqual(err, kv.ErrNotExist) { 257 err = nil 258 } else if err != nil { 259 return hashMeta{}, errors.Trace(err) 260 } 261 262 meta := hashMeta{FieldCount: 0} 263 if v == nil { 264 return meta, nil 265 } 266 267 if len(v) != 8 { 268 return meta, errInvalidListMetaData 269 } 270 271 meta.FieldCount = int64(binary.BigEndian.Uint64(v[0:8])) 272 return meta, nil 273 } 274 275 func (t *TxStructure) loadHashValue(dataKey []byte) ([]byte, error) { 276 v, err := t.txn.Get(dataKey) 277 if terror.ErrorEqual(err, kv.ErrNotExist) { 278 err = nil 279 v = nil 280 } else if err != nil { 281 return nil, errors.Trace(err) 282 } 283 284 return v, nil 285 }