]> Sergey Matveev's repositories - btrtrc.git/blob - storage/sqlite/sqlite-storage_test.go
Progress testing without cgo a bit
[btrtrc.git] / storage / sqlite / sqlite-storage_test.go
1 //go:build cgo
2 // +build cgo
3
4 package sqliteStorage
5
6 import (
7         "bytes"
8         "errors"
9         "fmt"
10         "io"
11         "io/ioutil"
12         "path/filepath"
13         "sync"
14         "testing"
15         "time"
16
17         _ "github.com/anacrolix/envpprof"
18         "github.com/dustin/go-humanize"
19         qt "github.com/frankban/quicktest"
20         "github.com/stretchr/testify/assert"
21         "github.com/stretchr/testify/require"
22
23         "github.com/anacrolix/torrent/storage"
24         test_storage "github.com/anacrolix/torrent/storage/test"
25 )
26
27 func newConnsAndProv(t *testing.T, opts NewPoolOpts) (ConnPool, *provider) {
28         opts.Path = filepath.Join(t.TempDir(), "sqlite3.db")
29         pool, err := NewPool(opts)
30         qt.Assert(t, err, qt.IsNil)
31         // sqlitex.Pool.Close doesn't like being called more than once. Let it slide for now.
32         //t.Cleanup(func() { pool.Close() })
33         qt.Assert(t, initPoolDatabase(pool, InitDbOpts{}), qt.IsNil)
34         if !opts.Memory && opts.SetJournalMode == "" {
35                 opts.SetJournalMode = "wal"
36         }
37         qt.Assert(t, initPoolConns(nil, pool, opts.InitConnOpts), qt.IsNil)
38         prov, err := NewProvider(pool, ProviderOpts{BatchWrites: pool.NumConns() > 1})
39         require.NoError(t, err)
40         t.Cleanup(func() { prov.Close() })
41         return pool, prov
42 }
43
44 func TestTextBlobSize(t *testing.T) {
45         _, prov := newConnsAndProv(t, NewPoolOpts{})
46         a, _ := prov.NewInstance("a")
47         err := a.Put(bytes.NewBufferString("\x00hello"))
48         qt.Assert(t, err, qt.IsNil)
49         fi, err := a.Stat()
50         qt.Assert(t, err, qt.IsNil)
51         assert.EqualValues(t, 6, fi.Size())
52 }
53
54 func TestSimultaneousIncrementalBlob(t *testing.T) {
55         _, p := newConnsAndProv(t, NewPoolOpts{
56                 NumConns: 3,
57         })
58         a, err := p.NewInstance("a")
59         require.NoError(t, err)
60         const contents = "hello, world"
61         require.NoError(t, a.Put(bytes.NewReader([]byte("hello, world"))))
62         rc1, err := a.Get()
63         require.NoError(t, err)
64         rc2, err := a.Get()
65         require.NoError(t, err)
66         var b1, b2 []byte
67         var e1, e2 error
68         var wg sync.WaitGroup
69         doRead := func(b *[]byte, e *error, rc io.ReadCloser, n int) {
70                 defer wg.Done()
71                 defer rc.Close()
72                 *b, *e = ioutil.ReadAll(rc)
73                 require.NoError(t, *e, n)
74                 assert.EqualValues(t, contents, *b)
75         }
76         wg.Add(2)
77         go doRead(&b2, &e2, rc2, 2)
78         go doRead(&b1, &e1, rc1, 1)
79         wg.Wait()
80 }
81
82 func BenchmarkMarkComplete(b *testing.B) {
83         const pieceSize = test_storage.DefaultPieceSize
84         const noTriggers = false
85         var capacity int64 = test_storage.DefaultNumPieces * pieceSize / 2
86         if noTriggers {
87                 // Since we won't push out old pieces, we have to mark them incomplete manually.
88                 capacity = 0
89         }
90         runBench := func(b *testing.B, ci storage.ClientImpl) {
91                 test_storage.BenchmarkPieceMarkComplete(b, ci, pieceSize, test_storage.DefaultNumPieces, capacity)
92         }
93         c := qt.New(b)
94         b.Run("CustomDirect", func(b *testing.B) {
95                 var opts NewDirectStorageOpts
96                 opts.Capacity = capacity
97                 opts.NoTriggers = noTriggers
98                 benchOpts := func(b *testing.B) {
99                         opts.Path = filepath.Join(b.TempDir(), "storage.db")
100                         ci, err := NewDirectStorage(opts)
101                         c.Assert(err, qt.IsNil)
102                         defer ci.Close()
103                         runBench(b, ci)
104                 }
105                 b.Run("Default", benchOpts)
106         })
107         for _, memory := range []bool{false, true} {
108                 b.Run(fmt.Sprintf("Memory=%v", memory), func(b *testing.B) {
109                         b.Run("Direct", func(b *testing.B) {
110                                 var opts NewDirectStorageOpts
111                                 opts.Memory = memory
112                                 opts.Capacity = capacity
113                                 //opts.GcBlobs = true
114                                 opts.BlobFlushInterval = time.Second
115                                 opts.NoTriggers = noTriggers
116                                 directBench := func(b *testing.B) {
117                                         opts.Path = filepath.Join(b.TempDir(), "storage.db")
118                                         ci, err := NewDirectStorage(opts)
119                                         var ujm UnexpectedJournalMode
120                                         if errors.As(err, &ujm) {
121                                                 b.Skipf("setting journal mode %q: %v", opts.SetJournalMode, err)
122                                         }
123                                         c.Assert(err, qt.IsNil)
124                                         defer ci.Close()
125                                         runBench(b, ci)
126                                 }
127                                 for _, journalMode := range []string{"", "wal", "off", "truncate", "delete", "persist", "memory"} {
128                                         opts.SetJournalMode = journalMode
129                                         b.Run("JournalMode="+journalMode, func(b *testing.B) {
130                                                 for _, mmapSize := range []int64{-1} {
131                                                         if memory && mmapSize >= 0 {
132                                                                 continue
133                                                         }
134                                                         b.Run(fmt.Sprintf("MmapSize=%s", func() string {
135                                                                 if mmapSize < 0 {
136                                                                         return "default"
137                                                                 } else {
138                                                                         return humanize.IBytes(uint64(mmapSize))
139                                                                 }
140                                                         }()), func(b *testing.B) {
141                                                                 opts.MmapSize = mmapSize
142                                                                 opts.MmapSizeOk = true
143                                                                 directBench(b)
144                                                         })
145                                                 }
146                                         })
147                                 }
148                         })
149                         b.Run("ResourcePieces", func(b *testing.B) {
150                                 for _, batchWrites := range []bool{false, true} {
151                                         b.Run(fmt.Sprintf("BatchWrites=%v", batchWrites), func(b *testing.B) {
152                                                 var opts NewPiecesStorageOpts
153                                                 opts.Path = filepath.Join(b.TempDir(), "storage.db")
154                                                 //b.Logf("storage db path: %q", dbPath)
155                                                 opts.Capacity = capacity
156                                                 opts.Memory = memory
157                                                 opts.ProvOpts = func(opts *ProviderOpts) {
158                                                         opts.BatchWrites = batchWrites
159                                                 }
160                                                 ci, err := NewPiecesStorage(opts)
161                                                 c.Assert(err, qt.IsNil)
162                                                 defer ci.Close()
163                                                 runBench(b, ci)
164                                         })
165                                 }
166                         })
167                 })
168         }
169 }