3
3
const core = require ( 'datastore-core' )
4
4
const ShardingStore = core . ShardingDatastore
5
5
const Block = require ( 'ipld-block' )
6
- const { cidToKey, keyToCid } = require ( './blockstore-utils' )
6
+ const { cidToKey } = require ( './blockstore-utils' )
7
7
const map = require ( 'it-map' )
8
- const pipe = require ( 'it-pipe' )
8
+ const drain = require ( 'it-drain' )
9
+ const pushable = require ( 'it-pushable' )
9
10
10
11
module . exports = async ( filestore , options ) => {
11
12
const store = await maybeWithSharding ( filestore , options )
@@ -32,6 +33,7 @@ function createBaseStore (store) {
32
33
async * query ( query , options ) { // eslint-disable-line require-await
33
34
yield * store . query ( query , options )
34
35
} ,
36
+
35
37
/**
36
38
* Get a single block by CID.
37
39
*
@@ -41,27 +43,11 @@ function createBaseStore (store) {
41
43
*/
42
44
async get ( cid , options ) {
43
45
const key = cidToKey ( cid )
44
- let blockData
45
- try {
46
- blockData = await store . get ( key , options )
47
- return new Block ( blockData , cid )
48
- } catch ( err ) {
49
- if ( err . code === 'ERR_NOT_FOUND' ) {
50
- const otherCid = cidToOtherVersion ( cid )
51
-
52
- if ( ! otherCid ) {
53
- throw err
54
- }
55
-
56
- const otherKey = cidToKey ( otherCid )
57
- const blockData = await store . get ( otherKey , options )
58
- await store . put ( key , blockData )
59
- return new Block ( blockData , cid )
60
- }
46
+ const blockData = await store . get ( key , options )
61
47
62
- throw err
63
- }
48
+ return new Block ( blockData , cid )
64
49
} ,
50
+
65
51
/**
66
52
* Like get, but for more.
67
53
*
@@ -74,6 +60,7 @@ function createBaseStore (store) {
74
60
yield this . get ( cid , options )
75
61
}
76
62
} ,
63
+
77
64
/**
78
65
* Write a single block to the store.
79
66
*
@@ -86,59 +73,69 @@ function createBaseStore (store) {
86
73
throw new Error ( 'invalid block' )
87
74
}
88
75
89
- const exists = await this . has ( block . cid )
76
+ const key = cidToKey ( block . cid )
77
+ const exists = await store . has ( key , options )
90
78
91
- if ( exists ) {
92
- return this . get ( block . cid , options )
79
+ if ( ! exists ) {
80
+ await store . put ( key , block . data , options )
93
81
}
94
82
95
- await store . put ( cidToKey ( block . cid ) , block . data , options )
96
-
97
83
return block
98
84
} ,
99
85
100
86
/**
101
- * Like put, but for more.
87
+ * Like put, but for more
102
88
*
103
89
* @param {AsyncIterable<Block>|Iterable<Block> } blocks
104
90
* @param {Object } options
105
91
* @returns {AsyncIterable<Block> }
106
92
*/
107
93
async * putMany ( blocks , options ) { // eslint-disable-line require-await
108
- yield * pipe (
109
- blocks ,
110
- ( source ) => {
111
- // turn them into a key/value pair
112
- return map ( source , ( block ) => {
113
- return { key : cidToKey ( block . cid ) , value : block . data }
114
- } )
115
- } ,
116
- ( source ) => {
117
- // put them into the datastore
118
- return store . putMany ( source , options )
119
- } ,
120
- ( source ) => {
121
- // map the returned key/value back into a block
122
- return map ( source , ( { key, value } ) => {
123
- return new Block ( value , keyToCid ( key ) )
124
- } )
94
+ // we cannot simply chain to `store.putMany` because we convert a CID into
95
+ // a key based on the multihash only, so we lose the version & codec and
96
+ // cannot give the user back the CID they used to create the block
97
+ // nb. we want to use `store.putMany` here so bitswap can control batching
98
+ // up block HAVEs to send to the network - if we use multiple `store.put`s
99
+ // it will not be able to guess we are about to `store.put` more blocks
100
+ const output = pushable ( )
101
+
102
+ setImmediate ( async ( ) => {
103
+ try {
104
+ await drain ( store . putMany ( async function * ( ) {
105
+ for await ( const block of blocks ) {
106
+ const key = cidToKey ( block . cid )
107
+ const exists = await store . has ( key , options )
108
+
109
+ if ( ! exists ) {
110
+ yield { key, value : block . data }
111
+ }
112
+
113
+ // there is an assumption here that after the yield has completed
114
+ // the underlying datastore has finished writing the block
115
+ output . push ( block )
116
+ }
117
+ } ( ) ) )
118
+
119
+ output . end ( )
120
+ } catch ( err ) {
121
+ output . end ( err )
125
122
}
126
- )
123
+ } )
124
+
125
+ yield * output
127
126
} ,
127
+
128
128
/**
129
- * Does the store contain block with this cid ?
129
+ * Does the store contain block with this CID ?
130
130
*
131
131
* @param {CID } cid
132
132
* @param {Object } options
133
133
* @returns {Promise<bool> }
134
134
*/
135
- async has ( cid , options ) {
136
- const exists = await store . has ( cidToKey ( cid ) , options )
137
- if ( exists ) return exists
138
- const otherCid = cidToOtherVersion ( cid )
139
- if ( ! otherCid ) return false
140
- return store . has ( cidToKey ( otherCid ) , options )
135
+ async has ( cid , options ) { // eslint-disable-line require-await
136
+ return store . has ( cidToKey ( cid ) , options )
141
137
} ,
138
+
142
139
/**
143
140
* Delete a block from the store
144
141
*
@@ -149,6 +146,7 @@ function createBaseStore (store) {
149
146
async delete ( cid , options ) { // eslint-disable-line require-await
150
147
return store . delete ( cidToKey ( cid ) , options )
151
148
} ,
149
+
152
150
/**
153
151
* Delete a block from the store
154
152
*
@@ -157,12 +155,9 @@ function createBaseStore (store) {
157
155
* @returns {Promise<void> }
158
156
*/
159
157
async * deleteMany ( cids , options ) { // eslint-disable-line require-await
160
- yield * store . deleteMany ( ( async function * ( ) {
161
- for await ( const cid of cids ) {
162
- yield cidToKey ( cid )
163
- }
164
- } ( ) ) , options )
158
+ yield * store . deleteMany ( map ( cids , cid => cidToKey ( cid ) ) , options )
165
159
} ,
160
+
166
161
/**
167
162
* Close the store
168
163
*
@@ -173,11 +168,3 @@ function createBaseStore (store) {
173
168
}
174
169
}
175
170
}
176
-
177
- function cidToOtherVersion ( cid ) {
178
- try {
179
- return cid . version === 0 ? cid . toV1 ( ) : cid . toV0 ( )
180
- } catch ( err ) {
181
- return null
182
- }
183
- }
0 commit comments