private Void readColumnFamily(Table table, ColumnFamilyDescriptor column) {
      byte[] startKey = null;
      Scan scan = null;
      ResultScanner rs = null;
      StopWatch stopWatch = new StopWatch();
      startKey = region.getStartKey();
      // Can't do a get on empty start row so do a Scan of first element if any instead.
      if (startKey.length > 0) {
        Get get = new Get(startKey);
        get.setCacheBlocks(false);
        get.setFilter(new FirstKeyOnlyFilter());
        get.addFamily(column.getName());
        // Converting get object to scan to enable RAW SCAN.
        // This will work for all the regions of the HBase tables except first region of the table.
        scan = new Scan(get);
        scan.setRaw(rawScanEnabled);
      } else {
        scan = new Scan();
        // In case of first region of the HBase Table, we do not have start-key for the region.
        // For Region Canary, we only need to scan a single row/cell in the region to make sure that
        // region is accessible.
        //
        // When HBase table has more than 1 empty regions at start of the row-key space, Canary will
        // create multiple scan object to find first available row in the table by scanning all the
        // regions in sequence until it can find first available row.
        //
        // This could result in multiple millions of scans based on the size of table and number of
        // empty regions in sequence. In test environment, A table with no data and 1100 empty
        // regions, Single canary run was creating close to half million to 1 million scans to
        // successfully do canary run for the table.
        //
        // Since First region of the table doesn't have any start key, We should set End Key as
        // stop row and set inclusive=false to limit scan to single region only.
        //
        // TODO : In future, we can streamline Canary behaviour for all the regions by doing scan
        // with startRow inclusive and stopRow exclusive instead of different behaviour for First
        // Region of the table and rest of the region of the table. This way implementation is
        // simplified. As of now this change has been kept minimal to avoid any unnecessary
        // perf impact.
        scan.withStopRow(region.getEndKey(), false);
        LOG.debug("rawScan {} for {}", rawScanEnabled, region.getTable());
        scan.setRaw(rawScanEnabled);
        scan.setCaching(1);
        scan.setCacheBlocks(false);
        scan.setFilter(new FirstKeyOnlyFilter());
        scan.addFamily(column.getName());
        scan.setMaxResultSize(1L);
        scan.setOneRowLimit();
      }
      LOG.debug("Reading from {} {} {} {}", region.getTable(), region.getRegionNameAsString(),
        column.getNameAsString(), Bytes.toStringBinary(startKey));
      try {
        stopWatch.start();
        rs = table.getScanner(scan);
        rs.next();
        stopWatch.stop();
        this.readWriteLatency.add(stopWatch.getTime());
        sink.publishReadTiming(serverName, region, column, stopWatch.getTime());
      } catch (Exception e) {
        sink.publishReadFailure(serverName, region, column, e);
        sink.updateReadFailures(region.getRegionNameAsString(),
          serverName == null ? "NULL" : serverName.getHostname());
      } finally {
        if (rs != null) {
          rs.close();
        }
      }
      return null;
    }
Run a single Region Task and then exit. For each column family of the Region, get one row and
output latency or failure.
hbase-server/src/main/java/org/apache/hadoop/hbase/tool/CanaryTool.java