sqlite-piece-completion.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // modernc.org/sqlite depends on modernc.org/libc which doesn't work for JS (and probably wasm but I
  2. // think JS is the stronger signal).
  3. //go:build cgo && !nosqlite
  4. // +build cgo,!nosqlite
  5. package storage
  6. import (
  7. "errors"
  8. "path/filepath"
  9. "sync"
  10. "github.com/go-llsqlite/adapter"
  11. "github.com/go-llsqlite/adapter/sqlitex"
  12. "github.com/anacrolix/torrent/metainfo"
  13. )
  14. // sqlite is always the default when available.
  15. func NewDefaultPieceCompletionForDir(dir string) (PieceCompletion, error) {
  16. return NewSqlitePieceCompletion(dir)
  17. }
  18. type sqlitePieceCompletion struct {
  19. mu sync.Mutex
  20. closed bool
  21. db *sqlite.Conn
  22. }
  23. var _ PieceCompletion = (*sqlitePieceCompletion)(nil)
  24. func NewSqlitePieceCompletion(dir string) (ret *sqlitePieceCompletion, err error) {
  25. p := filepath.Join(dir, ".torrent.db")
  26. db, err := sqlite.OpenConn(p, 0)
  27. if err != nil {
  28. return
  29. }
  30. err = sqlitex.ExecScript(db, `create table if not exists piece_completion(infohash, "index", complete, unique(infohash, "index"))`)
  31. if err != nil {
  32. db.Close()
  33. return
  34. }
  35. ret = &sqlitePieceCompletion{db: db}
  36. return
  37. }
  38. func (me *sqlitePieceCompletion) Get(pk metainfo.PieceKey) (c Completion, err error) {
  39. me.mu.Lock()
  40. defer me.mu.Unlock()
  41. err = sqlitex.Exec(
  42. me.db, `select complete from piece_completion where infohash=? and "index"=?`,
  43. func(stmt *sqlite.Stmt) error {
  44. c.Complete = stmt.ColumnInt(0) != 0
  45. c.Ok = true
  46. return nil
  47. },
  48. pk.InfoHash.HexString(), pk.Index)
  49. return
  50. }
  51. func (me *sqlitePieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
  52. me.mu.Lock()
  53. defer me.mu.Unlock()
  54. if me.closed {
  55. return errors.New("closed")
  56. }
  57. return sqlitex.Exec(
  58. me.db,
  59. `insert or replace into piece_completion(infohash, "index", complete) values(?, ?, ?)`,
  60. nil,
  61. pk.InfoHash.HexString(), pk.Index, b)
  62. }
  63. func (me *sqlitePieceCompletion) Close() (err error) {
  64. me.mu.Lock()
  65. defer me.mu.Unlock()
  66. if me.closed {
  67. return
  68. }
  69. err = me.db.Close()
  70. me.db = nil
  71. me.closed = true
  72. return
  73. }