Skip to content

Commit

Permalink
CBG-342 - Check for explicit KeyNotFound in gocb Incr's amt=0 handling (
Browse files Browse the repository at this point in the history
#4095)

* CBG-342 Check for explicit KeyNotFoundError in gocbbucket.Incr

Prevents Incr from reporting incorrect zero value under cases where the
Get fails for other unexpected reasons (like persistent network timeouts)

* Add test to cover amt=0 in Incr for gocb bucket

* Use existing test bucket pattern for TestIncrAmtZero

* Make TestIncrAmtZero run on all bucket types - change def param to expected SG usage
  • Loading branch information
bbrks authored and adamcfraser committed May 1, 2019
1 parent 9e9cf3f commit cde8f82
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
7 changes: 6 additions & 1 deletion base/bucket_gocb.go
Original file line number Diff line number Diff line change
Expand Up @@ -1796,9 +1796,14 @@ func (bucket *CouchbaseBucketGoCB) Incr(k string, amt, def uint64, exp uint32) (
if amt == 0 {
var result uint64
_, err := bucket.Get(k, &result)
if err != nil {
if bucket.IsKeyNotFoundError(err) {
// Return Incr value as zero
return uint64(0), nil
} else if err != nil {
// Got an error when trying to fetch the value
return 0, err
}
// Got a non-zero value to return
return result, nil
}

Expand Down
32 changes: 32 additions & 0 deletions base/bucket_gocb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,38 @@ func TestIncrCounter(t *testing.T) {

}

// TestIncrAmtZero covers the special handling in Incr for when amt=0 on an unknown key
func TestIncrAmtZero(t *testing.T) {

testBucket := GetTestBucketOrPanic()
defer testBucket.Close()
bucket := testBucket.Bucket

key := "TestIncrAmtZero"

defer func() {
err := bucket.Delete(key)
if err != nil {
t.Errorf("Error removing counter from bucket")
}
}()

// key hasn't been created, so we'll fall into the special 'Get' handling in Incr
val, err := bucket.Incr(key, 0, 0, 0)
assert.NoError(t, err)
assert.Equal(t, uint64(0), val)

// Actually increment key to create it
val, err = bucket.Incr(key, 1, 1, 0)
assert.NoError(t, err)
assert.Equal(t, uint64(1), val)

// Do another amt=0 to make sure we get the new incremented value
val, err = bucket.Incr(key, 0, 0, 0)
assert.NoError(t, err)
assert.Equal(t, uint64(1), val)
}

func TestGetAndTouchRaw(t *testing.T) {

// There's no easy way to validate the expiry time of a doc (that I know of)
Expand Down
2 changes: 1 addition & 1 deletion base/leaky_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type LeakyBucket struct {
// The config object that controls the LeakyBucket behavior
type LeakyBucketConfig struct {

// Incr() fails 3 times before finally succeeding
// Incr() fails N times before finally succeeding
IncrTemporaryFailCount uint16

// Allows us to force a number of failed executions of GetDDoc, DeleteDDoc and DropIndex. It will fail the
Expand Down

0 comments on commit cde8f82

Please sign in to comment.