Codebase list golang-github-pzhin-go-sophia / 9031ff1
New upstream version 0.0~git20191015.0.afcd224 Sascha Steinbiss 4 years ago
15 changed file(s) with 279 addition(s) and 130 deletion(s). Raw diff Collapse all Expand all
00 language: go
11 sudo: false
22 go:
3 - 1.8
4 - 1.7
5 - tip
3 - 1.7.x
4 - 1.8.x
5 - 1.9.x
6 - 1.10.x
7 - 1.11.x
8 - 1.12.x
9 - 1.13.x
10 - master
611 before_install:
712 - go get github.com/mattn/goveralls
813 - go get github.com/stretchr/testify
66 )
77
88 var cache = map[string]*C.char{}
9 var mLock sync.Mutex
9 var mLock sync.RWMutex
1010
1111 func getCStringFromCache(str string) *C.char {
12 mLock.RLock()
1213 cStr, ok := cache[str]
14 mLock.RUnlock()
1315 if ok {
1416 return cStr
1517 }
18
1619 mLock.Lock()
1720 cStr, ok = cache[str]
18 if ok {
19 return cStr
21 if !ok {
22 cStr = cString(str)
23 cache[str] = cStr
2024 }
21 cStr = cString(str)
22 cache[str] = cStr
2325 mLock.Unlock()
2426 return cStr
2527 }
0 package sophia
1
2 import (
3 "math/rand"
4 "runtime"
5 "sync"
6 "testing"
7 )
8
9 const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
10
11 func TestGetCStringFromCacheRace(t *testing.T) {
12 var wg sync.WaitGroup
13 workers := runtime.GOMAXPROCS(-1) * 8
14 const iterations = 100
15 for i := 0; i < workers; i ++ {
16 wg.Add(1)
17 go func(){
18 defer wg.Done()
19 for i := 0; i < iterations; i++ {
20 getCStringFromCache(generateString(32))
21 }
22 }()
23 }
24 wg.Wait()
25 }
26
27 func generateString(n int) string {
28 b := make([]byte, n)
29 for i := range b {
30 b[i] = letters[rand.Intn(len(letters))]
31 }
32 return string(b)
33 }
3333 // Cursor iterates over key-values in a database.
3434 type Cursor struct {
3535 ptr unsafe.Pointer
36 doc *Document
36 doc Document
3737 closed bool
3838 }
3939
5454
5555 // Next fetches the next row for the cursor
5656 // Returns next row if it exists else it will return nil
57 func (cur *Cursor) Next() *Document {
57 func (cur *Cursor) Next() Document {
5858 if cur.closed {
59 return nil
59 return Document{}
6060 }
6161 ptr := spGet(cur.ptr, cur.doc.ptr)
6262 if ptr == nil {
63 return nil
63 return Document{}
6464 }
6565 cur.doc.ptr = ptr
6666 return cur.doc
5858
5959 func testCursorError(t *testing.T, db *Database) {
6060 doc := db.Document()
61 require.NotNil(t, doc)
61 require.False(t, doc.IsEmpty())
6262
6363 cursor, err := db.Cursor(doc)
6464 require.Nil(t, err)
6868 require.Nil(t, err)
6969
7070 require.Error(t, cursor.Close())
71 require.Nil(t, cursor.Next())
71 d := cursor.Next()
72 require.True(t, d.IsEmpty())
7273 }
7374
7475 func testCursor(t *testing.T, db *Database, start, count int64, valueTemplate string) {
7576 id := start
7677 doc := db.Document()
77 require.NotNil(t, doc)
78 require.False(t, doc.IsEmpty())
7879 if start != 0 {
7980 doc.SetInt("key", start)
8081 }
9091 size int
9192 counter int64
9293 )
93 for d := cursor.Next(); d != nil; d = cursor.Next() {
94 for d := cursor.Next(); !d.IsEmpty(); d = cursor.Next() {
9495 require.Equal(t, id, d.GetInt("key"))
9596 require.Equal(t, fmt.Sprintf(valueTemplate, id), d.GetString("value", &size))
9697 counter++
101102
102103 func testReverseCursor(t *testing.T, db *Database, count int64, valueTemplate string) {
103104 doc := db.Document()
104 require.NotNil(t, doc)
105 require.False(t, doc.IsEmpty())
105106
106107 doc.Set(CursorOrder, LTE)
107108
116117 size int
117118 id int64 = count - 1
118119 )
119 for d := cursor.Next(); d != nil; d = cursor.Next() {
120 for d := cursor.Next(); !d.IsEmpty(); d = cursor.Next() {
120121 require.Equal(t, id, d.GetInt("key"))
121122 require.Equal(t, fmt.Sprintf(valueTemplate, id), d.GetString("value", &size))
122123 id--
184185 prefixStr = prefixStr[:len(prefixStr)-1]
185186
186187 doc := db.Document()
187 require.NotNil(t, doc)
188 require.False(t, doc.IsEmpty())
188189
189190 doc.Set(CursorPrefix, prefixStr)
190191
202203
203204 // get row that match prefix
204205 d := cursor.Next()
205 require.NotNil(t, d)
206 require.False(t, d.IsEmpty())
206207 require.Equal(t, prefixStr, d.GetString(keyPath, &size))
207208 require.Equal(t, fmt.Sprintf(valueTemplate, prefix/base), d.GetString(valuePath, &size))
208209
209210 // get rows that have additional symbol at the end
210 for d := cursor.Next(); d != nil; d = cursor.Next() {
211 for d := cursor.Next(); !d.IsEmpty(); d = cursor.Next() {
211212 id := prefix + count
212213 require.Equal(t, strconv.FormatInt(int64(id), base), d.GetString(keyPath, &size))
213214 require.Equal(t, fmt.Sprintf(valueTemplate, id), d.GetString(valuePath, &size))
1515 }
1616
1717 // Get retrieves the row for the set of keys.
18 func (d *dataStore) Get(doc *Document) (*Document, error) {
18 func (d *dataStore) Get(doc Document) (Document, error) {
1919 ptr := spGet(d.ptr, doc.ptr)
2020 if ptr == nil {
2121 err := d.env.Error()
2222 if err == nil {
23 return nil, ErrNotFound
23 return Document{}, ErrNotFound
2424 }
25 return nil, fmt.Errorf("failed Get document: err=%v", err)
25 return Document{}, fmt.Errorf("failed Get document: err=%v", err)
2626 }
2727 return newDocument(ptr, 0), nil
2828 }
2929
3030 // Set sets the row of the set of keys.
31 func (d *dataStore) Set(doc *Document) error {
31 func (d *dataStore) Set(doc Document) error {
3232 if !spSet(d.ptr, doc.ptr) {
3333 return fmt.Errorf("failed Set document: err=%v", d.env.Error())
3434 }
3636 }
3737
3838 // Upsert sets the row of the set of keys.
39 func (d *dataStore) Upsert(doc *Document) error {
39 func (d *dataStore) Upsert(doc Document) error {
4040 if !spUpsert(d.ptr, doc.ptr) {
4141 return fmt.Errorf("failed Upsert document: err=%v", d.env.Error())
4242 }
4444 }
4545
4646 // Delete deletes row with specified set of keys.
47 func (d *dataStore) Delete(doc *Document) error {
47 func (d *dataStore) Delete(doc Document) error {
4848 if !spDelete(d.ptr, doc.ptr) {
4949 return fmt.Errorf("failed Delete document: err=%v", d.env.Error())
5050 }
8585 }
8686
8787 // Document creates a Document for a single or multi-statement transactions
88 func (db *Database) Document() *Document {
88 func (db *Database) Document() Document {
8989 ptr := spDocument(db.ptr)
9090 if ptr == nil {
91 return nil
91 return Document{}
9292 }
9393 return newDocument(ptr, db.fieldsCount)
9494 }
9595
9696 // Cursor returns a Cursor for iterating over rows in the database
97 func (db *Database) Cursor(doc *Document) (*Cursor, error) {
98 if nil == doc {
97 func (db *Database) Cursor(doc Document) (*Cursor, error) {
98 if doc.IsEmpty() {
9999 return nil, errors.New("failed to create cursor: nil Document")
100100 }
101101 cPtr := spCursor(db.env.ptr)
3535 defer env.Close()
3636
3737 doc := db.Document()
38 require.NotNil(t, doc)
38 require.False(t, doc.IsEmpty())
3939 require.Nil(t, env.Error())
4040 }
4141
6363 require.NotNil(t, db)
6464
6565 doc := db.Document()
66 require.NotNil(t, doc)
66 require.False(t, doc.IsEmpty())
6767 require.Nil(t, env.Error())
6868 defer doc.Free()
6969
100100 defer env.Close()
101101
102102 doc := db.Document()
103 require.NotNil(t, doc)
103 require.False(t, doc.IsEmpty())
104104 require.Nil(t, env.Error())
105105 defer doc.Free()
106106
130130 require.NotNil(t, db)
131131
132132 doc := db.Document()
133 require.NotNil(t, doc)
133 require.False(t, doc.IsEmpty())
134134 require.Nil(t, env.Error())
135135 defer doc.Free()
136136
138138
139139 d, err := db.Get(doc)
140140 require.NotNil(t, err)
141 require.Nil(t, d)
141 require.True(t, d.IsEmpty())
142142 }
143143
144144 func TestDatabaseGet(t *testing.T) {
168168 defer env.Close()
169169
170170 doc := db.Document()
171 require.NotNil(t, doc)
171 require.False(t, doc.IsEmpty())
172172 require.Nil(t, env.Error())
173173
174174 require.True(t, doc.SetString(keyPath, expectedKey))
178178 doc.Free()
179179
180180 doc = db.Document()
181 require.NotNil(t, doc)
181 require.False(t, doc.IsEmpty())
182182 require.Nil(t, env.Error())
183183 defer doc.Free()
184184
186186
187187 d, err := db.Get(doc)
188188 require.Nil(t, err)
189 require.NotNil(t, d)
189 require.False(t, d.IsEmpty())
190190 d.Destroy()
191191 }
192192
210210 require.NotNil(t, db)
211211
212212 doc := db.Document()
213 require.NotNil(t, doc)
213 require.False(t, doc.IsEmpty())
214214 require.Nil(t, env.Error())
215215 defer doc.Free()
216216
246246 defer env.Close()
247247
248248 doc := db.Document()
249 require.NotNil(t, doc)
249 require.False(t, doc.IsEmpty())
250250 require.Nil(t, env.Error())
251251
252252 require.True(t, doc.SetString(keyPath, expectedKey))
256256 doc.Free()
257257
258258 doc = db.Document()
259 require.NotNil(t, doc)
259 require.False(t, doc.IsEmpty())
260260 require.Nil(t, env.Error())
261261
262262 require.True(t, doc.SetString(keyPath, expectedKey))
265265 doc.Free()
266266
267267 doc = db.Document()
268 require.NotNil(t, doc)
268 require.False(t, doc.IsEmpty())
269269 require.Nil(t, env.Error())
270270 defer doc.Free()
271271
274274 d, err := db.Get(doc)
275275 require.NotNil(t, err)
276276 require.Equal(t, ErrNotFound, err)
277 require.Nil(t, d)
277 require.True(t, d.IsEmpty())
278278 }
279279
280280 func TestDatabaseWithCustomSchema(t *testing.T) {
308308 const expectedValue int64 = 73
309309
310310 doc := db.Document()
311 require.NotNil(t, doc)
311 require.False(t, doc.IsEmpty())
312312 require.True(t, doc.Set(keyPath, expectedKey))
313313 require.True(t, doc.Set(valuePath, expectedValue))
314314
317317 require.Nil(t, err)
318318
319319 doc = db.Document()
320 require.NotNil(t, doc)
320 require.False(t, doc.IsEmpty())
321321 require.True(t, doc.Set(keyPath, expectedKey))
322322
323323 d, err := db.Get(doc)
324324 doc.Free()
325325 require.Nil(t, err)
326 require.NotNil(t, d)
327
328 defer d.Destroy()
326 require.False(t, d.IsEmpty())
329327
330328 require.Equal(t, expectedKey, d.GetInt(keyPath))
331329 require.Equal(t, expectedValue, d.GetInt(valuePath))
332
333 doc = db.Document()
334 require.NotNil(t, doc)
330 d.Destroy()
331
332 doc = db.Document()
333 require.False(t, doc.IsEmpty())
335334 require.Nil(t, env.Error())
336335
337336 require.True(t, doc.Set(keyPath, expectedKey))
340339 doc.Free()
341340
342341 doc = db.Document()
343 require.NotNil(t, doc)
342 require.False(t, doc.IsEmpty())
344343 require.Nil(t, env.Error())
345344 defer doc.Free()
346345
349348 d, err = db.Get(doc)
350349 require.NotNil(t, err)
351350 require.Equal(t, ErrNotFound, err)
352 require.Nil(t, d)
351 require.True(t, d.IsEmpty())
353352 }
354353
355354 func TestDatabaseWithMultipleKeys(t *testing.T) {
393392 )
394393
395394 doc := db.Document()
396 require.NotNil(t, doc)
395 require.False(t, doc.IsEmpty())
397396 require.True(t, doc.Set(key1Path, expectedKey1))
398397 require.True(t, doc.Set(key2Path, expectedKey2))
399398 require.True(t, doc.Set(key3Path, expectedKey3))
404403 require.Nil(t, err)
405404
406405 doc = db.Document()
407 require.NotNil(t, doc)
406 require.False(t, doc.IsEmpty())
408407 require.True(t, doc.Set(key1Path, expectedKey1))
409408 require.True(t, doc.Set(key2Path, expectedKey2))
410409 require.True(t, doc.Set(key3Path, expectedKey3))
412411 d, err := db.Get(doc)
413412 doc.Free()
414413 require.Nil(t, err)
415 require.NotNil(t, d)
416
417 defer d.Destroy()
414 require.False(t, d.IsEmpty())
418415
419416 require.Equal(t, expectedKey1, d.GetInt(key1Path))
420417 require.Equal(t, expectedKey2, d.GetInt(key2Path))
421418 require.Equal(t, expectedKey3, d.GetInt(key3Path))
422419 require.Equal(t, expectedValue, d.GetInt(valuePath))
423
424 doc = db.Document()
425 require.NotNil(t, doc)
420 d.Destroy()
421
422 doc = db.Document()
423 require.False(t, doc.IsEmpty())
426424 require.Nil(t, env.Error())
427425
428426 require.True(t, doc.Set(key1Path, expectedKey1))
433431 doc.Free()
434432
435433 doc = db.Document()
436 require.NotNil(t, doc)
434 require.False(t, doc.IsEmpty())
437435 require.Nil(t, env.Error())
438436 defer doc.Free()
439437
444442 d, err = db.Get(doc)
445443 require.NotNil(t, err)
446444 require.Equal(t, ErrNotFound, err)
447 require.Nil(t, d)
445 require.True(t, d.IsEmpty())
448446 }
449447
450448 func TestDatabaseUseSomeDocumentsAtTheSameTime(t *testing.T) {
494492 doc2.Free()
495493
496494 doc := db.Document()
497 require.NotNil(t, doc)
495 require.False(t, doc.IsEmpty())
498496
499497 doc.Set(keyPath, expectedKey1)
500498 d, err := db.Get(doc)
501499 doc.Free()
502 require.NotNil(t, d)
500 require.False(t, d.IsEmpty())
503501 require.Nil(t, err)
504502 size := 0
505503 require.Equal(t, expectedValue1, d.GetString(valuePath, &size))
507505 d.Destroy()
508506
509507 doc = db.Document()
510 require.NotNil(t, doc)
508 require.False(t, doc.IsEmpty())
511509
512510 doc.Set(keyPath, expectedKey2)
513511 d, err = db.Get(doc)
514512 doc.Free()
515 require.NotNil(t, d)
513 require.False(t, d.IsEmpty())
516514 require.Nil(t, err)
517515 size = 0
518516 require.Equal(t, expectedValue2, d.GetString(valuePath, &size))
548546 require.Nil(t, db.Delete(doc))
549547 }
550548
551 // ATTN - This benchmark don't show real performance
552 // It is just a long running tests
553549 func BenchmarkDatabaseSet(b *testing.B) {
554550 const (
555551 keyPath = "key"
591587 value: fmt.Sprintf(ValueTemplate, i),
592588 })
593589 }
590
594591 b.ResetTimer()
595592 for i := 0; i < b.N; i++ {
596593 index := i % RecordsCountBench
597594 doc := db.Document()
598 require.True(b, doc.Set(keyPath, pairs[index].key))
599 require.True(b, doc.Set(valuePath, pairs[index].value))
600 require.Nil(b, db.Set(doc))
595 doc.Set(keyPath, pairs[index].key)
596 doc.Set(valuePath, pairs[index].value)
597 db.Set(doc)
601598 doc.Free()
602599 }
603600 }
604601
605 // ATTN - This benchmark don't show real performance
606 // It is just a long running tests
607602 func BenchmarkDatabaseGet(b *testing.B) {
608603 const (
609604 keyPath = "key"
654649 doc.Free()
655650 }
656651
657 var size int
658652 b.ResetTimer()
659653 for i := 0; i < b.N; i++ {
660654 index := i % RecordsCountBench
661655 doc := db.Document()
662656 require.True(b, doc.Set(keyPath, pairs[index].key))
663 d, err := db.Get(doc)
657 d, _ := db.Get(doc)
664658 doc.Free()
665 require.Nil(b, err)
666 require.Equal(b, pairs[index].value, d.GetString(valuePath, &size))
667659 d.Destroy()
668660 }
669661 }
77 // Document is a representation of a row in a database.
88 // Destroy should be called after Document usage.
99 type Document struct {
10 *varStore
10 varStore
1111 }
1212
13 func newDocument(ptr unsafe.Pointer, size int) *Document {
14 return &Document{
13 func newDocument(ptr unsafe.Pointer, size int) Document {
14 return Document{
1515 varStore: newVarStore(ptr, size),
1616 }
1717 }
1313 // Take it's name from sophia
1414 // Usually object with same features are called 'database'
1515 type Environment struct {
16 *varStore
16 varStore
1717 }
1818
1919 // NewEnvironment creates a new environment for opening a database.
99 "github.com/pzhin/go-sophia"
1010 )
1111
12 func upsertCallback(count int, src []unsafe.Pointer, srcSize uint32,
13 upsert []unsafe.Pointer, upsertSize uint32, result []unsafe.Pointer,
14 resultSize uint32, arg unsafe.Pointer) int {
12 func upsertCallback(count int, src []unsafe.Pointer, srcSize []uint32,
13 upsert []unsafe.Pointer, upsertSize []uint32, result []unsafe.Pointer,
14 resultSize []uint32, arg unsafe.Pointer) int {
15
16 if src == nil {
17 return 0
18 }
1519 ca := *(*uint32)(src[1])
1620 cb := *(*uint32)(upsert[1])
1721 cret := ca + cb
7882 log.Fatal(err)
7983 }
8084
81 for d := cursor.Next(); d != nil; d = cursor.Next() {
85 for d := cursor.Next(); !d.IsEmpty(); d = cursor.Next() {
8286 var size int
8387 fmt.Println(d.GetString("key", &size), ":", d.GetInt("value"), ":", d.GetInt("value2"), ":", size)
8488 }
8383 require.Nil(t, err)
8484
8585 doc = db.Document()
86 require.NotNil(t, doc)
86 require.False(t, doc.IsEmpty())
8787 require.True(t, doc.Set(keyPath, expectedKey))
8888
8989 d, err := tx.Get(doc)
9090 doc.Free()
9191
92 require.NotNil(t, d)
92 require.False(t, d.IsEmpty())
9393 require.Nil(t, err)
9494
9595 var size int
134134 doc.Free()
135135
136136 doc = db.Document()
137 require.NotNil(t, doc)
137 require.False(t, doc.IsEmpty())
138138 require.True(t, doc.Set(keyPath, expectedKey))
139139
140140 d, err := db.Get(doc)
141141 doc.Free()
142 require.NotNil(t, d)
142 require.False(t, d.IsEmpty())
143143 require.Nil(t, err)
144144
145145 var size int
151151 require.Nil(t, err)
152152
153153 doc = db.Document()
154 require.NotNil(t, doc)
154 require.False(t, doc.IsEmpty())
155155 require.True(t, doc.Set(keyPath, expectedKey))
156156 require.Nil(t, tx.Delete(doc))
157157 doc.Free()
158158
159159 doc = db.Document()
160 require.NotNil(t, doc)
160 require.False(t, doc.IsEmpty())
161161 require.True(t, doc.Set(keyPath, expectedKey))
162162 d, err = tx.Get(doc)
163163 doc.Free()
164 require.Nil(t, d)
164 require.True(t, d.IsEmpty())
165165 require.NotNil(t, err)
166166
167167 require.Equal(t, TxOk, tx.Commit())
208208 require.True(t, doc.Set(keyPath, expectedKey))
209209
210210 d, err := db.Get(doc)
211 require.Nil(t, d)
211 require.True(t, d.IsEmpty())
212212 require.Equal(t, ErrNotFound, err)
213213 doc.Free()
214214 }
277277 d, err := db.Get(doc)
278278 doc.Free()
279279 require.Nil(t, err)
280 require.NotNil(t, d)
280 require.False(t, d.IsEmpty())
281281 value := d.GetString(valuePath, &size)
282282 require.Equal(t, expectedValue1, value)
283283 d.Destroy()
3333 // UpsertFunc golang equivalent of upsert_callback.
3434 // Should return 0 in case of success, otherwise -1.
3535 type UpsertFunc func(count int,
36 src []unsafe.Pointer, srcSize uint32,
37 upsert []unsafe.Pointer, upsertSize uint32,
38 result []unsafe.Pointer, resultSize uint32,
36 src []unsafe.Pointer, srcSize []uint32,
37 upsert []unsafe.Pointer, upsertSize []uint32,
38 result []unsafe.Pointer, resultSize []uint32,
3939 arg unsafe.Pointer) int
4040
4141 //export goUpsertCall
9898 indexPtr := &index
9999
100100 upsertMap[indexPtr] = func(count C.int,
101 src **C.char, srcSize *C.uint32_t,
102 upsert **C.char, upsertSize *C.uint32_t,
103 result **C.char, resultSize *C.uint32_t,
101 srcC **C.char, srcSizesC *C.uint32_t,
102 upsertC **C.char, upsertSizesC *C.uint32_t,
103 resultC **C.char, resultSizesC *C.uint32_t,
104104 arg unsafe.Pointer) C.int {
105105
106 if src == nil {
107 return C.int(0)
108 }
109 var sSize uint32
110 if srcSize != nil {
111 sSize = uint32(*srcSize)
112 }
113 uSize := uint32(*upsertSize)
114 rSize := uint32(*resultSize)
115106 countN := int(count)
116107
117108 // We receive C pointer to pointer which can be interpreted as an array of pointers.
118109 // Here we cast C pointer to pointer to Go slice of pointers.
119 slice1 := (*[1 << 4]unsafe.Pointer)(unsafe.Pointer(src))[:countN:countN]
120 slice2 := (*[1 << 4]unsafe.Pointer)(unsafe.Pointer(upsert))[:countN:countN]
121 slice3 := (*[1 << 4]unsafe.Pointer)(unsafe.Pointer(result))[:countN:countN]
110 upsertSizes := (*[16]uint32)(unsafe.Pointer(upsertSizesC))[:countN]
111 resultSizes := (*[16]uint32)(unsafe.Pointer(resultSizesC))[:countN]
112
113 upsert := (*[16]unsafe.Pointer)(unsafe.Pointer(upsertC))[:countN]
114 result := (*[16]unsafe.Pointer)(unsafe.Pointer(resultC))[:countN]
115
116 var src []unsafe.Pointer
117 var srcSizes []uint32
118 if srcC != nil {
119 srcSizes = (*[16]uint32)(unsafe.Pointer(srcSizesC))[:countN]
120 src = (*[16]unsafe.Pointer)(unsafe.Pointer(srcC))[:countN]
121 }
122122
123123 res := upsertFunc(countN,
124 slice1, sSize,
125 slice2, uSize,
126 slice3, rSize,
124 src, srcSizes,
125 upsert, upsertSizes,
126 result, resultSizes,
127127 arg)
128128
129129 return C.int(res)
00 package sophia
11
22 import (
3 "fmt"
4 "io/ioutil"
35 "os"
46 "testing"
57 "unsafe"
6
7 "io/ioutil"
88
99 "github.com/stretchr/testify/require"
1010 )
117117 }
118118
119119 func upsertCallback(count int,
120 src []unsafe.Pointer, srcSize uint32,
121 upsert []unsafe.Pointer, upsertSize uint32,
122 result []unsafe.Pointer, resultSize uint32,
120 src []unsafe.Pointer, srcSize []uint32,
121 upsert []unsafe.Pointer, upsertSize []uint32,
122 result []unsafe.Pointer, resultSize []uint32,
123123 arg unsafe.Pointer) int {
124
125 if src == nil {
126 return 0
127 }
124128 var a uint32 = *(*uint32)(src[1])
125129 var b uint32 = *(*uint32)(upsert[1])
126130 ret := a + b
130134 }
131135
132136 func upsertCallbackWithArg(count int,
133 src []unsafe.Pointer, srcSize uint32,
134 upsert []unsafe.Pointer, upsertSize uint32,
135 result []unsafe.Pointer, resultSize uint32,
137 src []unsafe.Pointer, srcSize []uint32,
138 upsert []unsafe.Pointer, upsertSize []uint32,
139 result []unsafe.Pointer, resultSize []uint32,
136140 arg unsafe.Pointer) int {
141
142 if src == nil {
143 return 0
144 }
137145 var a uint32 = *(*uint32)(src[1])
138146 var b uint32 = *(*uint32)(upsert[1])
139147 var c uint32 = *(*uint32)(arg)
170178 require.Nil(t, env.Open())
171179 defer env.Close()
172180 doc := db.Document()
173 require.NotNil(t, doc)
181 require.False(t, doc.IsEmpty())
174182 require.True(t, doc.Set("key", 1))
175183 require.True(t, doc.Set("id", 1))
176184 require.NotNil(t, db.Upsert(doc))
177185 }
186
187 func TestDatabaseUpsertArguments(t *testing.T) {
188 const keyPath = "key"
189 const valuePath = "id"
190 tmpDir, err := ioutil.TempDir("", "sophia_test")
191 require.Nil(t, err)
192 defer os.RemoveAll(tmpDir)
193
194 env, err := NewEnvironment()
195 require.Nil(t, err)
196 require.NotNil(t, env)
197
198 require.True(t, env.SetString(EnvironmentPath, tmpDir))
199
200 schema := &Schema{}
201 require.Nil(t, schema.AddKey(keyPath, FieldTypeUInt32))
202 require.Nil(t, schema.AddValue(valuePath, FieldTypeUInt32))
203
204 db, err := env.NewDatabase(DatabaseConfig{
205 Name: "test_database",
206 Schema: schema,
207 Upsert: func(count int,
208 src []unsafe.Pointer, srcSize []uint32,
209 upsert []unsafe.Pointer, upsertSize []uint32,
210 result []unsafe.Pointer, resultSize []uint32,
211 arg unsafe.Pointer) int {
212
213 if count != 4 {
214 panic(fmt.Sprintf("count should be equals 4, got: %v", count))
215 }
216
217 if src != nil {
218 if len(src) != count {
219 panic(fmt.Sprintf("length of src should be equals count, got: %v", len(src)))
220 }
221 if len(srcSize) != count {
222 panic(fmt.Sprintf("length of srcSize should be equals count, got: %v", len(src)))
223 }
224 }
225
226 if len(upsert) != count {
227 panic(fmt.Sprintf("length of upsert should be equals count, got: %v", len(upsert)))
228 }
229 if len(upsertSize) != count {
230 panic(fmt.Sprintf("length of upsertSize should be equals count, got: %v", len(upsertSize)))
231 }
232
233 if len(result) != count {
234 panic(fmt.Sprintf("length of result should be equals count, got: %v", len(result)))
235 }
236 if len(resultSize) != count {
237 panic(fmt.Sprintf("length of resultSize should be equals count, got: %v", len(resultSize)))
238 }
239
240 if arg != nil {
241 panic(fmt.Sprintf("arg should be nil, got: %#v", arg))
242 }
243
244 return upsertCallback(count, src, srcSize, upsert, upsertSize, result, resultSize, arg)
245 },
246 })
247 require.Nil(t, err)
248 require.NotNil(t, db)
249
250 require.Nil(t, env.Open())
251 defer env.Close()
252
253 const key uint32 = 1234
254 const value uint32 = 1
255 expectedUpsertArgs := []struct {
256 key, value uint32
257 }{
258 {key: key, value: value},
259 {key: key, value: value * 2},
260 {key: key, value: value * 3},
261 {key: key, value: value * 4},
262 {key: key, value: value * 5},
263 {key: key, value: value * 6},
264 }
265
266 for _, expected := range expectedUpsertArgs {
267 doc := db.Document()
268 doc.Set(keyPath, key)
269 doc.Set(valuePath, value)
270 require.Nil(t, db.Upsert(doc))
271 doc.Free()
272
273 doc = db.Document()
274 doc.Set(keyPath, key)
275
276 result, err := db.Get(doc)
277 require.Nil(t, err)
278 require.NotNil(t, result)
279
280 require.EqualValues(t, expected.key, result.GetInt(keyPath))
281 require.EqualValues(t, expected.key, result.GetInt(keyPath))
282 }
283 }
1616 pointers []unsafe.Pointer
1717 }
1818
19 func newVarStore(ptr unsafe.Pointer, size int) *varStore {
20 return &varStore{
21 ptr: ptr,
22 pointers: make([]unsafe.Pointer, 0, size),
19 func newVarStore(ptr unsafe.Pointer, size int) varStore {
20 ret := varStore{ptr: ptr}
21 if size > 0 {
22 ret.pointers = make([]unsafe.Pointer, 0, size)
2323 }
24 return ret
25 }
26
27 func (s *varStore) IsEmpty() bool {
28 return s.ptr == nil
2429 }
2530
2631 // TODO :: implement custom types