diff --git a/go.mod b/go.mod index 2a0e12f..078466d 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,18 @@ module github.com/ucwong/golang-kv go 1.20 require ( - github.com/cockroachdb/pebble v0.0.0-20230510135629-fe7ae7a62e0f - github.com/dgraph-io/badger/v4 v4.0.2-0.20230509100715-ef0e55289cf7 + github.com/cockroachdb/pebble v0.0.0-20230519195609-e892f45bc7e2 + github.com/dgraph-io/badger/v4 v4.0.2-0.20230519043050-44b59785a8cd + github.com/nutsdb/nutsdb v0.12.3-0.20230521084054-b0a6e1ba0c39 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d github.com/ucwong/go-ttlmap v1.0.2-0.20221020173635-331e7ddde2bb - go.etcd.io/bbolt v1.3.7-0.20230508234803-8b1ee10512cc + go.etcd.io/bbolt v1.3.7-0.20230518005001-07579acf0c9a ) require ( github.com/DataDog/zstd v1.5.2 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -36,6 +38,8 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/xujiajun/mmap-go v1.0.1 // indirect + github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 // indirect go.opencensus.io v0.24.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/net v0.8.0 // indirect diff --git a/go.sum b/go.sum index aa55db8..77b26fd 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,11 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -29,8 +32,8 @@ github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZO github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230510135629-fe7ae7a62e0f h1:NQ2CYGSQoozmZlh8Md436mTqO7B0DNFgeitYw7Gn0LU= -github.com/cockroachdb/pebble v0.0.0-20230510135629-fe7ae7a62e0f/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= +github.com/cockroachdb/pebble v0.0.0-20230519195609-e892f45bc7e2 h1:MnVO2CIKkGvP82UJopWja6nw7GZsxVLUKWGtzTKYa5I= +github.com/cockroachdb/pebble v0.0.0-20230519195609-e892f45bc7e2/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= @@ -43,8 +46,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger/v4 v4.0.2-0.20230509100715-ef0e55289cf7 h1:b7OofX+02tsxy3Midj88nwRsktdcsglG0yEnvHnLhes= -github.com/dgraph-io/badger/v4 v4.0.2-0.20230509100715-ef0e55289cf7/go.mod h1:P50u28d39ibBRmIJuQC/NSdBOg46HnHw7al2SW5QRHg= +github.com/dgraph-io/badger/v4 v4.0.2-0.20230519043050-44b59785a8cd h1:cPJbXgrVKbBIwa7rxVa6PJG6KVWYjLY42h1V1wWoQNc= +github.com/dgraph-io/badger/v4 v4.0.2-0.20230519043050-44b59785a8cd/go.mod h1:P50u28d39ibBRmIJuQC/NSdBOg46HnHw7al2SW5QRHg= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= @@ -191,6 +194,8 @@ github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5Vgl github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nutsdb/nutsdb v0.12.3-0.20230521084054-b0a6e1ba0c39 h1:Rb5K/Rn/cyH0IUEF5mUqhsbw2avjjc7ufAlo8QW04e4= +github.com/nutsdb/nutsdb v0.12.3-0.20230521084054-b0a6e1ba0c39/go.mod h1:FSztXVhUSK5YmedmZQ6m37cU/KpVbGaezUEmUBP8DEo= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -273,6 +278,11 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xujiajun/gorouter v1.2.0/go.mod h1:yJrIta+bTNpBM/2UT8hLOaEAFckO+m/qmR3luMIQygM= +github.com/xujiajun/mmap-go v1.0.1 h1:7Se7ss1fLPPRW+ePgqGpCkfGIZzJV6JPq9Wq9iv/WHc= +github.com/xujiajun/mmap-go v1.0.1/go.mod h1:CNN6Sw4SL69Sui00p0zEzcZKbt+5HtEnYUsc6BKKRMg= +github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 h1:w0si+uee0iAaCJO9q86T6yrhdadgcsoNuh47LrUykzg= +github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235/go.mod h1:MR4+0R6A9NS5IABnIM3384FfOq8QFVnm7WDrBOhIaMU= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= @@ -280,8 +290,8 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.7-0.20230508234803-8b1ee10512cc h1:eJpgKB8ZyD4N7Ke0pmCFXkz9voA3wELHbtnr02fssS4= -go.etcd.io/bbolt v1.3.7-0.20230508234803-8b1ee10512cc/go.mod h1:Gpl72SbxgstRmiprmz97EAQ8YY0qrKG6jHQEVYP+DKY= +go.etcd.io/bbolt v1.3.7-0.20230518005001-07579acf0c9a h1:ujWV+qUt0smDnhcCocmcKP3ZlxSp4AiZeP1rkN0qU7I= +go.etcd.io/bbolt v1.3.7-0.20230518005001-07579acf0c9a/go.mod h1:Gpl72SbxgstRmiprmz97EAQ8YY0qrKG6jHQEVYP+DKY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -340,6 +350,7 @@ golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -365,6 +376,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/kv.go b/kv.go index c3d11ab..fe9fa59 100644 --- a/kv.go +++ b/kv.go @@ -19,6 +19,7 @@ import ( "github.com/ucwong/golang-kv/badger" "github.com/ucwong/golang-kv/bolt" "github.com/ucwong/golang-kv/leveldb" + "github.com/ucwong/golang-kv/nutsdb" "github.com/ucwong/golang-kv/pebble" ) @@ -37,3 +38,7 @@ func LevelDB(path string, opt ...leveldb.LevelDBOption) Bucket { func Pebble(path string, opt ...pebble.PebbleOption) Bucket { return pebble.Open(path, opt...) } + +func NutsDB(path string, opt ...nutsdb.NutsdbOption) Bucket { + return nutsdb.Open(path, opt...) +} diff --git a/kv_test.go b/kv_test.go index e132581..01850a9 100644 --- a/kv_test.go +++ b/kv_test.go @@ -27,6 +27,7 @@ func TestLocal(t *testing.T) { bolt1() badger1() leveldb1() + nutsdb1() } var batch int = 10 @@ -271,3 +272,87 @@ func badger1() { fmt.Printf("...........%s\n", string(f2)) db.Close() } + +func nutsdb1() { + var db Bucket + + db = NutsDB("") + if db == nil { + panic("nutsdb create err") + } + db.Set([]byte("yx"), []byte("yx")) + db.Set([]byte("yy"), []byte("yy")) + db.Set([]byte("a"), []byte("a")) + db.Set([]byte("b"), []byte("b")) + db.Set([]byte("x"), []byte("x")) + db.Set([]byte("y"), []byte("y")) + db.Set([]byte("xxy"), []byte("xxy")) + db.Set([]byte("xxx"), []byte("xxx")) + db.Set([]byte("xxxyx"), []byte("xxxyx")) + db.Set([]byte("xyy"), []byte("xyy")) + db.SetTTL([]byte("ttlxxxyx"), []byte("ttlxxxyx"), 1000*time.Millisecond) + db.SetTTL([]byte("ttlxxxyx1"), []byte("ttlxxxyx1"), 2000*time.Millisecond) + db.SetTTL([]byte("ttlxxxyx2"), []byte("ttlxxxyx2"), 5000*time.Millisecond) + db.SetTTL([]byte("ttlxxxyx3"), []byte("ttlxxxyx3"), 5000*time.Millisecond) + for i := 0; i < batch; i++ { + db.SetTTL([]byte("ttlxxxyx3"+strconv.Itoa(i)), []byte("ttlxxxyx3"+strconv.Itoa(i)), 2000*time.Millisecond) + } + for i := 0; i < batch; i++ { + db.SetTTL([]byte("ttlxxxyx4"+strconv.Itoa(i)), []byte("ttlxxxyx4"+strconv.Itoa(i)), 5000*time.Millisecond) + } + res := db.Scan() + for _, i := range res { + fmt.Printf("scan...%v...%s\n", len(res), string(i)) + } + res = db.Range([]byte("xxx"), []byte("xxz")) + for _, i := range res { + fmt.Printf("range...%v...%s\n", len(res), string(i)) + } + res = db.Prefix([]byte("xx")) + for _, i := range res { + fmt.Printf("prefix...%v...%s\n", len(res), string(i)) + } + res = db.Suffix([]byte("x")) + for _, i := range res { + fmt.Printf("suffix...%v...%s\n", len(res), string(i)) + } + res = db.Scan() + for _, i := range res { + fmt.Printf("scan...%v...%v\n", len(res), len(i)) + } + //db.Del([]byte("xxy")) + //res = db.Scan() + //for _, i := range res { + // fmt.Printf("...%v...%s\n", len(res), string(i)) + //} + db.Del([]byte("xx")) + time.Sleep(500 * time.Millisecond) + f := db.Get([]byte("ttlxxxyx")) + fmt.Printf("...........%s\n", string(f)) + + f1 := db.Get([]byte("xxy")) + fmt.Printf("...........%s\n", string(f1)) + + for i := 0; i < batch/2; i++ { + db.Set([]byte("ttlxxxyx4"+strconv.Itoa(i)), []byte("reset -> ttlxxxyx4"+strconv.Itoa(i))) + } + + for i := 0; i < batch; i++ { + fmt.Printf("...........%s\n", string(db.Get([]byte("ttlxxxyx4"+strconv.Itoa(i))))) + } + + db.Del([]byte("ttlxxxyx1")) + + time.Sleep(3000 * time.Millisecond) + m := db.Get([]byte("ttlxxxyx")) + fmt.Printf("...........%s\n", string(m)) + + db.Del([]byte("ttlxxxyx1")) + + m2 := db.Get([]byte("ttlxxxyx1")) + fmt.Printf("...........%s\n", string(m2)) + + f2 := db.Get([]byte("xxy")) + fmt.Printf("...........%s\n", string(f2)) + db.Close() +} diff --git a/nutsdb/nutsdb.go b/nutsdb/nutsdb.go new file mode 100644 index 0000000..7a52ccc --- /dev/null +++ b/nutsdb/nutsdb.go @@ -0,0 +1,182 @@ +// Copyright (C) 2023 ucwong +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +package nutsdb + +import ( + "bytes" + "os" + "path/filepath" + "time" + + "github.com/ucwong/golang-kv/common" + + nutsdb "github.com/nutsdb/nutsdb" +) + +type NutsDB struct { + engine *nutsdb.DB +} + +const GLOBAL = "m41gA7omIWU4s" + +type NutsdbOption func(nutsdb.Options) nutsdb.Options + +func Open(path string, opts ...NutsdbOption) *NutsDB { + //if len(path) == 0 { + path = filepath.Join(path, common.GLOBAL_SPACE, ".nuts") + err := os.MkdirAll(path, 0777) //os.FileMode(os.ModePerm)) + if err != nil { + return nil + } + //} + b := &NutsDB{} + + var option nutsdb.Options + for _, opt := range opts { + option = opt(option) + } + if db, err := nutsdb.Open(nutsdb.DefaultOptions, nutsdb.WithDir(filepath.Join(path, ".nuts"))); err == nil { + b.engine = db + } else { + //panic(err) + return nil + } + + return b +} + +func (b *NutsDB) Get(k []byte) (v []byte) { + b.engine.View(func(tx *nutsdb.Tx) error { + if e, err := tx.Get(GLOBAL, k); err != nil { + return err + } else { + v = e.Value + } + return nil + }) + return +} + +func (b *NutsDB) Set(k, v []byte) (err error) { + return b.engine.View(func(tx *nutsdb.Tx) error { + return tx.Put(GLOBAL, k, v, 0) + }) +} + +func (b *NutsDB) Del(k []byte) (err error) { + err = b.engine.Update(func(tx *nutsdb.Tx) error { + return tx.Delete(GLOBAL, k) + }) + + return +} + +func (b *NutsDB) Prefix(prefix []byte) (res [][]byte) { + b.engine.View(func(tx *nutsdb.Tx) error { + if entries, _, err := tx.PrefixScan(GLOBAL, prefix, 25, 100); err != nil { + return err + } else { + for _, entry := range entries { + res = append(res, common.SafeCopy(nil, entry.Value)) + } + } + + return nil + }) + + return +} + +func (b *NutsDB) Suffix(suffix []byte) (res [][]byte) { + b.engine.View(func(tx *nutsdb.Tx) error { + entries, err := tx.GetAll(GLOBAL) + if err != nil { + return err + } + + for _, entry := range entries { + if bytes.HasSuffix(entry.Key, suffix) { + res = append(res, common.SafeCopy(nil, entry.Value)) + } + } + + return nil + }) + + return +} + +func (b *NutsDB) Scan() (res [][]byte) { + b.engine.View(func(tx *nutsdb.Tx) error { + entries, err := tx.GetAll(GLOBAL) + if err != nil { + return err + } + + for _, entry := range entries { + res = append(res, common.SafeCopy(nil, entry.Value)) + } + return nil + }) + + return +} + +func (b *NutsDB) SetTTL(k, v []byte, expire time.Duration) (err error) { + err = b.engine.Update(func(tx *nutsdb.Tx) error { + if err := tx.Put(GLOBAL, k, v, uint32(expire.Seconds())); err != nil { + return err + } + return nil + }) + + return +} + +func (b *NutsDB) Range(start, limit []byte) (res [][]byte) { + b.engine.View(func(tx *nutsdb.Tx) error { + if entries, err := tx.RangeScan(GLOBAL, start, limit); err != nil { + return err + } else { + for _, entry := range entries { + res = append(res, common.SafeCopy(nil, entry.Value)) + } + } + + return nil + }) + return +} + +func (b *NutsDB) Close() error { + return b.engine.Close() +} + +func (b *NutsDB) BatchSet(kvs map[string][]byte) error { + err := b.engine.Update(func(tx *nutsdb.Tx) error { + for k, v := range kvs { + if err := tx.Put(GLOBAL, []byte(k), v, 0); err != nil { + return err + } + } + return nil + }) + return err +} + +func (b *NutsDB) Name() string { + return "nutsdb" +}