]> Sergey Matveev's repositories - btrtrc.git/blob - storage/bolt_piece.go
sortimports
[btrtrc.git] / storage / bolt_piece.go
1 package storage
2
3 import (
4         "encoding/binary"
5
6         "github.com/anacrolix/missinggo/x"
7         "github.com/boltdb/bolt"
8
9         "github.com/anacrolix/torrent/metainfo"
10 )
11
12 type boltDBPiece struct {
13         db  *bolt.DB
14         p   metainfo.Piece
15         ih  metainfo.Hash
16         key [24]byte
17 }
18
19 var (
20         _             PieceImpl = (*boltDBPiece)(nil)
21         dataBucketKey           = []byte("data")
22 )
23
24 func (me *boltDBPiece) pc() PieceCompletionGetSetter {
25         return boltPieceCompletion{me.db}
26 }
27
28 func (me *boltDBPiece) pk() metainfo.PieceKey {
29         return metainfo.PieceKey{me.ih, me.p.Index()}
30 }
31
32 func (me *boltDBPiece) Completion() Completion {
33         c, err := me.pc().Get(me.pk())
34         x.Pie(err)
35         return c
36 }
37
38 func (me *boltDBPiece) MarkComplete() error {
39         return me.pc().Set(me.pk(), true)
40 }
41
42 func (me *boltDBPiece) MarkNotComplete() error {
43         return me.pc().Set(me.pk(), false)
44 }
45 func (me *boltDBPiece) ReadAt(b []byte, off int64) (n int, err error) {
46         err = me.db.View(func(tx *bolt.Tx) error {
47                 db := tx.Bucket(dataBucketKey)
48                 if db == nil {
49                         return nil
50                 }
51                 ci := off / chunkSize
52                 off %= chunkSize
53                 for len(b) != 0 {
54                         ck := me.chunkKey(int(ci))
55                         _b := db.Get(ck[:])
56                         if len(_b) != chunkSize {
57                                 break
58                         }
59                         n1 := copy(b, _b[off:])
60                         off = 0
61                         ci++
62                         b = b[n1:]
63                         n += n1
64                 }
65                 return nil
66         })
67         return
68 }
69
70 func (me *boltDBPiece) chunkKey(index int) (ret [26]byte) {
71         copy(ret[:], me.key[:])
72         binary.BigEndian.PutUint16(ret[24:], uint16(index))
73         return
74 }
75
76 func (me *boltDBPiece) WriteAt(b []byte, off int64) (n int, err error) {
77         err = me.db.Update(func(tx *bolt.Tx) error {
78                 db, err := tx.CreateBucketIfNotExists(dataBucketKey)
79                 if err != nil {
80                         return err
81                 }
82                 ci := off / chunkSize
83                 off %= chunkSize
84                 for len(b) != 0 {
85                         _b := make([]byte, chunkSize)
86                         ck := me.chunkKey(int(ci))
87                         copy(_b, db.Get(ck[:]))
88                         n1 := copy(_b[off:], b)
89                         db.Put(ck[:], _b)
90                         if n1 > len(b) {
91                                 break
92                         }
93                         b = b[n1:]
94                         off = 0
95                         ci++
96                         n += n1
97                 }
98                 return nil
99         })
100         return
101 }