// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
// vim: ts=8 sw=2 smarttab
#ifndef CEPH_INODE_BACKTRACE_H
#define CEPH_INODE_BACKTRACE_H

/** metadata backpointers **/

/*
 * - inode_backpointer_t is just the _pointer_ portion; it doesn't
 *   tell us who we point _from_.
 *
 * - it _does_ include a version of the source object, so we can look
 *   at two different pointers (from the same inode) and tell which is
 *   newer.
 */
struct inode_backpointer_t {
  inodeno_t dirino;    // containing directory ino
  string dname;        // linking dentry name
  version_t version;   // child's version at time of backpointer creation

  inode_backpointer_t() : version(0) {}
  inode_backpointer_t(inodeno_t i, const string &d, version_t v) : dirino(i), dname(d), version(v) {}

  void encode(bufferlist& bl) const {
    ::encode(dirino, bl);
    ::encode(dname, bl);
    ::encode(version, bl);
  }
  void decode(bufferlist::iterator& bl) {
    ::decode(dirino, bl);
    ::decode(dname, bl);
    ::decode(version, bl);
  }
};
WRITE_CLASS_ENCODER(inode_backpointer_t)

inline ostream& operator<<(ostream& out, const inode_backpointer_t& ib) {
  return out << "<" << ib.dirino << "/" << ib.dname << " v" << ib.version << ">";
}

/*
 * inode_backtrace_t is a complete ancestor backtraces for a given inode.
 * we include who _we_ are, so that the backtrace can stand alone (as, say,
 * an xattr on an object).
 */
struct inode_backtrace_t {
  inodeno_t ino;       // my ino
  vector<inode_backpointer_t> ancestors;

  void encode(bufferlist& bl) const {
    __u8 v = 3;
    ::encode(v, bl);
    ::encode(ino, bl);
    ::encode(ancestors, bl);
  }

  void decode(bufferlist::iterator& bl) {
    __u8 v;
    ::decode(v, bl);
    if (v < 3)
      return;  // sorry, the old data was crap
    ::decode(ino, bl);
    ::decode(ancestors, bl);
  }
};
WRITE_CLASS_ENCODER(inode_backtrace_t)

inline ostream& operator<<(ostream& out, const inode_backtrace_t& it) {
  return out << it.ino << ":" << it.ancestors;
}


#endif

