state = STATE_INITIAL;
- projected_version = version = 0;
+ memset(&fnode, 0, sizeof(fnode));
+
committing_version = 0;
committed_version_equivalent = committed_version = 0;
+
+
+
+
+
+
/***
* linking fun
*/
cache->lru.lru_insert_mid(dn);
dn->dir = this;
- dn->version = projected_version;
+ dn->version = get_projected_version();
// add to dir
assert(items.count(dn->name) == 0);
cache->lru.lru_insert_mid(dn);
dn->dir = this;
- dn->version = projected_version;
+ dn->version = get_projected_version();
// add to dir
assert(items.count(dn->name) == 0);
cache->lru.lru_insert_mid(dn);
dn->dir = this;
- dn->version = projected_version;
+ dn->version = get_projected_version();
// add to dir
assert(items.count(dn->name) == 0);
dn->mark_clean();
remove_dentry(dn);
- if (version == projected_version &&
+ if (!is_projected() &&
committing_version == committed_version &&
num_dirty == 0) {
- dout(10) << "try_remove_unlinked_dn committed_equivalent now " << version
+ dout(10) << "try_remove_unlinked_dn committed_equivalent now " << get_version()
<< " vs committed " << committed_version
<< dendl;
committed_version_equivalent = committed_version;
get(PIN_CHILD);
if (dn->is_null())
nnull++;
- else
+ else {
nitems++;
+ fnode.size++;
+ if (dn->is_primary()) {
+ fnode.nprimary++;
+ fnode.nested.rbytes += dn->get_inode()->inode.accounted_nested.rbytes;
+ fnode.nested.rfiles += dn->get_inode()->inode.accounted_nested.rfiles;
+ } else {
+ fnode.nremote++;
+ }
+ }
nested_auth_pins += dn->auth_pins + dn->nested_auth_pins;
if (dn->is_dirty())
f->replica_map = replica_map;
f->dir_auth = dir_auth;
f->init_fragment_pins();
- f->version = version;
- f->projected_version = projected_version;
+ f->fnode.version = get_version();
f->pop_me = pop_me;
f->pop_me *= fac;
// dirty/clean
+fnode_t *CDir::project_fnode()
+{
+ fnode_t *p = new fnode_t;
+ *p = *get_projected_fnode();
+ projected_fnode.push_back(p);
+ dout(10) << "project_fnode " << p << dendl;
+ return p;
+}
+
version_t CDir::pre_dirty(version_t min)
{
- if (min > projected_version)
- projected_version = min;
- ++projected_version;
- dout(10) << "pre_dirty " << projected_version << dendl;
- return projected_version;
+ fnode_t *pf = project_fnode();
+ if (min > pf->version)
+ pf->version = min;
+ ++pf->version;
+ dout(10) << "pre_dirty " << pf->version << dendl;
+ return pf->version;
+}
+
+void CDir::mark_dirty(version_t pv, LogSegment *ls)
+{
+ assert(get_version() < pv);
+ pop_and_dirty_projected_fnode(ls);
+}
+
+void CDir::pop_and_dirty_projected_fnode(LogSegment *ls)
+{
+ assert(!projected_fnode.empty());
+ dout(15) << "pop_and_dirty_projected_fnode " << projected_fnode.front()
+ << " v" << projected_fnode.front()->version << dendl;
+ _mark_dirty(ls);
+ fnode = *projected_fnode.front();
+ delete projected_fnode.front();
+ projected_fnode.pop_front();
}
void CDir::_mark_dirty(LogSegment *ls)
{
if (!state_test(STATE_DIRTY)) {
state_set(STATE_DIRTY);
- dout(10) << "mark_dirty (was clean) " << *this << " version " << version << dendl;
+ dout(10) << "mark_dirty (was clean) " << *this << " version " << get_version() << dendl;
get(PIN_DIRTY);
assert(ls);
} else {
- dout(10) << "mark_dirty (already dirty) " << *this << " version " << version << dendl;
+ dout(10) << "mark_dirty (already dirty) " << *this << " version " << get_version() << dendl;
}
if (ls)
ls->dirty_dirfrags.push_back(&xlist_dirty);
}
-void CDir::mark_dirty(version_t pv, LogSegment *ls)
-{
- assert(version < pv);
- version = pv;
- _mark_dirty(ls);
-}
-
void CDir::mark_clean()
{
- dout(10) << "mark_clean " << *this << " version " << version << dendl;
+ dout(10) << "mark_clean " << *this << " version " << get_version() << dendl;
if (state_test(STATE_DIRTY)) {
state_clear(STATE_DIRTY);
put(PIN_DIRTY);
// decode.
int len = bl.length();
bufferlist::iterator p = bl.begin();
- version_t got_version;
-
- ::decode(got_version, p);
- dout(10) << "_fetched version " << got_version
+ fnode_t got_fnode;
+ ::decode(got_fnode, p);
+
+ dout(10) << "_fetched version " << got_fnode.version
<< ", " << len << " bytes"
<< dendl;
*/
if (committed_version == 0 &&
dn &&
- dn->get_version() <= got_version &&
+ dn->get_version() <= got_fnode.version &&
dn->is_dirty()) {
dout(10) << "_fetched had underwater dentry " << *dn << ", marking clean" << dendl;
dn->mark_clean();
if (dn->get_inode()) {
- assert(dn->get_inode()->get_version() <= got_version);
+ assert(dn->get_inode()->get_version() <= got_fnode.version);
dout(10) << "_fetched had underwater inode " << *dn->get_inode() << ", marking clean" << dendl;
dn->get_inode()->mark_clean();
}
}
//assert(off == len); FIXME no, directories may shrink. add this back in when we properly truncate objects on write.
- // take the loaded version?
+ // take the loaded fnode?
// only if we are a fresh CDir* with no prior state.
- if (version == 0) {
- assert(projected_version == 0);
+ if (get_version() == 0) {
+ assert(!is_projected());
assert(!state_test(STATE_COMMITTING));
- projected_version = version = committing_version = committed_version = got_version;
+ fnode = got_fnode;
+ committing_version = committed_version = got_fnode.version;
}
//cache->mds->logger->inc("newin", num_new_inodes_loaded);
void CDir::commit(version_t want, Context *c)
{
dout(10) << "commit want " << want << " on " << *this << dendl;
- if (want == 0) want = version;
+ if (want == 0) want = get_version();
// preconditions
- assert(want <= version || version == 0); // can't commit the future
+ assert(want <= get_version() || get_version() == 0); // can't commit the future
assert(want > committed_version); // the caller is stupid
assert(is_auth());
assert(can_auth_pin());
// we can't commit things in the future.
// (even the projected future.)
- assert(want <= version || version == 0);
+ assert(want <= get_version() || get_version() == 0);
// check pre+postconditions.
assert(is_auth());
}
// commit.
- committing_version = version;
+ committing_version = get_version();
// mark committing (if not already)
if (!state_test(STATE_COMMITTING)) {
// encode
bufferlist bl;
- ::encode(version, bl);
+ ::encode(fnode, bl);
int32_t n = nitems;
::encode(n, bl);
cache->mds->objecter->osdmap->file_to_object_layout( get_ondisk_object(),
g_default_mds_dir_layout ),
bl, 0,
- NULL, new C_Dir_Committed(this, version) );
+ NULL, new C_Dir_Committed(this, get_version()) );
}
state_clear(CDir::STATE_COMMITTING);
// dir clean?
- if (committed_version == version)
+ if (committed_version == get_version())
mark_clean();
// dentries clean?
void CDir::encode_export(bufferlist& bl)
{
- ::encode(version, bl);
+ assert(!is_projected());
+ ::encode(fnode, bl);
::encode(committed_version, bl);
::encode(committed_version_equivalent, bl);
void CDir::decode_import(bufferlist::iterator& blp)
{
- ::decode(version, blp);
+ ::decode(fnode, blp);
::decode(committed_version, blp);
::decode(committed_version_equivalent, blp);
committing_version = committed_version;
- projected_version = version;
unsigned s;
::decode(s, blp);
//int hack_num_accessed;
+protected:
+ fnode_t fnode;
+ list<fnode_t*> projected_fnode;
+
+public:
+ version_t get_version() { return fnode.version; }
+ void set_version(version_t v) {
+ assert(projected_fnode.empty());
+ fnode.version = v;
+ }
+ fnode_t *get_projected_fnode() {
+ if (projected_fnode.empty())
+ return &fnode;
+ else
+ return projected_fnode.back();
+ }
+ version_t get_projected_version() { return get_projected_fnode()->version; }
+ fnode_t *project_fnode();
+ void pop_and_dirty_projected_fnode(LogSegment *ls);
+ bool is_projected() { return !projected_fnode.empty(); }
+ version_t pre_dirty(version_t min=0);
+ void _mark_dirty(LogSegment *ls);
+ void mark_dirty(version_t pv, LogSegment *ls);
+ void mark_clean();
+
public:
//typedef hash_map<string, CDentry*> map_t; // there is a bug somewhere, valgrind me.
typedef map<string, CDentry*> map_t;
protected:
+
// contents
map_t items; // non-null AND null
unsigned nitems; // # non-null
int num_dirty;
-
// state
- version_t version;
version_t committing_version;
version_t committed_version;
version_t committed_version_equivalent; // in case of, e.g., temporary file
- version_t projected_version;
xlist<CDir*>::item xlist_dirty;
void wait_for_commit(Context *c, version_t v=0);
// -- dirtyness --
- version_t get_version() { return version; }
- void set_version(version_t v) { projected_version = version = v; }
- version_t get_projected_version() { return projected_version; }
version_t get_committing_version() { return committing_version; }
version_t get_committed_version() { return committed_version; }
version_t get_committed_version_equivalent() { return committed_version_equivalent; }
void set_committed_version(version_t v) { committed_version = v; }
- version_t pre_dirty(version_t min=0);
- void _mark_dirty(LogSegment *ls);
- void mark_dirty(version_t pv, LogSegment *ls);
- void mark_clean();
void mark_complete() { state_set(STATE_COMPLETE); }