db_bench_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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. seed := 0
  29. size := 1000
  30. const numBlocks = 1000
  31. for size < 200_000 {
  32. for {
  33. local, err := db.CountLocal(folderID, protocol.LocalDeviceID)
  34. if err != nil {
  35. b.Fatal(err)
  36. }
  37. if local.Files >= size {
  38. break
  39. }
  40. fs := make([]protocol.FileInfo, 1000)
  41. for i := range fs {
  42. fs[i] = genFile(rand.String(24), numBlocks, 0)
  43. }
  44. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  45. b.Fatal(err)
  46. }
  47. }
  48. b.Run(fmt.Sprintf("n=Insert100Loc/size=%d", size), func(b *testing.B) {
  49. for range b.N {
  50. for i := range fs {
  51. fs[i] = genFile(rand.String(24), numBlocks, 0)
  52. }
  53. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  54. b.Fatal(err)
  55. }
  56. }
  57. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  58. })
  59. b.Run(fmt.Sprintf("n=RepBlocks100/size=%d", size), func(b *testing.B) {
  60. for range b.N {
  61. for i := range fs {
  62. fs[i].Blocks = genBlocks(fs[i].Name, seed, 64)
  63. fs[i].Version = fs[i].Version.Update(42)
  64. }
  65. seed++
  66. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  67. b.Fatal(err)
  68. }
  69. }
  70. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  71. })
  72. b.Run(fmt.Sprintf("n=RepSame100/size=%d", size), func(b *testing.B) {
  73. for range b.N {
  74. for i := range fs {
  75. fs[i].Version = fs[i].Version.Update(42)
  76. }
  77. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  78. b.Fatal(err)
  79. }
  80. }
  81. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  82. })
  83. b.Run(fmt.Sprintf("n=Insert100Rem/size=%d", size), func(b *testing.B) {
  84. for range b.N {
  85. for i := range fs {
  86. fs[i].Blocks = genBlocks(fs[i].Name, seed, 64)
  87. fs[i].Version = fs[i].Version.Update(42)
  88. fs[i].Sequence = timeutil.StrictlyMonotonicNanos()
  89. }
  90. if err := db.Update(folderID, protocol.DeviceID{42}, fs); err != nil {
  91. b.Fatal(err)
  92. }
  93. }
  94. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  95. })
  96. b.Run(fmt.Sprintf("n=GetGlobal100/size=%d", size), func(b *testing.B) {
  97. for range b.N {
  98. for i := range fs {
  99. _, ok, err := db.GetGlobalFile(folderID, fs[i].Name)
  100. if err != nil {
  101. b.Fatal(err)
  102. }
  103. if !ok {
  104. b.Fatal("should exist")
  105. }
  106. }
  107. }
  108. b.ReportMetric(float64(b.N)*100.0/b.Elapsed().Seconds(), "files/s")
  109. })
  110. b.Run(fmt.Sprintf("n=LocalSequenced/size=%d", size), func(b *testing.B) {
  111. count := 0
  112. for range b.N {
  113. cur, err := db.GetDeviceSequence(folderID, protocol.LocalDeviceID)
  114. if err != nil {
  115. b.Fatal(err)
  116. }
  117. it, errFn := db.AllLocalFilesBySequence(folderID, protocol.LocalDeviceID, cur-100, 0)
  118. for f := range it {
  119. count++
  120. globalFi = f
  121. }
  122. if err := errFn(); err != nil {
  123. b.Fatal(err)
  124. }
  125. }
  126. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "files/s")
  127. })
  128. b.Run(fmt.Sprintf("n=AllLocalBlocksWithHash/size=%d", size), func(b *testing.B) {
  129. count := 0
  130. for range b.N {
  131. it, errFn := db.AllLocalBlocksWithHash(folderID, globalFi.Blocks[0].Hash)
  132. for range it {
  133. count++
  134. }
  135. if err := errFn(); err != nil {
  136. b.Fatal(err)
  137. }
  138. }
  139. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "blocks/s")
  140. })
  141. b.Run(fmt.Sprintf("n=GetDeviceSequenceLoc/size=%d", size), func(b *testing.B) {
  142. for range b.N {
  143. _, err := db.GetDeviceSequence(folderID, protocol.LocalDeviceID)
  144. if err != nil {
  145. b.Fatal(err)
  146. }
  147. }
  148. })
  149. b.Run(fmt.Sprintf("n=GetDeviceSequenceRem/size=%d", size), func(b *testing.B) {
  150. for range b.N {
  151. _, err := db.GetDeviceSequence(folderID, protocol.DeviceID{42})
  152. if err != nil {
  153. b.Fatal(err)
  154. }
  155. }
  156. })
  157. b.Run(fmt.Sprintf("n=RemoteNeed/size=%d", size), func(b *testing.B) {
  158. count := 0
  159. for range b.N {
  160. it, errFn := db.AllNeededGlobalFiles(folderID, protocol.DeviceID{42}, config.PullOrderAlphabetic, 0, 0)
  161. for f := range it {
  162. count++
  163. globalFi = f
  164. }
  165. if err := errFn(); err != nil {
  166. b.Fatal(err)
  167. }
  168. }
  169. b.ReportMetric(float64(count)/b.Elapsed().Seconds(), "files/s")
  170. })
  171. b.Run(fmt.Sprintf("n=LocalNeed100Largest/size=%d", size), func(b *testing.B) {
  172. count := 0
  173. for range b.N {
  174. it, errFn := db.AllNeededGlobalFiles(folderID, protocol.LocalDeviceID, config.PullOrderLargestFirst, 100, 0)
  175. for f := range it {
  176. globalFi = f
  177. count++
  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. size += 1000
  186. }
  187. }
  188. func TestBenchmarkDropAllRemote(t *testing.T) {
  189. if testing.Short() {
  190. t.Skip("slow test")
  191. }
  192. db, err := Open(t.TempDir())
  193. if err != nil {
  194. t.Fatal(err)
  195. }
  196. t.Cleanup(func() {
  197. if err := db.Close(); err != nil {
  198. t.Fatal(err)
  199. }
  200. })
  201. fs := make([]protocol.FileInfo, 1000)
  202. seq := 0
  203. for {
  204. local, err := db.CountLocal(folderID, protocol.LocalDeviceID)
  205. if err != nil {
  206. t.Fatal(err)
  207. }
  208. if local.Files >= 15_000 {
  209. break
  210. }
  211. for i := range fs {
  212. seq++
  213. fs[i] = genFile(rand.String(24), 64, seq)
  214. }
  215. if err := db.Update(folderID, protocol.DeviceID{42}, fs); err != nil {
  216. t.Fatal(err)
  217. }
  218. if err := db.Update(folderID, protocol.LocalDeviceID, fs); err != nil {
  219. t.Fatal(err)
  220. }
  221. }
  222. t0 := time.Now()
  223. if err := db.DropAllFiles(folderID, protocol.DeviceID{42}); err != nil {
  224. t.Fatal(err)
  225. }
  226. d := time.Since(t0)
  227. t.Log("drop all took", d)
  228. }