github.com/rosedblabs/rosedb/v2@v2.3.7-0.20240423093736-a89ea823e5b9/db_test.go (about)

     1  package rosedb
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"math/rand"
     7  	"os"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/rosedblabs/rosedb/v2/utils"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  func TestDB_Put_Normal(t *testing.T) {
    17  	options := DefaultOptions
    18  	db, err := Open(options)
    19  	assert.Nil(t, err)
    20  	defer destroyDB(db)
    21  
    22  	for i := 0; i < 100; i++ {
    23  		err := db.Put(utils.GetTestKey(rand.Int()), utils.RandomValue(128))
    24  		assert.Nil(t, err)
    25  		err = db.Put(utils.GetTestKey(rand.Int()), utils.RandomValue(KB))
    26  		assert.Nil(t, err)
    27  		err = db.Put(utils.GetTestKey(rand.Int()), utils.RandomValue(5*KB))
    28  		assert.Nil(t, err)
    29  	}
    30  
    31  	// reopen
    32  	err = db.Close()
    33  	assert.Nil(t, err)
    34  	db2, err := Open(options)
    35  	assert.Nil(t, err)
    36  	defer func() {
    37  		_ = db2.Close()
    38  	}()
    39  	stat := db2.Stat()
    40  	assert.Equal(t, 300, stat.KeysNum)
    41  }
    42  
    43  func TestDB_Get_Normal(t *testing.T) {
    44  	options := DefaultOptions
    45  	db, err := Open(options)
    46  	assert.Nil(t, err)
    47  	defer destroyDB(db)
    48  
    49  	// not exist
    50  	val1, err := db.Get([]byte("not-exist"))
    51  	assert.Nil(t, val1)
    52  	assert.Equal(t, ErrKeyNotFound, err)
    53  
    54  	generateData(t, db, 1, 100, 128)
    55  	for i := 1; i < 100; i++ {
    56  		val, err := db.Get(utils.GetTestKey(i))
    57  		assert.Nil(t, err)
    58  		assert.Equal(t, len(val), len(utils.RandomValue(128)))
    59  	}
    60  	generateData(t, db, 200, 300, KB)
    61  	for i := 200; i < 300; i++ {
    62  		val, err := db.Get(utils.GetTestKey(i))
    63  		assert.Nil(t, err)
    64  		assert.Equal(t, len(val), len(utils.RandomValue(KB)))
    65  	}
    66  	generateData(t, db, 400, 500, 4*KB)
    67  	for i := 400; i < 500; i++ {
    68  		val, err := db.Get(utils.GetTestKey(i))
    69  		assert.Nil(t, err)
    70  		assert.Equal(t, len(val), len(utils.RandomValue(4*KB)))
    71  	}
    72  }
    73  
    74  func TestDB_Close_Sync(t *testing.T) {
    75  	options := DefaultOptions
    76  	db, err := Open(options)
    77  	assert.Nil(t, err)
    78  	defer destroyDB(db)
    79  
    80  	err = db.Sync()
    81  	assert.Nil(t, err)
    82  }
    83  
    84  func TestDB_Concurrent_Put(t *testing.T) {
    85  	options := DefaultOptions
    86  	db, err := Open(options)
    87  	assert.Nil(t, err)
    88  	defer destroyDB(db)
    89  
    90  	wg := sync.WaitGroup{}
    91  	m := sync.Map{}
    92  	wg.Add(10)
    93  	for i := 0; i < 10; i++ {
    94  		go func() {
    95  			defer wg.Done()
    96  			for i := 0; i < 10000; i++ {
    97  				key := utils.GetTestKey(rand.Int())
    98  				m.Store(string(key), struct{}{})
    99  				e := db.Put(key, utils.RandomValue(128))
   100  				assert.Nil(t, e)
   101  			}
   102  		}()
   103  	}
   104  	wg.Wait()
   105  
   106  	var count int
   107  	m.Range(func(key, value any) bool {
   108  		count++
   109  		return true
   110  	})
   111  	assert.Equal(t, count, db.index.Size())
   112  }
   113  
   114  func TestDB_Ascend(t *testing.T) {
   115  	// Create a test database instance
   116  	options := DefaultOptions
   117  	db, err := Open(options)
   118  	assert.Nil(t, err)
   119  	defer destroyDB(db)
   120  
   121  	// Insert some test data
   122  	data := []struct {
   123  		key   []byte
   124  		value []byte
   125  	}{
   126  		{[]byte("key1"), []byte("value1")},
   127  		{[]byte("key2"), []byte("value2")},
   128  		{[]byte("key3"), []byte("value3")},
   129  	}
   130  
   131  	for _, d := range data {
   132  		if err := db.Put(d.key, d.value); err != nil {
   133  			t.Fatalf("Failed to put data: %v", err)
   134  		}
   135  	}
   136  
   137  	// Test Ascend function
   138  	var result []string
   139  	db.Ascend(func(k []byte, v []byte) (bool, error) {
   140  		result = append(result, string(k))
   141  		return true, nil // No error here
   142  	})
   143  
   144  	if err != nil {
   145  		t.Errorf("Ascend returned an error: %v", err)
   146  	}
   147  
   148  	expected := []string{"key1", "key2", "key3"}
   149  	if len(result) != len(expected) {
   150  		t.Errorf("Unexpected number of results. Expected: %v, Got: %v", expected, result)
   151  	} else {
   152  		for i, val := range expected {
   153  			if result[i] != val {
   154  				t.Errorf("Unexpected result at index %d. Expected: %v, Got: %v", i, val, result[i])
   155  			}
   156  		}
   157  	}
   158  }
   159  
   160  func TestDB_Descend(t *testing.T) {
   161  	// Create a test database instance
   162  	options := DefaultOptions
   163  	db, err := Open(options)
   164  	assert.Nil(t, err)
   165  	defer destroyDB(db)
   166  
   167  	// Insert some test data
   168  	data := []struct {
   169  		key   []byte
   170  		value []byte
   171  	}{
   172  		{[]byte("key1"), []byte("value1")},
   173  		{[]byte("key2"), []byte("value2")},
   174  		{[]byte("key3"), []byte("value3")},
   175  	}
   176  
   177  	for _, d := range data {
   178  		if err := db.Put(d.key, d.value); err != nil {
   179  			t.Fatalf("Failed to put data: %v", err)
   180  		}
   181  	}
   182  
   183  	// Test Descend function
   184  	var result []string
   185  	db.Descend(func(k []byte, v []byte) (bool, error) {
   186  		result = append(result, string(k))
   187  		return true, nil
   188  	})
   189  
   190  	if err != nil {
   191  		t.Errorf("Descend returned an error: %v", err)
   192  	}
   193  
   194  	expected := []string{"key3", "key2", "key1"}
   195  	if len(result) != len(expected) {
   196  		t.Errorf("Unexpected number of results. Expected: %v, Got: %v", expected, result)
   197  	} else {
   198  		for i, val := range expected {
   199  			if result[i] != val {
   200  				t.Errorf("Unexpected result at index %d. Expected: %v, Got: %v", i, val, result[i])
   201  			}
   202  		}
   203  	}
   204  }
   205  
   206  func TestDB_AscendRange(t *testing.T) {
   207  	// Create a test database instance
   208  	options := DefaultOptions
   209  	db, err := Open(options)
   210  	assert.Nil(t, err)
   211  	defer destroyDB(db)
   212  
   213  	// Insert some test data
   214  	data := []struct {
   215  		key   []byte
   216  		value []byte
   217  	}{
   218  		{[]byte("apple"), []byte("value1")},
   219  		{[]byte("banana"), []byte("value2")},
   220  		{[]byte("cherry"), []byte("value3")},
   221  		{[]byte("date"), []byte("value4")},
   222  		{[]byte("grape"), []byte("value5")},
   223  		{[]byte("kiwi"), []byte("value6")},
   224  	}
   225  
   226  	for _, d := range data {
   227  		if err := db.Put(d.key, d.value); err != nil {
   228  			t.Fatalf("Failed to put data: %v", err)
   229  		}
   230  	}
   231  
   232  	// Test AscendRange
   233  	var resultAscendRange []string
   234  	db.AscendRange([]byte("banana"), []byte("grape"), func(k []byte, v []byte) (bool, error) {
   235  		resultAscendRange = append(resultAscendRange, string(k))
   236  		return true, nil
   237  	})
   238  	assert.Equal(t, []string{"banana", "cherry", "date"}, resultAscendRange)
   239  }
   240  
   241  func TestDB_DescendRange(t *testing.T) {
   242  	// Create a test database instance
   243  	options := DefaultOptions
   244  	db, err := Open(options)
   245  	assert.Nil(t, err)
   246  	defer destroyDB(db)
   247  
   248  	// Insert some test data
   249  	data := []struct {
   250  		key   []byte
   251  		value []byte
   252  	}{
   253  		{[]byte("apple"), []byte("value1")},
   254  		{[]byte("banana"), []byte("value2")},
   255  		{[]byte("cherry"), []byte("value3")},
   256  		{[]byte("date"), []byte("value4")},
   257  		{[]byte("grape"), []byte("value5")},
   258  		{[]byte("kiwi"), []byte("value6")},
   259  	}
   260  
   261  	for _, d := range data {
   262  		if err := db.Put(d.key, d.value); err != nil {
   263  			t.Fatalf("Failed to put data: %v", err)
   264  		}
   265  	}
   266  
   267  	// Test DescendRange
   268  	var resultDescendRange []string
   269  	db.DescendRange([]byte("grape"), []byte("cherry"), func(k []byte, v []byte) (bool, error) {
   270  		resultDescendRange = append(resultDescendRange, string(k))
   271  		return true, nil
   272  	})
   273  	assert.Equal(t, []string{"grape", "date"}, resultDescendRange)
   274  }
   275  
   276  func TestDB_AscendGreaterOrEqual(t *testing.T) {
   277  	// Create a test database instance
   278  	options := DefaultOptions
   279  	db, err := Open(options)
   280  	assert.Nil(t, err)
   281  	defer destroyDB(db)
   282  
   283  	// Insert some test data
   284  	data := []struct {
   285  		key   []byte
   286  		value []byte
   287  	}{
   288  		{[]byte("apple"), []byte("value1")},
   289  		{[]byte("banana"), []byte("value2")},
   290  		{[]byte("cherry"), []byte("value3")},
   291  		{[]byte("date"), []byte("value4")},
   292  		{[]byte("grape"), []byte("value5")},
   293  		{[]byte("kiwi"), []byte("value6")},
   294  	}
   295  
   296  	for _, d := range data {
   297  		if err := db.Put(d.key, d.value); err != nil {
   298  			t.Fatalf("Failed to put data: %v", err)
   299  		}
   300  	}
   301  
   302  	// Test AscendGreaterOrEqual
   303  	var resultAscendGreaterOrEqual []string
   304  	db.AscendGreaterOrEqual([]byte("date"), func(k []byte, v []byte) (bool, error) {
   305  		resultAscendGreaterOrEqual = append(resultAscendGreaterOrEqual, string(k))
   306  		return true, nil
   307  	})
   308  	assert.Equal(t, []string{"date", "grape", "kiwi"}, resultAscendGreaterOrEqual)
   309  }
   310  
   311  func TestDB_DescendLessOrEqual(t *testing.T) {
   312  	// Create a test database instance
   313  	options := DefaultOptions
   314  	db, err := Open(options)
   315  	assert.Nil(t, err)
   316  	defer destroyDB(db)
   317  
   318  	// Insert some test data
   319  	data := []struct {
   320  		key   []byte
   321  		value []byte
   322  	}{
   323  		{[]byte("apple"), []byte("value1")},
   324  		{[]byte("banana"), []byte("value2")},
   325  		{[]byte("cherry"), []byte("value3")},
   326  		{[]byte("date"), []byte("value4")},
   327  		{[]byte("grape"), []byte("value5")},
   328  		{[]byte("kiwi"), []byte("value6")},
   329  	}
   330  
   331  	for _, d := range data {
   332  		if err := db.Put(d.key, d.value); err != nil {
   333  			t.Fatalf("Failed to put data: %v", err)
   334  		}
   335  	}
   336  
   337  	// Test DescendLessOrEqual
   338  	var resultDescendLessOrEqual []string
   339  	db.DescendLessOrEqual([]byte("grape"), func(k []byte, v []byte) (bool, error) {
   340  		resultDescendLessOrEqual = append(resultDescendLessOrEqual, string(k))
   341  		return true, nil
   342  	})
   343  	assert.Equal(t, []string{"grape", "date", "cherry", "banana", "apple"}, resultDescendLessOrEqual)
   344  }
   345  
   346  func TestDB_AscendKeys(t *testing.T) {
   347  	options := DefaultOptions
   348  	db, err := Open(options)
   349  	assert.Nil(t, err)
   350  	defer destroyDB(db)
   351  
   352  	err = db.Put([]byte("aacd"), utils.RandomValue(10))
   353  	assert.Nil(t, err)
   354  
   355  	validate := func(target [][]byte, pattern []byte) {
   356  		var keys [][]byte
   357  		db.AscendKeys(pattern, false, func(k []byte) (bool, error) {
   358  			keys = append(keys, k)
   359  			return true, nil
   360  		})
   361  		assert.Equal(t, keys, target)
   362  	}
   363  
   364  	validate([][]byte{[]byte("aacd")}, nil)
   365  
   366  	err = db.Put([]byte("bbde"), utils.RandomValue(10))
   367  	assert.Nil(t, err)
   368  	err = db.Put([]byte("cdea"), utils.RandomValue(10))
   369  	assert.Nil(t, err)
   370  	err = db.Put([]byte("bcae"), utils.RandomValue(10))
   371  	assert.Nil(t, err)
   372  
   373  	validate([][]byte{[]byte("aacd"), []byte("bbde"), []byte("bcae"), []byte("cdea")}, nil)
   374  }
   375  
   376  func TestDB_AscendKeysExpired(t *testing.T) {
   377  	options := DefaultOptions
   378  	db, err := Open(options)
   379  	assert.Nil(t, err)
   380  	defer destroyDB(db)
   381  
   382  	validate := func(target [][]byte, pattern []byte) {
   383  		var keys [][]byte
   384  		db.AscendKeys(pattern, true, func(k []byte) (bool, error) {
   385  			keys = append(keys, k)
   386  			return true, nil
   387  		})
   388  		assert.Equal(t, keys, target)
   389  	}
   390  
   391  	err = db.PutWithTTL([]byte("bbde"), utils.RandomValue(10), time.Millisecond*500)
   392  	assert.Nil(t, err)
   393  	err = db.Put([]byte("cdea"), utils.RandomValue(10))
   394  	assert.Nil(t, err)
   395  	err = db.Put([]byte("bcae"), utils.RandomValue(10))
   396  	assert.Nil(t, err)
   397  	time.Sleep(time.Millisecond * 600)
   398  
   399  	validate([][]byte{[]byte("bcae"), []byte("cdea")}, nil)
   400  }
   401  
   402  func TestDB_DescendKeys(t *testing.T) {
   403  	options := DefaultOptions
   404  	db, err := Open(options)
   405  	assert.Nil(t, err)
   406  	defer destroyDB(db)
   407  
   408  	err = db.Put([]byte("aacd"), utils.RandomValue(10))
   409  	assert.Nil(t, err)
   410  
   411  	validate := func(target [][]byte, pattern []byte) {
   412  		var keys [][]byte
   413  		db.DescendKeys(pattern, false, func(k []byte) (bool, error) {
   414  			keys = append(keys, k)
   415  			return true, nil
   416  		})
   417  		assert.Equal(t, keys, target)
   418  	}
   419  
   420  	validate([][]byte{[]byte("aacd")}, nil)
   421  
   422  	err = db.Put([]byte("bbde"), utils.RandomValue(10))
   423  	assert.Nil(t, err)
   424  	err = db.Put([]byte("cdea"), utils.RandomValue(10))
   425  	assert.Nil(t, err)
   426  	err = db.Put([]byte("bcae"), utils.RandomValue(10))
   427  	assert.Nil(t, err)
   428  
   429  	validate([][]byte{[]byte("cdea"), []byte("bcae"), []byte("bbde"), []byte("aacd")}, nil)
   430  }
   431  
   432  func TestDB_DescendKeysExpired(t *testing.T) {
   433  	options := DefaultOptions
   434  	db, err := Open(options)
   435  	assert.Nil(t, err)
   436  	defer destroyDB(db)
   437  
   438  	validate := func(target [][]byte, pattern []byte) {
   439  		var keys [][]byte
   440  		db.DescendKeys(pattern, true, func(k []byte) (bool, error) {
   441  			keys = append(keys, k)
   442  			return true, nil
   443  		})
   444  		assert.Equal(t, keys, target)
   445  	}
   446  
   447  	err = db.Put([]byte("bbde"), utils.RandomValue(10))
   448  	assert.Nil(t, err)
   449  	err = db.PutWithTTL([]byte("cdea"), utils.RandomValue(10), time.Millisecond*500)
   450  	assert.Nil(t, err)
   451  	err = db.PutWithTTL([]byte("bcae"), utils.RandomValue(10), time.Millisecond*500)
   452  	assert.Nil(t, err)
   453  
   454  	time.Sleep(time.Millisecond * 600)
   455  
   456  	validate([][]byte{[]byte("bbde")}, nil)
   457  }
   458  
   459  func TestDB_PutWithTTL(t *testing.T) {
   460  	options := DefaultOptions
   461  	db, err := Open(options)
   462  	assert.Nil(t, err)
   463  	defer destroyDB(db)
   464  
   465  	err = db.PutWithTTL(utils.GetTestKey(1), utils.RandomValue(128), time.Millisecond*100)
   466  	assert.Nil(t, err)
   467  	val1, err := db.Get(utils.GetTestKey(1))
   468  	assert.Nil(t, err)
   469  	assert.NotNil(t, val1)
   470  	time.Sleep(time.Millisecond * 200)
   471  	val2, err := db.Get(utils.GetTestKey(1))
   472  	assert.Equal(t, err, ErrKeyNotFound)
   473  	assert.Nil(t, val2)
   474  
   475  	err = db.PutWithTTL(utils.GetTestKey(2), utils.RandomValue(128), time.Millisecond*200)
   476  	assert.Nil(t, err)
   477  	// rewrite
   478  	err = db.Put(utils.GetTestKey(2), utils.RandomValue(128))
   479  	assert.Nil(t, err)
   480  	time.Sleep(time.Millisecond * 200)
   481  	val3, err := db.Get(utils.GetTestKey(2))
   482  	assert.Nil(t, err)
   483  	assert.NotNil(t, val3)
   484  
   485  	err = db.Close()
   486  	assert.Nil(t, err)
   487  
   488  	db2, err := Open(options)
   489  	assert.Nil(t, err)
   490  
   491  	val4, err := db2.Get(utils.GetTestKey(1))
   492  	assert.Equal(t, err, ErrKeyNotFound)
   493  	assert.Nil(t, val4)
   494  
   495  	val5, err := db2.Get(utils.GetTestKey(2))
   496  	assert.Nil(t, err)
   497  	assert.NotNil(t, val5)
   498  
   499  	_ = db2.Close()
   500  }
   501  
   502  func TestDB_RePutWithTTL(t *testing.T) {
   503  	options := DefaultOptions
   504  	db, err := Open(options)
   505  	assert.Nil(t, err)
   506  	defer destroyDB(db)
   507  
   508  	err = db.Put(utils.GetTestKey(10), utils.RandomValue(10))
   509  	assert.Nil(t, err)
   510  	err = db.PutWithTTL(utils.GetTestKey(10), utils.RandomValue(10), time.Millisecond*100)
   511  	assert.Nil(t, err)
   512  	time.Sleep(time.Second * 1) // wait for expired
   513  
   514  	val1, err := db.Get(utils.GetTestKey(10))
   515  	assert.Equal(t, err, ErrKeyNotFound)
   516  	assert.Nil(t, val1)
   517  
   518  	err = db.Merge(true)
   519  	assert.Nil(t, err)
   520  
   521  	val2, err := db.Get(utils.GetTestKey(10))
   522  	assert.Equal(t, err, ErrKeyNotFound)
   523  	assert.Nil(t, val2)
   524  }
   525  
   526  func TestDB_PutWithTTL_Merge(t *testing.T) {
   527  	options := DefaultOptions
   528  	db, err := Open(options)
   529  	assert.Nil(t, err)
   530  	defer destroyDB(db)
   531  	for i := 0; i < 100; i++ {
   532  		err = db.PutWithTTL(utils.GetTestKey(i), utils.RandomValue(10), time.Second*2)
   533  		assert.Nil(t, err)
   534  	}
   535  	for i := 100; i < 150; i++ {
   536  		err = db.PutWithTTL(utils.GetTestKey(i), utils.RandomValue(10), time.Second*20)
   537  		assert.Nil(t, err)
   538  	}
   539  	time.Sleep(time.Second * 3)
   540  
   541  	err = db.Merge(true)
   542  	assert.Nil(t, err)
   543  
   544  	for i := 0; i < 100; i++ {
   545  		val, err := db.Get(utils.GetTestKey(i))
   546  		assert.Nil(t, val)
   547  		assert.Equal(t, err, ErrKeyNotFound)
   548  	}
   549  	for i := 100; i < 150; i++ {
   550  		val, err := db.Get(utils.GetTestKey(i))
   551  		assert.Nil(t, err)
   552  		assert.NotNil(t, val)
   553  	}
   554  }
   555  
   556  func TestDB_Expire(t *testing.T) {
   557  	options := DefaultOptions
   558  	db, err := Open(options)
   559  	assert.Nil(t, err)
   560  	defer destroyDB(db)
   561  
   562  	err = db.Put(utils.GetTestKey(1), utils.RandomValue(10))
   563  	assert.Nil(t, err)
   564  
   565  	err = db.Expire(utils.GetTestKey(1), time.Second*100)
   566  	assert.Nil(t, err)
   567  	tt1, err := db.TTL(utils.GetTestKey(1))
   568  	assert.Nil(t, err)
   569  	assert.True(t, tt1.Seconds() > 90)
   570  
   571  	err = db.PutWithTTL(utils.GetTestKey(2), utils.RandomValue(10), time.Second*1)
   572  	assert.Nil(t, err)
   573  
   574  	tt2, err := db.TTL(utils.GetTestKey(2))
   575  	assert.Nil(t, err)
   576  	assert.True(t, tt2.Microseconds() > 500)
   577  
   578  	err = db.Close()
   579  	assert.Nil(t, err)
   580  
   581  	db2, err := Open(options)
   582  	assert.Nil(t, err)
   583  	defer func() {
   584  		_ = db2.Close()
   585  	}()
   586  
   587  	tt3, err := db2.TTL(utils.GetTestKey(1))
   588  	assert.Nil(t, err)
   589  	assert.True(t, tt3.Seconds() > 90)
   590  
   591  	time.Sleep(time.Second)
   592  	tt4, err := db2.TTL(utils.GetTestKey(2))
   593  	assert.Equal(t, tt4, time.Duration(-1))
   594  	assert.Equal(t, err, ErrKeyNotFound)
   595  }
   596  
   597  func TestDB_Expire2(t *testing.T) {
   598  	options := DefaultOptions
   599  	db, err := Open(options)
   600  	assert.Nil(t, err)
   601  	defer destroyDB(db)
   602  
   603  	// expire an expired key
   604  	_ = db.PutWithTTL(utils.GetTestKey(1), utils.RandomValue(10), time.Second*1)
   605  	_ = db.Put(utils.GetTestKey(2), utils.RandomValue(10))
   606  	err = db.Expire(utils.GetTestKey(2), time.Second*2)
   607  	assert.Nil(t, err)
   608  
   609  	time.Sleep(time.Second * 2)
   610  	_ = db.Close()
   611  
   612  	db2, err := Open(options)
   613  	assert.Nil(t, err)
   614  	defer func() {
   615  		_ = db2.Close()
   616  	}()
   617  	err = db2.Expire(utils.GetTestKey(1), time.Second)
   618  	assert.Equal(t, err, ErrKeyNotFound)
   619  	err = db2.Expire(utils.GetTestKey(2), time.Second)
   620  	assert.Equal(t, err, ErrKeyNotFound)
   621  }
   622  
   623  func TestDB_DeleteExpiredKeys(t *testing.T) {
   624  	options := DefaultOptions
   625  	db, err := Open(options)
   626  	assert.Nil(t, err)
   627  	defer destroyDB(db)
   628  
   629  	for i := 0; i < 100001; i++ {
   630  		err = db.PutWithTTL(utils.GetTestKey(i), utils.RandomValue(10), time.Second*1)
   631  		assert.Nil(t, err)
   632  	}
   633  
   634  	// wait for key to expire
   635  	time.Sleep(time.Second * 2)
   636  
   637  	err = db.DeleteExpiredKeys(time.Second * 2)
   638  	assert.Nil(t, err)
   639  	assert.Equal(t, 0, db.Stat().KeysNum)
   640  
   641  }
   642  
   643  func TestDB_Multi_DeleteExpiredKeys(t *testing.T) {
   644  	options := DefaultOptions
   645  	db, err := Open(options)
   646  	assert.Nil(t, err)
   647  	defer destroyDB(db)
   648  
   649  	for i := 0; i < 3; i++ {
   650  		for i := 0; i < 10000; i++ {
   651  			err = db.Put(utils.GetTestKey(i), utils.RandomValue(10))
   652  			assert.Nil(t, err)
   653  		}
   654  		for i := 10000; i < 100001; i++ {
   655  			err = db.PutWithTTL(utils.GetTestKey(i), utils.RandomValue(10), time.Second*1)
   656  			assert.Nil(t, err)
   657  		}
   658  
   659  		// wait for key to expire
   660  		time.Sleep(time.Second * 2)
   661  
   662  		err = db.DeleteExpiredKeys(time.Second * 2)
   663  		assert.Nil(t, err)
   664  		assert.Equal(t, 10000, db.Stat().KeysNum)
   665  	}
   666  }
   667  
   668  func TestDB_Persist(t *testing.T) {
   669  	options := DefaultOptions
   670  	db, err := Open(options)
   671  	assert.Nil(t, err)
   672  	defer destroyDB(db)
   673  
   674  	// not exist
   675  	err = db.Persist(utils.GetTestKey(1))
   676  	assert.Equal(t, err, ErrKeyNotFound)
   677  
   678  	err = db.PutWithTTL(utils.GetTestKey(1), utils.RandomValue(10), time.Second*1)
   679  	assert.Nil(t, err)
   680  
   681  	// exist
   682  	err = db.Persist(utils.GetTestKey(1))
   683  	assert.Nil(t, err)
   684  	time.Sleep(time.Second * 2)
   685  	// check ttl
   686  	ttl, err := db.TTL(utils.GetTestKey(1))
   687  	assert.Nil(t, err)
   688  	assert.Equal(t, ttl, time.Duration(-1))
   689  	val1, err := db.Get(utils.GetTestKey(1))
   690  	assert.Nil(t, err)
   691  	assert.NotNil(t, val1)
   692  
   693  	// restart
   694  	err = db.Close()
   695  	assert.Nil(t, err)
   696  
   697  	db2, err := Open(options)
   698  	assert.Nil(t, err)
   699  	defer func() {
   700  		_ = db2.Close()
   701  	}()
   702  
   703  	ttl2, err := db2.TTL(utils.GetTestKey(1))
   704  	assert.Nil(t, err)
   705  	assert.Equal(t, ttl2, time.Duration(-1))
   706  	val2, err := db2.Get(utils.GetTestKey(1))
   707  	assert.Nil(t, err)
   708  	assert.NotNil(t, val2)
   709  }
   710  
   711  func TestDB_Invalid_Cron_Expression(t *testing.T) {
   712  	options := DefaultOptions
   713  	options.AutoMergeCronExpr = "*/1 * * * * * *"
   714  	_, err := Open(options)
   715  	assert.NotNil(t, err)
   716  }
   717  
   718  func TestDB_Valid_Cron_Expression(t *testing.T) {
   719  	options := DefaultOptions
   720  	{
   721  		options.AutoMergeCronExpr = "* */1 * * * *"
   722  		db, err := Open(options)
   723  		assert.Nil(t, err)
   724  		destroyDB(db)
   725  	}
   726  
   727  	{
   728  		options.AutoMergeCronExpr = "*/1 * * * *"
   729  		db, err := Open(options)
   730  		assert.Nil(t, err)
   731  		destroyDB(db)
   732  	}
   733  
   734  	{
   735  		options.AutoMergeCronExpr = "5 0 * 8 *"
   736  		db, err := Open(options)
   737  		assert.Nil(t, err)
   738  		destroyDB(db)
   739  	}
   740  
   741  	{
   742  		options.AutoMergeCronExpr = "*/2 14 1 * *"
   743  		db, err := Open(options)
   744  		assert.Nil(t, err)
   745  		destroyDB(db)
   746  	}
   747  
   748  	{
   749  		options.AutoMergeCronExpr = "@hourly"
   750  		db, err := Open(options)
   751  		assert.Nil(t, err)
   752  		destroyDB(db)
   753  	}
   754  }
   755  
   756  func TestDB_Auto_Merge(t *testing.T) {
   757  	options := DefaultOptions
   758  	db, err := Open(options)
   759  	assert.Nil(t, err)
   760  	defer destroyDB(db)
   761  
   762  	for i := 0; i < 2000; i++ {
   763  		delKey := utils.GetTestKey(rand.Int())
   764  		err := db.Put(delKey, utils.RandomValue(128))
   765  		assert.Nil(t, err)
   766  		err = db.Put(utils.GetTestKey(rand.Int()), utils.RandomValue(2*KB))
   767  		assert.Nil(t, err)
   768  		err = db.Delete(delKey)
   769  		assert.Nil(t, err)
   770  	}
   771  
   772  	{
   773  		reader := db.dataFiles.NewReader()
   774  		var keyCnt int
   775  		for {
   776  			if _, _, err := reader.Next(); errors.Is(err, io.EOF) {
   777  				break
   778  			}
   779  			keyCnt++
   780  		}
   781  		// each record has one data wal and commit at end of batch with wal
   782  		// so totally is 2000 * 3 * 2 = 12000
   783  		assert.Equal(t, 12000, keyCnt)
   784  	}
   785  
   786  	mergeDirPath := mergeDirPath(options.DirPath)
   787  	if _, err := os.Stat(mergeDirPath); err != nil {
   788  		assert.True(t, os.IsNotExist(err))
   789  	}
   790  	assert.NoError(t, db.Close())
   791  
   792  	{
   793  		options.AutoMergeCronExpr = "* * * * * *" // every second
   794  		db, err := Open(options)
   795  		assert.Nil(t, err)
   796  		{
   797  			<-time.After(time.Second * 2)
   798  			reader := db.dataFiles.NewReader()
   799  			var keyCnt int
   800  			for {
   801  				if _, _, err := reader.Next(); errors.Is(err, io.EOF) {
   802  					break
   803  				}
   804  				keyCnt++
   805  			}
   806  			// after merge records are only valid data, so totally is 2000
   807  			assert.Equal(t, 2000, keyCnt)
   808  		}
   809  		destroyDB(db)
   810  	}
   811  }