@@ -64,11 +64,12 @@ func newBlockfileMgr(conf *Conf) *blockfileMgr {
64
64
}
65
65
if cpInfo == nil {
66
66
cpInfo = & checkpointInfo {latestFileChunkSuffixNum : 0 , latestFileChunksize : 0 }
67
- err = mgr .saveCurrentInfo (cpInfo )
67
+ err = mgr .saveCurrentInfo (cpInfo , true )
68
68
if err != nil {
69
69
panic (fmt .Sprintf ("Could not save next block file info to db: %s" , err ))
70
70
}
71
71
}
72
+ updateCPInfo (conf , cpInfo )
72
73
currentFileWriter , err := newBlockfileWriter (deriveBlockfilePath (rootDir , cpInfo .latestFileChunkSuffixNum ))
73
74
if err != nil {
74
75
panic (fmt .Sprintf ("Could not open writer to current file: %s" , err ))
@@ -81,9 +82,12 @@ func newBlockfileMgr(conf *Conf) *blockfileMgr {
81
82
mgr .index = newBlockIndex (db )
82
83
mgr .cpInfo = cpInfo
83
84
mgr .currentFileWriter = currentFileWriter
84
-
85
85
// init BlockchainInfo
86
- bcInfo := & protos.BlockchainInfo {Height : 0 , CurrentBlockHash : nil , PreviousBlockHash : nil }
86
+ bcInfo := & protos.BlockchainInfo {
87
+ Height : 0 ,
88
+ CurrentBlockHash : nil ,
89
+ PreviousBlockHash : nil }
90
+
87
91
if cpInfo .lastBlockNumber > 0 {
88
92
lastBlock , err := mgr .retrieveSerBlockByNumber (cpInfo .lastBlockNumber )
89
93
if err != nil {
@@ -104,11 +108,37 @@ func newBlockfileMgr(conf *Conf) *blockfileMgr {
104
108
}
105
109
106
110
func initDB (conf * Conf ) * db.DB {
107
- dbInst := db .CreateDB (& db.Conf {DBPath : conf .dbPath , CFNames : []string {blockIndexCF }})
111
+ dbInst := db .CreateDB (& db.Conf {
112
+ DBPath : conf .dbPath ,
113
+ CFNames : []string {blockIndexCF },
114
+ DisableWAL : true })
115
+
108
116
dbInst .Open ()
109
117
return dbInst
110
118
}
111
119
120
+ func updateCPInfo (conf * Conf , cpInfo * checkpointInfo ) {
121
+ logger .Debugf ("Starting checkpoint=%s" , cpInfo )
122
+ rootDir := conf .blockfilesDir
123
+ filePath := deriveBlockfilePath (rootDir , cpInfo .latestFileChunkSuffixNum )
124
+ exists , size , err := util .FileExists (filePath )
125
+ if err != nil {
126
+ panic (fmt .Sprintf ("Error in checking whether file [%s] exists: %s" , filePath , err ))
127
+ }
128
+ logger .Debugf ("status of file [%s]: exists=[%t], size=[%d]" , filePath , exists , size )
129
+ if ! exists || int (size ) == cpInfo .latestFileChunksize {
130
+ // check point info is in sync with the file on disk
131
+ return
132
+ }
133
+ endOffsetLastBlock , numBlocks , err := scanForLastCompleteBlock (filePath , int64 (cpInfo .latestFileChunksize ))
134
+ if err != nil {
135
+ panic (fmt .Sprintf ("Could not open current file for detecting last block in the file: %s" , err ))
136
+ }
137
+ cpInfo .lastBlockNumber += uint64 (numBlocks )
138
+ cpInfo .latestFileChunksize = int (endOffsetLastBlock )
139
+ logger .Debugf ("Checkpoint after updates by scanning the last file segment:%s" , cpInfo )
140
+ }
141
+
112
142
func deriveBlockfilePath (rootDir string , suffixNum int ) string {
113
143
return rootDir + "/" + blockfilePrefix + fmt .Sprintf ("%06d" , suffixNum )
114
144
}
@@ -123,13 +153,18 @@ func (mgr *blockfileMgr) close() {
123
153
}
124
154
125
155
func (mgr * blockfileMgr ) moveToNextFile () {
126
- nextFileInfo := & checkpointInfo {latestFileChunkSuffixNum : mgr .cpInfo .latestFileChunkSuffixNum + 1 , latestFileChunksize : 0 }
127
- nextFileWriter , err := newBlockfileWriter (deriveBlockfilePath (mgr .rootDir , nextFileInfo .latestFileChunkSuffixNum ))
156
+ nextFileInfo := & checkpointInfo {
157
+ latestFileChunkSuffixNum : mgr .cpInfo .latestFileChunkSuffixNum + 1 ,
158
+ latestFileChunksize : 0 }
159
+
160
+ nextFileWriter , err := newBlockfileWriter (
161
+ deriveBlockfilePath (mgr .rootDir , nextFileInfo .latestFileChunkSuffixNum ))
162
+
128
163
if err != nil {
129
164
panic (fmt .Sprintf ("Could not open writer to next file: %s" , err ))
130
165
}
131
166
mgr .currentFileWriter .close ()
132
- err = mgr .saveCurrentInfo (nextFileInfo )
167
+ err = mgr .saveCurrentInfo (nextFileInfo , true )
133
168
if err != nil {
134
169
panic (fmt .Sprintf ("Could not save next block file info to db: %s" , err ))
135
170
}
@@ -145,49 +180,44 @@ func (mgr *blockfileMgr) addBlock(block *protos.Block2) error {
145
180
blockBytes := serBlock .GetBytes ()
146
181
blockHash := serBlock .ComputeHash ()
147
182
txOffsets , err := serBlock .GetTxOffsets ()
183
+ currentOffset := mgr .cpInfo .latestFileChunksize
148
184
if err != nil {
149
185
return fmt .Errorf ("Error while serializing block: %s" , err )
150
186
}
151
- currentOffset := mgr . cpInfo . latestFileChunksize
152
- length := len ( blockBytes )
153
- encodedLen := proto . EncodeVarint ( uint64 ( length ) )
154
- totalLen := length + len ( encodedLen )
155
- if currentOffset + totalLen > mgr .conf .maxBlockfileSize {
187
+ blockBytesLen := len ( blockBytes )
188
+ blockBytesEncodedLen := proto . EncodeVarint ( uint64 ( blockBytesLen ) )
189
+ totalBytesToAppend := blockBytesLen + len ( blockBytesEncodedLen )
190
+
191
+ if currentOffset + totalBytesToAppend > mgr .conf .maxBlockfileSize {
156
192
mgr .moveToNextFile ()
157
193
currentOffset = 0
158
194
}
159
- err = mgr .currentFileWriter .append (encodedLen )
160
- if err != nil {
161
- err1 := mgr .currentFileWriter .truncateFile (mgr .cpInfo .latestFileChunksize )
162
- if err1 != nil {
163
- panic (fmt .Sprintf ("Could not truncate current file to known size after an error while appending a block: %s" , err ))
164
- }
165
- return fmt .Errorf ("Error while appending block to file: %s" , err )
195
+ err = mgr .currentFileWriter .append (blockBytesEncodedLen , false )
196
+ if err == nil {
197
+ err = mgr .currentFileWriter .append (blockBytes , true )
166
198
}
167
-
168
- err = mgr .currentFileWriter .append (blockBytes )
169
199
if err != nil {
170
- err1 := mgr .currentFileWriter .truncateFile (mgr .cpInfo .latestFileChunksize )
171
- if err1 != nil {
172
- panic (fmt .Sprintf ("Could not truncate current file to known size after an error while appending a block: %s" , err ))
200
+ truncateErr := mgr .currentFileWriter .truncateFile (mgr .cpInfo .latestFileChunksize )
201
+ if truncateErr != nil {
202
+ panic (fmt .Sprintf ("Could not truncate current file to known size after an error during block append : %s" , err ))
173
203
}
174
204
return fmt .Errorf ("Error while appending block to file: %s" , err )
175
205
}
176
206
177
- mgr .cpInfo .latestFileChunksize += totalLen
207
+ mgr .cpInfo .latestFileChunksize += totalBytesToAppend
178
208
mgr .cpInfo .lastBlockNumber ++
179
- err = mgr .saveCurrentInfo (mgr .cpInfo )
209
+ err = mgr .saveCurrentInfo (mgr .cpInfo , false )
180
210
if err != nil {
181
- mgr .cpInfo .latestFileChunksize -= totalLen
182
- err1 := mgr .currentFileWriter .truncateFile (mgr .cpInfo .latestFileChunksize )
183
- if err1 != nil {
184
- panic (fmt .Sprintf ("Could not truncate current file to known size after an error while appending a block : %s" , err ))
211
+ mgr .cpInfo .latestFileChunksize -= totalBytesToAppend
212
+ truncateErr := mgr .currentFileWriter .truncateFile (mgr .cpInfo .latestFileChunksize )
213
+ if truncateErr != nil {
214
+ panic (fmt .Sprintf ("Error in truncating current file to known size after an error in saving checkpoint info : %s" , err ))
185
215
}
186
216
return fmt .Errorf ("Error while saving current file info to db: %s" , err )
187
217
}
188
218
blockFLP := & fileLocPointer {fileSuffixNum : mgr .cpInfo .latestFileChunkSuffixNum }
189
219
blockFLP .offset = currentOffset
190
- mgr .index .indexBlock (mgr .cpInfo .lastBlockNumber , blockHash , blockFLP , length , len (encodedLen ), txOffsets )
220
+ mgr .index .indexBlock (mgr .cpInfo .lastBlockNumber , blockHash , blockFLP , blockBytesLen , len (blockBytesEncodedLen ), txOffsets )
191
221
mgr .updateBlockchainInfo (blockHash , block )
192
222
return nil
193
223
}
@@ -198,7 +228,11 @@ func (mgr *blockfileMgr) getBlockchainInfo() *protos.BlockchainInfo {
198
228
199
229
func (mgr * blockfileMgr ) updateBlockchainInfo (latestBlockHash []byte , latestBlock * protos.Block2 ) {
200
230
currentBCInfo := mgr .getBlockchainInfo ()
201
- newBCInfo := & protos.BlockchainInfo {Height : currentBCInfo .Height + 1 , CurrentBlockHash : latestBlockHash , PreviousBlockHash : latestBlock .PreviousBlockHash }
231
+ newBCInfo := & protos.BlockchainInfo {
232
+ Height : currentBCInfo .Height + 1 ,
233
+ CurrentBlockHash : latestBlockHash ,
234
+ PreviousBlockHash : latestBlock .PreviousBlockHash }
235
+
202
236
mgr .bcInfo .Store (newBCInfo )
203
237
}
204
238
@@ -315,33 +349,59 @@ func (mgr *blockfileMgr) fetchRawBytes(lp *fileLocPointer) ([]byte, error) {
315
349
}
316
350
317
351
func (mgr * blockfileMgr ) loadCurrentInfo () (* checkpointInfo , error ) {
318
- b , err := mgr .db .Get (mgr .defaultCF , blkMgrInfoKey )
319
- if err != nil {
320
- return nil , err
321
- }
322
- if b == nil {
352
+ var b []byte
353
+ var err error
354
+ if b , err = mgr .db .Get (mgr .defaultCF , blkMgrInfoKey ); b == nil || err != nil {
323
355
return nil , err
324
356
}
325
357
i := & checkpointInfo {}
326
358
if err = i .unmarshal (b ); err != nil {
327
359
return nil , err
328
360
}
361
+ logger .Debugf ("loaded checkpointInfo:%s" , i )
329
362
return i , nil
330
363
}
331
364
332
- func (mgr * blockfileMgr ) saveCurrentInfo (i * checkpointInfo ) error {
365
+ func (mgr * blockfileMgr ) saveCurrentInfo (i * checkpointInfo , flush bool ) error {
333
366
b , err := i .marshal ()
334
367
if err != nil {
335
368
return err
336
369
}
337
- err = mgr .db .Put (mgr .defaultCF , blkMgrInfoKey , b )
338
- if err != nil {
370
+ if err = mgr .db .Put (mgr .defaultCF , blkMgrInfoKey , b ); err != nil {
339
371
return err
340
372
}
373
+ if flush {
374
+ if err = mgr .db .Flush (true ); err != nil {
375
+ return err
376
+ }
377
+ logger .Debugf ("saved checkpointInfo:%s" , i )
378
+ }
341
379
return nil
342
380
}
343
381
344
- // blkMgrInfo
382
+ func scanForLastCompleteBlock (filePath string , startingOffset int64 ) (int64 , int , error ) {
383
+ logger .Debugf ("scanForLastCompleteBlock(): filePath=[%s], startingOffset=[%d]" , filePath , startingOffset )
384
+ numBlocks := 0
385
+ blockStream , err := newBlockStream (filePath , startingOffset )
386
+ if err != nil {
387
+ return 0 , 0 , err
388
+ }
389
+ defer blockStream .close ()
390
+ for {
391
+ blockBytes , err := blockStream .nextBlockBytes ()
392
+ if blockBytes == nil || err != nil {
393
+ logger .Debugf (`scanForLastCompleteBlock(): error=[%s].
394
+ This may happen if a crash has happened during block appending.
395
+ Returning current offset as a last complete block's end offset` , err )
396
+ break
397
+ }
398
+ numBlocks ++
399
+ }
400
+ logger .Debugf ("scanForLastCompleteBlock(): last complete block ends at offset=[%d]" , blockStream .currentFileOffset )
401
+ return blockStream .currentFileOffset , numBlocks , err
402
+ }
403
+
404
+ // checkpointInfo
345
405
type checkpointInfo struct {
346
406
latestFileChunkSuffixNum int
347
407
latestFileChunksize int
@@ -385,3 +445,8 @@ func (i *checkpointInfo) unmarshal(b []byte) error {
385
445
386
446
return nil
387
447
}
448
+
449
+ func (i * checkpointInfo ) String () string {
450
+ return fmt .Sprintf ("latestFileChunkSuffixNum=[%d], latestFileChunksize=[%d], lastBlockNumber=[%d]" ,
451
+ i .latestFileChunkSuffixNum , i .latestFileChunksize , i .lastBlockNumber )
452
+ }
0 commit comments