@@ -36,7 +36,8 @@ var logger = logging.MustGetLogger("statecouchdb")
36
36
37
37
var compositeKeySep = []byte {0x00 }
38
38
var lastKeyIndicator = byte (0x01 )
39
- var savePointKey = []byte {0x00 }
39
+
40
+ var binaryWrapper = "valueBytes"
40
41
41
42
// VersionedDBProvider implements interface VersionedDBProvider
42
43
type VersionedDBProvider struct {
@@ -119,70 +120,71 @@ func (vdb *VersionedDB) GetState(namespace string, key string) (*statedb.Version
119
120
120
121
compositeKey := constructCompositeKey (namespace , key )
121
122
122
- docBytes , _ , err := vdb .db .ReadDoc (string (compositeKey ))
123
+ couchDoc , _ , err := vdb .db .ReadDoc (string (compositeKey ))
123
124
if err != nil {
124
125
return nil , err
125
126
}
126
- if docBytes == nil {
127
+ if couchDoc == nil {
127
128
return nil , nil
128
129
}
129
130
130
131
// trace the first 200 bytes of value only, in case it is huge
131
- if docBytes != nil && logger .IsEnabledFor (logging .DEBUG ) {
132
- if len (docBytes ) < 200 {
133
- logger .Debugf ("getCommittedValueAndVersion() Read docBytes %s" , docBytes )
132
+ if couchDoc . JSONValue != nil && logger .IsEnabledFor (logging .DEBUG ) {
133
+ if len (couchDoc . JSONValue ) < 200 {
134
+ logger .Debugf ("getCommittedValueAndVersion() Read docBytes %s" , couchDoc . JSONValue )
134
135
} else {
135
- logger .Debugf ("getCommittedValueAndVersion() Read docBytes %s..." , docBytes [0 :200 ])
136
+ logger .Debugf ("getCommittedValueAndVersion() Read docBytes %s..." , couchDoc . JSONValue [0 :200 ])
136
137
}
137
138
}
138
139
139
140
//remove the data wrapper and return the value and version
140
- returnValue , returnVersion := removeDataWrapper (docBytes )
141
+ returnValue , returnVersion := removeDataWrapper (couchDoc . JSONValue , couchDoc . Attachments )
141
142
142
143
return & statedb.VersionedValue {Value : returnValue , Version : & returnVersion }, nil
143
144
}
144
145
145
- func removeDataWrapper (wrappedValue []byte ) ([]byte , version.Height ) {
146
+ func removeDataWrapper (wrappedValue []byte , attachments []couchdb. Attachment ) ([]byte , version.Height ) {
146
147
147
148
//initialize the return value
148
- returnValue := []byte {}
149
+ returnValue := []byte {} // TODO: empty byte or nil
149
150
150
151
//initialize a default return version
151
152
returnVersion := version .NewHeight (0 , 0 )
152
153
153
- //if this is a JSON, then remove the data wrapper
154
- if couchdb .IsJSON (string (wrappedValue )) {
155
-
156
- //create a generic map for the json
157
- jsonResult := make (map [string ]interface {})
154
+ //create a generic map for the json
155
+ jsonResult := make (map [string ]interface {})
158
156
159
- //unmarshal the selected json into the generic map
160
- json .Unmarshal (wrappedValue , & jsonResult )
157
+ //unmarshal the selected json into the generic map
158
+ json .Unmarshal (wrappedValue , & jsonResult )
161
159
160
+ // handle binary or json data
161
+ if jsonResult [dataWrapper ] == nil && attachments != nil { // binary attachment
162
+ // get binary data from attachment
163
+ for _ , attachment := range attachments {
164
+ if attachment .Name == binaryWrapper {
165
+ returnValue = attachment .AttachmentBytes
166
+ }
167
+ }
168
+ } else {
162
169
//place the result json in the data key
163
170
returnMap := jsonResult [dataWrapper ]
164
171
165
172
//marshal the mapped data. this wrappers the result in a key named "data"
166
173
returnValue , _ = json .Marshal (returnMap )
167
174
168
- //create an array containing the blockNum and txNum
169
- versionArray := strings .Split (fmt .Sprintf ("%s" , jsonResult ["version" ]), ":" )
170
-
171
- //convert the blockNum from String to unsigned int
172
- blockNum , _ := strconv .ParseUint (versionArray [0 ], 10 , 64 )
175
+ }
173
176
174
- //convert the txNum from String to unsigned int
175
- txNum , _ := strconv . ParseUint ( versionArray [ 1 ], 10 , 64 )
177
+ //create an array containing the blockNum and txNum
178
+ versionArray := strings . Split ( fmt . Sprintf ( "%s" , jsonResult [ "version" ]), ":" )
176
179
177
- //create the version based on the blockNum and txNum
178
- returnVersion = version . NewHeight ( blockNum , txNum )
180
+ //convert the blockNum from String to unsigned int
181
+ blockNum , _ := strconv . ParseUint ( versionArray [ 0 ], 10 , 64 )
179
182
180
- } else {
183
+ //convert the txNum from String to unsigned int
184
+ txNum , _ := strconv .ParseUint (versionArray [1 ], 10 , 64 )
181
185
182
- //this is a binary, so decode the value and version from the binary
183
- returnValue , returnVersion = statedb .DecodeValue (wrappedValue )
184
-
185
- }
186
+ //create the version based on the blockNum and txNum
187
+ returnVersion = version .NewHeight (blockNum , txNum )
186
188
187
189
return returnValue , * returnVersion
188
190
@@ -262,41 +264,34 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
262
264
vdb .db .DeleteDoc (string (compositeKey ), "" )
263
265
264
266
} else {
267
+ couchDoc := & couchdb.CouchDoc {}
265
268
266
269
//Check to see if the value is a valid JSON
267
270
//If this is not a valid JSON, then store as an attachment
268
271
if couchdb .IsJSON (string (vv .Value )) {
269
-
270
- // SaveDoc using couchdb client and use JSON format
271
- rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , addVersionAndChainCodeID (vv .Value , ns , vv .Version ), nil )
272
- if err != nil {
273
- logger .Errorf ("Error during Commit(): %s\n " , err .Error ())
274
- return err
275
- }
276
- if rev != "" {
277
- logger .Debugf ("Saved document revision number: %s\n " , rev )
278
- }
279
-
272
+ // Handle it as json
273
+ couchDoc .JSONValue = addVersionAndChainCodeID (vv .Value , ns , vv .Version )
280
274
} else { // if the data is not JSON, save as binary attachment in Couch
281
-
282
275
//Create an attachment structure and load the bytes
283
276
attachment := & couchdb.Attachment {}
284
- attachment .AttachmentBytes = statedb . EncodeValue ( vv .Value , vv . Version )
277
+ attachment .AttachmentBytes = vv .Value
285
278
attachment .ContentType = "application/octet-stream"
286
- attachment .Name = "valueBytes"
279
+ attachment .Name = binaryWrapper
287
280
288
281
attachments := []couchdb.Attachment {}
289
282
attachments = append (attachments , * attachment )
283
+ couchDoc .Attachments = append (couchDoc .Attachments , * attachment )
284
+ couchDoc .JSONValue = addVersionAndChainCodeID (nil , ns , vv .Version )
285
+ }
290
286
291
- // SaveDoc using couchdb client and use attachment to persist the binary data
292
- rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , addVersionAndChainCodeID (nil , ns , vv .Version ), attachments )
293
- if err != nil {
294
- logger .Errorf ("Error during Commit(): %s\n " , err .Error ())
295
- return err
296
- }
297
- if rev != "" {
298
- logger .Debugf ("Saved document revision number: %s\n " , rev )
299
- }
287
+ // SaveDoc using couchdb client and use attachment to persist the binary data
288
+ rev , err := vdb .db .SaveDoc (string (compositeKey ), "" , couchDoc )
289
+ if err != nil {
290
+ logger .Errorf ("Error during Commit(): %s\n " , err .Error ())
291
+ return err
292
+ }
293
+ if rev != "" {
294
+ logger .Debugf ("Saved document revision number: %s\n " , rev )
300
295
}
301
296
}
302
297
}
@@ -381,7 +376,7 @@ func (vdb *VersionedDB) recordSavepoint(height *version.Height) error {
381
376
}
382
377
383
378
// SaveDoc using couchdb client and use JSON format
384
- _ , err = vdb .db .SaveDoc (savepointDocID , "" , savepointDocJSON , nil )
379
+ _ , err = vdb .db .SaveDoc (savepointDocID , "" , & couchdb. CouchDoc { JSONValue : savepointDocJSON , Attachments : nil } )
385
380
if err != nil {
386
381
logger .Errorf ("Failed to save the savepoint to DB %s\n " , err .Error ())
387
382
return err
@@ -400,19 +395,19 @@ func (vdb *VersionedDB) recordSavepoint(height *version.Height) error {
400
395
func (vdb * VersionedDB ) GetLatestSavePoint () (* version.Height , error ) {
401
396
402
397
var err error
403
- savepointJSON , _ , err := vdb .db .ReadDoc (savepointDocID )
398
+ couchDoc , _ , err := vdb .db .ReadDoc (savepointDocID )
404
399
if err != nil {
405
400
logger .Errorf ("Failed to read savepoint data %s\n " , err .Error ())
406
401
return & version.Height {BlockNum : 0 , TxNum : 0 }, err
407
402
}
408
403
409
404
// ReadDoc() not found (404) will result in nil response, in these cases return height 0
410
- if savepointJSON == nil {
405
+ if couchDoc . JSONValue == nil {
411
406
return & version.Height {BlockNum : 0 , TxNum : 0 }, nil
412
407
}
413
408
414
409
savepointDoc := & couchSavepointData {}
415
- err = json .Unmarshal (savepointJSON , & savepointDoc )
410
+ err = json .Unmarshal (couchDoc . JSONValue , & savepointDoc )
416
411
if err != nil {
417
412
logger .Errorf ("Failed to unmarshal savepoint data %s\n " , err .Error ())
418
413
return & version.Height {BlockNum : 0 , TxNum : 0 }, err
@@ -456,7 +451,7 @@ func (scanner *kvScanner) Next() (statedb.QueryResult, error) {
456
451
_ , key := splitCompositeKey ([]byte (selectedKV .ID ))
457
452
458
453
//remove the data wrapper and return the value and version
459
- returnValue , returnVersion := removeDataWrapper (selectedKV .Value )
454
+ returnValue , returnVersion := removeDataWrapper (selectedKV .Value , selectedKV . Attachments )
460
455
461
456
return & statedb.VersionedKV {
462
457
CompositeKey : statedb.CompositeKey {Namespace : scanner .namespace , Key : key },
@@ -489,7 +484,7 @@ func (scanner *queryScanner) Next() (statedb.QueryResult, error) {
489
484
namespace , key := splitCompositeKey ([]byte (selectedResultRecord .ID ))
490
485
491
486
//remove the data wrapper and return the value and version
492
- returnValue , returnVersion := removeDataWrapper (selectedResultRecord .Value )
487
+ returnValue , returnVersion := removeDataWrapper (selectedResultRecord .Value , selectedResultRecord . Attachments )
493
488
494
489
return & statedb.VersionedQueryRecord {
495
490
Namespace : namespace ,
0 commit comments