"Fossies" - the Fresh Open Source Software Archive

Member "xdelta3-3.0.11/testing/file.h" (8 Jan 2016, 7767 Bytes) of package /linux/misc/xdelta3-3.0.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* -*- Mode: C++ -*-  */
    2 class Block;
    3 class BlockIterator;
    4 class TmpFile;
    5 
    6 class Block {
    7 public:
    8   Block()
    9     : data_(NULL),
   10       data_size_(0),
   11       size_(0) { }
   12 
   13   ~Block() {
   14     if (data_) {
   15       delete [] data_;
   16     }
   17   }
   18 
   19   size_t Size() const {
   20     return size_;
   21   }
   22 
   23   uint8_t operator[](size_t i) const {
   24     CHECK_LT(i, size_);
   25     return data_[i];
   26   }
   27 
   28   uint8_t* Data() const {
   29     if (data_ == NULL) {
   30       CHECK_EQ(0, size_);
   31       data_size_ = 1;
   32       data_ = new uint8_t[1];
   33     }
   34     return data_;
   35   }
   36 
   37   // For writing to blocks
   38   void Append(const uint8_t *data, size_t size) {
   39     if (data_ == NULL) {
   40       CHECK_EQ(0, size_);
   41       CHECK_EQ(0, data_size_);
   42       data_ = new uint8_t[Constants::BLOCK_SIZE];
   43       data_size_ = Constants::BLOCK_SIZE;
   44     }
   45 
   46     if (size_ + size > data_size_) {
   47       uint8_t *tmp = data_;
   48       while (size_ + size > data_size_) {
   49     data_size_ *= 2;
   50       }
   51       data_ = new uint8_t[data_size_];
   52       memcpy(data_, tmp, size_);
   53       delete [] tmp;
   54     }
   55 
   56     memcpy(data_ + size_, data, size);
   57     size_ += size;
   58   }
   59 
   60   // For cleaing a block
   61   void Reset() {
   62     size_ = 0;
   63   }
   64 
   65   void Print() const {
   66     xoff_t pos = 0;
   67     for (size_t i = 0; i < Size(); i++) {
   68       if (pos % 16 == 0) {
   69     DP(RINT "%5"Q"x: ", pos);
   70       }
   71       DP(RINT "%02x ", (*this)[i]);
   72       if (pos % 16 == 15) {
   73     DP(RINT "\n");
   74       }
   75       pos++;
   76     }
   77     DP(RINT "\n");
   78   }
   79 
   80   void WriteTmpFile(TmpFile *f) const {
   81     f->Append(this);
   82   }
   83 
   84   void SetSize(size_t size) {
   85     uint8_t *t = NULL;
   86     if (data_size_ < size) {
   87       if (data_) {
   88     t = data_;
   89       }
   90       data_ = new uint8_t[size];
   91       data_size_ = size;
   92     }
   93     if (t && size < size_) {
   94       memcpy(data_, t, size);
   95     }
   96     delete [] t;
   97     size_ = size;
   98   }
   99 
  100 private:
  101   friend class BlockIterator;
  102 
  103   mutable uint8_t *data_;
  104   mutable size_t data_size_;
  105   size_t size_;
  106 };
  107 
  108 class FileSpec {
  109  public:
  110   FileSpec(MTRandom *rand)
  111     : rand_(rand) {
  112   }
  113 
  114   // Generates a file with a known size
  115   void GenerateFixedSize(xoff_t size) {
  116     Reset();
  117 
  118     for (xoff_t p = 0; p < size; ) {
  119       xoff_t t = min(Constants::BLOCK_SIZE, size - p);
  120       table_.insert(make_pair(p, Segment(t, rand_)));
  121       p += t;
  122     }
  123   }
  124 
  125   // Generates a file with exponential-random distributed size
  126   void GenerateRandomSize(xoff_t mean) {
  127     GenerateFixedSize(rand_->ExpRand(mean));
  128   }
  129 
  130   // Returns the size of the file
  131   xoff_t Size() const {
  132     if (table_.empty()) {
  133       return 0;
  134     }
  135     ConstSegmentMapIterator i = --table_.end();
  136     return i->first + i->second.Size();
  137   }
  138 
  139   // Returns the number of blocks
  140   xoff_t Blocks(size_t blksize = Constants::BLOCK_SIZE) const {
  141     if (table_.empty()) {
  142       return 0;
  143     }
  144     return ((Size() - 1) / blksize) + 1;
  145   }
  146 
  147   // Returns the number of segments
  148   xoff_t Segments() const {
  149     return table_.size();
  150   }
  151 
  152   // Create a mutation according to "what".
  153   void ModifyTo(const Mutator &mutator,
  154         FileSpec *modify) const {
  155     modify->Reset();
  156     mutator.Mutate(&modify->table_, &table_, rand_);
  157     modify->CheckSegments();
  158   }
  159 
  160   void CheckSegments() const {
  161     for (ConstSegmentMapIterator iter(table_.begin());
  162      iter != table_.end(); ) {
  163       ConstSegmentMapIterator iter0(iter++);
  164       if (iter == table_.end()) {
  165     break;
  166       }
  167       CHECK_EQ(iter0->first + iter0->second.Size(), iter->first);
  168     }
  169   }
  170 
  171   void Reset() {
  172     table_.clear();
  173   }
  174 
  175   void Print() const {
  176     for (ConstSegmentMapIterator iter(table_.begin());
  177      iter != table_.end();
  178      ++iter) {
  179       const Segment &seg = iter->second;
  180       cerr << "Segment at " << iter->first
  181        << " (" << seg.ToString() << ")" << endl;
  182     }
  183   }
  184 
  185   void PrintData() const {
  186     Block block;
  187     for (BlockIterator iter(*this); !iter.Done(); iter.Next()) {
  188       iter.Get(&block);
  189       block.Print();
  190     }
  191   }
  192 
  193   void WriteTmpFile(TmpFile *f) const {
  194     Block block;
  195     for (BlockIterator iter(*this); !iter.Done(); iter.Next()) {
  196       iter.Get(&block);
  197       f->Append(&block);
  198     }
  199   }
  200 
  201   void Get(Block *block, xoff_t offset, size_t size) const {
  202     size_t got = 0;
  203     block->SetSize(size);
  204 
  205     ConstSegmentMapIterator pos = table_.upper_bound(offset);
  206     if (pos == table_.begin()) {
  207       CHECK_EQ(0, Size());
  208       return;
  209     }
  210     --pos;
  211 
  212     while (got < size) {
  213       CHECK(pos != table_.end());
  214       CHECK_GE(offset, pos->first);
  215 
  216       const Segment &seg = pos->second;
  217 
  218       // The position of this segment may start before this block starts,
  219       // and then the position of the data may be offset from the seeding
  220       // position.
  221       size_t seg_offset = offset - pos->first;
  222       size_t advance = min(seg.Size() - seg_offset,
  223                size - got);
  224 
  225       seg.Fill(seg_offset, advance, block->Data() + got);
  226 
  227       got += advance;
  228       offset += advance;
  229       ++pos;
  230     }
  231   }
  232 
  233   typedef BlockIterator iterator;
  234 
  235  private:
  236   friend class BlockIterator;
  237 
  238   MTRandom *rand_;
  239   SegmentMap table_;
  240 };
  241 
  242 class BlockIterator {
  243 public:
  244   explicit BlockIterator(const FileSpec& spec)
  245     : spec_(spec),
  246       blkno_(0),
  247       blksize_(Constants::BLOCK_SIZE) { }
  248 
  249   BlockIterator(const FileSpec& spec,
  250         size_t blksize)
  251     : spec_(spec),
  252       blkno_(0),
  253       blksize_(blksize) { }
  254 
  255   bool Done() const {
  256     return blkno_ >= spec_.Blocks(blksize_);
  257   }
  258 
  259   void Next() {
  260     blkno_++;
  261   }
  262 
  263   xoff_t Blkno() const {
  264     return blkno_;
  265   }
  266 
  267   xoff_t Blocks() const {
  268     return spec_.Blocks(blksize_);
  269   }
  270 
  271   xoff_t Offset() const {
  272     return blkno_ * blksize_;
  273   }
  274 
  275   void SetBlock(xoff_t blkno) {
  276     CHECK_LE(blkno, Blocks());
  277     blkno_ = blkno;
  278   }
  279 
  280   void Get(Block *block) const {
  281     spec_.Get(block, blkno_ * blksize_, BytesOnBlock());
  282   }
  283 
  284   size_t BytesOnBlock() const {
  285     xoff_t blocks = spec_.Blocks(blksize_);
  286     xoff_t size = spec_.Size();
  287 
  288     DCHECK((blkno_ < blocks) ||
  289        (blkno_ == blocks && size % blksize_ == 0));
  290 
  291     if (blkno_ == blocks) {
  292       return 0;
  293     }
  294     if (blkno_ + 1 == blocks) {
  295       return ((size - 1) % blksize_) + 1;
  296     }
  297     return blksize_;
  298   }
  299 
  300   size_t BlockSize() const {
  301     return blksize_;
  302   }
  303 
  304 private:
  305   const FileSpec& spec_;
  306   xoff_t blkno_;
  307   size_t blksize_;
  308 };
  309 
  310 class ExtFile {
  311 public:
  312   ExtFile() {
  313     static int static_counter = 0;
  314     pid_t pid = getpid();
  315     char buf[64];
  316     xoff_t xpid = pid;
  317     snprintf(buf, 64, "/tmp/regtest.%" Q "u.%d", xpid, static_counter++);
  318     filename_.append(buf);
  319     unlink(filename_.c_str());
  320   }
  321 
  322   ~ExtFile() {
  323     unlink(filename_.c_str());
  324   }
  325 
  326   const char* Name() const {
  327     return filename_.c_str();
  328   }
  329 
  330   // Check whether a real file matches a file spec.
  331   bool EqualsSpec(const FileSpec &spec) const {
  332     main_file t;
  333     main_file_init(&t);
  334     CHECK_EQ(0, main_file_open(&t, Name(), XO_READ));
  335 
  336     Block tblock;
  337     Block sblock;
  338     for (BlockIterator iter(spec); !iter.Done(); iter.Next()) {
  339       iter.Get(&sblock);
  340       tblock.SetSize(sblock.Size());
  341       size_t tread;
  342       CHECK_EQ(0, main_file_read(&t,
  343                  tblock.Data(),
  344                  tblock.Size(), &tread, "read failed"));
  345       CHECK_EQ(0, CmpDifferentBlockBytes(tblock, sblock));
  346     }
  347 
  348     CHECK_EQ(0, main_file_close(&t));
  349     main_file_cleanup(&t);
  350     return true;
  351   }
  352 
  353 protected:
  354   string filename_;
  355 };
  356 
  357 class TmpFile : public ExtFile {
  358 public:
  359   TmpFile() {
  360     main_file_init(&file_);
  361     CHECK_EQ(0, main_file_open(&file_, Name(), XO_WRITE));
  362   }
  363 
  364   ~TmpFile() {
  365     main_file_cleanup(&file_);
  366   }
  367 
  368   void Append(const Block *block) {
  369     CHECK_EQ(0, main_file_write(&file_,
  370                 block->Data(), block->Size(),
  371                 "tmpfile write failed"));
  372   }
  373 
  374   const char* Name() const {
  375     if (main_file_isopen(&file_)) {
  376       CHECK_EQ(0, main_file_close(&file_));
  377     }
  378     return ExtFile::Name();
  379   }
  380 
  381 private:
  382   mutable main_file file_;
  383 };