98 lines
1.9 KiB
Go
98 lines
1.9 KiB
Go
//go:build !noboltdb && !wasm
|
|
// +build !noboltdb,!wasm
|
|
|
|
package storage
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"go.etcd.io/bbolt"
|
|
|
|
"github.com/anacrolix/torrent/metainfo"
|
|
)
|
|
|
|
const (
|
|
boltDbCompleteValue = "c"
|
|
boltDbIncompleteValue = "i"
|
|
)
|
|
|
|
var completionBucketKey = []byte("completion")
|
|
|
|
type boltPieceCompletion struct {
|
|
db *bbolt.DB
|
|
}
|
|
|
|
var _ PieceCompletion = (*boltPieceCompletion)(nil)
|
|
|
|
func NewBoltPieceCompletion(dir string) (ret PieceCompletion, err error) {
|
|
os.MkdirAll(dir, 0o750)
|
|
p := filepath.Join(dir, ".torrent.bolt.db")
|
|
db, err := bbolt.Open(p, 0o660, &bbolt.Options{
|
|
Timeout: time.Second,
|
|
})
|
|
if err != nil {
|
|
return
|
|
}
|
|
db.NoSync = true
|
|
ret = &boltPieceCompletion{db}
|
|
return
|
|
}
|
|
|
|
func (me boltPieceCompletion) Get(pk metainfo.PieceKey) (cn Completion, err error) {
|
|
err = me.db.View(func(tx *bbolt.Tx) error {
|
|
cb := tx.Bucket(completionBucketKey)
|
|
if cb == nil {
|
|
return nil
|
|
}
|
|
ih := cb.Bucket(pk.InfoHash[:])
|
|
if ih == nil {
|
|
return nil
|
|
}
|
|
var key [4]byte
|
|
binary.BigEndian.PutUint32(key[:], uint32(pk.Index))
|
|
cn.Ok = true
|
|
switch string(ih.Get(key[:])) {
|
|
case boltDbCompleteValue:
|
|
cn.Complete = true
|
|
case boltDbIncompleteValue:
|
|
cn.Complete = false
|
|
default:
|
|
cn.Ok = false
|
|
}
|
|
return nil
|
|
})
|
|
return
|
|
}
|
|
|
|
func (me boltPieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
|
|
if c, err := me.Get(pk); err == nil && c.Ok && c.Complete == b {
|
|
return nil
|
|
}
|
|
return me.db.Update(func(tx *bbolt.Tx) error {
|
|
c, err := tx.CreateBucketIfNotExists(completionBucketKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ih, err := c.CreateBucketIfNotExists(pk.InfoHash[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var key [4]byte
|
|
binary.BigEndian.PutUint32(key[:], uint32(pk.Index))
|
|
return ih.Put(key[:], []byte(func() string {
|
|
if b {
|
|
return boltDbCompleteValue
|
|
} else {
|
|
return boltDbIncompleteValue
|
|
}
|
|
}()))
|
|
})
|
|
}
|
|
|
|
func (me *boltPieceCompletion) Close() error {
|
|
return me.db.Close()
|
|
}
|