| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- //go:build !noboltdb && !wasm
- // +build !noboltdb,!wasm
- package storage
- import (
- "encoding/binary"
- "io"
- "go.etcd.io/bbolt"
- "github.com/anacrolix/torrent/metainfo"
- )
- type boltPiece struct {
- db *bbolt.DB
- p metainfo.Piece
- ih metainfo.Hash
- key [24]byte
- }
- var (
- _ PieceImpl = (*boltPiece)(nil)
- dataBucketKey = []byte("data")
- )
- func (me *boltPiece) pc() PieceCompletionGetSetter {
- return boltPieceCompletion{me.db}
- }
- func (me *boltPiece) pk() metainfo.PieceKey {
- return metainfo.PieceKey{me.ih, me.p.Index()}
- }
- func (me *boltPiece) Completion() Completion {
- c, err := me.pc().Get(me.pk())
- switch err {
- case bbolt.ErrDatabaseNotOpen:
- return Completion{}
- case nil:
- default:
- panic(err)
- }
- return c
- }
- func (me *boltPiece) MarkComplete() error {
- return me.pc().Set(me.pk(), true)
- }
- func (me *boltPiece) MarkNotComplete() error {
- return me.pc().Set(me.pk(), false)
- }
- func (me *boltPiece) ReadAt(b []byte, off int64) (n int, err error) {
- err = me.db.View(func(tx *bbolt.Tx) error {
- db := tx.Bucket(dataBucketKey)
- if db == nil {
- return io.EOF
- }
- ci := off / chunkSize
- off %= chunkSize
- for len(b) != 0 {
- ck := me.chunkKey(int(ci))
- _b := db.Get(ck[:])
- // If the chunk is the wrong size, assume it's missing as we can't rely on the data.
- if len(_b) != chunkSize {
- return io.EOF
- }
- n1 := copy(b, _b[off:])
- off = 0
- ci++
- b = b[n1:]
- n += n1
- }
- return nil
- })
- return
- }
- func (me *boltPiece) chunkKey(index int) (ret [26]byte) {
- copy(ret[:], me.key[:])
- binary.BigEndian.PutUint16(ret[24:], uint16(index))
- return
- }
- func (me *boltPiece) WriteAt(b []byte, off int64) (n int, err error) {
- err = me.db.Update(func(tx *bbolt.Tx) error {
- db, err := tx.CreateBucketIfNotExists(dataBucketKey)
- if err != nil {
- return err
- }
- ci := off / chunkSize
- off %= chunkSize
- for len(b) != 0 {
- _b := make([]byte, chunkSize)
- ck := me.chunkKey(int(ci))
- copy(_b, db.Get(ck[:]))
- n1 := copy(_b[off:], b)
- db.Put(ck[:], _b)
- if n1 > len(b) {
- break
- }
- b = b[n1:]
- off = 0
- ci++
- n += n1
- }
- return nil
- })
- return
- }
|