@@ -8,6 +8,7 @@ package filedao
8
8
9
9
import (
10
10
"context"
11
+ "fmt"
11
12
12
13
"github.com/pkg/errors"
13
14
"go.uber.org/zap"
@@ -18,7 +19,6 @@ import (
18
19
"github.com/iotexproject/iotex-core/action"
19
20
"github.com/iotexproject/iotex-core/blockchain/block"
20
21
"github.com/iotexproject/iotex-core/config"
21
- "github.com/iotexproject/iotex-core/pkg/lifecycle"
22
22
"github.com/iotexproject/iotex-core/pkg/log"
23
23
)
24
24
35
35
36
36
// vars
37
37
var (
38
+ ErrFileNotExist = errors .New ("file does not exist" )
39
+ ErrFileInvalid = errors .New ("file format is not valid" )
38
40
ErrNotSupported = errors .New ("feature not supported" )
39
41
ErrAlreadyExist = errors .New ("block already exist" )
40
42
ErrInvalidTipHeight = errors .New ("invalid tip height" )
@@ -60,20 +62,42 @@ type (
60
62
61
63
// fileDAO implements FileDAO
62
64
fileDAO struct {
63
- lifecycle lifecycle.Lifecycle
64
- currFd FileDAO
65
- legacyFd FileDAO
66
- v2Fd map [uint64 ]FileDAO
65
+ currFd FileDAO
66
+ legacyFd FileDAO
67
+ v2Fd FileV2Manager // a collection of v2 db files
67
68
}
68
69
)
69
70
70
71
// NewFileDAO creates an instance of FileDAO
71
72
func NewFileDAO (compressLegacy bool , cfg config.DB ) (FileDAO , error ) {
72
- legacyFd , err := NewFileDAOLegacy ( compressLegacy , cfg )
73
- if err != nil {
73
+ header , v2Files , err := checkChainDBFiles ( cfg )
74
+ if err == ErrFileInvalid {
74
75
return nil , err
75
76
}
76
- return CreateFileDAO (legacyFd , nil )
77
+
78
+ if err == ErrFileNotExist {
79
+ // start new chain db using v2 format
80
+ if err := createNewV2File (1 , cfg ); err != nil {
81
+ return nil , err
82
+ }
83
+ return CreateFileDAO (nil , []string {cfg .DbPath }, cfg )
84
+ }
85
+
86
+ switch header .Version {
87
+ case FileLegacyMaster :
88
+ // default file is legacy format
89
+ legacyFd , err := NewFileDAOLegacy (compressLegacy , cfg )
90
+ if err != nil {
91
+ return nil , err
92
+ }
93
+ return CreateFileDAO (legacyFd , v2Files , cfg )
94
+ case FileV2 :
95
+ // default file is v2 format, add it to filenames
96
+ v2Files = append (v2Files , cfg .DbPath )
97
+ return CreateFileDAO (nil , v2Files , cfg )
98
+ default :
99
+ panic (fmt .Errorf ("corrupted file version: %s" , header .Version ))
100
+ }
77
101
}
78
102
79
103
// NewFileDAOInMemForTest creates an in-memory FileDAO for testing
@@ -82,35 +106,59 @@ func NewFileDAOInMemForTest(cfg config.DB) (FileDAO, error) {
82
106
if err != nil {
83
107
return nil , err
84
108
}
85
- return CreateFileDAO (legacyFd , nil )
109
+ return CreateFileDAO (legacyFd , nil , cfg )
86
110
}
87
111
88
112
func (fd * fileDAO ) Start (ctx context.Context ) error {
89
- return fd .lifecycle .OnStart (ctx )
113
+ if fd .legacyFd != nil {
114
+ if err := fd .legacyFd .Start (ctx ); err != nil {
115
+ return err
116
+ }
117
+ }
118
+ if fd .v2Fd != nil {
119
+ if err := fd .v2Fd .Start (ctx ); err != nil {
120
+ return err
121
+ }
122
+ }
123
+
124
+ if fd .v2Fd != nil {
125
+ fd .currFd = fd .v2Fd .TopFd ()
126
+ } else {
127
+ fd .currFd = fd .legacyFd
128
+ }
129
+ return nil
90
130
}
91
131
92
132
func (fd * fileDAO ) Stop (ctx context.Context ) error {
93
- return fd .lifecycle .OnStop (ctx )
133
+ if fd .legacyFd != nil {
134
+ if err := fd .legacyFd .Stop (ctx ); err != nil {
135
+ return err
136
+ }
137
+ }
138
+ if fd .v2Fd != nil {
139
+ return fd .v2Fd .Stop (ctx )
140
+ }
141
+ return nil
94
142
}
95
143
96
144
func (fd * fileDAO ) Height () (uint64 , error ) {
97
145
return fd .currFd .Height ()
98
146
}
99
147
100
148
func (fd * fileDAO ) GetBlockHash (height uint64 ) (hash.Hash256 , error ) {
101
- var (
102
- h hash.Hash256
103
- err error
104
- )
105
- for _ , file := range fd .v2Fd {
106
- if h , err = file .GetBlockHash (height ); err == nil {
107
- return h , nil
149
+ if fd .v2Fd != nil {
150
+ if height == 0 {
151
+ return hash .ZeroHash256 , nil
152
+ }
153
+ if v2 := fd .v2Fd .FileDAOByHeight (height ); v2 != nil {
154
+ return v2 .GetBlockHash (height )
108
155
}
109
156
}
157
+
110
158
if fd .legacyFd != nil {
111
159
return fd .legacyFd .GetBlockHash (height )
112
160
}
113
- return hash .ZeroHash256 , err
161
+ return hash .ZeroHash256 , ErrNotSupported
114
162
}
115
163
116
164
func (fd * fileDAO ) GetBlockHeight (hash hash.Hash256 ) (uint64 , error ) {
@@ -119,10 +167,11 @@ func (fd *fileDAO) GetBlockHeight(hash hash.Hash256) (uint64, error) {
119
167
err error
120
168
)
121
169
for _ , file := range fd .v2Fd {
122
- if height , err = file .GetBlockHeight (hash ); err == nil {
170
+ if height , err = file .fd . GetBlockHeight (hash ); err == nil {
123
171
return height , nil
124
172
}
125
173
}
174
+
126
175
if fd .legacyFd != nil {
127
176
return fd .legacyFd .GetBlockHeight (hash )
128
177
}
@@ -135,46 +184,41 @@ func (fd *fileDAO) GetBlock(hash hash.Hash256) (*block.Block, error) {
135
184
err error
136
185
)
137
186
for _ , file := range fd .v2Fd {
138
- if blk , err = file .GetBlock (hash ); err == nil {
187
+ if blk , err = file .fd . GetBlock (hash ); err == nil {
139
188
return blk , nil
140
189
}
141
190
}
191
+
142
192
if fd .legacyFd != nil {
143
193
return fd .legacyFd .GetBlock (hash )
144
194
}
145
195
return nil , err
146
196
}
147
197
148
198
func (fd * fileDAO ) GetBlockByHeight (height uint64 ) (* block.Block , error ) {
149
- var (
150
- blk * block.Block
151
- err error
152
- )
153
- for _ , file := range fd .v2Fd {
154
- if blk , err = file .GetBlockByHeight (height ); err == nil {
155
- return blk , nil
199
+ if fd .v2Fd != nil {
200
+ if v2 := fd .v2Fd .FileDAOByHeight (height ); v2 != nil {
201
+ return v2 .GetBlockByHeight (height )
156
202
}
157
203
}
204
+
158
205
if fd .legacyFd != nil {
159
206
return fd .legacyFd .GetBlockByHeight (height )
160
207
}
161
- return nil , err
208
+ return nil , ErrNotSupported
162
209
}
163
210
164
211
func (fd * fileDAO ) GetReceipts (height uint64 ) ([]* action.Receipt , error ) {
165
- var (
166
- receipts []* action.Receipt
167
- err error
168
- )
169
- for _ , file := range fd .v2Fd {
170
- if receipts , err = file .GetReceipts (height ); err == nil {
171
- return receipts , nil
212
+ if fd .v2Fd != nil {
213
+ if v2 := fd .v2Fd .FileDAOByHeight (height ); v2 != nil {
214
+ return v2 .GetReceipts (height )
172
215
}
173
216
}
217
+
174
218
if fd .legacyFd != nil {
175
219
return fd .legacyFd .GetReceipts (height )
176
220
}
177
- return nil , err
221
+ return nil , ErrNotSupported
178
222
}
179
223
180
224
func (fd * fileDAO ) ContainsTransactionLog () bool {
@@ -183,19 +227,16 @@ func (fd *fileDAO) ContainsTransactionLog() bool {
183
227
}
184
228
185
229
func (fd * fileDAO ) TransactionLogs (height uint64 ) (* iotextypes.TransactionLogs , error ) {
186
- var (
187
- log * iotextypes.TransactionLogs
188
- err error
189
- )
190
- for _ , file := range fd .v2Fd {
191
- if log , err = file .TransactionLogs (height ); err == nil {
192
- return log , nil
230
+ if fd .v2Fd != nil {
231
+ if v2 := fd .v2Fd .FileDAOByHeight (height ); v2 != nil {
232
+ return v2 .TransactionLogs (height )
193
233
}
194
234
}
235
+
195
236
if fd .legacyFd != nil {
196
237
return fd .legacyFd .TransactionLogs (height )
197
238
}
198
- return nil , err
239
+ return nil , ErrNotSupported
199
240
}
200
241
201
242
func (fd * fileDAO ) PutBlock (ctx context.Context , blk * block.Block ) error {
@@ -214,44 +255,38 @@ func (fd *fileDAO) DeleteTipBlock() error {
214
255
}
215
256
216
257
// CreateFileDAO creates FileDAO from legacy and new files
217
- func CreateFileDAO (legacy FileDAO , newFile map [uint64 ]FileDAO ) (FileDAO , error ) {
218
- fileDAO := & fileDAO {
219
- legacyFd : legacy ,
220
- v2Fd : newFile ,
258
+ func CreateFileDAO (legacy FileDAO , v2Files []string , cfg config.DB ) (FileDAO , error ) {
259
+ if legacy == nil && len (v2Files ) == 0 {
260
+ return nil , ErrNotSupported
221
261
}
222
262
223
- var (
224
- tipHeight uint64
225
- currFd FileDAO
226
- )
227
-
228
- // find the file with highest start height
229
- for start , fd := range newFile {
230
- if currFd == nil {
231
- currFd = fd
232
- tipHeight = start
233
- } else {
234
- if start > tipHeight {
235
- currFd = fd
236
- tipHeight = start
237
- }
238
- }
239
- fileDAO .lifecycle .Add (fd )
240
- }
241
- if legacy != nil {
242
- fileDAO .lifecycle .Add (legacy )
243
- if currFd == nil {
244
- currFd = legacy
263
+ var v2Fd FileV2Manager
264
+ if len (v2Files ) > 0 {
265
+ fds := make ([]* fileDAOv2 , len (v2Files ))
266
+ for i , name := range v2Files {
267
+ cfg .DbPath = name
268
+ fds [i ] = openFileDAOv2 (cfg )
245
269
}
270
+ v2Fd = NewFileV2Manager (fds )
246
271
}
247
272
248
- if currFd == nil {
249
- return nil , errors .New ("failed to find valid chain db file" )
250
- }
251
- fileDAO .currFd = currFd
252
- return fileDAO , nil
273
+ return & fileDAO {
274
+ legacyFd : legacy ,
275
+ v2Fd : v2Fd ,
276
+ }, nil
253
277
}
254
278
255
- func hashKey (h hash.Hash256 ) []byte {
256
- return append (hashPrefix , h [:]... )
279
+ // createNewV2File creates a new v2 chain db file
280
+ func createNewV2File (start uint64 , cfg config.DB ) error {
281
+ v2 , err := newFileDAOv2 (start , cfg )
282
+ if err != nil {
283
+ return err
284
+ }
285
+
286
+ // calling Start() will write the header
287
+ ctx := context .Background ()
288
+ if err := v2 .Start (ctx ); err != nil {
289
+ return err
290
+ }
291
+ return v2 .Stop (ctx )
257
292
}
0 commit comments