2021-07-14 12:35:52 +08:00
|
|
|
//go:build !noboltdb && !wasm
|
2021-10-28 16:53:04 +08:00
|
|
|
// +build !noboltdb,!wasm
|
2021-05-25 16:48:59 +08:00
|
|
|
|
2016-10-25 16:07:26 +08:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
2017-06-01 09:20:50 +08:00
|
|
|
"os"
|
2016-10-25 16:07:26 +08:00
|
|
|
"path/filepath"
|
|
|
|
"time"
|
|
|
|
|
2020-03-24 09:54:57 +08:00
|
|
|
"go.etcd.io/bbolt"
|
2019-08-21 18:58:40 +08:00
|
|
|
|
|
|
|
"github.com/anacrolix/torrent/metainfo"
|
2016-10-25 16:07:26 +08:00
|
|
|
)
|
|
|
|
|
2017-10-12 13:09:32 +08:00
|
|
|
const (
|
|
|
|
boltDbCompleteValue = "c"
|
|
|
|
boltDbIncompleteValue = "i"
|
|
|
|
)
|
|
|
|
|
2016-10-25 16:07:26 +08:00
|
|
|
var (
|
2017-10-12 13:09:32 +08:00
|
|
|
completionBucketKey = []byte("completion")
|
2016-10-25 16:07:26 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type boltPieceCompletion struct {
|
2020-03-24 09:54:57 +08:00
|
|
|
db *bbolt.DB
|
2016-10-25 16:07:26 +08:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:09:32 +08:00
|
|
|
var _ PieceCompletion = (*boltPieceCompletion)(nil)
|
|
|
|
|
2017-05-22 10:15:48 +08:00
|
|
|
func NewBoltPieceCompletion(dir string) (ret PieceCompletion, err error) {
|
2021-11-01 08:50:12 +08:00
|
|
|
os.MkdirAll(dir, 0750)
|
2016-10-25 16:07:26 +08:00
|
|
|
p := filepath.Join(dir, ".torrent.bolt.db")
|
2020-03-24 09:54:57 +08:00
|
|
|
db, err := bbolt.Open(p, 0660, &bbolt.Options{
|
2016-10-25 16:07:26 +08:00
|
|
|
Timeout: time.Second,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-01-09 20:11:34 +08:00
|
|
|
db.NoSync = true
|
2016-10-25 16:07:26 +08:00
|
|
|
ret = &boltPieceCompletion{db}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-10-12 13:09:32 +08:00
|
|
|
func (me boltPieceCompletion) Get(pk metainfo.PieceKey) (cn Completion, err error) {
|
2020-03-24 09:54:57 +08:00
|
|
|
err = me.db.View(func(tx *bbolt.Tx) error {
|
2017-10-12 13:09:32 +08:00
|
|
|
cb := tx.Bucket(completionBucketKey)
|
|
|
|
if cb == nil {
|
2016-10-25 16:07:26 +08:00
|
|
|
return nil
|
|
|
|
}
|
2017-10-12 13:09:32 +08:00
|
|
|
ih := cb.Bucket(pk.InfoHash[:])
|
2016-10-25 16:07:26 +08:00
|
|
|
if ih == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var key [4]byte
|
|
|
|
binary.BigEndian.PutUint32(key[:], uint32(pk.Index))
|
2017-10-12 13:09:32 +08:00
|
|
|
cn.Ok = true
|
|
|
|
switch string(ih.Get(key[:])) {
|
|
|
|
case boltDbCompleteValue:
|
|
|
|
cn.Complete = true
|
|
|
|
case boltDbIncompleteValue:
|
|
|
|
cn.Complete = false
|
|
|
|
default:
|
|
|
|
cn.Ok = false
|
|
|
|
}
|
2016-10-25 16:07:26 +08:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-10-12 13:09:32 +08:00
|
|
|
func (me boltPieceCompletion) Set(pk metainfo.PieceKey, b bool) error {
|
2021-02-22 11:51:34 +08:00
|
|
|
if c, err := me.Get(pk); err == nil && c.Ok && c.Complete == b {
|
|
|
|
return nil
|
|
|
|
}
|
2020-03-24 09:54:57 +08:00
|
|
|
return me.db.Update(func(tx *bbolt.Tx) error {
|
2017-10-12 13:09:32 +08:00
|
|
|
c, err := tx.CreateBucketIfNotExists(completionBucketKey)
|
2016-10-25 16:07:26 +08:00
|
|
|
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))
|
2017-10-12 13:09:32 +08:00
|
|
|
return ih.Put(key[:], []byte(func() string {
|
|
|
|
if b {
|
|
|
|
return boltDbCompleteValue
|
|
|
|
} else {
|
|
|
|
return boltDbIncompleteValue
|
|
|
|
}
|
|
|
|
}()))
|
2016-10-25 16:07:26 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (me *boltPieceCompletion) Close() error {
|
|
|
|
return me.db.Close()
|
|
|
|
}
|