github.com/bhojpur/cache@v0.0.4/pkg/memory/bucket_test.go (about)

     1  package memory_test
     2  
     3  // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved.
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in
    13  // all copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    21  // THE SOFTWARE.
    22  
    23  import (
    24  	"bytes"
    25  	"encoding/binary"
    26  	"errors"
    27  	"fmt"
    28  	"log"
    29  	"math/rand"
    30  	"os"
    31  	"strconv"
    32  	"strings"
    33  	"testing"
    34  	"testing/quick"
    35  
    36  	memcache "github.com/bhojpur/cache/pkg/memory"
    37  )
    38  
    39  // Ensure that a bucket that gets a non-existent key returns nil.
    40  func TestBucket_Get_NonExistent(t *testing.T) {
    41  	db := MustOpenDB()
    42  	defer db.MustClose()
    43  
    44  	if err := db.Update(func(tx *memcache.Tx) error {
    45  		b, err := tx.CreateBucket([]byte("widgets"))
    46  		if err != nil {
    47  			t.Fatal(err)
    48  		}
    49  		if v := b.Get([]byte("foo")); v != nil {
    50  			t.Fatal("expected nil value")
    51  		}
    52  		return nil
    53  	}); err != nil {
    54  		t.Fatal(err)
    55  	}
    56  }
    57  
    58  // Ensure that a bucket can read a value that is not flushed yet.
    59  func TestBucket_Get_FromNode(t *testing.T) {
    60  	db := MustOpenDB()
    61  	defer db.MustClose()
    62  
    63  	if err := db.Update(func(tx *memcache.Tx) error {
    64  		b, err := tx.CreateBucket([]byte("widgets"))
    65  		if err != nil {
    66  			t.Fatal(err)
    67  		}
    68  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
    69  			t.Fatal(err)
    70  		}
    71  		if v := b.Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) {
    72  			t.Fatalf("unexpected value: %v", v)
    73  		}
    74  		return nil
    75  	}); err != nil {
    76  		t.Fatal(err)
    77  	}
    78  }
    79  
    80  // Ensure that a bucket retrieved via Get() returns a nil.
    81  func TestBucket_Get_IncompatibleValue(t *testing.T) {
    82  	db := MustOpenDB()
    83  	defer db.MustClose()
    84  	if err := db.Update(func(tx *memcache.Tx) error {
    85  		_, err := tx.CreateBucket([]byte("widgets"))
    86  		if err != nil {
    87  			t.Fatal(err)
    88  		}
    89  
    90  		if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
    91  			t.Fatal(err)
    92  		}
    93  
    94  		if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil {
    95  			t.Fatal("expected nil value")
    96  		}
    97  		return nil
    98  	}); err != nil {
    99  		t.Fatal(err)
   100  	}
   101  }
   102  
   103  // Ensure that a slice returned from a bucket has a capacity equal to its length.
   104  // This also allows slices to be appended to since it will require a realloc by Go.
   105  func TestBucket_Get_Capacity(t *testing.T) {
   106  	db := MustOpenDB()
   107  	defer db.MustClose()
   108  
   109  	// Write key to a bucket.
   110  	if err := db.Update(func(tx *memcache.Tx) error {
   111  		b, err := tx.CreateBucket([]byte("bucket"))
   112  		if err != nil {
   113  			return err
   114  		}
   115  		return b.Put([]byte("key"), []byte("val"))
   116  	}); err != nil {
   117  		t.Fatal(err)
   118  	}
   119  
   120  	// Retrieve value and attempt to append to it.
   121  	if err := db.Update(func(tx *memcache.Tx) error {
   122  		k, v := tx.Bucket([]byte("bucket")).Cursor().First()
   123  
   124  		// Verify capacity.
   125  		if len(k) != cap(k) {
   126  			t.Fatalf("unexpected key slice capacity: %d", cap(k))
   127  		} else if len(v) != cap(v) {
   128  			t.Fatalf("unexpected value slice capacity: %d", cap(v))
   129  		}
   130  
   131  		// Ensure slice can be appended to without a segfault.
   132  		k = append(k, []byte("123")...)
   133  		v = append(v, []byte("123")...)
   134  
   135  		return nil
   136  	}); err != nil {
   137  		t.Fatal(err)
   138  	}
   139  }
   140  
   141  // Ensure that a bucket can write a key/value.
   142  func TestBucket_Put(t *testing.T) {
   143  	db := MustOpenDB()
   144  	defer db.MustClose()
   145  	if err := db.Update(func(tx *memcache.Tx) error {
   146  		b, err := tx.CreateBucket([]byte("widgets"))
   147  		if err != nil {
   148  			t.Fatal(err)
   149  		}
   150  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
   151  			t.Fatal(err)
   152  		}
   153  
   154  		v := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
   155  		if !bytes.Equal([]byte("bar"), v) {
   156  			t.Fatalf("unexpected value: %v", v)
   157  		}
   158  		return nil
   159  	}); err != nil {
   160  		t.Fatal(err)
   161  	}
   162  }
   163  
   164  // Ensure that a bucket can rewrite a key in the same transaction.
   165  func TestBucket_Put_Repeat(t *testing.T) {
   166  	db := MustOpenDB()
   167  	defer db.MustClose()
   168  	if err := db.Update(func(tx *memcache.Tx) error {
   169  		b, err := tx.CreateBucket([]byte("widgets"))
   170  		if err != nil {
   171  			t.Fatal(err)
   172  		}
   173  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
   174  			t.Fatal(err)
   175  		}
   176  		if err := b.Put([]byte("foo"), []byte("baz")); err != nil {
   177  			t.Fatal(err)
   178  		}
   179  
   180  		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
   181  		if !bytes.Equal([]byte("baz"), value) {
   182  			t.Fatalf("unexpected value: %v", value)
   183  		}
   184  		return nil
   185  	}); err != nil {
   186  		t.Fatal(err)
   187  	}
   188  }
   189  
   190  // Ensure that a bucket can write a bunch of large values.
   191  func TestBucket_Put_Large(t *testing.T) {
   192  	db := MustOpenDB()
   193  	defer db.MustClose()
   194  
   195  	count, factor := 100, 200
   196  	if err := db.Update(func(tx *memcache.Tx) error {
   197  		b, err := tx.CreateBucket([]byte("widgets"))
   198  		if err != nil {
   199  			t.Fatal(err)
   200  		}
   201  		for i := 1; i < count; i++ {
   202  			if err := b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))); err != nil {
   203  				t.Fatal(err)
   204  			}
   205  		}
   206  		return nil
   207  	}); err != nil {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	if err := db.View(func(tx *memcache.Tx) error {
   212  		b := tx.Bucket([]byte("widgets"))
   213  		for i := 1; i < count; i++ {
   214  			value := b.Get([]byte(strings.Repeat("0", i*factor)))
   215  			if !bytes.Equal(value, []byte(strings.Repeat("X", (count-i)*factor))) {
   216  				t.Fatalf("unexpected value: %v", value)
   217  			}
   218  		}
   219  		return nil
   220  	}); err != nil {
   221  		t.Fatal(err)
   222  	}
   223  }
   224  
   225  // Ensure that a database can perform multiple large appends safely.
   226  func TestDB_Put_VeryLarge(t *testing.T) {
   227  	if testing.Short() {
   228  		t.Skip("skipping test in short mode.")
   229  	}
   230  
   231  	n, batchN := 400000, 200000
   232  	ksize, vsize := 8, 500
   233  
   234  	db := MustOpenDB()
   235  	defer db.MustClose()
   236  
   237  	for i := 0; i < n; i += batchN {
   238  		if err := db.Update(func(tx *memcache.Tx) error {
   239  			b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
   240  			if err != nil {
   241  				t.Fatal(err)
   242  			}
   243  			for j := 0; j < batchN; j++ {
   244  				k, v := make([]byte, ksize), make([]byte, vsize)
   245  				binary.BigEndian.PutUint32(k, uint32(i+j))
   246  				if err := b.Put(k, v); err != nil {
   247  					t.Fatal(err)
   248  				}
   249  			}
   250  			return nil
   251  		}); err != nil {
   252  			t.Fatal(err)
   253  		}
   254  	}
   255  }
   256  
   257  // Ensure that a setting a value on a key with a bucket value returns an error.
   258  func TestBucket_Put_IncompatibleValue(t *testing.T) {
   259  	db := MustOpenDB()
   260  	defer db.MustClose()
   261  
   262  	if err := db.Update(func(tx *memcache.Tx) error {
   263  		b0, err := tx.CreateBucket([]byte("widgets"))
   264  		if err != nil {
   265  			t.Fatal(err)
   266  		}
   267  
   268  		if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
   269  			t.Fatal(err)
   270  		}
   271  		if err := b0.Put([]byte("foo"), []byte("bar")); err != memcache.ErrIncompatibleValue {
   272  			t.Fatalf("unexpected error: %s", err)
   273  		}
   274  		return nil
   275  	}); err != nil {
   276  		t.Fatal(err)
   277  	}
   278  }
   279  
   280  // Ensure that a setting a value while the transaction is closed returns an error.
   281  func TestBucket_Put_Closed(t *testing.T) {
   282  	db := MustOpenDB()
   283  	defer db.MustClose()
   284  	tx, err := db.Begin(true)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  
   289  	b, err := tx.CreateBucket([]byte("widgets"))
   290  	if err != nil {
   291  		t.Fatal(err)
   292  	}
   293  
   294  	if err := tx.Rollback(); err != nil {
   295  		t.Fatal(err)
   296  	}
   297  
   298  	if err := b.Put([]byte("foo"), []byte("bar")); err != memcache.ErrTxClosed {
   299  		t.Fatalf("unexpected error: %s", err)
   300  	}
   301  }
   302  
   303  // Ensure that setting a value on a read-only bucket returns an error.
   304  func TestBucket_Put_ReadOnly(t *testing.T) {
   305  	db := MustOpenDB()
   306  	defer db.MustClose()
   307  
   308  	if err := db.Update(func(tx *memcache.Tx) error {
   309  		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
   310  			t.Fatal(err)
   311  		}
   312  		return nil
   313  	}); err != nil {
   314  		t.Fatal(err)
   315  	}
   316  
   317  	if err := db.View(func(tx *memcache.Tx) error {
   318  		b := tx.Bucket([]byte("widgets"))
   319  		if err := b.Put([]byte("foo"), []byte("bar")); err != memcache.ErrTxNotWritable {
   320  			t.Fatalf("unexpected error: %s", err)
   321  		}
   322  		return nil
   323  	}); err != nil {
   324  		t.Fatal(err)
   325  	}
   326  }
   327  
   328  // Ensure that a bucket can delete an existing key.
   329  func TestBucket_Delete(t *testing.T) {
   330  	db := MustOpenDB()
   331  	defer db.MustClose()
   332  
   333  	if err := db.Update(func(tx *memcache.Tx) error {
   334  		b, err := tx.CreateBucket([]byte("widgets"))
   335  		if err != nil {
   336  			t.Fatal(err)
   337  		}
   338  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
   339  			t.Fatal(err)
   340  		}
   341  		if err := b.Delete([]byte("foo")); err != nil {
   342  			t.Fatal(err)
   343  		}
   344  		if v := b.Get([]byte("foo")); v != nil {
   345  			t.Fatalf("unexpected value: %v", v)
   346  		}
   347  		return nil
   348  	}); err != nil {
   349  		t.Fatal(err)
   350  	}
   351  }
   352  
   353  // Ensure that deleting a large set of keys will work correctly.
   354  func TestBucket_Delete_Large(t *testing.T) {
   355  	db := MustOpenDB()
   356  	defer db.MustClose()
   357  
   358  	if err := db.Update(func(tx *memcache.Tx) error {
   359  		b, err := tx.CreateBucket([]byte("widgets"))
   360  		if err != nil {
   361  			t.Fatal(err)
   362  		}
   363  
   364  		for i := 0; i < 100; i++ {
   365  			if err := b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))); err != nil {
   366  				t.Fatal(err)
   367  			}
   368  		}
   369  
   370  		return nil
   371  	}); err != nil {
   372  		t.Fatal(err)
   373  	}
   374  
   375  	if err := db.Update(func(tx *memcache.Tx) error {
   376  		b := tx.Bucket([]byte("widgets"))
   377  		for i := 0; i < 100; i++ {
   378  			if err := b.Delete([]byte(strconv.Itoa(i))); err != nil {
   379  				t.Fatal(err)
   380  			}
   381  		}
   382  		return nil
   383  	}); err != nil {
   384  		t.Fatal(err)
   385  	}
   386  
   387  	if err := db.View(func(tx *memcache.Tx) error {
   388  		b := tx.Bucket([]byte("widgets"))
   389  		for i := 0; i < 100; i++ {
   390  			if v := b.Get([]byte(strconv.Itoa(i))); v != nil {
   391  				t.Fatalf("unexpected value: %v, i=%d", v, i)
   392  			}
   393  		}
   394  		return nil
   395  	}); err != nil {
   396  		t.Fatal(err)
   397  	}
   398  }
   399  
   400  // Deleting a very large list of keys will cause the freelist to use overflow.
   401  func TestBucket_Delete_FreelistOverflow(t *testing.T) {
   402  	if testing.Short() {
   403  		t.Skip("skipping test in short mode.")
   404  	}
   405  
   406  	db := MustOpenDB()
   407  	defer db.MustClose()
   408  
   409  	k := make([]byte, 16)
   410  	for i := uint64(0); i < 10000; i++ {
   411  		if err := db.Update(func(tx *memcache.Tx) error {
   412  			b, err := tx.CreateBucketIfNotExists([]byte("0"))
   413  			if err != nil {
   414  				t.Fatalf("bucket error: %s", err)
   415  			}
   416  
   417  			for j := uint64(0); j < 1000; j++ {
   418  				binary.BigEndian.PutUint64(k[:8], i)
   419  				binary.BigEndian.PutUint64(k[8:], j)
   420  				if err := b.Put(k, nil); err != nil {
   421  					t.Fatalf("put error: %s", err)
   422  				}
   423  			}
   424  
   425  			return nil
   426  		}); err != nil {
   427  			t.Fatal(err)
   428  		}
   429  	}
   430  
   431  	// Delete all of them in one large transaction
   432  	if err := db.Update(func(tx *memcache.Tx) error {
   433  		b := tx.Bucket([]byte("0"))
   434  		c := b.Cursor()
   435  		for k, _ := c.First(); k != nil; k, _ = c.Next() {
   436  			if err := c.Delete(); err != nil {
   437  				t.Fatal(err)
   438  			}
   439  		}
   440  		return nil
   441  	}); err != nil {
   442  		t.Fatal(err)
   443  	}
   444  }
   445  
   446  // Ensure that accessing and updating nested buckets is ok across transactions.
   447  func TestBucket_Nested(t *testing.T) {
   448  	db := MustOpenDB()
   449  	defer db.MustClose()
   450  
   451  	if err := db.Update(func(tx *memcache.Tx) error {
   452  		// Create a widgets bucket.
   453  		b, err := tx.CreateBucket([]byte("widgets"))
   454  		if err != nil {
   455  			t.Fatal(err)
   456  		}
   457  
   458  		// Create a widgets/foo bucket.
   459  		_, err = b.CreateBucket([]byte("foo"))
   460  		if err != nil {
   461  			t.Fatal(err)
   462  		}
   463  
   464  		// Create a widgets/bar key.
   465  		if err := b.Put([]byte("bar"), []byte("0000")); err != nil {
   466  			t.Fatal(err)
   467  		}
   468  
   469  		return nil
   470  	}); err != nil {
   471  		t.Fatal(err)
   472  	}
   473  	db.MustCheck()
   474  
   475  	// Update widgets/bar.
   476  	if err := db.Update(func(tx *memcache.Tx) error {
   477  		b := tx.Bucket([]byte("widgets"))
   478  		if err := b.Put([]byte("bar"), []byte("xxxx")); err != nil {
   479  			t.Fatal(err)
   480  		}
   481  		return nil
   482  	}); err != nil {
   483  		t.Fatal(err)
   484  	}
   485  	db.MustCheck()
   486  
   487  	// Cause a split.
   488  	if err := db.Update(func(tx *memcache.Tx) error {
   489  		var b = tx.Bucket([]byte("widgets"))
   490  		for i := 0; i < 10000; i++ {
   491  			if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
   492  				t.Fatal(err)
   493  			}
   494  		}
   495  		return nil
   496  	}); err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	db.MustCheck()
   500  
   501  	// Insert into widgets/foo/baz.
   502  	if err := db.Update(func(tx *memcache.Tx) error {
   503  		var b = tx.Bucket([]byte("widgets"))
   504  		if err := b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")); err != nil {
   505  			t.Fatal(err)
   506  		}
   507  		return nil
   508  	}); err != nil {
   509  		t.Fatal(err)
   510  	}
   511  	db.MustCheck()
   512  
   513  	// Verify.
   514  	if err := db.View(func(tx *memcache.Tx) error {
   515  		var b = tx.Bucket([]byte("widgets"))
   516  		if v := b.Bucket([]byte("foo")).Get([]byte("baz")); !bytes.Equal(v, []byte("yyyy")) {
   517  			t.Fatalf("unexpected value: %v", v)
   518  		}
   519  		if v := b.Get([]byte("bar")); !bytes.Equal(v, []byte("xxxx")) {
   520  			t.Fatalf("unexpected value: %v", v)
   521  		}
   522  		for i := 0; i < 10000; i++ {
   523  			if v := b.Get([]byte(strconv.Itoa(i))); !bytes.Equal(v, []byte(strconv.Itoa(i))) {
   524  				t.Fatalf("unexpected value: %v", v)
   525  			}
   526  		}
   527  		return nil
   528  	}); err != nil {
   529  		t.Fatal(err)
   530  	}
   531  }
   532  
   533  // Ensure that deleting a bucket using Delete() returns an error.
   534  func TestBucket_Delete_Bucket(t *testing.T) {
   535  	db := MustOpenDB()
   536  	defer db.MustClose()
   537  	if err := db.Update(func(tx *memcache.Tx) error {
   538  		b, err := tx.CreateBucket([]byte("widgets"))
   539  		if err != nil {
   540  			t.Fatal(err)
   541  		}
   542  		if _, err := b.CreateBucket([]byte("foo")); err != nil {
   543  			t.Fatal(err)
   544  		}
   545  		if err := b.Delete([]byte("foo")); err != memcache.ErrIncompatibleValue {
   546  			t.Fatalf("unexpected error: %s", err)
   547  		}
   548  		return nil
   549  	}); err != nil {
   550  		t.Fatal(err)
   551  	}
   552  }
   553  
   554  // Ensure that deleting a key on a read-only bucket returns an error.
   555  func TestBucket_Delete_ReadOnly(t *testing.T) {
   556  	db := MustOpenDB()
   557  	defer db.MustClose()
   558  
   559  	if err := db.Update(func(tx *memcache.Tx) error {
   560  		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
   561  			t.Fatal(err)
   562  		}
   563  		return nil
   564  	}); err != nil {
   565  		t.Fatal(err)
   566  	}
   567  
   568  	if err := db.View(func(tx *memcache.Tx) error {
   569  		if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != memcache.ErrTxNotWritable {
   570  			t.Fatalf("unexpected error: %s", err)
   571  		}
   572  		return nil
   573  	}); err != nil {
   574  		t.Fatal(err)
   575  	}
   576  }
   577  
   578  // Ensure that a deleting value while the transaction is closed returns an error.
   579  func TestBucket_Delete_Closed(t *testing.T) {
   580  	db := MustOpenDB()
   581  	defer db.MustClose()
   582  
   583  	tx, err := db.Begin(true)
   584  	if err != nil {
   585  		t.Fatal(err)
   586  	}
   587  
   588  	b, err := tx.CreateBucket([]byte("widgets"))
   589  	if err != nil {
   590  		t.Fatal(err)
   591  	}
   592  
   593  	if err := tx.Rollback(); err != nil {
   594  		t.Fatal(err)
   595  	}
   596  	if err := b.Delete([]byte("foo")); err != memcache.ErrTxClosed {
   597  		t.Fatalf("unexpected error: %s", err)
   598  	}
   599  }
   600  
   601  // Ensure that deleting a bucket causes nested buckets to be deleted.
   602  func TestBucket_DeleteBucket_Nested(t *testing.T) {
   603  	db := MustOpenDB()
   604  	defer db.MustClose()
   605  
   606  	if err := db.Update(func(tx *memcache.Tx) error {
   607  		widgets, err := tx.CreateBucket([]byte("widgets"))
   608  		if err != nil {
   609  			t.Fatal(err)
   610  		}
   611  
   612  		foo, err := widgets.CreateBucket([]byte("foo"))
   613  		if err != nil {
   614  			t.Fatal(err)
   615  		}
   616  
   617  		bar, err := foo.CreateBucket([]byte("bar"))
   618  		if err != nil {
   619  			t.Fatal(err)
   620  		}
   621  		if err := bar.Put([]byte("baz"), []byte("bat")); err != nil {
   622  			t.Fatal(err)
   623  		}
   624  		if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != nil {
   625  			t.Fatal(err)
   626  		}
   627  		return nil
   628  	}); err != nil {
   629  		t.Fatal(err)
   630  	}
   631  }
   632  
   633  // Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed.
   634  func TestBucket_DeleteBucket_Nested2(t *testing.T) {
   635  	db := MustOpenDB()
   636  	defer db.MustClose()
   637  
   638  	if err := db.Update(func(tx *memcache.Tx) error {
   639  		widgets, err := tx.CreateBucket([]byte("widgets"))
   640  		if err != nil {
   641  			t.Fatal(err)
   642  		}
   643  
   644  		foo, err := widgets.CreateBucket([]byte("foo"))
   645  		if err != nil {
   646  			t.Fatal(err)
   647  		}
   648  
   649  		bar, err := foo.CreateBucket([]byte("bar"))
   650  		if err != nil {
   651  			t.Fatal(err)
   652  		}
   653  
   654  		if err := bar.Put([]byte("baz"), []byte("bat")); err != nil {
   655  			t.Fatal(err)
   656  		}
   657  		return nil
   658  	}); err != nil {
   659  		t.Fatal(err)
   660  	}
   661  
   662  	if err := db.Update(func(tx *memcache.Tx) error {
   663  		widgets := tx.Bucket([]byte("widgets"))
   664  		if widgets == nil {
   665  			t.Fatal("expected widgets bucket")
   666  		}
   667  
   668  		foo := widgets.Bucket([]byte("foo"))
   669  		if foo == nil {
   670  			t.Fatal("expected foo bucket")
   671  		}
   672  
   673  		bar := foo.Bucket([]byte("bar"))
   674  		if bar == nil {
   675  			t.Fatal("expected bar bucket")
   676  		}
   677  
   678  		if v := bar.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
   679  			t.Fatalf("unexpected value: %v", v)
   680  		}
   681  		if err := tx.DeleteBucket([]byte("widgets")); err != nil {
   682  			t.Fatal(err)
   683  		}
   684  		return nil
   685  	}); err != nil {
   686  		t.Fatal(err)
   687  	}
   688  
   689  	if err := db.View(func(tx *memcache.Tx) error {
   690  		if tx.Bucket([]byte("widgets")) != nil {
   691  			t.Fatal("expected bucket to be deleted")
   692  		}
   693  		return nil
   694  	}); err != nil {
   695  		t.Fatal(err)
   696  	}
   697  }
   698  
   699  // Ensure that deleting a child bucket with multiple pages causes all pages to get collected.
   700  // NOTE: Consistency check in memcache_test.DB.Close() will panic if pages not freed properly.
   701  func TestBucket_DeleteBucket_Large(t *testing.T) {
   702  	db := MustOpenDB()
   703  	defer db.MustClose()
   704  
   705  	if err := db.Update(func(tx *memcache.Tx) error {
   706  		widgets, err := tx.CreateBucket([]byte("widgets"))
   707  		if err != nil {
   708  			t.Fatal(err)
   709  		}
   710  
   711  		foo, err := widgets.CreateBucket([]byte("foo"))
   712  		if err != nil {
   713  			t.Fatal(err)
   714  		}
   715  
   716  		for i := 0; i < 1000; i++ {
   717  			if err := foo.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))); err != nil {
   718  				t.Fatal(err)
   719  			}
   720  		}
   721  		return nil
   722  	}); err != nil {
   723  		t.Fatal(err)
   724  	}
   725  
   726  	if err := db.Update(func(tx *memcache.Tx) error {
   727  		if err := tx.DeleteBucket([]byte("widgets")); err != nil {
   728  			t.Fatal(err)
   729  		}
   730  		return nil
   731  	}); err != nil {
   732  		t.Fatal(err)
   733  	}
   734  }
   735  
   736  // Ensure that a simple value retrieved via Bucket() returns a nil.
   737  func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
   738  	db := MustOpenDB()
   739  	defer db.MustClose()
   740  
   741  	if err := db.Update(func(tx *memcache.Tx) error {
   742  		widgets, err := tx.CreateBucket([]byte("widgets"))
   743  		if err != nil {
   744  			t.Fatal(err)
   745  		}
   746  
   747  		if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
   748  			t.Fatal(err)
   749  		}
   750  		if b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo")); b != nil {
   751  			t.Fatal("expected nil bucket")
   752  		}
   753  		return nil
   754  	}); err != nil {
   755  		t.Fatal(err)
   756  	}
   757  }
   758  
   759  // Ensure that creating a bucket on an existing non-bucket key returns an error.
   760  func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
   761  	db := MustOpenDB()
   762  	defer db.MustClose()
   763  	if err := db.Update(func(tx *memcache.Tx) error {
   764  		widgets, err := tx.CreateBucket([]byte("widgets"))
   765  		if err != nil {
   766  			t.Fatal(err)
   767  		}
   768  
   769  		if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
   770  			t.Fatal(err)
   771  		}
   772  		if _, err := widgets.CreateBucket([]byte("foo")); err != memcache.ErrIncompatibleValue {
   773  			t.Fatalf("unexpected error: %s", err)
   774  		}
   775  		return nil
   776  	}); err != nil {
   777  		t.Fatal(err)
   778  	}
   779  }
   780  
   781  // Ensure that deleting a bucket on an existing non-bucket key returns an error.
   782  func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
   783  	db := MustOpenDB()
   784  	defer db.MustClose()
   785  
   786  	if err := db.Update(func(tx *memcache.Tx) error {
   787  		widgets, err := tx.CreateBucket([]byte("widgets"))
   788  		if err != nil {
   789  			t.Fatal(err)
   790  		}
   791  		if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
   792  			t.Fatal(err)
   793  		}
   794  		if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != memcache.ErrIncompatibleValue {
   795  			t.Fatalf("unexpected error: %s", err)
   796  		}
   797  		return nil
   798  	}); err != nil {
   799  		t.Fatal(err)
   800  	}
   801  }
   802  
   803  // Ensure bucket can set and update its sequence number.
   804  func TestBucket_Sequence(t *testing.T) {
   805  	db := MustOpenDB()
   806  	defer db.MustClose()
   807  
   808  	if err := db.Update(func(tx *memcache.Tx) error {
   809  		bkt, err := tx.CreateBucket([]byte("0"))
   810  		if err != nil {
   811  			t.Fatal(err)
   812  		}
   813  
   814  		// Retrieve sequence.
   815  		if v := bkt.Sequence(); v != 0 {
   816  			t.Fatalf("unexpected sequence: %d", v)
   817  		}
   818  
   819  		// Update sequence.
   820  		if err := bkt.SetSequence(1000); err != nil {
   821  			t.Fatal(err)
   822  		}
   823  
   824  		// Read sequence again.
   825  		if v := bkt.Sequence(); v != 1000 {
   826  			t.Fatalf("unexpected sequence: %d", v)
   827  		}
   828  
   829  		return nil
   830  	}); err != nil {
   831  		t.Fatal(err)
   832  	}
   833  
   834  	// Verify sequence in separate transaction.
   835  	if err := db.View(func(tx *memcache.Tx) error {
   836  		if v := tx.Bucket([]byte("0")).Sequence(); v != 1000 {
   837  			t.Fatalf("unexpected sequence: %d", v)
   838  		}
   839  		return nil
   840  	}); err != nil {
   841  		t.Fatal(err)
   842  	}
   843  }
   844  
   845  // Ensure that a bucket can return an autoincrementing sequence.
   846  func TestBucket_NextSequence(t *testing.T) {
   847  	db := MustOpenDB()
   848  	defer db.MustClose()
   849  
   850  	if err := db.Update(func(tx *memcache.Tx) error {
   851  		widgets, err := tx.CreateBucket([]byte("widgets"))
   852  		if err != nil {
   853  			t.Fatal(err)
   854  		}
   855  		woojits, err := tx.CreateBucket([]byte("woojits"))
   856  		if err != nil {
   857  			t.Fatal(err)
   858  		}
   859  
   860  		// Make sure sequence increments.
   861  		if seq, err := widgets.NextSequence(); err != nil {
   862  			t.Fatal(err)
   863  		} else if seq != 1 {
   864  			t.Fatalf("unexpecte sequence: %d", seq)
   865  		}
   866  
   867  		if seq, err := widgets.NextSequence(); err != nil {
   868  			t.Fatal(err)
   869  		} else if seq != 2 {
   870  			t.Fatalf("unexpected sequence: %d", seq)
   871  		}
   872  
   873  		// Buckets should be separate.
   874  		if seq, err := woojits.NextSequence(); err != nil {
   875  			t.Fatal(err)
   876  		} else if seq != 1 {
   877  			t.Fatalf("unexpected sequence: %d", 1)
   878  		}
   879  
   880  		return nil
   881  	}); err != nil {
   882  		t.Fatal(err)
   883  	}
   884  }
   885  
   886  // Ensure that a bucket will persist an autoincrementing sequence even if its
   887  // the only thing updated on the bucket.
   888  func TestBucket_NextSequence_Persist(t *testing.T) {
   889  	db := MustOpenDB()
   890  	defer db.MustClose()
   891  
   892  	if err := db.Update(func(tx *memcache.Tx) error {
   893  		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
   894  			t.Fatal(err)
   895  		}
   896  		return nil
   897  	}); err != nil {
   898  		t.Fatal(err)
   899  	}
   900  
   901  	if err := db.Update(func(tx *memcache.Tx) error {
   902  		if _, err := tx.Bucket([]byte("widgets")).NextSequence(); err != nil {
   903  			t.Fatal(err)
   904  		}
   905  		return nil
   906  	}); err != nil {
   907  		t.Fatal(err)
   908  	}
   909  
   910  	if err := db.Update(func(tx *memcache.Tx) error {
   911  		seq, err := tx.Bucket([]byte("widgets")).NextSequence()
   912  		if err != nil {
   913  			t.Fatalf("unexpected error: %s", err)
   914  		} else if seq != 2 {
   915  			t.Fatalf("unexpected sequence: %d", seq)
   916  		}
   917  		return nil
   918  	}); err != nil {
   919  		t.Fatal(err)
   920  	}
   921  }
   922  
   923  // Ensure that retrieving the next sequence on a read-only bucket returns an error.
   924  func TestBucket_NextSequence_ReadOnly(t *testing.T) {
   925  	db := MustOpenDB()
   926  	defer db.MustClose()
   927  
   928  	if err := db.Update(func(tx *memcache.Tx) error {
   929  		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
   930  			t.Fatal(err)
   931  		}
   932  		return nil
   933  	}); err != nil {
   934  		t.Fatal(err)
   935  	}
   936  
   937  	if err := db.View(func(tx *memcache.Tx) error {
   938  		_, err := tx.Bucket([]byte("widgets")).NextSequence()
   939  		if err != memcache.ErrTxNotWritable {
   940  			t.Fatalf("unexpected error: %s", err)
   941  		}
   942  		return nil
   943  	}); err != nil {
   944  		t.Fatal(err)
   945  	}
   946  }
   947  
   948  // Ensure that retrieving the next sequence for a bucket on a closed database return an error.
   949  func TestBucket_NextSequence_Closed(t *testing.T) {
   950  	db := MustOpenDB()
   951  	defer db.MustClose()
   952  	tx, err := db.Begin(true)
   953  	if err != nil {
   954  		t.Fatal(err)
   955  	}
   956  	b, err := tx.CreateBucket([]byte("widgets"))
   957  	if err != nil {
   958  		t.Fatal(err)
   959  	}
   960  	if err := tx.Rollback(); err != nil {
   961  		t.Fatal(err)
   962  	}
   963  	if _, err := b.NextSequence(); err != memcache.ErrTxClosed {
   964  		t.Fatal(err)
   965  	}
   966  }
   967  
   968  // Ensure a user can loop over all key/value pairs in a bucket.
   969  func TestBucket_ForEach(t *testing.T) {
   970  	db := MustOpenDB()
   971  	defer db.MustClose()
   972  
   973  	if err := db.Update(func(tx *memcache.Tx) error {
   974  		b, err := tx.CreateBucket([]byte("widgets"))
   975  		if err != nil {
   976  			t.Fatal(err)
   977  		}
   978  		if err := b.Put([]byte("foo"), []byte("0000")); err != nil {
   979  			t.Fatal(err)
   980  		}
   981  		if err := b.Put([]byte("baz"), []byte("0001")); err != nil {
   982  			t.Fatal(err)
   983  		}
   984  		if err := b.Put([]byte("bar"), []byte("0002")); err != nil {
   985  			t.Fatal(err)
   986  		}
   987  
   988  		var index int
   989  		if err := b.ForEach(func(k, v []byte) error {
   990  			switch index {
   991  			case 0:
   992  				if !bytes.Equal(k, []byte("bar")) {
   993  					t.Fatalf("unexpected key: %v", k)
   994  				} else if !bytes.Equal(v, []byte("0002")) {
   995  					t.Fatalf("unexpected value: %v", v)
   996  				}
   997  			case 1:
   998  				if !bytes.Equal(k, []byte("baz")) {
   999  					t.Fatalf("unexpected key: %v", k)
  1000  				} else if !bytes.Equal(v, []byte("0001")) {
  1001  					t.Fatalf("unexpected value: %v", v)
  1002  				}
  1003  			case 2:
  1004  				if !bytes.Equal(k, []byte("foo")) {
  1005  					t.Fatalf("unexpected key: %v", k)
  1006  				} else if !bytes.Equal(v, []byte("0000")) {
  1007  					t.Fatalf("unexpected value: %v", v)
  1008  				}
  1009  			}
  1010  			index++
  1011  			return nil
  1012  		}); err != nil {
  1013  			t.Fatal(err)
  1014  		}
  1015  
  1016  		if index != 3 {
  1017  			t.Fatalf("unexpected index: %d", index)
  1018  		}
  1019  
  1020  		return nil
  1021  	}); err != nil {
  1022  		t.Fatal(err)
  1023  	}
  1024  }
  1025  
  1026  // Ensure a database can stop iteration early.
  1027  func TestBucket_ForEach_ShortCircuit(t *testing.T) {
  1028  	db := MustOpenDB()
  1029  	defer db.MustClose()
  1030  	if err := db.Update(func(tx *memcache.Tx) error {
  1031  		b, err := tx.CreateBucket([]byte("widgets"))
  1032  		if err != nil {
  1033  			t.Fatal(err)
  1034  		}
  1035  		if err := b.Put([]byte("bar"), []byte("0000")); err != nil {
  1036  			t.Fatal(err)
  1037  		}
  1038  		if err := b.Put([]byte("baz"), []byte("0000")); err != nil {
  1039  			t.Fatal(err)
  1040  		}
  1041  		if err := b.Put([]byte("foo"), []byte("0000")); err != nil {
  1042  			t.Fatal(err)
  1043  		}
  1044  
  1045  		var index int
  1046  		if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
  1047  			index++
  1048  			if bytes.Equal(k, []byte("baz")) {
  1049  				return errors.New("marker")
  1050  			}
  1051  			return nil
  1052  		}); err == nil || err.Error() != "marker" {
  1053  			t.Fatalf("unexpected error: %s", err)
  1054  		}
  1055  		if index != 2 {
  1056  			t.Fatalf("unexpected index: %d", index)
  1057  		}
  1058  
  1059  		return nil
  1060  	}); err != nil {
  1061  		t.Fatal(err)
  1062  	}
  1063  }
  1064  
  1065  // Ensure that looping over a bucket on a closed database returns an error.
  1066  func TestBucket_ForEach_Closed(t *testing.T) {
  1067  	db := MustOpenDB()
  1068  	defer db.MustClose()
  1069  
  1070  	tx, err := db.Begin(true)
  1071  	if err != nil {
  1072  		t.Fatal(err)
  1073  	}
  1074  
  1075  	b, err := tx.CreateBucket([]byte("widgets"))
  1076  	if err != nil {
  1077  		t.Fatal(err)
  1078  	}
  1079  
  1080  	if err := tx.Rollback(); err != nil {
  1081  		t.Fatal(err)
  1082  	}
  1083  
  1084  	if err := b.ForEach(func(k, v []byte) error { return nil }); err != memcache.ErrTxClosed {
  1085  		t.Fatalf("unexpected error: %s", err)
  1086  	}
  1087  }
  1088  
  1089  // Ensure that an error is returned when inserting with an empty key.
  1090  func TestBucket_Put_EmptyKey(t *testing.T) {
  1091  	db := MustOpenDB()
  1092  	defer db.MustClose()
  1093  
  1094  	if err := db.Update(func(tx *memcache.Tx) error {
  1095  		b, err := tx.CreateBucket([]byte("widgets"))
  1096  		if err != nil {
  1097  			t.Fatal(err)
  1098  		}
  1099  		if err := b.Put([]byte(""), []byte("bar")); err != memcache.ErrKeyRequired {
  1100  			t.Fatalf("unexpected error: %s", err)
  1101  		}
  1102  		if err := b.Put(nil, []byte("bar")); err != memcache.ErrKeyRequired {
  1103  			t.Fatalf("unexpected error: %s", err)
  1104  		}
  1105  		return nil
  1106  	}); err != nil {
  1107  		t.Fatal(err)
  1108  	}
  1109  }
  1110  
  1111  // Ensure that an error is returned when inserting with a key that's too large.
  1112  func TestBucket_Put_KeyTooLarge(t *testing.T) {
  1113  	db := MustOpenDB()
  1114  	defer db.MustClose()
  1115  	if err := db.Update(func(tx *memcache.Tx) error {
  1116  		b, err := tx.CreateBucket([]byte("widgets"))
  1117  		if err != nil {
  1118  			t.Fatal(err)
  1119  		}
  1120  		if err := b.Put(make([]byte, 32769), []byte("bar")); err != memcache.ErrKeyTooLarge {
  1121  			t.Fatalf("unexpected error: %s", err)
  1122  		}
  1123  		return nil
  1124  	}); err != nil {
  1125  		t.Fatal(err)
  1126  	}
  1127  }
  1128  
  1129  // Ensure that an error is returned when inserting a value that's too large.
  1130  func TestBucket_Put_ValueTooLarge(t *testing.T) {
  1131  	// Skip this test on DroneCI because the machine is resource constrained.
  1132  	if os.Getenv("DRONE") == "true" {
  1133  		t.Skip("not enough RAM for test")
  1134  	}
  1135  
  1136  	db := MustOpenDB()
  1137  	defer db.MustClose()
  1138  
  1139  	if err := db.Update(func(tx *memcache.Tx) error {
  1140  		b, err := tx.CreateBucket([]byte("widgets"))
  1141  		if err != nil {
  1142  			t.Fatal(err)
  1143  		}
  1144  		if err := b.Put([]byte("foo"), make([]byte, memcache.MaxValueSize+1)); err != memcache.ErrValueTooLarge {
  1145  			t.Fatalf("unexpected error: %s", err)
  1146  		}
  1147  		return nil
  1148  	}); err != nil {
  1149  		t.Fatal(err)
  1150  	}
  1151  }
  1152  
  1153  // Ensure a bucket can calculate stats.
  1154  func TestBucket_Stats(t *testing.T) {
  1155  	db := MustOpenDB()
  1156  	defer db.MustClose()
  1157  
  1158  	// Add bucket with fewer keys but one big value.
  1159  	bigKey := []byte("really-big-value")
  1160  	for i := 0; i < 500; i++ {
  1161  		if err := db.Update(func(tx *memcache.Tx) error {
  1162  			b, err := tx.CreateBucketIfNotExists([]byte("woojits"))
  1163  			if err != nil {
  1164  				t.Fatal(err)
  1165  			}
  1166  
  1167  			if err := b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))); err != nil {
  1168  				t.Fatal(err)
  1169  			}
  1170  			return nil
  1171  		}); err != nil {
  1172  			t.Fatal(err)
  1173  		}
  1174  	}
  1175  	if err := db.Update(func(tx *memcache.Tx) error {
  1176  		if err := tx.Bucket([]byte("woojits")).Put(bigKey, []byte(strings.Repeat("*", 10000))); err != nil {
  1177  			t.Fatal(err)
  1178  		}
  1179  		return nil
  1180  	}); err != nil {
  1181  		t.Fatal(err)
  1182  	}
  1183  
  1184  	db.MustCheck()
  1185  
  1186  	if err := db.View(func(tx *memcache.Tx) error {
  1187  		stats := tx.Bucket([]byte("woojits")).Stats()
  1188  		if stats.BranchPageN != 1 {
  1189  			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
  1190  		} else if stats.BranchOverflowN != 0 {
  1191  			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
  1192  		} else if stats.LeafPageN != 7 {
  1193  			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
  1194  		} else if stats.LeafOverflowN != 2 {
  1195  			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
  1196  		} else if stats.KeyN != 501 {
  1197  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
  1198  		} else if stats.Depth != 2 {
  1199  			t.Fatalf("unexpected Depth: %d", stats.Depth)
  1200  		}
  1201  
  1202  		branchInuse := 16     // branch page header
  1203  		branchInuse += 7 * 16 // branch elements
  1204  		branchInuse += 7 * 3  // branch keys (6 3-byte keys)
  1205  		if stats.BranchInuse != branchInuse {
  1206  			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
  1207  		}
  1208  
  1209  		leafInuse := 7 * 16                      // leaf page header
  1210  		leafInuse += 501 * 16                    // leaf elements
  1211  		leafInuse += 500*3 + len(bigKey)         // leaf keys
  1212  		leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values
  1213  		if stats.LeafInuse != leafInuse {
  1214  			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
  1215  		}
  1216  
  1217  		// Only check allocations for 4KB pages.
  1218  		if os.Getpagesize() == 4096 {
  1219  			if stats.BranchAlloc != 4096 {
  1220  				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
  1221  			} else if stats.LeafAlloc != 36864 {
  1222  				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
  1223  			}
  1224  		}
  1225  
  1226  		if stats.BucketN != 1 {
  1227  			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
  1228  		} else if stats.InlineBucketN != 0 {
  1229  			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
  1230  		} else if stats.InlineBucketInuse != 0 {
  1231  			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
  1232  		}
  1233  
  1234  		return nil
  1235  	}); err != nil {
  1236  		t.Fatal(err)
  1237  	}
  1238  }
  1239  
  1240  // Ensure a bucket with random insertion utilizes fill percentage correctly.
  1241  func TestBucket_Stats_RandomFill(t *testing.T) {
  1242  	if testing.Short() {
  1243  		t.Skip("skipping test in short mode.")
  1244  	} else if os.Getpagesize() != 4096 {
  1245  		t.Skip("invalid page size for test")
  1246  	}
  1247  
  1248  	db := MustOpenDB()
  1249  	defer db.MustClose()
  1250  
  1251  	// Add a set of values in random order. It will be the same random
  1252  	// order so we can maintain consistency between test runs.
  1253  	var count int
  1254  	rand := rand.New(rand.NewSource(42))
  1255  	for _, i := range rand.Perm(1000) {
  1256  		if err := db.Update(func(tx *memcache.Tx) error {
  1257  			b, err := tx.CreateBucketIfNotExists([]byte("woojits"))
  1258  			if err != nil {
  1259  				t.Fatal(err)
  1260  			}
  1261  			b.FillPercent = 0.9
  1262  			for _, j := range rand.Perm(100) {
  1263  				index := (j * 10000) + i
  1264  				if err := b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000")); err != nil {
  1265  					t.Fatal(err)
  1266  				}
  1267  				count++
  1268  			}
  1269  			return nil
  1270  		}); err != nil {
  1271  			t.Fatal(err)
  1272  		}
  1273  	}
  1274  
  1275  	db.MustCheck()
  1276  
  1277  	if err := db.View(func(tx *memcache.Tx) error {
  1278  		stats := tx.Bucket([]byte("woojits")).Stats()
  1279  		if stats.KeyN != 100000 {
  1280  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
  1281  		}
  1282  
  1283  		if stats.BranchPageN != 98 {
  1284  			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
  1285  		} else if stats.BranchOverflowN != 0 {
  1286  			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
  1287  		} else if stats.BranchInuse != 130984 {
  1288  			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
  1289  		} else if stats.BranchAlloc != 401408 {
  1290  			t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
  1291  		}
  1292  
  1293  		if stats.LeafPageN != 3412 {
  1294  			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
  1295  		} else if stats.LeafOverflowN != 0 {
  1296  			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
  1297  		} else if stats.LeafInuse != 4742482 {
  1298  			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
  1299  		} else if stats.LeafAlloc != 13975552 {
  1300  			t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
  1301  		}
  1302  		return nil
  1303  	}); err != nil {
  1304  		t.Fatal(err)
  1305  	}
  1306  }
  1307  
  1308  // Ensure a bucket can calculate stats.
  1309  func TestBucket_Stats_Small(t *testing.T) {
  1310  	db := MustOpenDB()
  1311  	defer db.MustClose()
  1312  
  1313  	if err := db.Update(func(tx *memcache.Tx) error {
  1314  		// Add a bucket that fits on a single root leaf.
  1315  		b, err := tx.CreateBucket([]byte("whozawhats"))
  1316  		if err != nil {
  1317  			t.Fatal(err)
  1318  		}
  1319  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  1320  			t.Fatal(err)
  1321  		}
  1322  
  1323  		return nil
  1324  	}); err != nil {
  1325  		t.Fatal(err)
  1326  	}
  1327  
  1328  	db.MustCheck()
  1329  
  1330  	if err := db.View(func(tx *memcache.Tx) error {
  1331  		b := tx.Bucket([]byte("whozawhats"))
  1332  		stats := b.Stats()
  1333  		if stats.BranchPageN != 0 {
  1334  			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
  1335  		} else if stats.BranchOverflowN != 0 {
  1336  			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
  1337  		} else if stats.LeafPageN != 0 {
  1338  			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
  1339  		} else if stats.LeafOverflowN != 0 {
  1340  			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
  1341  		} else if stats.KeyN != 1 {
  1342  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
  1343  		} else if stats.Depth != 1 {
  1344  			t.Fatalf("unexpected Depth: %d", stats.Depth)
  1345  		} else if stats.BranchInuse != 0 {
  1346  			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
  1347  		} else if stats.LeafInuse != 0 {
  1348  			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
  1349  		}
  1350  
  1351  		if os.Getpagesize() == 4096 {
  1352  			if stats.BranchAlloc != 0 {
  1353  				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
  1354  			} else if stats.LeafAlloc != 0 {
  1355  				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
  1356  			}
  1357  		}
  1358  
  1359  		if stats.BucketN != 1 {
  1360  			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
  1361  		} else if stats.InlineBucketN != 1 {
  1362  			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
  1363  		} else if stats.InlineBucketInuse != 16+16+6 {
  1364  			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
  1365  		}
  1366  
  1367  		return nil
  1368  	}); err != nil {
  1369  		t.Fatal(err)
  1370  	}
  1371  }
  1372  
  1373  func TestBucket_Stats_EmptyBucket(t *testing.T) {
  1374  	db := MustOpenDB()
  1375  	defer db.MustClose()
  1376  
  1377  	if err := db.Update(func(tx *memcache.Tx) error {
  1378  		// Add a bucket that fits on a single root leaf.
  1379  		if _, err := tx.CreateBucket([]byte("whozawhats")); err != nil {
  1380  			t.Fatal(err)
  1381  		}
  1382  		return nil
  1383  	}); err != nil {
  1384  		t.Fatal(err)
  1385  	}
  1386  
  1387  	db.MustCheck()
  1388  
  1389  	if err := db.View(func(tx *memcache.Tx) error {
  1390  		b := tx.Bucket([]byte("whozawhats"))
  1391  		stats := b.Stats()
  1392  		if stats.BranchPageN != 0 {
  1393  			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
  1394  		} else if stats.BranchOverflowN != 0 {
  1395  			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
  1396  		} else if stats.LeafPageN != 0 {
  1397  			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
  1398  		} else if stats.LeafOverflowN != 0 {
  1399  			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
  1400  		} else if stats.KeyN != 0 {
  1401  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
  1402  		} else if stats.Depth != 1 {
  1403  			t.Fatalf("unexpected Depth: %d", stats.Depth)
  1404  		} else if stats.BranchInuse != 0 {
  1405  			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
  1406  		} else if stats.LeafInuse != 0 {
  1407  			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
  1408  		}
  1409  
  1410  		if os.Getpagesize() == 4096 {
  1411  			if stats.BranchAlloc != 0 {
  1412  				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
  1413  			} else if stats.LeafAlloc != 0 {
  1414  				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
  1415  			}
  1416  		}
  1417  
  1418  		if stats.BucketN != 1 {
  1419  			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
  1420  		} else if stats.InlineBucketN != 1 {
  1421  			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
  1422  		} else if stats.InlineBucketInuse != 16 {
  1423  			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
  1424  		}
  1425  
  1426  		return nil
  1427  	}); err != nil {
  1428  		t.Fatal(err)
  1429  	}
  1430  }
  1431  
  1432  // Ensure a bucket can calculate stats.
  1433  func TestBucket_Stats_Nested(t *testing.T) {
  1434  	db := MustOpenDB()
  1435  	defer db.MustClose()
  1436  
  1437  	if err := db.Update(func(tx *memcache.Tx) error {
  1438  		b, err := tx.CreateBucket([]byte("foo"))
  1439  		if err != nil {
  1440  			t.Fatal(err)
  1441  		}
  1442  		for i := 0; i < 100; i++ {
  1443  			if err := b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i))); err != nil {
  1444  				t.Fatal(err)
  1445  			}
  1446  		}
  1447  
  1448  		bar, err := b.CreateBucket([]byte("bar"))
  1449  		if err != nil {
  1450  			t.Fatal(err)
  1451  		}
  1452  		for i := 0; i < 10; i++ {
  1453  			if err := bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
  1454  				t.Fatal(err)
  1455  			}
  1456  		}
  1457  
  1458  		baz, err := bar.CreateBucket([]byte("baz"))
  1459  		if err != nil {
  1460  			t.Fatal(err)
  1461  		}
  1462  		for i := 0; i < 10; i++ {
  1463  			if err := baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
  1464  				t.Fatal(err)
  1465  			}
  1466  		}
  1467  
  1468  		return nil
  1469  	}); err != nil {
  1470  		t.Fatal(err)
  1471  	}
  1472  
  1473  	db.MustCheck()
  1474  
  1475  	if err := db.View(func(tx *memcache.Tx) error {
  1476  		b := tx.Bucket([]byte("foo"))
  1477  		stats := b.Stats()
  1478  		if stats.BranchPageN != 0 {
  1479  			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
  1480  		} else if stats.BranchOverflowN != 0 {
  1481  			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
  1482  		} else if stats.LeafPageN != 2 {
  1483  			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
  1484  		} else if stats.LeafOverflowN != 0 {
  1485  			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
  1486  		} else if stats.KeyN != 122 {
  1487  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
  1488  		} else if stats.Depth != 3 {
  1489  			t.Fatalf("unexpected Depth: %d", stats.Depth)
  1490  		} else if stats.BranchInuse != 0 {
  1491  			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
  1492  		}
  1493  
  1494  		foo := 16            // foo (pghdr)
  1495  		foo += 101 * 16      // foo leaf elements
  1496  		foo += 100*2 + 100*2 // foo leaf key/values
  1497  		foo += 3 + 16        // foo -> bar key/value
  1498  
  1499  		bar := 16      // bar (pghdr)
  1500  		bar += 11 * 16 // bar leaf elements
  1501  		bar += 10 + 10 // bar leaf key/values
  1502  		bar += 3 + 16  // bar -> baz key/value
  1503  
  1504  		baz := 16      // baz (inline) (pghdr)
  1505  		baz += 10 * 16 // baz leaf elements
  1506  		baz += 10 + 10 // baz leaf key/values
  1507  
  1508  		if stats.LeafInuse != foo+bar+baz {
  1509  			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
  1510  		}
  1511  
  1512  		if os.Getpagesize() == 4096 {
  1513  			if stats.BranchAlloc != 0 {
  1514  				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
  1515  			} else if stats.LeafAlloc != 8192 {
  1516  				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
  1517  			}
  1518  		}
  1519  
  1520  		if stats.BucketN != 3 {
  1521  			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
  1522  		} else if stats.InlineBucketN != 1 {
  1523  			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
  1524  		} else if stats.InlineBucketInuse != baz {
  1525  			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
  1526  		}
  1527  
  1528  		return nil
  1529  	}); err != nil {
  1530  		t.Fatal(err)
  1531  	}
  1532  }
  1533  
  1534  // Ensure a large bucket can calculate stats.
  1535  func TestBucket_Stats_Large(t *testing.T) {
  1536  	if testing.Short() {
  1537  		t.Skip("skipping test in short mode.")
  1538  	}
  1539  
  1540  	db := MustOpenDB()
  1541  	defer db.MustClose()
  1542  
  1543  	var index int
  1544  	for i := 0; i < 100; i++ {
  1545  		// Add bucket with lots of keys.
  1546  		if err := db.Update(func(tx *memcache.Tx) error {
  1547  			b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
  1548  			if err != nil {
  1549  				t.Fatal(err)
  1550  			}
  1551  			for i := 0; i < 1000; i++ {
  1552  				if err := b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index))); err != nil {
  1553  					t.Fatal(err)
  1554  				}
  1555  				index++
  1556  			}
  1557  			return nil
  1558  		}); err != nil {
  1559  			t.Fatal(err)
  1560  		}
  1561  	}
  1562  
  1563  	db.MustCheck()
  1564  
  1565  	if err := db.View(func(tx *memcache.Tx) error {
  1566  		stats := tx.Bucket([]byte("widgets")).Stats()
  1567  		if stats.BranchPageN != 13 {
  1568  			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
  1569  		} else if stats.BranchOverflowN != 0 {
  1570  			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
  1571  		} else if stats.LeafPageN != 1196 {
  1572  			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
  1573  		} else if stats.LeafOverflowN != 0 {
  1574  			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
  1575  		} else if stats.KeyN != 100000 {
  1576  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
  1577  		} else if stats.Depth != 3 {
  1578  			t.Fatalf("unexpected Depth: %d", stats.Depth)
  1579  		} else if stats.BranchInuse != 25257 {
  1580  			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
  1581  		} else if stats.LeafInuse != 2596916 {
  1582  			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
  1583  		}
  1584  
  1585  		if os.Getpagesize() == 4096 {
  1586  			if stats.BranchAlloc != 53248 {
  1587  				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
  1588  			} else if stats.LeafAlloc != 4898816 {
  1589  				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
  1590  			}
  1591  		}
  1592  
  1593  		if stats.BucketN != 1 {
  1594  			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
  1595  		} else if stats.InlineBucketN != 0 {
  1596  			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
  1597  		} else if stats.InlineBucketInuse != 0 {
  1598  			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
  1599  		}
  1600  
  1601  		return nil
  1602  	}); err != nil {
  1603  		t.Fatal(err)
  1604  	}
  1605  }
  1606  
  1607  // Ensure that a bucket can write random keys and values across multiple transactions.
  1608  func TestBucket_Put_Single(t *testing.T) {
  1609  	if testing.Short() {
  1610  		t.Skip("skipping test in short mode.")
  1611  	}
  1612  
  1613  	index := 0
  1614  	if err := quick.Check(func(items testdata) bool {
  1615  		db := MustOpenDB()
  1616  		defer db.MustClose()
  1617  
  1618  		m := make(map[string][]byte)
  1619  
  1620  		if err := db.Update(func(tx *memcache.Tx) error {
  1621  			if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  1622  				t.Fatal(err)
  1623  			}
  1624  			return nil
  1625  		}); err != nil {
  1626  			t.Fatal(err)
  1627  		}
  1628  
  1629  		for _, item := range items {
  1630  			if err := db.Update(func(tx *memcache.Tx) error {
  1631  				if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil {
  1632  					panic("put error: " + err.Error())
  1633  				}
  1634  				m[string(item.Key)] = item.Value
  1635  				return nil
  1636  			}); err != nil {
  1637  				t.Fatal(err)
  1638  			}
  1639  
  1640  			// Verify all key/values so far.
  1641  			if err := db.View(func(tx *memcache.Tx) error {
  1642  				i := 0
  1643  				for k, v := range m {
  1644  					value := tx.Bucket([]byte("widgets")).Get([]byte(k))
  1645  					if !bytes.Equal(value, v) {
  1646  						t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v)
  1647  						db.CopyTempFile()
  1648  						t.FailNow()
  1649  					}
  1650  					i++
  1651  				}
  1652  				return nil
  1653  			}); err != nil {
  1654  				t.Fatal(err)
  1655  			}
  1656  		}
  1657  
  1658  		index++
  1659  		return true
  1660  	}, nil); err != nil {
  1661  		t.Error(err)
  1662  	}
  1663  }
  1664  
  1665  // Ensure that a transaction can insert multiple key/value pairs at once.
  1666  func TestBucket_Put_Multiple(t *testing.T) {
  1667  	if testing.Short() {
  1668  		t.Skip("skipping test in short mode.")
  1669  	}
  1670  
  1671  	if err := quick.Check(func(items testdata) bool {
  1672  		db := MustOpenDB()
  1673  		defer db.MustClose()
  1674  
  1675  		// Bulk insert all values.
  1676  		if err := db.Update(func(tx *memcache.Tx) error {
  1677  			if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  1678  				t.Fatal(err)
  1679  			}
  1680  			return nil
  1681  		}); err != nil {
  1682  			t.Fatal(err)
  1683  		}
  1684  
  1685  		if err := db.Update(func(tx *memcache.Tx) error {
  1686  			b := tx.Bucket([]byte("widgets"))
  1687  			for _, item := range items {
  1688  				if err := b.Put(item.Key, item.Value); err != nil {
  1689  					t.Fatal(err)
  1690  				}
  1691  			}
  1692  			return nil
  1693  		}); err != nil {
  1694  			t.Fatal(err)
  1695  		}
  1696  
  1697  		// Verify all items exist.
  1698  		if err := db.View(func(tx *memcache.Tx) error {
  1699  			b := tx.Bucket([]byte("widgets"))
  1700  			for _, item := range items {
  1701  				value := b.Get(item.Key)
  1702  				if !bytes.Equal(item.Value, value) {
  1703  					db.CopyTempFile()
  1704  					t.Fatalf("exp=%x; got=%x", item.Value, value)
  1705  				}
  1706  			}
  1707  			return nil
  1708  		}); err != nil {
  1709  			t.Fatal(err)
  1710  		}
  1711  
  1712  		return true
  1713  	}, qconfig()); err != nil {
  1714  		t.Error(err)
  1715  	}
  1716  }
  1717  
  1718  // Ensure that a transaction can delete all key/value pairs and return to a single leaf page.
  1719  func TestBucket_Delete_Quick(t *testing.T) {
  1720  	if testing.Short() {
  1721  		t.Skip("skipping test in short mode.")
  1722  	}
  1723  
  1724  	if err := quick.Check(func(items testdata) bool {
  1725  		db := MustOpenDB()
  1726  		defer db.MustClose()
  1727  
  1728  		// Bulk insert all values.
  1729  		if err := db.Update(func(tx *memcache.Tx) error {
  1730  			if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
  1731  				t.Fatal(err)
  1732  			}
  1733  			return nil
  1734  		}); err != nil {
  1735  			t.Fatal(err)
  1736  		}
  1737  
  1738  		if err := db.Update(func(tx *memcache.Tx) error {
  1739  			b := tx.Bucket([]byte("widgets"))
  1740  			for _, item := range items {
  1741  				if err := b.Put(item.Key, item.Value); err != nil {
  1742  					t.Fatal(err)
  1743  				}
  1744  			}
  1745  			return nil
  1746  		}); err != nil {
  1747  			t.Fatal(err)
  1748  		}
  1749  
  1750  		// Remove items one at a time and check consistency.
  1751  		for _, item := range items {
  1752  			if err := db.Update(func(tx *memcache.Tx) error {
  1753  				return tx.Bucket([]byte("widgets")).Delete(item.Key)
  1754  			}); err != nil {
  1755  				t.Fatal(err)
  1756  			}
  1757  		}
  1758  
  1759  		// Anything before our deletion index should be nil.
  1760  		if err := db.View(func(tx *memcache.Tx) error {
  1761  			if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
  1762  				t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3))
  1763  				return nil
  1764  			}); err != nil {
  1765  				t.Fatal(err)
  1766  			}
  1767  			return nil
  1768  		}); err != nil {
  1769  			t.Fatal(err)
  1770  		}
  1771  
  1772  		return true
  1773  	}, qconfig()); err != nil {
  1774  		t.Error(err)
  1775  	}
  1776  }
  1777  
  1778  func ExampleBucket_Put() {
  1779  	// Open the database.
  1780  	db, err := memcache.Open(tempfile(), 0666, nil)
  1781  	if err != nil {
  1782  		log.Fatal(err)
  1783  	}
  1784  	defer os.Remove(db.Path())
  1785  
  1786  	// Start a write transaction.
  1787  	if err := db.Update(func(tx *memcache.Tx) error {
  1788  		// Create a bucket.
  1789  		b, err := tx.CreateBucket([]byte("widgets"))
  1790  		if err != nil {
  1791  			return err
  1792  		}
  1793  
  1794  		// Set the value "bar" for the key "foo".
  1795  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  1796  			return err
  1797  		}
  1798  		return nil
  1799  	}); err != nil {
  1800  		log.Fatal(err)
  1801  	}
  1802  
  1803  	// Read value back in a different read-only transaction.
  1804  	if err := db.View(func(tx *memcache.Tx) error {
  1805  		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
  1806  		fmt.Printf("The value of 'foo' is: %s\n", value)
  1807  		return nil
  1808  	}); err != nil {
  1809  		log.Fatal(err)
  1810  	}
  1811  
  1812  	// Close database to release file lock.
  1813  	if err := db.Close(); err != nil {
  1814  		log.Fatal(err)
  1815  	}
  1816  
  1817  	// Output:
  1818  	// The value of 'foo' is: bar
  1819  }
  1820  
  1821  func ExampleBucket_Delete() {
  1822  	// Open the database.
  1823  	db, err := memcache.Open(tempfile(), 0666, nil)
  1824  	if err != nil {
  1825  		log.Fatal(err)
  1826  	}
  1827  	defer os.Remove(db.Path())
  1828  
  1829  	// Start a write transaction.
  1830  	if err := db.Update(func(tx *memcache.Tx) error {
  1831  		// Create a bucket.
  1832  		b, err := tx.CreateBucket([]byte("widgets"))
  1833  		if err != nil {
  1834  			return err
  1835  		}
  1836  
  1837  		// Set the value "bar" for the key "foo".
  1838  		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
  1839  			return err
  1840  		}
  1841  
  1842  		// Retrieve the key back from the database and verify it.
  1843  		value := b.Get([]byte("foo"))
  1844  		fmt.Printf("The value of 'foo' was: %s\n", value)
  1845  
  1846  		return nil
  1847  	}); err != nil {
  1848  		log.Fatal(err)
  1849  	}
  1850  
  1851  	// Delete the key in a different write transaction.
  1852  	if err := db.Update(func(tx *memcache.Tx) error {
  1853  		return tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
  1854  	}); err != nil {
  1855  		log.Fatal(err)
  1856  	}
  1857  
  1858  	// Retrieve the key again.
  1859  	if err := db.View(func(tx *memcache.Tx) error {
  1860  		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
  1861  		if value == nil {
  1862  			fmt.Printf("The value of 'foo' is now: nil\n")
  1863  		}
  1864  		return nil
  1865  	}); err != nil {
  1866  		log.Fatal(err)
  1867  	}
  1868  
  1869  	// Close database to release file lock.
  1870  	if err := db.Close(); err != nil {
  1871  		log.Fatal(err)
  1872  	}
  1873  
  1874  	// Output:
  1875  	// The value of 'foo' was: bar
  1876  	// The value of 'foo' is now: nil
  1877  }
  1878  
  1879  func ExampleBucket_ForEach() {
  1880  	// Open the database.
  1881  	db, err := memcache.Open(tempfile(), 0666, nil)
  1882  	if err != nil {
  1883  		log.Fatal(err)
  1884  	}
  1885  	defer os.Remove(db.Path())
  1886  
  1887  	// Insert data into a bucket.
  1888  	if err := db.Update(func(tx *memcache.Tx) error {
  1889  		b, err := tx.CreateBucket([]byte("animals"))
  1890  		if err != nil {
  1891  			return err
  1892  		}
  1893  
  1894  		if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
  1895  			return err
  1896  		}
  1897  		if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
  1898  			return err
  1899  		}
  1900  		if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
  1901  			return err
  1902  		}
  1903  
  1904  		// Iterate over items in sorted key order.
  1905  		if err := b.ForEach(func(k, v []byte) error {
  1906  			fmt.Printf("A %s is %s.\n", k, v)
  1907  			return nil
  1908  		}); err != nil {
  1909  			return err
  1910  		}
  1911  
  1912  		return nil
  1913  	}); err != nil {
  1914  		log.Fatal(err)
  1915  	}
  1916  
  1917  	// Close database to release file lock.
  1918  	if err := db.Close(); err != nil {
  1919  		log.Fatal(err)
  1920  	}
  1921  
  1922  	// Output:
  1923  	// A cat is lame.
  1924  	// A dog is fun.
  1925  	// A liger is awesome.
  1926  }