// SeekInfo specifies the range of requested blocks to return // If the start position is not found, an error is immediately returned // Otherwise, blocks are returned until a missing block is encountered, then behavior is dictated by the SeekBehavior specified. // If BLOCK_UNTIL_READY is specified, the reply will block until the requested blocks are available // if FAIL_IF_NOT_READY is specified, the reply will return an error indicating that the block is not found. // To request that all blocks be returned indefinitely as they are created, behavior should be set to BLOCK_UNTIL_READY and the stop should be set to specified with a number of MAX_UINT64 type SeekInfo struct { Start *SeekPosition Stop *SeekPosition Behavior SeekInfo_SeekBehavior }
// 根据seekInfo.Stop计算range的终止block number cursor, number := chain.Reader().Iterator(seekInfo.Start) defer cursor.Close() switch stop := seekInfo.Stop.Type.(type) { case *ab.SeekPosition_Oldest: stopNum = number case *ab.SeekPosition_Newest: stopNum = chain.Reader().Height() - 1 case *ab.SeekPosition_Specified: stopNum = stop.Specified.Number }
for { // 如果range超越当前到chain高度,fail fast if seekInfo.Behavior == ab.SeekInfo_FAIL_IF_NOT_READY { if number > chain.Reader().Height()-1 { return srv.SendStatusResponse(cb.Status_NOT_FOUND) } }
select { case <-ctx.Done(): // "context finished before block retrieved" return errors.Wrapf(ctx.Err(), "context finished before block retrieved") case <-erroredChan: // "Aborting deliver for request because of background error" return srv.SendStatusResponse(cb.Status_SERVICE_UNAVAILABLE) case <-iterCh: // Iterator has set the block and status vars,完成读取 }
// increment block number to support FAIL_IF_NOT_READY deliver behavior number++
// 再次通过权限校验 access control if err := accessControl.Evaluate(); err != nil { return srv.SendStatusResponse(cb.Status_FORBIDDEN) }
// Next blocks until there is a new block available, or until Close is called. // It returns an error if the next block is no longer retrievable. func(i *fileLedgerIterator)Next()(*cb.Block, cb.Status) { // 使用标准包sync.cond result, err := i.commonIterator.Next() if err != nil { logger.Error(err) returnnil, cb.Status_SERVICE_UNAVAILABLE } // Cover the case where another thread calls Close on the iterator. if result == nil { returnnil, cb.Status_SERVICE_UNAVAILABLE } return result.(*cb.Block), cb.Status_SUCCESS }