src/worker.cc
// Do randomized reads and (possibly) writes on a device.
// Return false on fatal SW error, true on SW success,
// regardless of whether HW failed.
Do randomized reads and (possibly) writes on a device.
Return false on fatal SW error, true on SW success,
regardless of whether HW failed.
Do randomized reads and ( possibly ) writes on a device . Return false on fatal SW error true on SW success regardless of whether HW failed .
bool DiskThread::DoWork(int fd) {
  int64 block_num = 0;
  int64 num_segments;
  if (segment_size_ == -1) {
    num_segments = 1;
  } else {
    num_segments = device_sectors_ / segment_size_;
    if (device_sectors_ % segment_size_ != 0)
      num_segments++;
  }
  sat_assert(device_sectors_ * kSectorSize > 3 * cache_size_);
   To prevent the read blocks from coming from the disk cache,
   enough blocks are written before read such that a block would
   be ejected from the disk cache by the time it is read.
   TODO(amistry): Implement some sort of read/write throttling.  The
                  flood of asynchronous I/O requests when a drive is
                  unplugged is causing the application and kernel to
                  become unresponsive.
  while (IsReadyToRun()) {
     Write blocks to disk.
    logprintf(16, "Log: Write phase %sfor disk %s (thread %d).\n",
              non_destructive_ ? "(disabled) " : "",
              device_name_.c_str(), thread_num_);
    while (IsReadyToRunNoPause() &&
           in_flight_sectors_.size() <
               static_cast<size_t>(queue_size_ + 1)) {
       Confine testing to a particular segment of the disk.
      int64 segment = (block_num / blocks_per_segment_) % num_segments;
      if (!non_destructive_ &&
          (block_num % blocks_per_segment_ == 0)) {
        logprintf(20, "Log: Starting to write segment %lld out of "
                  "%lld on disk %s (thread %d).\n",
                  segment, num_segments, device_name_.c_str(),
                  thread_num_);
      }
      block_num++;
      BlockData *block = block_table_->GetUnusedBlock(segment);
       If an unused sequence of sectors could not be found, skip to the
       next block to process.  Soon, a new segment will come and new
       sectors will be able to be allocated.  This effectively puts a
       minumim on the disk size at 3x the stated cache size, or 48MiB
       if a cache size is not given (since the cache is set as 16MiB
       by default).  Given that todays caches are at the low MiB range
       and drive sizes at the mid GB, this shouldn't pose a problem.
       The 3x minimum comes from the following:
         1. In order to allocate 'y' blocks from a segment, the
            segment must contain at least 2y blocks or else an
            allocation may not succeed.
         2. Assume the entire disk is one segment.
         3. A full write phase consists of writing blocks corresponding to
            3/2 cache size.
         4. Therefore, the one segment must have 2 * 3/2 * cache
            size worth of blocks = 3 * cache size worth of blocks
            to complete.
       In non-destructive mode, don't write anything to disk.
      if (!non_destructive_) {
        if (!WriteBlockToDisk(fd, block)) {
          block_table_->RemoveBlock(block);
          return true;
        }
        blocks_written_++;
      }
       Block is either initialized by writing, or in nondestructive case,
       initialized by being added into the datastructure for later reading.
      block->SetBlockAsInitialized();
      in_flight_sectors_.push(block);
    }
    if (!os_->FlushPageCache())  If O_DIRECT worked, this will be a NOP.
      return false;
     Verify blocks on disk.
    logprintf(20, "Log: Read phase for disk %s (thread %d).\n",
              device_name_.c_str(), thread_num_);
    while (IsReadyToRunNoPause() && !in_flight_sectors_.empty()) {
      BlockData *block = in_flight_sectors_.front();
      in_flight_sectors_.pop();
      if (!ValidateBlockOnDisk(fd, block))
        return true;
      block_table_->RemoveBlock(block);
      blocks_read_++;
    }
  }
  pages_copied_ = blocks_written_ + blocks_read_;
  return true;
}
bool DiskThread :: DoWork ( int fd ) { int64 block_num = 0 ; int64 num_segments ; if ( segment_size_ == -1 ) { num_segments = 1 ; } else { num_segments = device_sectors_ / segment_size_ ; if ( device_sectors_ % segment_size_ != 0 ) num_segments ++ ; } sat_assert ( device_sectors_ * kSectorSize > 3 * cache_size_ ) ; while ( IsReadyToRun ( ) ) { logprintf ( 16 , " \n " , non_destructive_ ? " " : " " , device_name_ . c_str ( ) , thread_num_ ) ; while ( IsReadyToRunNoPause ( ) && in_flight_sectors_ . size ( ) < static_cast < size_t > ( queue_size_ + 1 ) ) { int64 segment = ( block_num / blocks_per_segment_ ) % num_segments ; if ( ! non_destructive_ && ( block_num % blocks_per_segment_ == 0 ) ) { logprintf ( 20 , " " " \n " , segment , num_segments , device_name_ . c_str ( ) , thread_num_ ) ; } block_num ++ ; BlockData * block = block_table_ -> GetUnusedBlock ( segment ) ; if ( ! non_destructive_ ) { if ( ! WriteBlockToDisk ( fd , block ) ) { block_table_ -> RemoveBlock ( block ) ; return true ; } blocks_written_ ++ ; } block -> SetBlockAsInitialized ( ) ; in_flight_sectors_ . push ( block ) ; } if ( ! os_ -> FlushPageCache ( ) ) return false ; logprintf ( 20 , " \n " , device_name_ . c_str ( ) , thread_num_ ) ; while ( IsReadyToRunNoPause ( ) && ! in_flight_sectors_ . empty ( ) ) { BlockData * block = in_flight_sectors_ . front ( ) ; in_flight_sectors_ . pop ( ) ; if ( ! ValidateBlockOnDisk ( fd , block ) ) return true ; block_table_ -> RemoveBlock ( block ) ; blocks_read_ ++ ; } } pages_copied_ = blocks_written_ + blocks_read_ ; return true ; }
Do randomized reads and (possibly) writes on a device.
Do randomized reads and ( possibly ) writes on a device .
// Disk size should be at least 3x cache size.  See comment later for // details. // This disk test works by writing blocks with a certain pattern to // disk, then reading them back and verifying it against the pattern // at a later time.  A failure happens when either the block cannot // be written/read or when the read block is different than what was // written.  If a block takes too long to write/read, then a warning // is given instead of an error since taking too long is not // necessarily an error. // // To prevent the read blocks from coming from the disk cache, // enough blocks are written before read such that a block would // be ejected from the disk cache by the time it is read. // // TODO(amistry): Implement some sort of read/write throttling.  The //                flood of asynchronous I/O requests when a drive is //                unplugged is causing the application and kernel to //                become unresponsive. // Write blocks to disk. // Confine testing to a particular segment of the disk. // If an unused sequence of sectors could not be found, skip to the // next block to process.  Soon, a new segment will come and new // sectors will be able to be allocated.  This effectively puts a // minumim on the disk size at 3x the stated cache size, or 48MiB // if a cache size is not given (since the cache is set as 16MiB // by default).  Given that todays caches are at the low MiB range // and drive sizes at the mid GB, this shouldn't pose a problem. // The 3x minimum comes from the following: //   1. In order to allocate 'y' blocks from a segment, the //      segment must contain at least 2y blocks or else an //      allocation may not succeed. //   2. Assume the entire disk is one segment. //   3. A full write phase consists of writing blocks corresponding to //      3/2 cache size. //   4. Therefore, the one segment must have 2 * 3/2 * cache //      size worth of blocks = 3 * cache size worth of blocks //      to complete. // In non-destructive mode, don't write anything to disk. // Block is either initialized by writing, or in nondestructive case, // initialized by being added into the datastructure for later reading. // If O_DIRECT worked, this will be a NOP. // Verify blocks on disk.