4
4
package blockservice
5
5
6
6
import (
7
+ "context"
7
8
"errors"
8
9
"fmt"
9
10
10
11
blocks "github.com/ipfs/go-ipfs/blocks"
11
12
"github.com/ipfs/go-ipfs/blocks/blockstore"
12
13
exchange "github.com/ipfs/go-ipfs/exchange"
13
14
14
- context "context"
15
15
logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
16
16
cid "gx/ipfs/QmakyCk6Vnn16WEKjbkxieZmM2YLTzkFWizbmGowoYPjro/go-cid"
17
17
)
@@ -23,77 +23,112 @@ var ErrNotFound = errors.New("blockservice: key not found")
23
23
// BlockService is a hybrid block datastore. It stores data in a local
24
24
// datastore and may retrieve data from a remote Exchange.
25
25
// It uses an internal `datastore.Datastore` instance to store values.
26
- type BlockService struct {
27
- // TODO don't expose underlying impl details
28
- Blockstore blockstore.Blockstore
29
- Exchange exchange.Interface
26
+ type BlockService interface {
27
+ Blockstore () blockstore.Blockstore
28
+ Exchange () exchange.Interface
29
+ AddBlock (o blocks.Block ) (* cid.Cid , error )
30
+ AddBlocks (bs []blocks.Block ) ([]* cid.Cid , error )
31
+ GetBlock (ctx context.Context , c * cid.Cid ) (blocks.Block , error )
32
+ GetBlocks (ctx context.Context , ks []* cid.Cid ) <- chan blocks.Block
33
+ DeleteBlock (o blocks.Block ) error
34
+ Close () error
35
+ }
36
+
37
+ type blockService struct {
38
+ blockstore blockstore.Blockstore
39
+ exchange exchange.Interface
40
+ // If checkFirst is true then first check that a block doesn't
41
+ // already exist to avoid republishing the block on the exchange.
42
+ checkFirst bool
30
43
}
31
44
32
45
// NewBlockService creates a BlockService with given datastore instance.
33
- func New (bs blockstore.Blockstore , rem exchange.Interface ) * BlockService {
46
+ func New (bs blockstore.Blockstore , rem exchange.Interface ) BlockService {
47
+ if rem == nil {
48
+ log .Warning ("blockservice running in local (offline) mode." )
49
+ }
50
+
51
+ return & blockService {
52
+ blockstore : bs ,
53
+ exchange : rem ,
54
+ checkFirst : true ,
55
+ }
56
+ }
57
+
58
+ // NewWriteThrough ceates a BlockService that guarantees writes will go
59
+ // through to the blockstore and are not skipped by cache checks.
60
+ func NewWriteThrough (bs blockstore.Blockstore , rem exchange.Interface ) BlockService {
34
61
if rem == nil {
35
62
log .Warning ("blockservice running in local (offline) mode." )
36
63
}
37
64
38
- return & BlockService {
39
- Blockstore : bs ,
40
- Exchange : rem ,
65
+ return & blockService {
66
+ blockstore : bs ,
67
+ exchange : rem ,
68
+ checkFirst : false ,
41
69
}
42
70
}
43
71
72
+ func (bs * blockService ) Blockstore () blockstore.Blockstore {
73
+ return bs .blockstore
74
+ }
75
+
76
+ func (bs * blockService ) Exchange () exchange.Interface {
77
+ return bs .exchange
78
+ }
79
+
44
80
// AddBlock adds a particular block to the service, Putting it into the datastore.
45
81
// TODO pass a context into this if the remote.HasBlock is going to remain here.
46
- func (s * BlockService ) AddBlock (o blocks.Block ) (* cid.Cid , error ) {
47
- // TODO: while this is a great optimization, we should think about the
48
- // possibility of streaming writes directly to disk. If we can pass this object
49
- // all the way down to the datastore without having to 'buffer' its data,
50
- // we could implement a `WriteTo` method on it that could do a streaming write
51
- // of the content, saving us (probably) considerable memory.
82
+ func (s * blockService ) AddBlock (o blocks.Block ) (* cid.Cid , error ) {
52
83
c := o .Cid ()
53
- has , err := s .Blockstore .Has (c )
54
- if err != nil {
55
- return nil , err
56
- }
84
+ if s .checkFirst {
85
+ has , err := s .blockstore .Has (c )
86
+ if err != nil {
87
+ return nil , err
88
+ }
57
89
58
- if has {
59
- return c , nil
90
+ if has {
91
+ return c , nil
92
+ }
60
93
}
61
94
62
- err = s .Blockstore .Put (o )
95
+ err : = s .blockstore .Put (o )
63
96
if err != nil {
64
97
return nil , err
65
98
}
66
99
67
- if err := s .Exchange .HasBlock (o ); err != nil {
100
+ if err := s .exchange .HasBlock (o ); err != nil {
68
101
return nil , errors .New ("blockservice is closed" )
69
102
}
70
103
71
104
return c , nil
72
105
}
73
106
74
- func (s * BlockService ) AddBlocks (bs []blocks.Block ) ([]* cid.Cid , error ) {
107
+ func (s * blockService ) AddBlocks (bs []blocks.Block ) ([]* cid.Cid , error ) {
75
108
var toput []blocks.Block
76
- for _ , b := range bs {
77
- has , err := s .Blockstore .Has (b .Cid ())
78
- if err != nil {
79
- return nil , err
80
- }
81
-
82
- if has {
83
- continue
109
+ if s .checkFirst {
110
+ for _ , b := range bs {
111
+ has , err := s .blockstore .Has (b .Cid ())
112
+ if err != nil {
113
+ return nil , err
114
+ }
115
+ if has {
116
+ continue
117
+ }
118
+ toput = append (toput , b )
84
119
}
85
-
86
- toput = append ( toput , b )
120
+ } else {
121
+ toput = bs
87
122
}
88
123
89
- err := s .Blockstore .PutMany (toput )
124
+ err := s .blockstore .PutMany (toput )
90
125
if err != nil {
91
126
return nil , err
92
127
}
93
128
94
129
var ks []* cid.Cid
95
130
for _ , o := range toput {
96
- if err := s .Exchange .HasBlock (o ); err != nil {
131
+ if err := s .exchange .HasBlock (o ); err != nil {
97
132
return nil , fmt .Errorf ("blockservice is closed (%s)" , err )
98
133
}
99
134
@@ -104,19 +139,19 @@ func (s *BlockService) AddBlocks(bs []blocks.Block) ([]*cid.Cid, error) {
104
139
105
140
// GetBlock retrieves a particular block from the service,
106
141
// Getting it from the datastore using the key (hash).
107
- func (s * BlockService ) GetBlock (ctx context.Context , c * cid.Cid ) (blocks.Block , error ) {
142
+ func (s * blockService ) GetBlock (ctx context.Context , c * cid.Cid ) (blocks.Block , error ) {
108
143
log .Debugf ("BlockService GetBlock: '%s'" , c )
109
144
110
- block , err := s .Blockstore .Get (c )
145
+ block , err := s .blockstore .Get (c )
111
146
if err == nil {
112
147
return block , nil
113
148
}
114
149
115
- if err == blockstore .ErrNotFound && s .Exchange != nil {
150
+ if err == blockstore .ErrNotFound && s .exchange != nil {
116
151
// TODO be careful checking ErrNotFound. If the underlying
117
152
// implementation changes, this will break.
118
153
log .Debug ("Blockservice: Searching bitswap" )
119
- blk , err := s .Exchange .GetBlock (ctx , c )
154
+ blk , err := s .exchange .GetBlock (ctx , c )
120
155
if err != nil {
121
156
if err == blockstore .ErrNotFound {
122
157
return nil , ErrNotFound
@@ -137,13 +172,13 @@ func (s *BlockService) GetBlock(ctx context.Context, c *cid.Cid) (blocks.Block,
137
172
// GetBlocks gets a list of blocks asynchronously and returns through
138
173
// the returned channel.
139
174
// NB: No guarantees are made about order.
140
- func (s * BlockService ) GetBlocks (ctx context.Context , ks []* cid.Cid ) <- chan blocks.Block {
175
+ func (s * blockService ) GetBlocks (ctx context.Context , ks []* cid.Cid ) <- chan blocks.Block {
141
176
out := make (chan blocks.Block , 0 )
142
177
go func () {
143
178
defer close (out )
144
179
var misses []* cid.Cid
145
180
for _ , c := range ks {
146
- hit , err := s .Blockstore .Get (c )
181
+ hit , err := s .blockstore .Get (c )
147
182
if err != nil {
148
183
misses = append (misses , c )
149
184
continue
@@ -160,7 +195,7 @@ func (s *BlockService) GetBlocks(ctx context.Context, ks []*cid.Cid) <-chan bloc
160
195
return
161
196
}
162
197
163
- rblocks , err := s .Exchange .GetBlocks (ctx , misses )
198
+ rblocks , err := s .exchange .GetBlocks (ctx , misses )
164
199
if err != nil {
165
200
log .Debugf ("Error with GetBlocks: %s" , err )
166
201
return
@@ -178,11 +213,11 @@ func (s *BlockService) GetBlocks(ctx context.Context, ks []*cid.Cid) <-chan bloc
178
213
}
179
214
180
215
// DeleteBlock deletes a block in the blockservice from the datastore
181
- func (s * BlockService ) DeleteBlock (o blocks.Block ) error {
182
- return s .Blockstore .DeleteBlock (o .Cid ())
216
+ func (s * blockService ) DeleteBlock (o blocks.Block ) error {
217
+ return s .blockstore .DeleteBlock (o .Cid ())
183
218
}
184
219
185
- func (s * BlockService ) Close () error {
220
+ func (s * blockService ) Close () error {
186
221
log .Debug ("blockservice is shutting down..." )
187
- return s .Exchange .Close ()
222
+ return s .exchange .Close ()
188
223
}
0 commit comments