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  }