initial code repo
[stor4nfv.git] / src / ceph / src / test / osd / Object.h
diff --git a/src/ceph/src/test/osd/Object.h b/src/ceph/src/test/osd/Object.h
new file mode 100644 (file)
index 0000000..09a59a9
--- /dev/null
@@ -0,0 +1,514 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+#include "include/interval_set.h"
+#include "include/buffer.h"
+#include "include/encoding.h"
+#include <list>
+#include <map>
+#include <set>
+#include <random>
+
+#ifndef OBJECT_H
+#define OBJECT_H
+
+class ContDesc {
+public:
+  int objnum;
+  int cursnap;
+  unsigned seqnum;
+  std::string prefix;
+  std::string oid;
+
+  ContDesc() :
+    objnum(0), cursnap(0),
+    seqnum(0), prefix("") {}
+
+  ContDesc(int objnum,
+          int cursnap,
+          unsigned seqnum,
+          const std::string &prefix) :
+    objnum(objnum), cursnap(cursnap),
+    seqnum(seqnum), prefix(prefix) {}
+
+  bool operator==(const ContDesc &rhs) {
+    return (rhs.objnum == objnum &&
+           rhs.cursnap == cursnap &&
+           rhs.seqnum == seqnum &&
+           rhs.prefix == prefix &&
+           rhs.oid == oid);
+  }
+
+  bool operator<(const ContDesc &rhs) const {
+    return seqnum < rhs.seqnum;
+  }
+
+  bool operator!=(const ContDesc &rhs) {
+    return !((*this) == rhs);
+  }
+  void encode(bufferlist &bl) const;
+  void decode(bufferlist::iterator &bp);
+};
+WRITE_CLASS_ENCODER(ContDesc)
+
+std::ostream &operator<<(std::ostream &out, const ContDesc &rhs);
+
+class ContentsGenerator {
+public:
+
+  class iterator_impl {
+  public:
+    virtual char operator*() = 0;
+    virtual iterator_impl &operator++() = 0;
+    virtual void seek(uint64_t pos) = 0;
+    virtual bool end() = 0;
+    virtual ContDesc get_cont() const = 0;
+    virtual uint64_t get_pos() const = 0;
+    virtual bufferlist gen_bl_advance(uint64_t s) {
+      bufferptr ret = buffer::create(s);
+      for (uint64_t i = 0; i < s; ++i, ++(*this)) {
+       ret[i] = **this;
+      }
+      bufferlist _ret;
+      _ret.push_back(ret);
+      return _ret;
+    }
+    virtual bool check_bl_advance(bufferlist &bl, uint64_t *off = nullptr) {
+      uint64_t _off = 0;
+      for (bufferlist::iterator i = bl.begin();
+          !i.end();
+          ++i, ++_off, ++(*this)) {
+       if (*i != **this) {
+         if (off)
+           *off = _off;
+         return false;
+       }
+      }
+      return true;
+    }
+    virtual ~iterator_impl() {};
+  };
+
+  class iterator {
+  public:
+    ContentsGenerator *parent;
+    iterator_impl *impl;
+    char operator *() { return **impl; }
+    iterator &operator++() { ++(*impl); return *this; };
+    void seek(uint64_t pos) { impl->seek(pos); }
+    bool end() { return impl->end(); }
+    ~iterator() { parent->put_iterator_impl(impl); }
+    iterator(const iterator &rhs) : parent(rhs.parent) {
+      impl = parent->dup_iterator_impl(rhs.impl);
+    }
+    iterator &operator=(const iterator &rhs) {
+      iterator new_iter(rhs);
+      swap(new_iter);
+      return *this;
+    }
+    void swap(iterator &other) {
+      ContentsGenerator *otherparent = other.parent;
+      other.parent = parent;
+      parent = otherparent;
+
+      iterator_impl *otherimpl = other.impl;
+      other.impl = impl;
+      impl = otherimpl;
+    }
+    bufferlist gen_bl_advance(uint64_t s) {
+      return impl->gen_bl_advance(s);
+    }
+    bool check_bl_advance(bufferlist &bl, uint64_t *off = nullptr) {
+      return impl->check_bl_advance(bl, off);
+    }
+    iterator(ContentsGenerator *parent, iterator_impl *impl) :
+      parent(parent), impl(impl) {}
+  };
+
+  virtual uint64_t get_length(const ContDesc &in) = 0;
+
+  virtual void get_ranges_map(
+    const ContDesc &cont, std::map<uint64_t, uint64_t> &out) = 0;
+  void get_ranges(const ContDesc &cont, interval_set<uint64_t> &out) {
+    std::map<uint64_t, uint64_t> ranges;
+    get_ranges_map(cont, ranges);
+    for (std::map<uint64_t, uint64_t>::iterator i = ranges.begin();
+        i != ranges.end();
+        ++i) {
+      out.insert(i->first, i->second);
+    }
+  }
+
+
+  virtual iterator_impl *get_iterator_impl(const ContDesc &in) = 0;
+
+  virtual iterator_impl *dup_iterator_impl(const iterator_impl *in) = 0;
+
+  virtual void put_iterator_impl(iterator_impl *in) = 0;
+
+  virtual ~ContentsGenerator() {};
+
+  iterator get_iterator(const ContDesc &in) {
+    return iterator(this, get_iterator_impl(in));
+  }
+};
+
+class RandGenerator : public ContentsGenerator {
+public:
+  typedef std::minstd_rand0 RandWrap;
+
+  class iterator_impl : public ContentsGenerator::iterator_impl {
+  public:
+    uint64_t pos;
+    ContDesc cont;
+    RandWrap rand;
+    RandGenerator *cont_gen;
+    char current;
+    iterator_impl(const ContDesc &cont, RandGenerator *cont_gen) : 
+      pos(0), cont(cont), rand(cont.seqnum), cont_gen(cont_gen) {
+      current = rand();
+    }
+
+    ContDesc get_cont() const override { return cont; }
+    uint64_t get_pos() const override { return pos; }
+
+    iterator_impl &operator++() override {
+      pos++;
+      current = rand();
+      return *this;
+    }
+
+    char operator*() override {
+      return current;
+    }
+
+    void seek(uint64_t _pos) override {
+      if (_pos < pos) {
+       iterator_impl begin = iterator_impl(cont, cont_gen);
+       begin.seek(_pos);
+       *this = begin;
+      }
+      while (pos < _pos) {
+       ++(*this);
+      }
+    }
+
+    bool end() override {
+      return pos >= cont_gen->get_length(cont);
+    }
+  };
+
+  ContentsGenerator::iterator_impl *get_iterator_impl(const ContDesc &in) override {
+    RandGenerator::iterator_impl *i = new iterator_impl(in, this);
+    return i;
+  }
+
+  void put_iterator_impl(ContentsGenerator::iterator_impl *in) override {
+    delete in;
+  }
+
+  ContentsGenerator::iterator_impl *dup_iterator_impl(
+    const ContentsGenerator::iterator_impl *in) override {
+    ContentsGenerator::iterator_impl *retval = get_iterator_impl(in->get_cont());
+    retval->seek(in->get_pos());
+    return retval;
+  }
+};
+
+class VarLenGenerator : public RandGenerator {
+  uint64_t max_length;
+  uint64_t min_stride_size;
+  uint64_t max_stride_size;
+public:
+  VarLenGenerator(
+    uint64_t length, uint64_t min_stride_size, uint64_t max_stride_size) :
+    max_length(length),
+    min_stride_size(min_stride_size),
+    max_stride_size(max_stride_size) {}
+  void get_ranges_map(
+    const ContDesc &cont, std::map<uint64_t, uint64_t> &out) override;
+  uint64_t get_length(const ContDesc &in) override {
+    RandWrap rand(in.seqnum);
+    if (max_length == 0)
+      return 0;
+    return (rand() % (max_length/2)) + ((max_length - 1)/2) + 1;
+  }
+};
+
+class AttrGenerator : public RandGenerator {
+  uint64_t max_len;
+  uint64_t big_max_len;
+public:
+  AttrGenerator(uint64_t max_len, uint64_t big_max_len)
+    : max_len(max_len), big_max_len(big_max_len) {}
+  void get_ranges_map(
+    const ContDesc &cont, std::map<uint64_t, uint64_t> &out) override {
+    out.insert(std::pair<uint64_t, uint64_t>(0, get_length(cont)));
+  }
+  uint64_t get_length(const ContDesc &in) override {
+    RandWrap rand(in.seqnum);
+    // make some attrs big
+    if (in.seqnum & 3)
+      return (rand() % max_len);
+    else
+      return (rand() % big_max_len);
+  }
+  bufferlist gen_bl(const ContDesc &in) {
+    bufferlist bl;
+    for (iterator i = get_iterator(in); !i.end(); ++i) {
+      bl.append(*i);
+    }
+    assert(bl.length() < big_max_len);
+    return bl;
+  }
+};
+
+class AppendGenerator : public RandGenerator {
+  uint64_t off;
+  uint64_t alignment;
+  uint64_t min_append_size;
+  uint64_t max_append_size;
+  uint64_t max_append_total;
+
+  uint64_t round_up(uint64_t in, uint64_t by) {
+    if (by)
+      in += (by - (in % by));
+    return in;
+  }
+
+public:
+  AppendGenerator(
+    uint64_t off,
+    uint64_t alignment,
+    uint64_t min_append_size,
+    uint64_t _max_append_size,
+    uint64_t max_append_multiple) :
+    off(off), alignment(alignment),
+    min_append_size(round_up(min_append_size, alignment)),
+    max_append_size(round_up(_max_append_size, alignment)) {
+    if (_max_append_size == min_append_size)
+      max_append_size += alignment;
+    max_append_total = max_append_multiple * max_append_size;
+  }
+  uint64_t get_append_size(const ContDesc &in) {
+    RandWrap rand(in.seqnum);
+    return round_up(rand() % max_append_total, alignment);
+  }
+  uint64_t get_length(const ContDesc &in) override {
+    return off + get_append_size(in);
+  }
+  void get_ranges_map(
+    const ContDesc &cont, std::map<uint64_t, uint64_t> &out) override;
+};
+
+class ObjectDesc {
+public:
+  ObjectDesc()
+    : exists(false), dirty(false),
+      version(0) {}
+  ObjectDesc(const ContDesc &init, ContentsGenerator *cont_gen)
+    : exists(false), dirty(false),
+      version(0) {
+    layers.push_front(std::pair<ceph::shared_ptr<ContentsGenerator>, ContDesc>(ceph::shared_ptr<ContentsGenerator>(cont_gen), init));
+  }
+
+  class iterator {
+  public:
+    uint64_t pos;
+    uint64_t size;
+    uint64_t cur_valid_till;
+
+    class ContState {
+      interval_set<uint64_t> ranges;
+      const uint64_t size;
+
+    public:
+      ContDesc cont;
+      ceph::shared_ptr<ContentsGenerator> gen;
+      ContentsGenerator::iterator iter;
+
+      ContState(
+       ContDesc _cont,
+       ceph::shared_ptr<ContentsGenerator> _gen,
+       ContentsGenerator::iterator _iter)
+       : size(_gen->get_length(_cont)), cont(_cont), gen(_gen), iter(_iter) {
+       gen->get_ranges(cont, ranges);
+      }
+
+      const interval_set<uint64_t> &get_ranges() {
+       return ranges;
+      }
+
+      uint64_t get_size() {
+       return gen->get_length(cont);
+      }
+
+      bool covers(uint64_t pos) {
+       return ranges.contains(pos) || (!ranges.starts_after(pos) && pos >= size);
+      }
+
+      uint64_t next(uint64_t pos) {
+       assert(!covers(pos));
+       return ranges.starts_after(pos) ? ranges.start_after(pos) : size;
+      }
+
+      uint64_t valid_till(uint64_t pos) {
+       assert(covers(pos));
+       return ranges.contains(pos) ?
+         ranges.end_after(pos) :
+         std::numeric_limits<uint64_t>::max();
+      }
+    };
+    std::list<ContState> layers;
+
+    struct StackState {
+      const uint64_t next;
+      const uint64_t size;
+    };
+    std::list<std::pair<std::list<ContState>::iterator, StackState> > stack;
+    std::list<ContState>::iterator current;
+
+    explicit iterator(ObjectDesc &obj) :
+      pos(0),
+      size(obj.layers.begin()->first->get_length(obj.layers.begin()->second)),
+      cur_valid_till(0) {
+      for (auto &&i : obj.layers) {
+       layers.push_back({i.second, i.first, i.first->get_iterator(i.second)});
+      }
+      current = layers.begin();
+
+      adjust_stack();
+    }
+
+    void adjust_stack();
+    iterator &operator++() {
+      assert(cur_valid_till >= pos);
+      ++pos;
+      if (pos >= cur_valid_till) {
+       adjust_stack();
+      }
+      return *this;
+    }
+
+    char operator*() {
+      if (current == layers.end()) {
+       return '\0';
+      } else {
+       return pos >= size ? '\0' : *(current->iter);
+      }
+    }
+
+    bool end() {
+      return pos >= size;
+    }
+
+    void seek(uint64_t _pos) {
+      if (_pos < pos) {
+       ceph_abort();
+      }
+      while (pos < _pos) {
+       assert(cur_valid_till >= pos);
+       uint64_t next = std::min(_pos - pos, cur_valid_till - pos);
+       pos += next;
+
+       if (pos >= cur_valid_till) {
+         assert(pos == cur_valid_till);
+         adjust_stack();
+       }
+      }
+      assert(pos == _pos);
+    }
+
+    bufferlist gen_bl_advance(uint64_t s) {
+      bufferlist ret;
+      while (s > 0) {
+       assert(cur_valid_till >= pos);
+       uint64_t next = std::min(s, cur_valid_till - pos);
+       if (current != layers.end() && pos < size) {
+         ret.append(current->iter.gen_bl_advance(next));
+       } else {
+         ret.append_zero(next);
+       }
+
+       pos += next;
+       assert(next <= s);
+       s -= next;
+
+       if (pos >= cur_valid_till) {
+         assert(cur_valid_till == pos);
+         adjust_stack();
+       }
+      }
+      return ret;
+    }
+
+    bool check_bl_advance(bufferlist &bl, uint64_t *error_at = nullptr) {
+      uint64_t off = 0;
+      while (off < bl.length()) {
+       assert(cur_valid_till >= pos);
+       uint64_t next = std::min(bl.length() - off, cur_valid_till - pos);
+
+       bufferlist to_check;
+       to_check.substr_of(bl, off, next);
+       if (current != layers.end() && pos < size) {
+         if (!current->iter.check_bl_advance(to_check, error_at)) {
+           if (error_at)
+             *error_at += off;
+           return false;
+         }
+       } else {
+         uint64_t at = pos;
+         for (auto i = to_check.begin(); !i.end(); ++i, ++at) {
+           if (*i) {
+             if (error_at)
+               *error_at = at;
+             return false;
+           }
+         }
+       }
+
+       pos += next;
+       off += next;
+       assert(off <= bl.length());
+
+       if (pos >= cur_valid_till) {
+         assert(cur_valid_till == pos);
+         adjust_stack();
+       }
+      }
+      assert(off == bl.length());
+      return true;
+    }
+  };
+    
+  iterator begin() {
+    return iterator(*this);
+  }
+
+  bool deleted() {
+    return !exists;
+  }
+
+  bool has_contents() {
+    return layers.size();
+  }
+
+  // takes ownership of gen
+  void update(ContentsGenerator *gen, const ContDesc &next);
+  bool check(bufferlist &to_check);
+  bool check_sparse(const std::map<uint64_t, uint64_t>& extends,
+                   bufferlist &to_check);
+  const ContDesc &most_recent();
+  ContentsGenerator *most_recent_gen() {
+    return layers.begin()->first.get();
+  }
+  std::map<std::string, ContDesc> attrs; // Both omap and xattrs
+  bufferlist header;
+  bool exists;
+  bool dirty;
+
+  uint64_t version;
+  std::string redirect_target;
+private:
+  std::list<std::pair<ceph::shared_ptr<ContentsGenerator>, ContDesc> > layers;
+};
+
+#endif