db_bench_test.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright (C) 2025 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package sqlite
  7. import (
  8. "fmt"
  9. "testing"
  10. "time"
  11. "github.com/syncthing/syncthing/internal/timeutil"
  12. "github.com/syncthing/syncthing/lib/config"
  13. "github.com/syncthing/syncthing/lib/protocol"
  14. "github.com/syncthing/syncthing/lib/rand"
  15. )
  16. var globalFi protocol.FileInfo
  17. func BenchmarkUpdate(b *testing.B) {
  18. db, err := Open(b.TempDir())
  19. if err != nil {
  20. b.Fatal(err)
  21. }
  22. b.Cleanup(func() {
  23. if err := db.Close(); err != nil {
  24. b.Fatal(err)
  25. }
  26. })
  27. fs := make([]protocol.FileInfo, 100)
  28. t0 := time.Now()
  29. seed := 0
  30. size := 1000
  31. const numBlocks = 500
  32. fdb, err := db.getFolderDB(folderID, true)
  33. if err != nil {
  34. b.Fatal(err)
  35. }
  36. for size < 200_000 {
  37. for {
  38. local, err := db.CountLocal(folderID, protocol.LocalDeviceID)
  39. if err != nil {
  40. b.Fatal(err)
  41. }
  42. if local.Files >= size {
  43. break
  44. }
  45. fs := make([]protocol.FileInfo, 1000)
  46. for i := range fs {
  47. fs[i] = genFile(rand.String(24), numBlocks, 0)
  48. }
  49. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  50. b.Fatal(err)
  51. }
  52. }
  53. var files, blocks int
  54. if err := fdb.sql.QueryRowx(`SELECT count(*) FROM files`).Scan(&files); err != nil {
  55. b.Fatal(err)
  56. }
  57. if err := fdb.sql.QueryRowx(`SELECT count(*) FROM blocks`).Scan(&blocks); err != nil {
  58. b.Fatal(err)
  59. }
  60. d := time.Since(t0)
  61. b.Logf("t=%s, files=%d, blocks=%d, files/s=%.01f, blocks/s=%.01f", d, files, blocks, float64(files)/d.Seconds(), float64(blocks)/d.Seconds())
  62. b.Run(fmt.Sprintf("n=Insert100Loc/size=%d", size), func(b *testing.B) {
  63. for range b.N {
  64. for i := range fs {
  65. fs[i] = genFile(rand.String(24), numBlocks, 0)
  66. }
  67. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  68. b.Fatal(err)
  69. }
  70. }
  71. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  72. })
  73. b.Run(fmt.Sprintf("n=RepBlocks100/size=%d", size), func(b *testing.B) {
  74. for range b.N {
  75. for i := range fs {
  76. fs[i].Blocks = genBlocks(fs[i].Name, seed, 64)
  77. fs[i].Version = fs[i].Version.Update(42)
  78. }
  79. seed++
  80. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  81. b.Fatal(err)
  82. }
  83. }
  84. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  85. })
  86. b.Run(fmt.Sprintf("n=RepSame100/size=%d", size), func(b *testing.B) {
  87. for range b.N {
  88. for i := range fs {
  89. fs[i].Version = fs[i].Version.Update(42)
  90. }
  91. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  92. b.Fatal(err)
  93. }
  94. }
  95. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  96. })
  97. b.Run(fmt.Sprintf("n=Insert100Rem/size=%d", size), func(b *testing.B) {
  98. for range b.N {
  99. for i := range fs {
  100. fs[i].Blocks = genBlocks(fs[i].Name, seed, 64)
  101. fs[i].Version = fs[i].Version.Update(42)
  102. fs[i].Sequence = timeutil.StrictlyMonotonicNanos()
  103. }
  104. if err := db.Update(folderID, protocol.DeviceID{42}, fs); err != nil {
  105. b.Fatal(err)
  106. }
  107. }
  108. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  109. })
  110. b.Run(fmt.Sprintf("n=GetGlobal100/size=%d", size), func(b *testing.B) {
  111. for range b.N {
  112. for i := range fs {
  113. _, ok, err := db.GetGlobalFile(folderID, fs[i].Name)
  114. if err != nil {
  115. b.Fatal(err)
  116. }
  117. if !ok {
  118. b.Fatal("should exist")
  119. }
  120. }
  121. }
  122. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  123. })
  124. b.Run(fmt.Sprintf("n=LocalSequenced/size=%d", size), func(b *testing.B) {
  125. count := 0
  126. for range b.N {
  127. cur, err := db.GetDeviceSequence(folderID, protocol.LocalDeviceID)
  128. if err != nil {
  129. b.Fatal(err)
  130. }
  131. it, errFn := db.AllLocalFilesBySequence(folderID, protocol.LocalDeviceID, cur-100, 0)
  132. for f := range it {
  133. count++
  134. globalFi = f
  135. }
  136. if err := errFn(); err != nil {
  137. b.Fatal(err)
  138. }
  139. }
  140. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "files/s")
  141. })
  142. b.Run(fmt.Sprintf("n=AllLocalBlocksWithHash/size=%d", size), func(b *testing.B) {
  143. count := 0
  144. for range b.N {
  145. it, errFn := db.AllLocalBlocksWithHash(folderID, globalFi.Blocks[0].Hash)
  146. for range it {
  147. count++
  148. }
  149. if err := errFn(); err != nil {
  150. b.Fatal(err)
  151. }
  152. }
  153. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "blocks/s")
  154. })
  155. b.Run(fmt.Sprintf("n=GetDeviceSequenceLoc/size=%d", size), func(b *testing.B) {
  156. for range b.N {
  157. _, err := db.GetDeviceSequence(folderID, protocol.LocalDeviceID)
  158. if err != nil {
  159. b.Fatal(err)
  160. }
  161. }
  162. })
  163. b.Run(fmt.Sprintf("n=GetDeviceSequenceRem/size=%d", size), func(b *testing.B) {
  164. for range b.N {
  165. _, err := db.GetDeviceSequence(folderID, protocol.DeviceID{42})
  166. if err != nil {
  167. b.Fatal(err)
  168. }
  169. }
  170. })
  171. b.Run(fmt.Sprintf("n=RemoteNeed/size=%d", size), func(b *testing.B) {
  172. count := 0
  173. for range b.N {
  174. it, errFn := db.AllNeededGlobalFiles(folderID, protocol.DeviceID{42}, config.PullOrderAlphabetic, 0, 0)
  175. for f := range it {
  176. count++
  177. globalFi = f
  178. }
  179. if err := errFn(); err != nil {
  180. b.Fatal(err)
  181. }
  182. }
  183. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "files/s")
  184. })
  185. b.Run(fmt.Sprintf("n=LocalNeed100Largest/size=%d", size), func(b *testing.B) {
  186. count := 0
  187. for range b.N {
  188. it, errFn := db.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderLargestFirst, 100, 0)
  189. for f := range it {
  190. globalFi = f
  191. count++
  192. }
  193. if err := errFn(); err != nil {
  194. b.Fatal(err)
  195. }
  196. }
  197. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "files/s")
  198. })
  199. size += 1000
  200. }
  201. }
  202. func TestBenchmarkDropAllRemote(t *testing.T) {
  203. if testing.Short() {
  204. t.Skip("slow test")
  205. }
  206. db, err := Open(t.TempDir())
  207. if err != nil {
  208. t.Fatal(err)
  209. }
  210. t.Cleanup(func() {
  211. if err := db.Close(); err != nil {
  212. t.Fatal(err)
  213. }
  214. })
  215. fs := make([]protocol.FileInfo, 1000)
  216. seq := 0
  217. for {
  218. local, err := db.CountLocal(folderID, protocol.LocalDeviceID)
  219. if err != nil {
  220. t.Fatal(err)
  221. }
  222. if local.Files >= 15_000 {
  223. break
  224. }
  225. for i := range fs {
  226. seq++
  227. fs[i] = genFile(rand.String(24), 64, seq)
  228. }
  229. if err := db.Update(folderID, protocol.DeviceID{42}, fs); err != nil {
  230. t.Fatal(err)
  231. }
  232. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  233. t.Fatal(err)
  234. }
  235. }
  236. t0 := time.Now()
  237. if err := db.DropAllFiles(folderID, protocol.DeviceID{42}); err != nil {
  238. t.Fatal(err)
  239. }
  240. d := time.Since(t0)
  241. t.Log("drop all took", d)
  242. }