code: @Override
      public Iterator<MultiTableScanResult> multiTableScan(final MultiTableScanOptions query, final TableSet tables,
                                                           final LimitCounter limit, final ReadConsistency consistency, @Nullable Instant cutoffTime) {
          checkNotNull(query, "query");
          String placementName = checkNotNull(query.getPlacement(), "placement");
          final DeltaPlacement placement = (DeltaPlacement) _placementCache.get(placementName);
  
          ScanRange scanRange = Objects.firstNonNull(query.getScanRange(), ScanRange.all());
  
          // Since the range may wrap from high to low end of the token range we need to unwrap it
          List<ScanRange> ranges = scanRange.unwrapped();
  
          return touch(FluentIterable.from(ranges)
                  .transformAndConcat(new Function<ScanRange, Iterable<MultiTableScanResult>>() {
                      @Override
                      public Iterable<MultiTableScanResult> apply(final ScanRange rowRange) {
                          return new Iterable<MultiTableScanResult>() {
                              @Override
                              public Iterator<MultiTableScanResult> iterator() {
                                  return scanMultiTableRows(
                                          tables, placement, rowRange.asByteBufferRange(), limit, query.isIncludeDeletedTables(),
                                          query.isIncludeMirrorTables(), _maxColumnsRange.getLimit(), consistency, cutoffTime);
                              }
                          };
                      }
                  })
                  .iterator());
  
      }
docs: Queries for records across multiple tables.  Data is returned in order by by shard then table.  If the caller
  wants to get all rows for a table he will need to stitch the data together.