bolt-piece-completion.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. //go:build !noboltdb && !wasm
  2. // +build !noboltdb,!wasm
  3. package storage
  4. import (
  5. "encoding/binary"
  6. "os"
  7. "path/filepath"
  8. "time"
  9. "go.etcd.io/bbolt"
  10. "github.com/anacrolix/torrent/metainfo"
  11. )
  12. const (
  13. boltDbCompleteValue = "c"
  14. boltDbIncompleteValue = "i"
  15. )
  16. var completionBucketKey = []byte("completion")
  17. type boltPieceCompletion struct {
  18. db *bbolt.DB
  19. }
  20. var _ PieceCompletion = (*boltPieceCompletion)(nil)
  21. func NewBoltPieceCompletion(dir string) (ret PieceCompletion, err error) {
  22. os.MkdirAll(dir, 0o750)
  23. p := filepath.Join(dir, ".torrent.bolt.db")
  24. db, err := bbolt.Open(p, 0o660, &bbolt.Options{
  25. Timeout: time.Second,
  26. })
  27. if err != nil {
  28. return
  29. }
  30. db.NoSync = true
  31. ret = &boltPieceCompletion{db}
  32. return
  33. }
  34. func (me boltPieceCompletion) Get(pk metainfo.PieceKey) (cn Completion, err error) {
  35. err = me.db.View(func(tx *bbolt.Tx) error {
  36. cb := tx.Bucket(completionBucketKey)
  37. if cb == nil {
  38. return nil
  39. }
  40. ih := cb.Bucket(pk.InfoHash[:])
  41. if ih == nil {
  42. return nil
  43. }
  44. var key [4]byte
  45. binary.BigEndian.PutUint32(key[:], uint32(pk.Index))
  46. cn.Ok = true
  47. switch string(ih.Get(key[:])) {
  48. case boltDbCompleteValue:
  49. cn.Complete = true
  50. case boltDbIncompleteValue:
  51. cn.Complete = false
  52. default:
  53. cn.Ok = false
  54. }
  55. return nil
  56. })
  57. return
  58. }
  59. func (me boltPieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
  60. if c, err := me.Get(pk); err == nil && c.Ok && c.Complete == b {
  61. return nil
  62. }
  63. return me.db.Update(func(tx *bbolt.Tx) error {
  64. c, err := tx.CreateBucketIfNotExists(completionBucketKey)
  65. if err != nil {
  66. return err
  67. }
  68. ih, err := c.CreateBucketIfNotExists(pk.InfoHash[:])
  69. if err != nil {
  70. return err
  71. }
  72. var key [4]byte
  73. binary.BigEndian.PutUint32(key[:], uint32(pk.Index))
  74. return ih.Put(key[:], []byte(func() string {
  75. if b {
  76. return boltDbCompleteValue
  77. } else {
  78. return boltDbIncompleteValue
  79. }
  80. }()))
  81. })
  82. }
  83. func (me *boltPieceCompletion) Close() error {
  84. return me.db.Close()
  85. }