github.com/moontrade/mdbx-go@v0.4.0/mdbx_test.go (about)

     1  package mdbx
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"testing"
     9  	"unsafe"
    10  )
    11  
    12  func TestChk(t *testing.T) {
    13  	_, out, err := Chk("-v", "-w", "testdata/12539151/mdbx.dat")
    14  	if err != nil {
    15  		t.Fatal(err)
    16  	}
    17  	fmt.Println(string(out))
    18  }
    19  
    20  func TestStat(t *testing.T) {
    21  	_, out, err := Stat("-w", "testdata/75548709/mdbx.dat")
    22  	if err != nil {
    23  		t.Fatal(err)
    24  	}
    25  	fmt.Println(string(out))
    26  }
    27  
    28  func TestEnv_Open(t *testing.T) {
    29  	env, err := NewEnv()
    30  	if err != ErrSuccess {
    31  		t.Fatal(err)
    32  	}
    33  	if err = env.SetGeometry(Geometry{
    34  		SizeLower:       1024 * 1024 * 16,
    35  		SizeNow:         0,
    36  		SizeUpper:       1024 * 1024 * 1024 * 16,
    37  		GrowthStep:      1024 * 1024 * 16,
    38  		ShrinkThreshold: 0,
    39  		PageSize:        4096,
    40  	}); err != ErrSuccess {
    41  		t.Fatal(err)
    42  	}
    43  	if err = env.SetMaxDBS(4); err != ErrSuccess {
    44  		t.Fatal(err)
    45  	}
    46  	err = env.Open(
    47  		"testdata/1",
    48  		EnvNoTLS|EnvNoReadAhead|EnvCoalesce|EnvLIFOReclaim|EnvSafeNoSync,
    49  		0664,
    50  	)
    51  	if err != ErrSuccess {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	var txn Tx
    56  	if err = env.Begin(&txn, TxReadWrite); err != ErrSuccess {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	var dbi DBI
    61  	if dbi, err = txn.OpenDBI("", DBCreate); err != ErrSuccess {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	key := make([]byte, 8)
    66  	binary.BigEndian.PutUint64(key, uint64(101))
    67  	value := []byte("hello")
    68  
    69  	keyVal := Bytes(&key)
    70  	valueVal := Bytes(&value)
    71  
    72  	if err = txn.Put(dbi, &keyVal, &valueVal, 0); err != ErrSuccess {
    73  		t.Fatal(err)
    74  	}
    75  
    76  	var latency CommitLatency
    77  	txn.CommitEx(&latency)
    78  
    79  	err = env.Close(false)
    80  	if err != ErrSuccess {
    81  		t.Fatal(err)
    82  	}
    83  }
    84  
    85  type Engine struct {
    86  	env    *Env
    87  	rootDB DBI
    88  	write  Tx
    89  	rd     Tx
    90  }
    91  
    92  func (engine *Engine) BeginWrite() (*Tx, Error) {
    93  	engine.write.txn = nil
    94  	engine.write.env = engine.env
    95  	return &engine.write, engine.env.Begin(&engine.write, TxReadWrite)
    96  }
    97  
    98  func (engine *Engine) BeginRead() (*Tx, Error) {
    99  	engine.rd.env = engine.env
   100  	return &engine.rd, engine.rd.Renew()
   101  }
   102  
   103  func initDB(path string) (*Engine, Error) {
   104  	engine := &Engine{}
   105  	env, err := NewEnv()
   106  	if err != ErrSuccess {
   107  		return nil, err
   108  	}
   109  	engine.env = env
   110  	if err = env.SetGeometry(Geometry{
   111  		SizeLower:       1024 * 1024 * 16,
   112  		SizeNow:         1024 * 1024 * 16,
   113  		SizeUpper:       1024 * 1024 * 1024 * 16,
   114  		GrowthStep:      1024 * 1024 * 16,
   115  		ShrinkThreshold: 0,
   116  		PageSize:        16384,
   117  	}); err != ErrSuccess {
   118  		return nil, err
   119  	}
   120  	if err = env.SetMaxDBS(1); err != ErrSuccess {
   121  		return nil, err
   122  	}
   123  
   124  	os.Mkdir("testdata", 0755)
   125  	err = env.Open(
   126  		path,
   127  		//EnvNoMemInit|EnvCoalesce|EnvLIFOReclaim|EnvSyncDurable,
   128  		EnvNoMemInit|EnvCoalesce|EnvLIFOReclaim|EnvSafeNoSync|EnvWriteMap,
   129  		0664,
   130  	)
   131  	if err != ErrSuccess {
   132  		return nil, err
   133  	}
   134  
   135  	if err = env.Begin(&engine.write, TxReadWrite); err != ErrSuccess {
   136  		return nil, err
   137  	}
   138  
   139  	if engine.rootDB, err = engine.write.OpenDBI("m", DBIntegerKey|DBCreate); err != ErrSuccess {
   140  		return nil, err
   141  	}
   142  	//if engine.rootDB, err = engine.write.OpenDBIEx("m", DBCreate, CmpU64, nil); err != ErrSuccess {
   143  	//	return nil, err
   144  	//}
   145  
   146  	if err = engine.write.Commit(); err != ErrSuccess {
   147  		return nil, err
   148  	}
   149  
   150  	//if err = env.Begin(&engine.rd, TxReadOnly); err != ErrSuccess {
   151  	//	return nil, err
   152  	//}
   153  	//if err = engine.rd.Reset(); err != ErrSuccess {
   154  	//	return nil, err
   155  	//}
   156  
   157  	return engine, ErrSuccess
   158  }
   159  
   160  func BenchmarkTxn_Put(b *testing.B) {
   161  	engine, err := initDB("./testdata/" + strconv.Itoa(b.N))
   162  	if err != ErrSuccess {
   163  		b.Fatal(err)
   164  	}
   165  	defer engine.env.Close(true)
   166  
   167  	key := make([]byte, 8)
   168  	data := []byte("hello")
   169  
   170  	keyVal := Bytes(&key)
   171  	dataVal := Bytes(&data)
   172  
   173  	b.ResetTimer()
   174  	b.ReportAllocs()
   175  
   176  	txn, err := engine.BeginWrite()
   177  	if err != ErrSuccess {
   178  		b.Fatal(err)
   179  	}
   180  
   181  	for i := 0; i < b.N; i++ {
   182  		//binary.BigEndian.PutUint64(key, uint64(20))
   183  		//binary.LittleEndian.PutUint64(key, uint64(i))
   184  		*(*uint64)(unsafe.Pointer(keyVal.Base)) = uint64(i)
   185  		//keyVal = U64(uint64(i))
   186  		if err = txn.Put(engine.rootDB, &keyVal, &dataVal, PutAppend); err != ErrSuccess {
   187  			txn.Abort()
   188  			b.Fatal(err)
   189  		}
   190  	}
   191  
   192  	//var envInfo EnvInfo
   193  	//if err = txn.EnvInfo(&envInfo); err != ErrSuccess {
   194  	//	b.Fatal(err)
   195  	//}
   196  	//var info TxInfo
   197  	//if err = txn.Info(&info); err != ErrSuccess {
   198  	//	b.Fatal(err)
   199  	//}
   200  	if err = txn.Commit(); err != ErrSuccess {
   201  		b.Fatal(err)
   202  	}
   203  	//engine.env.Sync(true, false)
   204  	//engine.env.Sync(true, false)
   205  }
   206  
   207  func BenchmarkTxn_PutCursor(b *testing.B) {
   208  	engine, err := initDB("./testdata/" + strconv.Itoa(b.N))
   209  	if err != ErrSuccess {
   210  		b.Fatal(err)
   211  	}
   212  	defer engine.env.Close(true)
   213  
   214  	b.ReportAllocs()
   215  	b.ResetTimer()
   216  	key := uint64(0)
   217  	data := []byte("hello")
   218  
   219  	keyVal := U64(&key)
   220  	dataVal := Bytes(&data)
   221  
   222  	{
   223  		insert := func(low, high uint64) {
   224  			txn, err := engine.BeginWrite()
   225  			if err != ErrSuccess {
   226  				b.Fatal(err)
   227  			}
   228  
   229  			cursor, err := txn.OpenCursor(engine.rootDB)
   230  			if err != ErrSuccess {
   231  				b.Fatal(err)
   232  			}
   233  
   234  			for i := low; i < high; i++ {
   235  				key = i
   236  				if err = cursor.Put(&keyVal, &dataVal, PutAppend); err != ErrSuccess {
   237  					cursor.Close()
   238  					txn.Abort()
   239  					b.Fatal(err)
   240  				}
   241  			}
   242  
   243  			if err = cursor.Close(); err != ErrSuccess {
   244  				b.Fatal(err)
   245  			}
   246  			if err = txn.Commit(); err != ErrSuccess {
   247  				b.Fatal(err)
   248  			}
   249  		}
   250  
   251  		const batchSize = 1000000
   252  		for i := 0; i < b.N; i += batchSize {
   253  			end := i + batchSize
   254  			if end > b.N {
   255  				end = b.N
   256  			}
   257  			insert(uint64(i), uint64(end))
   258  		}
   259  	}
   260  }
   261  
   262  func BenchmarkTxn_Get(b *testing.B) {
   263  	engine, err := initDB("./testdata/" + strconv.Itoa(b.N))
   264  	if err != ErrSuccess {
   265  		b.Fatal(err)
   266  	}
   267  	defer engine.env.Close(true)
   268  
   269  	key := uint64(0)
   270  	data := []byte("hello")
   271  
   272  	keyVal := U64(&key)
   273  	dataVal := Bytes(&data)
   274  
   275  	{
   276  		insert := func(low, high uint64) {
   277  			txn, err := engine.BeginWrite()
   278  			if err != ErrSuccess {
   279  				b.Fatal(err)
   280  			}
   281  
   282  			cursor, err := txn.OpenCursor(engine.rootDB)
   283  			if err != ErrSuccess {
   284  				b.Fatal(err)
   285  			}
   286  
   287  			for i := low; i < high; i++ {
   288  				key = i
   289  				if err = cursor.Put(&keyVal, &dataVal, PutAppend); err != ErrSuccess {
   290  					cursor.Close()
   291  					txn.Abort()
   292  					b.Fatal(err)
   293  				}
   294  			}
   295  
   296  			if err = cursor.Close(); err != ErrSuccess {
   297  				b.Fatal(err)
   298  			}
   299  			if err = txn.Commit(); err != ErrSuccess {
   300  				b.Fatal(err)
   301  			}
   302  		}
   303  
   304  		const batchSize = 10000000
   305  		for i := 0; i < b.N; i += batchSize {
   306  			end := i + batchSize
   307  			if end > b.N {
   308  				end = b.N
   309  			}
   310  			insert(uint64(i), uint64(end))
   311  		}
   312  	}
   313  
   314  	txn := &Tx{}
   315  
   316  	//engine.env.Sync(true, false)
   317  	//engine.env.Sync(true, false)
   318  
   319  	if err = engine.env.Begin(txn, TxReadOnly); err != ErrSuccess {
   320  		b.Fatal(err)
   321  	}
   322  	b.ResetTimer()
   323  	b.ReportAllocs()
   324  
   325  	//fmt.Println(dataVal.String())
   326  
   327  	//binary.LittleEndian.PutUint64(key, 0)
   328  
   329  	count := 0
   330  
   331  	for i := 1; i < b.N; i++ {
   332  		key = uint64(i)
   333  		keyVal = U64(&key)
   334  		//binary.BigEndian.PutUint64(key, uint64(20))
   335  		//binary.BigEndian.PutUint64(key[8:], uint64(i))
   336  		if err = txn.Get(engine.rootDB, &keyVal, &dataVal); err != ErrSuccess && err != ErrNotFound {
   337  			txn.Reset()
   338  			b.Fatal(err)
   339  		}
   340  		count++
   341  	}
   342  
   343  	if err = txn.Reset(); err != ErrSuccess {
   344  		b.Fatal(err)
   345  	}
   346  
   347  	b.StopTimer()
   348  
   349  	fmt.Println("count", count)
   350  
   351  	//var envInfo EnvInfo
   352  	//if err = txn.EnvInfo(&envInfo); err != ErrSuccess {
   353  	//	b.Fatal(err)
   354  	//}
   355  	//var info TxInfo
   356  	//if err = txn.Info(&info); err != ErrSuccess {
   357  	//	b.Fatal(err)
   358  	//}
   359  
   360  	//engine.env.Sync(true, false)
   361  	//engine.env.Sync(true, false)
   362  }
   363  
   364  func BenchmarkTxn_GetCursor(b *testing.B) {
   365  	engine, err := initDB("./testdata/" + strconv.Itoa(b.N))
   366  	if err != ErrSuccess {
   367  		b.Fatal(err)
   368  	}
   369  	defer engine.env.Close(true)
   370  
   371  	key := uint64(0)
   372  	data := []byte("hello")
   373  
   374  	keyVal := U64(&key)
   375  	dataVal := Bytes(&data)
   376  
   377  	{
   378  		insert := func(low, high uint64) {
   379  			txn, err := engine.BeginWrite()
   380  			if err != ErrSuccess {
   381  				b.Fatal(err)
   382  			}
   383  
   384  			cursor, err := txn.OpenCursor(engine.rootDB)
   385  			if err != ErrSuccess {
   386  				b.Fatal(err)
   387  			}
   388  
   389  			for i := low; i < high; i++ {
   390  				key = i
   391  				if err = cursor.Put(&keyVal, &dataVal, PutAppend); err != ErrSuccess {
   392  					cursor.Close()
   393  					txn.Abort()
   394  					b.Fatal(err)
   395  				}
   396  			}
   397  
   398  			if err = cursor.Close(); err != ErrSuccess {
   399  				b.Fatal(err)
   400  			}
   401  			if err = txn.Commit(); err != ErrSuccess {
   402  				b.Fatal(err)
   403  			}
   404  		}
   405  
   406  		const batchSize = 1000000
   407  		for i := 0; i < b.N; i += batchSize {
   408  			end := i + batchSize
   409  			if end > b.N {
   410  				end = b.N
   411  			}
   412  			insert(uint64(i), uint64(end))
   413  		}
   414  	}
   415  
   416  	txn := &Tx{}
   417  
   418  	//engine.env.Sync(true, false)
   419  	//engine.env.Sync(true, false)
   420  
   421  	if err = engine.env.Begin(txn, TxReadOnly); err != ErrSuccess {
   422  		b.Fatal(err)
   423  	}
   424  	//txn, err = engine.BeginRead()
   425  	//if err != ErrSuccess {
   426  	//	b.Fatal(err)
   427  	//}
   428  
   429  	b.ResetTimer()
   430  	b.ReportAllocs()
   431  
   432  	cursor, err := txn.OpenCursor(engine.rootDB)
   433  	if err != ErrSuccess {
   434  		b.Fatal(err)
   435  	}
   436  
   437  	//binary.LittleEndian.PutUint64(key, uint64(b.N))
   438  
   439  	//if err = txn.Get(engine.rootDB, &keyVal, &dataVal); err != ErrSuccess {
   440  	//	b.Fatal(err)
   441  	//}
   442  
   443  	//keyInt := binary.LittleEndian.Uint64(key)
   444  
   445  	//if err = cursor.Get(&keyVal, &dataVal, CursorSet); err != ErrSuccess {
   446  	//	b.Fatal(err)
   447  	//}
   448  
   449  	dataVal = Val{}
   450  	keyVal = Val{}
   451  
   452  	//fmt.Println(dataVal.String())
   453  
   454  	//binary.LittleEndian.PutUint64(key, 0)
   455  
   456  	count := 0
   457  	//
   458  	for {
   459  		if err = cursor.Get(&keyVal, &dataVal, CursorNextNoDup); err != ErrSuccess {
   460  			break
   461  		}
   462  		//if keyVal.Base == nil {
   463  		//	break
   464  		//}
   465  		count++
   466  		//keyInt = binary.LittleEndian.Uint64(key)
   467  		//_ = keyInt
   468  
   469  		//keyVal = Val{}
   470  		//dataVal = Val{}
   471  
   472  		//if cursor.EOF() != 0 {
   473  		//	break
   474  		//}
   475  	}
   476  
   477  	//if count == 1000000 {
   478  	//	println("1m")
   479  	//}
   480  
   481  	//for i := 0; i < b.N; i++ {
   482  	//	*(*uint64)(unsafe.Pointer(&key[0])) = uint64(i)
   483  	//	//binary.BigEndian.PutUint64(key, uint64(20))
   484  	//	//binary.BigEndian.PutUint64(key[8:], uint64(i))
   485  	//	//keyVal = U64(uint64(i))
   486  	//	if err = txn.Get(engine.rootDB, &keyVal, &dataVal); err != ErrSuccess && err != ErrNotFound {
   487  	//		txn.Reset()
   488  	//		b.Fatal(err)
   489  	//	}
   490  	//}
   491  
   492  	if err = cursor.Close(); err != ErrSuccess {
   493  		b.Fatal(err)
   494  	}
   495  	if err = txn.Reset(); err != ErrSuccess {
   496  		b.Fatal(err)
   497  	}
   498  
   499  	b.StopTimer()
   500  
   501  	fmt.Println("count", count)
   502  
   503  	//var envInfo EnvInfo
   504  	//if err = txn.EnvInfo(&envInfo); err != ErrSuccess {
   505  	//	b.Fatal(err)
   506  	//}
   507  	//var info TxInfo
   508  	//if err = txn.Info(&info); err != ErrSuccess {
   509  	//	b.Fatal(err)
   510  	//}
   511  
   512  	//engine.env.Sync(true, false)
   513  	//engine.env.Sync(true, false)
   514  }
   515  
   516  func TestTxn_Cursor(b *testing.T) {
   517  	iterations := 100
   518  	engine, err := initDB("./testdata/" + strconv.Itoa(iterations))
   519  	if err != ErrSuccess {
   520  		b.Fatal(err)
   521  	}
   522  
   523  	key := make([]byte, 8)
   524  	data := []byte("hello")
   525  
   526  	keyVal := Bytes(&key)
   527  	dataVal := Bytes(&data)
   528  
   529  	txn, err := engine.BeginWrite()
   530  	if err != ErrSuccess {
   531  		b.Fatal(err)
   532  	}
   533  
   534  	for i := 0; i < iterations; i++ {
   535  		//binary.BigEndian.PutUint64(key, uint64(20))
   536  		//*(*uint64)(unsafe.Pointer(&key[0])) = uint64(i)
   537  		binary.LittleEndian.PutUint64(key, uint64(i))
   538  		//keyVal = U64(uint64(i))
   539  		if err = txn.Put(engine.rootDB, &keyVal, &dataVal, 0); err != ErrSuccess {
   540  			txn.Abort()
   541  			b.Fatal(err)
   542  		}
   543  	}
   544  
   545  	//*(*uint64)(unsafe.Pointer(&key[0])) = 0
   546  
   547  	if err = txn.Commit(); err != ErrSuccess {
   548  		b.Fatal(err)
   549  	}
   550  
   551  	txn = &Tx{}
   552  
   553  	//engine.env.Sync(true, false)
   554  	//engine.env.Sync(true, false)
   555  
   556  	if err = engine.env.Begin(txn, TxReadOnly); err != ErrSuccess {
   557  		b.Fatal(err)
   558  	}
   559  	//txn, err = engine.BeginRead()
   560  	//if err != ErrSuccess {
   561  	//	b.Fatal(err)
   562  	//}
   563  
   564  	cursor, err := txn.OpenCursor(engine.rootDB)
   565  	if err != ErrSuccess {
   566  		b.Fatal(err)
   567  	}
   568  
   569  	dataVal = Val{}
   570  	keyVal = Val{}
   571  
   572  	binary.LittleEndian.PutUint64(key, 0)
   573  
   574  	count := 0
   575  	//
   576  	for {
   577  		if err = cursor.Get(&keyVal, &dataVal, CursorNextNoDup); err != ErrSuccess {
   578  			break
   579  		}
   580  		//if keyVal.Base == nil {
   581  		//	break
   582  		//}
   583  		count++
   584  		keyInt := keyVal.U64()
   585  		println("key", keyInt)
   586  		_ = keyInt
   587  
   588  		//keyVal = Val{}
   589  		//dataVal = Val{}
   590  
   591  		//if cursor.EOF() != 0 {
   592  		//	break
   593  		//}
   594  	}
   595  
   596  	//for i := 0; i < b.N; i++ {
   597  	//	*(*uint64)(unsafe.Pointer(&key[0])) = uint64(i)
   598  	//	//binary.BigEndian.PutUint64(key, uint64(20))
   599  	//	//binary.BigEndian.PutUint64(key[8:], uint64(i))
   600  	//	//keyVal = U64(uint64(i))
   601  	//	if err = txn.Get(engine.rootDB, &keyVal, &dataVal); err != ErrSuccess && err != ErrNotFound {
   602  	//		txn.Reset()
   603  	//		b.Fatal(err)
   604  	//	}
   605  	//}
   606  
   607  	if err = cursor.Close(); err != ErrSuccess {
   608  		b.Fatal(err)
   609  	}
   610  	if err = txn.Reset(); err != ErrSuccess {
   611  		b.Fatal(err)
   612  	}
   613  
   614  	fmt.Println("count", count)
   615  
   616  	//var envInfo EnvInfo
   617  	//if err = txn.EnvInfo(&envInfo); err != ErrSuccess {
   618  	//	b.Fatal(err)
   619  	//}
   620  	//var info TxInfo
   621  	//if err = txn.Info(&info); err != ErrSuccess {
   622  	//	b.Fatal(err)
   623  	//}
   624  
   625  	//engine.env.Sync(true, false)
   626  	//engine.env.Sync(true, false)
   627  }