Skip to content

Commit

Permalink
structure: add HInc and HGetInt64
Browse files Browse the repository at this point in the history
  • Loading branch information
siddontang committed Oct 20, 2015
1 parent 8cb5e79 commit 4eb4c29
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 12 deletions.
66 changes: 55 additions & 11 deletions structure/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package structure
import (
"bytes"
"encoding/binary"
"strconv"

"github.com/juju/errors"
"github.com/pingcap/tidb/kv"
Expand All @@ -38,6 +39,53 @@ func (m hashMeta) IsEmpty() bool {

// HSet sets the string value of a hash field.
func (t *TStructure) HSet(key []byte, field []byte, value []byte) error {
return t.updateHash(key, field, func([]byte) ([]byte, error) {
return value, nil
})
}

// HGet gets the value of a hash field.
func (t *TStructure) HGet(key []byte, field []byte) ([]byte, error) {
dataKey := t.encodeHashDataKey(key, field)
value, err := t.txn.Get(dataKey)
if errors2.ErrorEqual(err, kv.ErrNotExist) {
err = nil
}
return value, errors.Trace(err)
}

// HInc increments the integer value of a hash field, by step, returns
// the value after the increment.
func (t *TStructure) HInc(key []byte, field []byte, step int64) (int64, error) {
base := int64(0)
err := t.updateHash(key, field, func(oldValue []byte) ([]byte, error) {
if oldValue != nil {
var err error
base, err = strconv.ParseInt(string(oldValue), 10, 64)
if err != nil {
return nil, errors.Trace(err)
}
}
base += step
return []byte(strconv.FormatInt(base, 10)), nil
})

return base, errors.Trace(err)
}

// HGetInt64 gets int64 value of a hash field.
func (t *TStructure) HGetInt64(key []byte, field []byte) (int64, error) {
value, err := t.HGet(key, field)
if err != nil || value == nil {
return 0, errors.Trace(err)
}

var n int64
n, err = strconv.ParseInt(string(value), 10, 64)
return n, errors.Trace(err)
}

func (t *TStructure) updateHash(key []byte, field []byte, fn func(oldValue []byte) ([]byte, error)) error {
metaKey := t.encodeHashMetaKey(key)
meta, err := t.loadHashMeta(metaKey)
if err != nil {
Expand All @@ -59,21 +107,17 @@ func (t *TStructure) HSet(key []byte, field []byte, value []byte) error {
meta.Length++
}

if err = t.txn.Set(dataKey, value); err != nil {
var newValue []byte
newValue, err = fn(oldValue)
if err != nil {
return errors.Trace(err)
}

return errors.Trace(t.txn.Set(metaKey, meta.Value()))
}

// HGet gets the value of a hash field.
func (t *TStructure) HGet(key []byte, field []byte) ([]byte, error) {
dataKey := t.encodeHashDataKey(key, field)
value, err := t.txn.Get(dataKey)
if errors2.ErrorEqual(err, kv.ErrNotExist) {
err = nil
if err = t.txn.Set(dataKey, newValue); err != nil {
return errors.Trace(err)
}
return value, errors.Trace(err)

return errors.Trace(t.txn.Set(metaKey, meta.Value()))
}

// HLen gets the number of fields in a hash.
Expand Down
22 changes: 21 additions & 1 deletion structure/structure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,32 @@ func (s *testStructureSuite) TestHash(c *C) {

value, err = tx.HGet(key, []byte("1"))
c.Assert(err, IsNil)
c.Assert(err, IsNil)
c.Assert(value, IsNil)

l, err = tx.HLen(key)
c.Assert(err, IsNil)
c.Assert(l, Equals, int64(1))

n, err := tx.HInc(key, []byte("1"), 1)
c.Assert(err, IsNil)
c.Assert(n, Equals, int64(1))

l, err = tx.HLen(key)
c.Assert(err, IsNil)
c.Assert(l, Equals, int64(2))

n, err = tx.HInc(key, []byte("1"), 1)
c.Assert(err, IsNil)
c.Assert(n, Equals, int64(2))

n, err = tx.HGetInt64(key, []byte("1"))
c.Assert(err, IsNil)
c.Assert(n, Equals, int64(2))

l, err = tx.HLen(key)
c.Assert(err, IsNil)
c.Assert(l, Equals, int64(2))

err = tx.HClear(key)
c.Assert(err, IsNil)

Expand Down

0 comments on commit 4eb4c29

Please sign in to comment.