github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/cursor_test.go (about)

     1  // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors.
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package bdb_test
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"fmt"
    21  	"log"
    22  	"os"
    23  	"reflect"
    24  	"sort"
    25  	"testing"
    26  	"testing/quick"
    27  
    28  	"github.com/zuoyebang/bitalosdb/bitree/bdb"
    29  )
    30  
    31  func TestCursor_Bucket(t *testing.T) {
    32  	db := MustOpenDB()
    33  	defer db.MustClose()
    34  	if err := db.Update(func(tx *bdb.Tx) error {
    35  		b, err := tx.CreateBucket([]byte("widgets"))
    36  		if err != nil {
    37  			t.Fatal(err)
    38  		}
    39  		if cb := b.Cursor().Bucket(); !reflect.DeepEqual(cb, b) {
    40  			t.Fatal("cursor bucket mismatch")
    41  		}
    42  		return nil
    43  	}); err != nil {
    44  		t.Fatal(err)
    45  	}
    46  }
    47  
    48  func TestCursor_Seek(t *testing.T) {
    49  	db := MustOpenDB()
    50  	defer db.MustClose()
    51  	if err := db.Update(func(tx *bdb.Tx) error {
    52  		b, err := tx.CreateBucket([]byte("widgets"))
    53  		if err != nil {
    54  			t.Fatal(err)
    55  		}
    56  		if err := b.Put([]byte("foo"), []byte("0001")); err != nil {
    57  			t.Fatal(err)
    58  		}
    59  		if err := b.Put([]byte("bar"), []byte("0002")); err != nil {
    60  			t.Fatal(err)
    61  		}
    62  		if err := b.Put([]byte("baz"), []byte("0003")); err != nil {
    63  			t.Fatal(err)
    64  		}
    65  
    66  		if _, err := b.CreateBucket([]byte("bkt")); err != nil {
    67  			t.Fatal(err)
    68  		}
    69  		return nil
    70  	}); err != nil {
    71  		t.Fatal(err)
    72  	}
    73  
    74  	if err := db.View(func(tx *bdb.Tx) error {
    75  		c := tx.Bucket([]byte("widgets")).Cursor()
    76  
    77  		if k, v := c.Seek([]byte("bar")); !bytes.Equal(k, []byte("bar")) {
    78  			t.Fatalf("unexpected key: %v", k)
    79  		} else if !bytes.Equal(v, []byte("0002")) {
    80  			t.Fatalf("unexpected value: %v", v)
    81  		}
    82  
    83  		if k, v := c.Seek([]byte("bas")); !bytes.Equal(k, []byte("baz")) {
    84  			t.Fatalf("unexpected key: %v", k)
    85  		} else if !bytes.Equal(v, []byte("0003")) {
    86  			t.Fatalf("unexpected value: %v", v)
    87  		}
    88  
    89  		if k, v := c.Seek([]byte("")); !bytes.Equal(k, []byte("bar")) {
    90  			t.Fatalf("unexpected key: %v", k)
    91  		} else if !bytes.Equal(v, []byte("0002")) {
    92  			t.Fatalf("unexpected value: %v", v)
    93  		}
    94  
    95  		if k, v := c.Seek([]byte("zzz")); k != nil {
    96  			t.Fatalf("expected nil key: %v", k)
    97  		} else if v != nil {
    98  			t.Fatalf("expected nil value: %v", v)
    99  		}
   100  
   101  		if k, v := c.Seek([]byte("bkt")); !bytes.Equal(k, []byte("bkt")) {
   102  			t.Fatalf("unexpected key: %v", k)
   103  		} else if v != nil {
   104  			t.Fatalf("expected nil value: %v", v)
   105  		}
   106  
   107  		return nil
   108  	}); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  }
   112  
   113  func TestCursor_Delete(t *testing.T) {
   114  	db := MustOpenDB()
   115  	defer db.MustClose()
   116  
   117  	const count = 1000
   118  
   119  	if err := db.Update(func(tx *bdb.Tx) error {
   120  		b, err := tx.CreateBucket([]byte("widgets"))
   121  		if err != nil {
   122  			t.Fatal(err)
   123  		}
   124  		for i := 0; i < count; i += 1 {
   125  			k := make([]byte, 8)
   126  			binary.BigEndian.PutUint64(k, uint64(i))
   127  			if err := b.Put(k, make([]byte, 100)); err != nil {
   128  				t.Fatal(err)
   129  			}
   130  		}
   131  		if _, err := b.CreateBucket([]byte("sub")); err != nil {
   132  			t.Fatal(err)
   133  		}
   134  		return nil
   135  	}); err != nil {
   136  		t.Fatal(err)
   137  	}
   138  
   139  	if err := db.Update(func(tx *bdb.Tx) error {
   140  		c := tx.Bucket([]byte("widgets")).Cursor()
   141  		bound := make([]byte, 8)
   142  		binary.BigEndian.PutUint64(bound, uint64(count/2))
   143  		for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() {
   144  			if err := c.Delete(); err != nil {
   145  				t.Fatal(err)
   146  			}
   147  		}
   148  
   149  		c.Seek([]byte("sub"))
   150  		if err := c.Delete(); err != bdb.ErrIncompatibleValue {
   151  			t.Fatalf("unexpected error: %s", err)
   152  		}
   153  
   154  		return nil
   155  	}); err != nil {
   156  		t.Fatal(err)
   157  	}
   158  
   159  	if err := db.View(func(tx *bdb.Tx) error {
   160  		stats := tx.Bucket([]byte("widgets")).Stats()
   161  		if stats.KeyN != count/2+1 {
   162  			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
   163  		}
   164  		return nil
   165  	}); err != nil {
   166  		t.Fatal(err)
   167  	}
   168  }
   169  
   170  func TestCursor_Seek_Large(t *testing.T) {
   171  	db := MustOpenDB()
   172  	defer db.MustClose()
   173  
   174  	var count = 10000
   175  
   176  	if err := db.Update(func(tx *bdb.Tx) error {
   177  		b, err := tx.CreateBucket([]byte("widgets"))
   178  		if err != nil {
   179  			t.Fatal(err)
   180  		}
   181  
   182  		for i := 0; i < count; i += 100 {
   183  			for j := i; j < i+100; j += 2 {
   184  				k := make([]byte, 8)
   185  				binary.BigEndian.PutUint64(k, uint64(j))
   186  				if err := b.Put(k, make([]byte, 100)); err != nil {
   187  					t.Fatal(err)
   188  				}
   189  			}
   190  		}
   191  		return nil
   192  	}); err != nil {
   193  		t.Fatal(err)
   194  	}
   195  
   196  	if err := db.View(func(tx *bdb.Tx) error {
   197  		c := tx.Bucket([]byte("widgets")).Cursor()
   198  		for i := 0; i < count; i++ {
   199  			seek := make([]byte, 8)
   200  			binary.BigEndian.PutUint64(seek, uint64(i))
   201  
   202  			k, _ := c.Seek(seek)
   203  
   204  			if i == count-1 {
   205  				if k != nil {
   206  					t.Fatal("expected nil key")
   207  				}
   208  				continue
   209  			}
   210  
   211  			num := binary.BigEndian.Uint64(k)
   212  			if i%2 == 0 {
   213  				if num != uint64(i) {
   214  					t.Fatalf("unexpected num: %d", num)
   215  				}
   216  			} else {
   217  				if num != uint64(i+1) {
   218  					t.Fatalf("unexpected num: %d", num)
   219  				}
   220  			}
   221  		}
   222  
   223  		return nil
   224  	}); err != nil {
   225  		t.Fatal(err)
   226  	}
   227  }
   228  
   229  func TestCursor_EmptyBucket(t *testing.T) {
   230  	db := MustOpenDB()
   231  	defer db.MustClose()
   232  	if err := db.Update(func(tx *bdb.Tx) error {
   233  		_, err := tx.CreateBucket([]byte("widgets"))
   234  		return err
   235  	}); err != nil {
   236  		t.Fatal(err)
   237  	}
   238  
   239  	if err := db.View(func(tx *bdb.Tx) error {
   240  		c := tx.Bucket([]byte("widgets")).Cursor()
   241  		k, v := c.First()
   242  		if k != nil {
   243  			t.Fatalf("unexpected key: %v", k)
   244  		} else if v != nil {
   245  			t.Fatalf("unexpected value: %v", v)
   246  		}
   247  		return nil
   248  	}); err != nil {
   249  		t.Fatal(err)
   250  	}
   251  }
   252  
   253  func TestCursor_EmptyBucketReverse(t *testing.T) {
   254  	db := MustOpenDB()
   255  	defer db.MustClose()
   256  
   257  	if err := db.Update(func(tx *bdb.Tx) error {
   258  		_, err := tx.CreateBucket([]byte("widgets"))
   259  		return err
   260  	}); err != nil {
   261  		t.Fatal(err)
   262  	}
   263  	if err := db.View(func(tx *bdb.Tx) error {
   264  		c := tx.Bucket([]byte("widgets")).Cursor()
   265  		k, v := c.Last()
   266  		if k != nil {
   267  			t.Fatalf("unexpected key: %v", k)
   268  		} else if v != nil {
   269  			t.Fatalf("unexpected value: %v", v)
   270  		}
   271  		return nil
   272  	}); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  }
   276  
   277  func TestCursor_Iterate_Leaf(t *testing.T) {
   278  	db := MustOpenDB()
   279  	defer db.MustClose()
   280  
   281  	if err := db.Update(func(tx *bdb.Tx) error {
   282  		b, err := tx.CreateBucket([]byte("widgets"))
   283  		if err != nil {
   284  			t.Fatal(err)
   285  		}
   286  		if err := b.Put([]byte("baz"), []byte{}); err != nil {
   287  			t.Fatal(err)
   288  		}
   289  		if err := b.Put([]byte("foo"), []byte{0}); err != nil {
   290  			t.Fatal(err)
   291  		}
   292  		if err := b.Put([]byte("bar"), []byte{1}); err != nil {
   293  			t.Fatal(err)
   294  		}
   295  		return nil
   296  	}); err != nil {
   297  		t.Fatal(err)
   298  	}
   299  	tx, err := db.Begin(false)
   300  	if err != nil {
   301  		t.Fatal(err)
   302  	}
   303  	defer func() { _ = tx.Rollback() }()
   304  
   305  	c := tx.Bucket([]byte("widgets")).Cursor()
   306  
   307  	k, v := c.First()
   308  	if !bytes.Equal(k, []byte("bar")) {
   309  		t.Fatalf("unexpected key: %v", k)
   310  	} else if !bytes.Equal(v, []byte{1}) {
   311  		t.Fatalf("unexpected value: %v", v)
   312  	}
   313  
   314  	k, v = c.Next()
   315  	if !bytes.Equal(k, []byte("baz")) {
   316  		t.Fatalf("unexpected key: %v", k)
   317  	} else if !bytes.Equal(v, []byte{}) {
   318  		t.Fatalf("unexpected value: %v", v)
   319  	}
   320  
   321  	k, v = c.Next()
   322  	if !bytes.Equal(k, []byte("foo")) {
   323  		t.Fatalf("unexpected key: %v", k)
   324  	} else if !bytes.Equal(v, []byte{0}) {
   325  		t.Fatalf("unexpected value: %v", v)
   326  	}
   327  
   328  	k, v = c.Next()
   329  	if k != nil {
   330  		t.Fatalf("expected nil key: %v", k)
   331  	} else if v != nil {
   332  		t.Fatalf("expected nil value: %v", v)
   333  	}
   334  
   335  	k, v = c.Next()
   336  	if k != nil {
   337  		t.Fatalf("expected nil key: %v", k)
   338  	} else if v != nil {
   339  		t.Fatalf("expected nil value: %v", v)
   340  	}
   341  
   342  	if err := tx.Rollback(); err != nil {
   343  		t.Fatal(err)
   344  	}
   345  }
   346  
   347  func TestCursor_LeafRootReverse(t *testing.T) {
   348  	db := MustOpenDB()
   349  	defer db.MustClose()
   350  
   351  	if err := db.Update(func(tx *bdb.Tx) error {
   352  		b, err := tx.CreateBucket([]byte("widgets"))
   353  		if err != nil {
   354  			t.Fatal(err)
   355  		}
   356  		if err := b.Put([]byte("baz"), []byte{}); err != nil {
   357  			t.Fatal(err)
   358  		}
   359  		if err := b.Put([]byte("foo"), []byte{0}); err != nil {
   360  			t.Fatal(err)
   361  		}
   362  		if err := b.Put([]byte("bar"), []byte{1}); err != nil {
   363  			t.Fatal(err)
   364  		}
   365  		return nil
   366  	}); err != nil {
   367  		t.Fatal(err)
   368  	}
   369  	tx, err := db.Begin(false)
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	c := tx.Bucket([]byte("widgets")).Cursor()
   374  
   375  	if k, v := c.Last(); !bytes.Equal(k, []byte("foo")) {
   376  		t.Fatalf("unexpected key: %v", k)
   377  	} else if !bytes.Equal(v, []byte{0}) {
   378  		t.Fatalf("unexpected value: %v", v)
   379  	}
   380  
   381  	if k, v := c.Prev(); !bytes.Equal(k, []byte("baz")) {
   382  		t.Fatalf("unexpected key: %v", k)
   383  	} else if !bytes.Equal(v, []byte{}) {
   384  		t.Fatalf("unexpected value: %v", v)
   385  	}
   386  
   387  	if k, v := c.Prev(); !bytes.Equal(k, []byte("bar")) {
   388  		t.Fatalf("unexpected key: %v", k)
   389  	} else if !bytes.Equal(v, []byte{1}) {
   390  		t.Fatalf("unexpected value: %v", v)
   391  	}
   392  
   393  	if k, v := c.Prev(); k != nil {
   394  		t.Fatalf("expected nil key: %v", k)
   395  	} else if v != nil {
   396  		t.Fatalf("expected nil value: %v", v)
   397  	}
   398  
   399  	if k, v := c.Prev(); k != nil {
   400  		t.Fatalf("expected nil key: %v", k)
   401  	} else if v != nil {
   402  		t.Fatalf("expected nil value: %v", v)
   403  	}
   404  
   405  	if err := tx.Rollback(); err != nil {
   406  		t.Fatal(err)
   407  	}
   408  }
   409  
   410  func TestCursor_Restart(t *testing.T) {
   411  	db := MustOpenDB()
   412  	defer db.MustClose()
   413  
   414  	if err := db.Update(func(tx *bdb.Tx) error {
   415  		b, err := tx.CreateBucket([]byte("widgets"))
   416  		if err != nil {
   417  			t.Fatal(err)
   418  		}
   419  		if err := b.Put([]byte("bar"), []byte{}); err != nil {
   420  			t.Fatal(err)
   421  		}
   422  		if err := b.Put([]byte("foo"), []byte{}); err != nil {
   423  			t.Fatal(err)
   424  		}
   425  		return nil
   426  	}); err != nil {
   427  		t.Fatal(err)
   428  	}
   429  
   430  	tx, err := db.Begin(false)
   431  	if err != nil {
   432  		t.Fatal(err)
   433  	}
   434  	c := tx.Bucket([]byte("widgets")).Cursor()
   435  
   436  	if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) {
   437  		t.Fatalf("unexpected key: %v", k)
   438  	}
   439  	if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) {
   440  		t.Fatalf("unexpected key: %v", k)
   441  	}
   442  
   443  	if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) {
   444  		t.Fatalf("unexpected key: %v", k)
   445  	}
   446  	if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) {
   447  		t.Fatalf("unexpected key: %v", k)
   448  	}
   449  
   450  	if err := tx.Rollback(); err != nil {
   451  		t.Fatal(err)
   452  	}
   453  }
   454  
   455  func TestCursor_First_EmptyPages(t *testing.T) {
   456  	db := MustOpenDB()
   457  	defer db.MustClose()
   458  
   459  	if err := db.Update(func(tx *bdb.Tx) error {
   460  		b, err := tx.CreateBucket([]byte("widgets"))
   461  		if err != nil {
   462  			t.Fatal(err)
   463  		}
   464  
   465  		for i := 0; i < 1000; i++ {
   466  			if err := b.Put(u64tob(uint64(i)), []byte{}); err != nil {
   467  				t.Fatal(err)
   468  			}
   469  		}
   470  
   471  		return nil
   472  	}); err != nil {
   473  		t.Fatal(err)
   474  	}
   475  
   476  	if err := db.Update(func(tx *bdb.Tx) error {
   477  		b := tx.Bucket([]byte("widgets"))
   478  		for i := 0; i < 600; i++ {
   479  			if err := b.Delete(u64tob(uint64(i))); err != nil {
   480  				t.Fatal(err)
   481  			}
   482  		}
   483  
   484  		c := b.Cursor()
   485  		var n int
   486  		for k, _ := c.First(); k != nil; k, _ = c.Next() {
   487  			n++
   488  		}
   489  		if n != 400 {
   490  			t.Fatalf("unexpected key count: %d", n)
   491  		}
   492  
   493  		return nil
   494  	}); err != nil {
   495  		t.Fatal(err)
   496  	}
   497  }
   498  
   499  func TestCursor_QuickCheck(t *testing.T) {
   500  	f := func(items testdata) bool {
   501  		db := MustOpenDB()
   502  		defer db.MustClose()
   503  
   504  		tx, err := db.Begin(true)
   505  		if err != nil {
   506  			t.Fatal(err)
   507  		}
   508  		b, err := tx.CreateBucket([]byte("widgets"))
   509  		if err != nil {
   510  			t.Fatal(err)
   511  		}
   512  		for _, item := range items {
   513  			if err := b.Put(item.Key, item.Value); err != nil {
   514  				t.Fatal(err)
   515  			}
   516  		}
   517  		if err := tx.Commit(); err != nil {
   518  			t.Fatal(err)
   519  		}
   520  
   521  		sort.Sort(items)
   522  
   523  		var index = 0
   524  		tx, err = db.Begin(false)
   525  		if err != nil {
   526  			t.Fatal(err)
   527  		}
   528  
   529  		c := tx.Bucket([]byte("widgets")).Cursor()
   530  		for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() {
   531  			if !bytes.Equal(k, items[index].Key) {
   532  				t.Fatalf("unexpected key: %v", k)
   533  			} else if !bytes.Equal(v, items[index].Value) {
   534  				t.Fatalf("unexpected value: %v", v)
   535  			}
   536  			index++
   537  		}
   538  		if len(items) != index {
   539  			t.Fatalf("unexpected item count: %v, expected %v", len(items), index)
   540  		}
   541  
   542  		if err := tx.Rollback(); err != nil {
   543  			t.Fatal(err)
   544  		}
   545  
   546  		return true
   547  	}
   548  	if err := quick.Check(f, qconfig()); err != nil {
   549  		t.Error(err)
   550  	}
   551  }
   552  
   553  func TestCursor_QuickCheck_Reverse(t *testing.T) {
   554  	f := func(items testdata) bool {
   555  		db := MustOpenDB()
   556  		defer db.MustClose()
   557  
   558  		tx, err := db.Begin(true)
   559  		if err != nil {
   560  			t.Fatal(err)
   561  		}
   562  		b, err := tx.CreateBucket([]byte("widgets"))
   563  		if err != nil {
   564  			t.Fatal(err)
   565  		}
   566  		for _, item := range items {
   567  			if err := b.Put(item.Key, item.Value); err != nil {
   568  				t.Fatal(err)
   569  			}
   570  		}
   571  		if err := tx.Commit(); err != nil {
   572  			t.Fatal(err)
   573  		}
   574  
   575  		sort.Sort(revtestdata(items))
   576  
   577  		var index = 0
   578  		tx, err = db.Begin(false)
   579  		if err != nil {
   580  			t.Fatal(err)
   581  		}
   582  		c := tx.Bucket([]byte("widgets")).Cursor()
   583  		for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() {
   584  			if !bytes.Equal(k, items[index].Key) {
   585  				t.Fatalf("unexpected key: %v", k)
   586  			} else if !bytes.Equal(v, items[index].Value) {
   587  				t.Fatalf("unexpected value: %v", v)
   588  			}
   589  			index++
   590  		}
   591  		if len(items) != index {
   592  			t.Fatalf("unexpected item count: %v, expected %v", len(items), index)
   593  		}
   594  
   595  		if err := tx.Rollback(); err != nil {
   596  			t.Fatal(err)
   597  		}
   598  
   599  		return true
   600  	}
   601  	if err := quick.Check(f, qconfig()); err != nil {
   602  		t.Error(err)
   603  	}
   604  }
   605  
   606  func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
   607  	db := MustOpenDB()
   608  	defer db.MustClose()
   609  
   610  	if err := db.Update(func(tx *bdb.Tx) error {
   611  		b, err := tx.CreateBucket([]byte("widgets"))
   612  		if err != nil {
   613  			t.Fatal(err)
   614  		}
   615  		if _, err := b.CreateBucket([]byte("foo")); err != nil {
   616  			t.Fatal(err)
   617  		}
   618  		if _, err := b.CreateBucket([]byte("bar")); err != nil {
   619  			t.Fatal(err)
   620  		}
   621  		if _, err := b.CreateBucket([]byte("baz")); err != nil {
   622  			t.Fatal(err)
   623  		}
   624  		return nil
   625  	}); err != nil {
   626  		t.Fatal(err)
   627  	}
   628  
   629  	if err := db.View(func(tx *bdb.Tx) error {
   630  		var names []string
   631  		c := tx.Bucket([]byte("widgets")).Cursor()
   632  		for k, v := c.First(); k != nil; k, v = c.Next() {
   633  			names = append(names, string(k))
   634  			if v != nil {
   635  				t.Fatalf("unexpected value: %v", v)
   636  			}
   637  		}
   638  		if !reflect.DeepEqual(names, []string{"bar", "baz", "foo"}) {
   639  			t.Fatalf("unexpected names: %+v", names)
   640  		}
   641  		return nil
   642  	}); err != nil {
   643  		t.Fatal(err)
   644  	}
   645  }
   646  
   647  func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
   648  	db := MustOpenDB()
   649  	defer db.MustClose()
   650  
   651  	if err := db.Update(func(tx *bdb.Tx) error {
   652  		b, err := tx.CreateBucket([]byte("widgets"))
   653  		if err != nil {
   654  			t.Fatal(err)
   655  		}
   656  		if _, err := b.CreateBucket([]byte("foo")); err != nil {
   657  			t.Fatal(err)
   658  		}
   659  		if _, err := b.CreateBucket([]byte("bar")); err != nil {
   660  			t.Fatal(err)
   661  		}
   662  		if _, err := b.CreateBucket([]byte("baz")); err != nil {
   663  			t.Fatal(err)
   664  		}
   665  		return nil
   666  	}); err != nil {
   667  		t.Fatal(err)
   668  	}
   669  
   670  	if err := db.View(func(tx *bdb.Tx) error {
   671  		var names []string
   672  		c := tx.Bucket([]byte("widgets")).Cursor()
   673  		for k, v := c.Last(); k != nil; k, v = c.Prev() {
   674  			names = append(names, string(k))
   675  			if v != nil {
   676  				t.Fatalf("unexpected value: %v", v)
   677  			}
   678  		}
   679  		if !reflect.DeepEqual(names, []string{"foo", "baz", "bar"}) {
   680  			t.Fatalf("unexpected names: %+v", names)
   681  		}
   682  		return nil
   683  	}); err != nil {
   684  		t.Fatal(err)
   685  	}
   686  }
   687  
   688  func ExampleCursor() {
   689  	db, err := bdb.Open(tempfile(), nil)
   690  	if err != nil {
   691  		log.Fatal(err)
   692  	}
   693  	defer os.Remove(db.Path())
   694  
   695  	if err := db.Update(func(tx *bdb.Tx) error {
   696  		b, err := tx.CreateBucket([]byte("animals"))
   697  		if err != nil {
   698  			return err
   699  		}
   700  
   701  		if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
   702  			log.Fatal(err)
   703  		}
   704  		if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
   705  			log.Fatal(err)
   706  		}
   707  		if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
   708  			log.Fatal(err)
   709  		}
   710  
   711  		c := b.Cursor()
   712  
   713  		for k, v := c.First(); k != nil; k, v = c.Next() {
   714  			fmt.Printf("A %s is %s.\n", k, v)
   715  		}
   716  
   717  		return nil
   718  	}); err != nil {
   719  		log.Fatal(err)
   720  	}
   721  
   722  	if err := db.Close(); err != nil {
   723  		log.Fatal(err)
   724  	}
   725  }
   726  
   727  func ExampleCursor_reverse() {
   728  	db, err := bdb.Open(tempfile(), nil)
   729  	if err != nil {
   730  		log.Fatal(err)
   731  	}
   732  	defer os.Remove(db.Path())
   733  
   734  	if err := db.Update(func(tx *bdb.Tx) error {
   735  		b, err := tx.CreateBucket([]byte("animals"))
   736  		if err != nil {
   737  			return err
   738  		}
   739  
   740  		if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
   741  			log.Fatal(err)
   742  		}
   743  		if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
   744  			log.Fatal(err)
   745  		}
   746  		if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
   747  			log.Fatal(err)
   748  		}
   749  
   750  		c := b.Cursor()
   751  
   752  		for k, v := c.Last(); k != nil; k, v = c.Prev() {
   753  			fmt.Printf("A %s is %s.\n", k, v)
   754  		}
   755  
   756  		return nil
   757  	}); err != nil {
   758  		log.Fatal(err)
   759  	}
   760  
   761  	if err := db.Close(); err != nil {
   762  		log.Fatal(err)
   763  	}
   764  }