*/
struct fnode_t {
version_t version;
+ utime_t mtime;
__u64 size; // files + dirs
__u64 nprimary, nremote;
__u64 nfiles; // files
__u64 nsubdirs; // subdirs
nested_info_t nested; // nested summation
+ nested_info_t accounted_nested; // nested summation
void encode(bufferlist &bl) const {
::encode(version, bl);
::encode(nfiles, bl);
::encode(nsubdirs, bl);
::encode(nested, bl);
+ ::encode(accounted_nested, bl);
}
void decode(bufferlist::iterator &bl) {
::decode(version, bl);
::decode(nfiles, bl);
::decode(nsubdirs, bl);
::decode(nested, bl);
+ ::decode(accounted_nested, bl);
}
};
WRITE_CLASS_ENCODER(fnode_t)
state == LOCK_LONER || state == LOCK_GLONERM ||
state == LOCK_GSYNCM || state == LOCK_GSYNCL;
}
- void get_wrlock() {
- assert(can_wrlock());
+ void get_wrlock(bool force) {
+ assert(force || can_wrlock());
if (num_wrlock == 0) parent->get(MDSCacheObject::PIN_LOCK);
++num_wrlock;
}
pi->version = in->pre_dirty();
pi->max_size = new_max;
EOpen *le = new EOpen(mds->mdlog);
- predirty_nested(mut, &le->metablob, in);
+ predirty_nested(mut, &le->metablob, in, false);
le->metablob.add_dir_context(in->get_parent_dir());
le->metablob.add_primary_dentry(in->parent, true, 0, pi);
le->add_ino(in->ino());
mut->ls->open_files.push_back(&in->xlist_open_file);
mds->mdlog->submit_entry(le, new C_Locker_FileUpdate_finish(this, in, mut, true));
- file_wrlock_start(&in->filelock, mut, forcewrlock); // wrlock for duration of journal
+ file_wrlock_force(&in->filelock, mut); // wrlock for duration of journal
return true;
}
}
Mutation *mut = new Mutation;
mut->ls = mds->mdlog->get_current_segment();
- file_wrlock_start(&in->filelock, mut); // wrlock for duration of journal
- predirty_nested(mut, &le->metablob, in);
+ file_wrlock_force(&in->filelock, mut); // wrlock for duration of journal
+ predirty_nested(mut, &le->metablob, in, false);
le->metablob.add_dir_context(in->get_parent_dir());
le->metablob.add_primary_dentry(in->parent, true, 0, pi);
mds->mdlog->submit_entry(le, new C_Locker_FileUpdate_finish(this, in, mut, change_max));
// nested ---------------------------------------------------------------
-void Locker::predirty_nested(Mutation *mut, EMetaBlob *blob, CInode *in)
+void Locker::predirty_nested(Mutation *mut, EMetaBlob *blob, CInode *in, bool parent_mtime)
{
CDir *parent = in->get_projected_parent_dn()->get_dir();
fnode_t *pf = parent->project_fnode();
pf->version = parent->pre_dirty();
+ if (parent_mtime) {
+ dout(10) << "predirty_nested updating mtime on " << *parent << dendl;
+ pf->mtime = rctime = mut->now;
+ }
pf->nested.rbytes += drbytes;
pf->nested.rfiles += drfiles;
pf->nested.rctime = rctime;
curi->accounted_nested.rfiles += drfiles;
curi->accounted_nested.rctime = rctime;
- // FIXME
- if (!pin->is_auth()) {
- assert(0);
+ if (!pin->is_auth())
break;
- }
// dirfrag -> diri
mut->add_projected_inode(pin);
version_t ppv = pin->pre_dirty();
inode_t *pi = pin->project_inode();
pi->version = ppv;
+ if (pf->mtime > pi->mtime)
+ pi->mtime = pf->mtime;
pi->nested.rbytes += drbytes;
pi->nested.rfiles += drfiles;
pi->nested.rctime = rctime;
+ pf->accounted_nested.rbytes += drbytes;
+ pf->accounted_nested.rfiles += drfiles;
+ pf->accounted_nested.rctime = rctime;
+
+ // next parent!
cur = pin;
curi = pi;
parent = cur->get_projected_parent_dn()->get_dir();
}
// now, stick it in the blob
+ assert(parent->is_auth());
blob->add_dir_context(parent);
+ blob->add_dir(parent, true);
+
for (list<CInode*>::iterator p = lsi.begin();
p != lsi.end();
p++) {
CInode *cur = *p;
inode_t *pi = cur->get_projected_inode();
- blob->add_primary_dentry(cur->get_parent_dn(), true, 0, pi);
+ blob->add_primary_dentry(cur->get_projected_parent_dn(), true, 0, pi);
}
}
return false;
}
-void Locker::scatter_rdlock_finish(ScatterLock *lock, MDRequest *mut)
+void Locker::scatter_rdlock_finish(ScatterLock *lock, Mutation *mut)
{
dout(7) << "scatter_rdlock_finish on " << *lock
<< " on " << *lock->get_parent() << dendl;
}
}
-void Locker::local_wrlock_finish(LocalLock *lock, MDRequest *mut)
+void Locker::local_wrlock_finish(LocalLock *lock, Mutation *mut)
{
dout(7) << "local_wrlock_finish on " << *lock
<< " on " << *lock->get_parent() << dendl;
return true;
}
-void Locker::local_xlock_finish(LocalLock *lock, MDRequest *mut)
+void Locker::local_xlock_finish(LocalLock *lock, Mutation *mut)
{
dout(7) << "local_xlock_finish on " << *lock
<< " on " << *lock->get_parent() << dendl;
-void Locker::file_rdlock_finish(FileLock *lock, MDRequest *mut)
+void Locker::file_rdlock_finish(FileLock *lock, Mutation *mut)
{
dout(7) << "rdlock_finish on " << *lock << " on " << *lock->get_parent() << dendl;
}
}
-bool Locker::file_wrlock_start(FileLock *lock, MDRequest *mut, bool force)
+bool Locker::file_wrlock_force(FileLock *lock, Mutation *mut)
{
- dout(7) << "file_wrlock_start on " << *lock
+ dout(7) << "file_wrlock_force on " << *lock
<< " on " << *lock->get_parent() << dendl;
- assert(force || lock->can_wrlock());
- lock->get_wrlock();
+ lock->get_wrlock(true);
mut->wrlocks.insert(lock);
mut->locks.insert(lock);
return true;
}
-void Locker::file_xlock_finish(FileLock *lock, MDRequest *mut)
+void Locker::file_xlock_finish(FileLock *lock, Mutation *mut)
{
dout(7) << "file_xlock_finish on " << *lock << " on " << *lock->get_parent() << dendl;
void scatter_writebehind_finish(ScatterLock *lock, LogSegment *ls);
public:
- void predirty_nested(Mutation *mut, EMetaBlob *blob, CInode *in);
+ void predirty_nested(Mutation *mut, EMetaBlob *blob, CInode *in, bool parent_mtime);
// local
protected:
bool file_rdlock_try(FileLock *lock, Context *con);
bool file_rdlock_start(FileLock *lock, MDRequest *mut);
void file_rdlock_finish(FileLock *lock, Mutation *mut);
- bool file_wrlock_start(FileLock *lock, MDRequest *mut, bool force=false);
- void file_wrlock_finish(FileLock *lock);
+ bool file_wrlock_force(FileLock *lock, Mutation *mut);
+ void file_wrlock_finish(FileLock *lock, Mutation *mut);
bool file_xlock_start(FileLock *lock, MDRequest *mut);
void file_xlock_finish(FileLock *lock, Mutation *mut);
};
struct Mutation {
+ metareqid_t reqid;
LogSegment *ls; // the log segment i'm committing to
utime_t now;
list<CDir*> projected_fnodes;
Mutation() : ls(0),
- done_locking(false), committing(false), aborted(false)
- {}
+ done_locking(false), committing(false), aborted(false) {}
+ Mutation(metareqid_t ri) : reqid(ri),
+ ls(0),
+ done_locking(false), committing(false), aborted(false) {}
+ virtual ~Mutation() {}
// pin items in cache
void pin(MDSCacheObject *o) {
}
}
+ void apply() {
+ pop_and_dirty_projected_inodes();
+ pop_and_dirty_projected_fnodes();
+ }
+
virtual void print(ostream &out) {
out << "mutation(" << this << ")";
}
* the request is finished or forwarded. see request_*().
*/
struct MDRequest : public Mutation {
- metareqid_t reqid;
Session *session;
// -- i am a client (master) request
slave_request(0), slave_to_mds(-1),
_more(0) {}
MDRequest(metareqid_t ri, MClientRequest *req) :
- reqid(ri), session(0), client_request(req), ref(0),
+ Mutation(ri),
+ session(0), client_request(req), ref(0),
slave_request(0), slave_to_mds(-1),
_more(0) {}
MDRequest(metareqid_t ri, int by) :
- reqid(ri), session(0), client_request(0), ref(0),
+ Mutation(ri),
+ session(0), client_request(0), ref(0),
slave_request(0), slave_to_mds(by),
_more(0) {}
~MDRequest() {
MDRequest *mdr;
CDentry *dn;
CInode *newi;
- version_t dirpv;
- version_t newdirpv;
public:
- C_MDS_mknod_finish(MDS *m, MDRequest *r, CDentry *d, CInode *ni, version_t dirpv_, version_t newdirpv_=0) :
- mds(m), mdr(r), dn(d), newi(ni),
- dirpv(dirpv_), newdirpv(newdirpv_) {}
+ C_MDS_mknod_finish(MDS *m, MDRequest *r, CDentry *d, CInode *ni) :
+ mds(m), mdr(r), dn(d), newi(ni) {}
void finish(int r) {
assert(r == 0);
newi->mark_dirty(newi->inode.version + 1, mdr->ls);
// mkdir?
- if (newdirpv) {
+ if (newi->inode.is_dir()) {
CDir *dir = newi->get_dirfrag(frag_t());
assert(dir);
- dir->mark_dirty(newdirpv, mdr->ls);
+ dir->mark_dirty(1, mdr->ls);
}
- // dir inode's mtime
- mds->server->dirty_dn_diri(mdr, dn, dirpv);
- mdr->pop_and_dirty_projected_inodes();
- mdr->pop_and_dirty_projected_fnodes();
+ mdr->apply();
// hit pop
mds->balancer->hit_inode(mdr->now, newi, META_POP_IWR);
EUpdate *le = new EUpdate(mdlog, "mknod");
le->metablob.add_client_req(req->get_reqid());
le->metablob.add_allocated_ino(newi->ino(), mds->idalloc->get_version());
- mds->locker->predirty_nested(mdr, &le->metablob, newi);
- version_t dirpv = predirty_dn_diri(mdr, dn, &le->metablob); // dir mtime too
- le->metablob.add_dir_context(dn->dir);
+
+ mds->locker->predirty_nested(mdr, &le->metablob, newi, true);
+ //version_t dirpv = predirty_dn_diri(mdr, dn, &le->metablob); // dir mtime too
+
le->metablob.add_primary_dentry(dn, true, newi, &newi->inode);
// log + wait
- mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi, dirpv));
+ mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi));
}
// ...and that new dir is empty.
CDir *newdir = newi->get_or_open_dirfrag(mds->mdcache, frag_t());
newdir->mark_complete();
- version_t newdirpv = newdir->pre_dirty();
+ newdir->pre_dirty();
//if (mds->logger) mds->logger->inc("mkdir");
EUpdate *le = new EUpdate(mdlog, "mkdir");
le->metablob.add_client_req(req->get_reqid());
le->metablob.add_allocated_ino(newi->ino(), mds->idalloc->get_version());
- version_t dirpv = predirty_dn_diri(mdr, dn, &le->metablob); // dir mtime too
- le->metablob.add_dir_context(dn->dir);
- mds->locker->predirty_nested(mdr, &le->metablob, newi);
+ mds->locker->predirty_nested(mdr, &le->metablob, newi, true);
le->metablob.add_primary_dentry(dn, true, newi, &newi->inode);
le->metablob.add_dir(newdir, true, true); // dirty AND complete
// log + wait
- mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi, dirpv, newdirpv));
+ mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi));
/* old export heuristic. pbly need to reimplement this at some point.
if (
EUpdate *le = new EUpdate(mdlog, "symlink");
le->metablob.add_client_req(req->get_reqid());
le->metablob.add_allocated_ino(newi->ino(), mds->idalloc->get_version());
- version_t dirpv = predirty_dn_diri(mdr, dn, &le->metablob); // dir mtime too
- le->metablob.add_dir_context(dn->dir);
- mds->locker->predirty_nested(mdr, &le->metablob, newi);
+ mds->locker->predirty_nested(mdr, &le->metablob, newi, true);
le->metablob.add_primary_dentry(dn, true, newi, &newi->inode);
// log + wait
- mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi, dirpv));
+ mdlog->submit_entry(le, new C_MDS_mknod_finish(mds, mdr, dn, newi));
}