github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/txmgr/query_executor.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package txmgr 8 9 import ( 10 commonledger "github.com/hechain20/hechain/common/ledger" 11 "github.com/hechain20/hechain/core/ledger" 12 "github.com/hechain20/hechain/core/ledger/internal/version" 13 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 14 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb" 15 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statemetadata" 16 "github.com/hechain20/hechain/core/ledger/util" 17 "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 18 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 19 "github.com/pkg/errors" 20 ) 21 22 const ( 23 queryReadsHashingEnabled = true 24 maxDegreeQueryReadsHashing = uint32(50) 25 ) 26 27 // queryExecutor is a query executor used in `LockBasedTxMgr` 28 type queryExecutor struct { 29 txmgr *LockBasedTxMgr 30 collNameValidator *collNameValidator 31 collectReadset bool 32 rwsetBuilder *rwsetutil.RWSetBuilder 33 itrs []*resultsItr 34 err error 35 doneInvoked bool 36 hasher rwsetutil.HashFunc 37 txid string 38 privateReads *ledger.PrivateReads 39 } 40 41 func newQueryExecutor(txmgr *LockBasedTxMgr, 42 txid string, 43 rwsetBuilder *rwsetutil.RWSetBuilder, 44 performCollCheck bool, 45 hashFunc rwsetutil.HashFunc) *queryExecutor { 46 logger.Debugf("constructing new query executor txid = [%s]", txid) 47 qe := &queryExecutor{} 48 qe.txid = txid 49 qe.txmgr = txmgr 50 if rwsetBuilder != nil { 51 qe.collectReadset = true 52 qe.rwsetBuilder = rwsetBuilder 53 } 54 qe.hasher = hashFunc 55 validator := newCollNameValidator(txmgr.ledgerid, txmgr.ccInfoProvider, qe, !performCollCheck) 56 qe.collNameValidator = validator 57 qe.privateReads = &ledger.PrivateReads{} 58 return qe 59 } 60 61 // GetState implements method in interface `ledger.QueryExecutor` 62 func (q *queryExecutor) GetState(ns, key string) ([]byte, error) { 63 val, _, err := q.getState(ns, key) 64 return val, err 65 } 66 67 func (q *queryExecutor) getState(ns, key string) ([]byte, []byte, error) { 68 if err := q.checkDone(); err != nil { 69 return nil, nil, err 70 } 71 versionedValue, err := q.txmgr.db.GetState(ns, key) 72 if err != nil { 73 return nil, nil, err 74 } 75 val, metadata, ver := decomposeVersionedValue(versionedValue) 76 if q.collectReadset { 77 q.rwsetBuilder.AddToReadSet(ns, key, ver) 78 } 79 return val, metadata, nil 80 } 81 82 // GetStateMetadata implements method in interface `ledger.QueryExecutor` 83 func (q *queryExecutor) GetStateMetadata(ns, key string) (map[string][]byte, error) { 84 if err := q.checkDone(); err != nil { 85 return nil, err 86 } 87 var metadata []byte 88 var err error 89 if !q.collectReadset { 90 if metadata, err = q.txmgr.db.GetStateMetadata(ns, key); err != nil { 91 return nil, err 92 } 93 } else { 94 if _, metadata, err = q.getState(ns, key); err != nil { 95 return nil, err 96 } 97 } 98 return statemetadata.Deserialize(metadata) 99 } 100 101 // GetStateMultipleKeys implements method in interface `ledger.QueryExecutor` 102 func (q *queryExecutor) GetStateMultipleKeys(ns string, keys []string) ([][]byte, error) { 103 if err := q.checkDone(); err != nil { 104 return nil, err 105 } 106 versionedValues, err := q.txmgr.db.GetStateMultipleKeys(ns, keys) 107 if err != nil { 108 return nil, nil 109 } 110 values := make([][]byte, len(versionedValues)) 111 for i, versionedValue := range versionedValues { 112 val, _, ver := decomposeVersionedValue(versionedValue) 113 if q.collectReadset { 114 q.rwsetBuilder.AddToReadSet(ns, keys[i], ver) 115 } 116 values[i] = val 117 } 118 return values, nil 119 } 120 121 // GetStateRangeScanIterator implements method in interface `ledger.QueryExecutor` 122 // startKey is included in the results and endKey is excluded. An empty startKey refers to the first available key 123 // and an empty endKey refers to the last available key. For scanning all the keys, both the startKey and the endKey 124 // can be supplied as empty strings. However, a full scan should be used judiciously for performance reasons. 125 func (q *queryExecutor) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (commonledger.ResultsIterator, error) { 126 if err := q.checkDone(); err != nil { 127 return nil, err 128 } 129 itr, err := newResultsItr( 130 namespace, 131 startKey, 132 endKey, 133 0, 134 q.txmgr.db, 135 q.rwsetBuilder, 136 queryReadsHashingEnabled, 137 maxDegreeQueryReadsHashing, 138 q.hasher, 139 ) 140 if err != nil { 141 return nil, err 142 } 143 q.itrs = append(q.itrs, itr) 144 return itr, nil 145 } 146 147 func (q *queryExecutor) GetStateRangeScanIteratorWithPagination(namespace string, startKey string, endKey string, pageSize int32) (ledger.QueryResultsIterator, error) { 148 if err := q.checkDone(); err != nil { 149 return nil, err 150 } 151 itr, err := newResultsItr( 152 namespace, 153 startKey, 154 endKey, 155 pageSize, 156 q.txmgr.db, 157 q.rwsetBuilder, 158 queryReadsHashingEnabled, 159 maxDegreeQueryReadsHashing, 160 q.hasher, 161 ) 162 if err != nil { 163 return nil, err 164 } 165 q.itrs = append(q.itrs, itr) 166 return itr, nil 167 } 168 169 // ExecuteQuery implements method in interface `ledger.QueryExecutor` 170 func (q *queryExecutor) ExecuteQuery(namespace, query string) (commonledger.ResultsIterator, error) { 171 if err := q.checkDone(); err != nil { 172 return nil, err 173 } 174 dbItr, err := q.txmgr.db.ExecuteQuery(namespace, query) 175 if err != nil { 176 return nil, err 177 } 178 return &queryResultsItr{DBItr: dbItr, RWSetBuilder: q.rwsetBuilder}, nil 179 } 180 181 func (q *queryExecutor) ExecuteQueryWithPagination(namespace, query, bookmark string, pageSize int32) (ledger.QueryResultsIterator, error) { 182 if err := q.checkDone(); err != nil { 183 return nil, err 184 } 185 dbItr, err := q.txmgr.db.ExecuteQueryWithPagination(namespace, query, bookmark, pageSize) 186 if err != nil { 187 return nil, err 188 } 189 return &queryResultsItr{DBItr: dbItr, RWSetBuilder: q.rwsetBuilder}, nil 190 } 191 192 // GetPrivateData implements method in interface `ledger.QueryExecutor` 193 func (q *queryExecutor) GetPrivateData(ns, coll, key string) ([]byte, error) { 194 if err := q.validateCollName(ns, coll); err != nil { 195 return nil, err 196 } 197 if err := q.checkDone(); err != nil { 198 return nil, err 199 } 200 201 var err error 202 var hashVersion *version.Height 203 var versionedValue *statedb.VersionedValue 204 205 if versionedValue, err = q.txmgr.db.GetPrivateData(ns, coll, key); err != nil { 206 return nil, err 207 } 208 209 // metadata is always nil for private data - because, the metadata is part of the hashed key (instead of raw key) 210 val, _, ver := decomposeVersionedValue(versionedValue) 211 212 keyHash := util.ComputeStringHash(key) 213 if hashVersion, err = q.txmgr.db.GetKeyHashVersion(ns, coll, keyHash); err != nil { 214 return nil, err 215 } 216 if !version.AreSame(hashVersion, ver) { 217 return nil, errors.Errorf( 218 "private data matching public hash version is not available. Public hash version = %s, Private data version = %s", 219 hashVersion, ver, 220 ) 221 } 222 if q.collectReadset { 223 q.rwsetBuilder.AddToHashedReadSet(ns, coll, key, ver) 224 q.privateReads.Add(ns, coll) 225 } 226 return val, nil 227 } 228 229 func (q *queryExecutor) GetPrivateDataHash(ns, coll, key string) ([]byte, error) { 230 if err := q.validateCollName(ns, coll); err != nil { 231 return nil, err 232 } 233 if err := q.checkDone(); err != nil { 234 return nil, err 235 } 236 var versionedValue *statedb.VersionedValue 237 var err error 238 if versionedValue, err = q.txmgr.db.GetPrivateDataHash(ns, coll, key); err != nil { 239 return nil, err 240 } 241 valHash, _, ver := decomposeVersionedValue(versionedValue) 242 if q.collectReadset { 243 q.rwsetBuilder.AddToHashedReadSet(ns, coll, key, ver) 244 } 245 return valHash, nil 246 } 247 248 // GetPrivateDataMetadata implements method in interface `ledger.QueryExecutor` 249 func (q *queryExecutor) GetPrivateDataMetadata(ns, coll, key string) (map[string][]byte, error) { 250 if !q.collectReadset { 251 // reads versions are not getting recorded, retrieve metadata value via optimized path 252 return q.getPrivateDataMetadataByHash(ns, coll, util.ComputeStringHash(key)) 253 } 254 if err := q.validateCollName(ns, coll); err != nil { 255 return nil, err 256 } 257 if err := q.checkDone(); err != nil { 258 return nil, err 259 } 260 _, metadataBytes, err := q.getPrivateDataValueHash(ns, coll, key) 261 if err != nil { 262 return nil, err 263 } 264 return statemetadata.Deserialize(metadataBytes) 265 } 266 267 func (q *queryExecutor) getPrivateDataValueHash(ns, coll, key string) (valueHash, metadataBytes []byte, err error) { 268 if err := q.validateCollName(ns, coll); err != nil { 269 return nil, nil, err 270 } 271 if err := q.checkDone(); err != nil { 272 return nil, nil, err 273 } 274 var versionedValue *statedb.VersionedValue 275 if versionedValue, err = q.txmgr.db.GetPrivateDataHash(ns, coll, key); err != nil { 276 return nil, nil, err 277 } 278 valHash, metadata, ver := decomposeVersionedValue(versionedValue) 279 if q.collectReadset { 280 q.rwsetBuilder.AddToHashedReadSet(ns, coll, key, ver) 281 } 282 return valHash, metadata, nil 283 } 284 285 // GetPrivateDataMetadataByHash implements method in interface `ledger.QueryExecutor` 286 func (q *queryExecutor) GetPrivateDataMetadataByHash(ns, coll string, keyhash []byte) (map[string][]byte, error) { 287 return q.getPrivateDataMetadataByHash(ns, coll, keyhash) 288 } 289 290 func (q *queryExecutor) getPrivateDataMetadataByHash(ns, coll string, keyhash []byte) (map[string][]byte, error) { 291 if err := q.validateCollName(ns, coll); err != nil { 292 return nil, err 293 } 294 if err := q.checkDone(); err != nil { 295 return nil, err 296 } 297 if q.collectReadset { 298 // this requires to improve rwset builder to accept a keyhash 299 return nil, errors.New("retrieving private data metadata by keyhash is not supported in simulation. This function is only available for query as yet") 300 } 301 metadataBytes, err := q.txmgr.db.GetPrivateDataMetadataByHash(ns, coll, keyhash) 302 if err != nil { 303 return nil, err 304 } 305 return statemetadata.Deserialize(metadataBytes) 306 } 307 308 // GetPrivateDataMultipleKeys implements method in interface `ledger.QueryExecutor` 309 func (q *queryExecutor) GetPrivateDataMultipleKeys(ns, coll string, keys []string) ([][]byte, error) { 310 if err := q.validateCollName(ns, coll); err != nil { 311 return nil, err 312 } 313 if err := q.checkDone(); err != nil { 314 return nil, err 315 } 316 versionedValues, err := q.txmgr.db.GetPrivateDataMultipleKeys(ns, coll, keys) 317 if err != nil { 318 return nil, nil 319 } 320 values := make([][]byte, len(versionedValues)) 321 for i, versionedValue := range versionedValues { 322 val, _, ver := decomposeVersionedValue(versionedValue) 323 if q.collectReadset { 324 q.rwsetBuilder.AddToHashedReadSet(ns, coll, keys[i], ver) 325 q.privateReads.Add(ns, coll) 326 } 327 values[i] = val 328 } 329 return values, nil 330 } 331 332 // GetPrivateDataRangeScanIterator implements method in interface `ledger.QueryExecutor` 333 func (q *queryExecutor) GetPrivateDataRangeScanIterator(ns, coll, startKey, endKey string) (commonledger.ResultsIterator, error) { 334 if err := q.validateCollName(ns, coll); err != nil { 335 return nil, err 336 } 337 if err := q.checkDone(); err != nil { 338 return nil, err 339 } 340 dbItr, err := q.txmgr.db.GetPrivateDataRangeScanIterator(ns, coll, startKey, endKey) 341 if err != nil { 342 return nil, err 343 } 344 return &pvtdataResultsItr{ns, coll, dbItr}, nil 345 } 346 347 // ExecuteQueryOnPrivateData implements method in interface `ledger.QueryExecutor` 348 func (q *queryExecutor) ExecuteQueryOnPrivateData(ns, coll, query string) (commonledger.ResultsIterator, error) { 349 if err := q.validateCollName(ns, coll); err != nil { 350 return nil, err 351 } 352 if err := q.checkDone(); err != nil { 353 return nil, err 354 } 355 dbItr, err := q.txmgr.db.ExecuteQueryOnPrivateData(ns, coll, query) 356 if err != nil { 357 return nil, err 358 } 359 return &pvtdataResultsItr{ns, coll, dbItr}, nil 360 } 361 362 // Done implements method in interface `ledger.QueryExecutor` 363 func (q *queryExecutor) Done() { 364 logger.Debugf("Done with transaction simulation / query execution [%s]", q.txid) 365 if q.doneInvoked { 366 return 367 } 368 369 defer func() { 370 q.txmgr.commitRWLock.RUnlock() 371 q.doneInvoked = true 372 for _, itr := range q.itrs { 373 itr.Close() 374 } 375 }() 376 } 377 378 func (q *queryExecutor) checkDone() error { 379 if q.doneInvoked { 380 return errors.New("this instance should not be used after calling Done()") 381 } 382 return nil 383 } 384 385 func (q *queryExecutor) validateCollName(ns, coll string) error { 386 return q.collNameValidator.validateCollName(ns, coll) 387 } 388 389 // resultsItr implements interface ledger.ResultsIterator 390 // this wraps the actual db iterator and intercept the calls 391 // to build rangeQueryInfo in the ReadWriteSet that is used 392 // for performing phantom read validation during commit 393 type resultsItr struct { 394 ns string 395 endKey string 396 dbItr statedb.ResultsIterator 397 rwSetBuilder *rwsetutil.RWSetBuilder 398 rangeQueryInfo *kvrwset.RangeQueryInfo 399 rangeQueryResultsHelper *rwsetutil.RangeQueryResultsHelper 400 } 401 402 func newResultsItr(ns string, startKey string, endKey string, pageSize int32, 403 db statedb.VersionedDB, rwsetBuilder *rwsetutil.RWSetBuilder, enableHashing bool, 404 maxDegree uint32, hashFunc rwsetutil.HashFunc) (*resultsItr, error) { 405 var err error 406 var dbItr statedb.ResultsIterator 407 if pageSize == 0 { 408 dbItr, err = db.GetStateRangeScanIterator(ns, startKey, endKey) 409 } else { 410 dbItr, err = db.GetStateRangeScanIteratorWithPagination(ns, startKey, endKey, pageSize) 411 } 412 if err != nil { 413 return nil, err 414 } 415 itr := &resultsItr{ns: ns, dbItr: dbItr} 416 // it's a simulation request so, enable capture of range query info 417 if rwsetBuilder != nil { 418 itr.rwSetBuilder = rwsetBuilder 419 itr.endKey = endKey 420 // just set the StartKey... set the EndKey later below in the Next() method. 421 itr.rangeQueryInfo = &kvrwset.RangeQueryInfo{StartKey: startKey} 422 resultsHelper, err := rwsetutil.NewRangeQueryResultsHelper(enableHashing, maxDegree, hashFunc) 423 if err != nil { 424 return nil, err 425 } 426 itr.rangeQueryResultsHelper = resultsHelper 427 } 428 return itr, nil 429 } 430 431 // Next implements method in interface ledger.ResultsIterator 432 // Before returning the next result, update the EndKey and ItrExhausted in rangeQueryInfo 433 // If we set the EndKey in the constructor (as we do for the StartKey) to what is 434 // supplied in the original query, we may be capturing the unnecessary longer range if the 435 // caller decides to stop iterating at some intermediate point. Alternatively, we could have 436 // set the EndKey and ItrExhausted in the Close() function but it may not be desirable to change 437 // transactional behaviour based on whether the Close() was invoked or not 438 func (itr *resultsItr) Next() (commonledger.QueryResult, error) { 439 queryResult, err := itr.dbItr.Next() 440 if err != nil { 441 return nil, err 442 } 443 if err := itr.updateRangeQueryInfo(queryResult); err != nil { 444 return nil, err 445 } 446 if queryResult == nil { 447 return nil, nil 448 } 449 450 return &queryresult.KV{ 451 Namespace: queryResult.Namespace, 452 Key: queryResult.Key, 453 Value: queryResult.Value, 454 }, nil 455 } 456 457 // GetBookmarkAndClose implements method in interface ledger.ResultsIterator 458 func (itr *resultsItr) GetBookmarkAndClose() string { 459 returnBookmark := "" 460 if queryResultIterator, ok := itr.dbItr.(statedb.QueryResultsIterator); ok { 461 returnBookmark = queryResultIterator.GetBookmarkAndClose() 462 } 463 return returnBookmark 464 } 465 466 // updateRangeQueryInfo updates two attributes of the rangeQueryInfo 467 // 1) The EndKey - set to either a) latest key that is to be returned to the caller (if the iterator is not exhausted) 468 // because, we do not know if the caller is again going to invoke Next() or not. 469 // or b) the last key that was supplied in the original query (if the iterator is exhausted) 470 // 2) The ItrExhausted - set to true if the iterator is going to return nil as a result of the Next() call 471 func (itr *resultsItr) updateRangeQueryInfo(queryResult *statedb.VersionedKV) error { 472 if itr.rwSetBuilder == nil { 473 return nil 474 } 475 476 if queryResult == nil { 477 // caller scanned till the iterator got exhausted. 478 // So, set the endKey to the actual endKey supplied in the query 479 itr.rangeQueryInfo.ItrExhausted = true 480 itr.rangeQueryInfo.EndKey = itr.endKey 481 return nil 482 } 483 484 if err := itr.rangeQueryResultsHelper.AddResult(rwsetutil.NewKVRead(queryResult.Key, queryResult.Version)); err != nil { 485 return err 486 } 487 // Set the end key to the latest key retrieved by the caller. 488 // Because, the caller may actually not invoke the Next() function again 489 itr.rangeQueryInfo.EndKey = queryResult.Key 490 return nil 491 } 492 493 // Close implements method in interface ledger.ResultsIterator 494 func (itr *resultsItr) Close() { 495 itr.dbItr.Close() 496 } 497 498 type queryResultsItr struct { 499 DBItr statedb.ResultsIterator 500 RWSetBuilder *rwsetutil.RWSetBuilder 501 } 502 503 // Next implements method in interface ledger.ResultsIterator 504 func (itr *queryResultsItr) Next() (commonledger.QueryResult, error) { 505 queryResult, err := itr.DBItr.Next() 506 if err != nil { 507 return nil, err 508 } 509 if queryResult == nil { 510 return nil, nil 511 } 512 logger.Debugf("queryResultsItr.Next() returned a record:%s", string(queryResult.Value)) 513 514 if itr.RWSetBuilder != nil { 515 itr.RWSetBuilder.AddToReadSet(queryResult.Namespace, queryResult.Key, queryResult.Version) 516 } 517 return &queryresult.KV{ 518 Namespace: queryResult.Namespace, 519 Key: queryResult.Key, 520 Value: queryResult.Value, 521 }, nil 522 } 523 524 // Close implements method in interface ledger.ResultsIterator 525 func (itr *queryResultsItr) Close() { 526 itr.DBItr.Close() 527 } 528 529 func (itr *queryResultsItr) GetBookmarkAndClose() string { 530 returnBookmark := "" 531 if queryResultIterator, ok := itr.DBItr.(statedb.QueryResultsIterator); ok { 532 returnBookmark = queryResultIterator.GetBookmarkAndClose() 533 } 534 return returnBookmark 535 } 536 537 func decomposeVersionedValue(versionedValue *statedb.VersionedValue) ([]byte, []byte, *version.Height) { 538 var value []byte 539 var metadata []byte 540 var ver *version.Height 541 if versionedValue != nil { 542 value = versionedValue.Value 543 ver = versionedValue.Version 544 metadata = versionedValue.Metadata 545 } 546 return value, metadata, ver 547 } 548 549 // pvtdataResultsItr iterates over results of a query on pvt data 550 type pvtdataResultsItr struct { 551 ns string 552 coll string 553 dbItr statedb.ResultsIterator 554 } 555 556 // Next implements method in interface ledger.ResultsIterator 557 func (itr *pvtdataResultsItr) Next() (commonledger.QueryResult, error) { 558 queryResult, err := itr.dbItr.Next() 559 if err != nil { 560 return nil, err 561 } 562 if queryResult == nil { 563 return nil, nil 564 } 565 return &queryresult.KV{ 566 Namespace: itr.ns, 567 Key: queryResult.Key, 568 Value: queryResult.Value, 569 }, nil 570 } 571 572 // Close implements method in interface ledger.ResultsIterator 573 func (itr *pvtdataResultsItr) Close() { 574 itr.dbItr.Close() 575 } 576 577 func (q *queryExecutor) addRangeQueryInfo() { 578 if !q.collectReadset { 579 return 580 } 581 for _, itr := range q.itrs { 582 results, hash, err := itr.rangeQueryResultsHelper.Done() 583 if err != nil { 584 q.err = err 585 return 586 } 587 if results != nil { 588 rwsetutil.SetRawReads(itr.rangeQueryInfo, results) 589 } 590 if hash != nil { 591 rwsetutil.SetMerkelSummary(itr.rangeQueryInfo, hash) 592 } 593 q.rwsetBuilder.AddToRangeQuerySet(itr.ns, itr.rangeQueryInfo) 594 } 595 }