Skip to content

Commit b266c7b

Browse files
committed
FAB-2228: CouchDB docs to have consistent header
Similar to Couch JSON documents, the version information is now stored in header elements of the JSON record. The ReadDoc and SaveDoc methods operate on CouchDoc type which encapsulates the JSON and binary data. Change-Id: I4343161a27fa39a79788063a2b37570046bb782b Signed-off-by: Balaji Viswanathan <[email protected]>
1 parent f590121 commit b266c7b

File tree

3 files changed

+196
-167
lines changed

3 files changed

+196
-167
lines changed

core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go

100644100755
+55-60
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ var logger = logging.MustGetLogger("statecouchdb")
3636

3737
var compositeKeySep = []byte{0x00}
3838
var lastKeyIndicator = byte(0x01)
39-
var savePointKey = []byte{0x00}
39+
40+
var binaryWrapper = "valueBytes"
4041

4142
// VersionedDBProvider implements interface VersionedDBProvider
4243
type VersionedDBProvider struct {
@@ -119,70 +120,71 @@ func (vdb *VersionedDB) GetState(namespace string, key string) (*statedb.Version
119120

120121
compositeKey := constructCompositeKey(namespace, key)
121122

122-
docBytes, _, err := vdb.db.ReadDoc(string(compositeKey))
123+
couchDoc, _, err := vdb.db.ReadDoc(string(compositeKey))
123124
if err != nil {
124125
return nil, err
125126
}
126-
if docBytes == nil {
127+
if couchDoc == nil {
127128
return nil, nil
128129
}
129130

130131
// 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)
134135
} else {
135-
logger.Debugf("getCommittedValueAndVersion() Read docBytes %s...", docBytes[0:200])
136+
logger.Debugf("getCommittedValueAndVersion() Read docBytes %s...", couchDoc.JSONValue[0:200])
136137
}
137138
}
138139

139140
//remove the data wrapper and return the value and version
140-
returnValue, returnVersion := removeDataWrapper(docBytes)
141+
returnValue, returnVersion := removeDataWrapper(couchDoc.JSONValue, couchDoc.Attachments)
141142

142143
return &statedb.VersionedValue{Value: returnValue, Version: &returnVersion}, nil
143144
}
144145

145-
func removeDataWrapper(wrappedValue []byte) ([]byte, version.Height) {
146+
func removeDataWrapper(wrappedValue []byte, attachments []couchdb.Attachment) ([]byte, version.Height) {
146147

147148
//initialize the return value
148-
returnValue := []byte{}
149+
returnValue := []byte{} // TODO: empty byte or nil
149150

150151
//initialize a default return version
151152
returnVersion := version.NewHeight(0, 0)
152153

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{})
158156

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)
161159

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 {
162169
//place the result json in the data key
163170
returnMap := jsonResult[dataWrapper]
164171

165172
//marshal the mapped data. this wrappers the result in a key named "data"
166173
returnValue, _ = json.Marshal(returnMap)
167174

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+
}
173176

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"]), ":")
176179

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)
179182

180-
} else {
183+
//convert the txNum from String to unsigned int
184+
txNum, _ := strconv.ParseUint(versionArray[1], 10, 64)
181185

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)
186188

187189
return returnValue, *returnVersion
188190

@@ -262,41 +264,34 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
262264
vdb.db.DeleteDoc(string(compositeKey), "")
263265

264266
} else {
267+
couchDoc := &couchdb.CouchDoc{}
265268

266269
//Check to see if the value is a valid JSON
267270
//If this is not a valid JSON, then store as an attachment
268271
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)
280274
} else { // if the data is not JSON, save as binary attachment in Couch
281-
282275
//Create an attachment structure and load the bytes
283276
attachment := &couchdb.Attachment{}
284-
attachment.AttachmentBytes = statedb.EncodeValue(vv.Value, vv.Version)
277+
attachment.AttachmentBytes = vv.Value
285278
attachment.ContentType = "application/octet-stream"
286-
attachment.Name = "valueBytes"
279+
attachment.Name = binaryWrapper
287280

288281
attachments := []couchdb.Attachment{}
289282
attachments = append(attachments, *attachment)
283+
couchDoc.Attachments = append(couchDoc.Attachments, *attachment)
284+
couchDoc.JSONValue = addVersionAndChainCodeID(nil, ns, vv.Version)
285+
}
290286

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)
300295
}
301296
}
302297
}
@@ -381,7 +376,7 @@ func (vdb *VersionedDB) recordSavepoint(height *version.Height) error {
381376
}
382377

383378
// 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})
385380
if err != nil {
386381
logger.Errorf("Failed to save the savepoint to DB %s\n", err.Error())
387382
return err
@@ -400,19 +395,19 @@ func (vdb *VersionedDB) recordSavepoint(height *version.Height) error {
400395
func (vdb *VersionedDB) GetLatestSavePoint() (*version.Height, error) {
401396

402397
var err error
403-
savepointJSON, _, err := vdb.db.ReadDoc(savepointDocID)
398+
couchDoc, _, err := vdb.db.ReadDoc(savepointDocID)
404399
if err != nil {
405400
logger.Errorf("Failed to read savepoint data %s\n", err.Error())
406401
return &version.Height{BlockNum: 0, TxNum: 0}, err
407402
}
408403

409404
// ReadDoc() not found (404) will result in nil response, in these cases return height 0
410-
if savepointJSON == nil {
405+
if couchDoc.JSONValue == nil {
411406
return &version.Height{BlockNum: 0, TxNum: 0}, nil
412407
}
413408

414409
savepointDoc := &couchSavepointData{}
415-
err = json.Unmarshal(savepointJSON, &savepointDoc)
410+
err = json.Unmarshal(couchDoc.JSONValue, &savepointDoc)
416411
if err != nil {
417412
logger.Errorf("Failed to unmarshal savepoint data %s\n", err.Error())
418413
return &version.Height{BlockNum: 0, TxNum: 0}, err
@@ -456,7 +451,7 @@ func (scanner *kvScanner) Next() (statedb.QueryResult, error) {
456451
_, key := splitCompositeKey([]byte(selectedKV.ID))
457452

458453
//remove the data wrapper and return the value and version
459-
returnValue, returnVersion := removeDataWrapper(selectedKV.Value)
454+
returnValue, returnVersion := removeDataWrapper(selectedKV.Value, selectedKV.Attachments)
460455

461456
return &statedb.VersionedKV{
462457
CompositeKey: statedb.CompositeKey{Namespace: scanner.namespace, Key: key},
@@ -489,7 +484,7 @@ func (scanner *queryScanner) Next() (statedb.QueryResult, error) {
489484
namespace, key := splitCompositeKey([]byte(selectedResultRecord.ID))
490485

491486
//remove the data wrapper and return the value and version
492-
returnValue, returnVersion := removeDataWrapper(selectedResultRecord.Value)
487+
returnValue, returnVersion := removeDataWrapper(selectedResultRecord.Value, selectedResultRecord.Attachments)
493488

494489
return &statedb.VersionedQueryRecord{
495490
Namespace: namespace,

0 commit comments

Comments
 (0)