db.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. "sync"
  9. "time"
  10. "github.com/jmoiron/sqlx"
  11. "github.com/syncthing/syncthing/internal/db"
  12. "github.com/syncthing/syncthing/lib/protocol"
  13. "github.com/thejerf/suture/v4"
  14. )
  15. type DB struct {
  16. sql *sqlx.DB
  17. localDeviceIdx int64
  18. deleteRetention time.Duration
  19. updateLock sync.Mutex
  20. updatePoints int
  21. statementsMut sync.RWMutex
  22. statements map[string]*sqlx.Stmt
  23. tplInput map[string]any
  24. }
  25. var _ db.DB = (*DB)(nil)
  26. type Option func(*DB)
  27. func WithDeleteRetention(d time.Duration) Option {
  28. return func(s *DB) {
  29. s.deleteRetention = d
  30. }
  31. }
  32. func (s *DB) Close() error {
  33. s.updateLock.Lock()
  34. s.statementsMut.Lock()
  35. defer s.updateLock.Unlock()
  36. defer s.statementsMut.Unlock()
  37. for _, stmt := range s.statements {
  38. stmt.Close()
  39. }
  40. return wrap(s.sql.Close())
  41. }
  42. func (s *DB) Service(maintenanceInterval time.Duration) suture.Service {
  43. return newService(s, maintenanceInterval)
  44. }
  45. func (s *DB) ListFolders() ([]string, error) {
  46. var res []string
  47. err := s.stmt(`
  48. SELECT folder_id FROM folders
  49. ORDER BY folder_id
  50. `).Select(&res)
  51. return res, wrap(err)
  52. }
  53. func (s *DB) ListDevicesForFolder(folder string) ([]protocol.DeviceID, error) {
  54. var res []string
  55. err := s.stmt(`
  56. SELECT d.device_id FROM counts s
  57. INNER JOIN folders o ON o.idx = s.folder_idx
  58. INNER JOIN devices d ON d.idx = s.device_idx
  59. WHERE o.folder_id = ? AND s.count > 0 AND s.device_idx != {{.LocalDeviceIdx}}
  60. GROUP BY d.device_id
  61. ORDER BY d.device_id
  62. `).Select(&res, folder)
  63. if err != nil {
  64. return nil, wrap(err)
  65. }
  66. devs := make([]protocol.DeviceID, len(res))
  67. for i, s := range res {
  68. devs[i], err = protocol.DeviceIDFromString(s)
  69. if err != nil {
  70. return nil, wrap(err)
  71. }
  72. }
  73. return devs, nil
  74. }