void CInode::pre_cow_old_inode()
{
- snapid_t follows = find_snaprealm()->get_latest_snap();
+ snapid_t follows = find_snaprealm()->get_newest_snap();
if (first <= follows)
cow_old_inode(follows, get_projected_inode());
}
CInode *in = dn->inode;
if (follows == CEPH_NOSNAP || follows == 0)
- follows = in->find_snaprealm()->get_latest_snap();
+ follows = in->find_snaprealm()->get_newest_snap();
// already cloned?
if (follows < in->first)
}
} else {
if (follows == CEPH_NOSNAP)
- follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+ follows = dn->dir->inode->find_snaprealm()->get_newest_snap();
// already cloned?
if (follows < dn->first)
// rstat
if (primary_dn) {
SnapRealm *prealm = parent->inode->find_snaprealm();
- snapid_t latest = prealm->get_latest_snap();
+ snapid_t latest = prealm->get_newest_snap();
snapid_t follows = cfollows;
if (follows == CEPH_NOSNAP || follows == 0)
dout(10) << "traverse: snapdir" << dendl;
snapid = CEPH_SNAPDIR;
depth++;
- assert(psnapdiri);
+ if (!psnapdiri)
+ return -EINVAL;
*psnapdiri = cur;
continue;
}
rdlocks.insert(&dn->lock); // existing dn, rdlock
wrlocks.insert(&dn->dir->inode->dirlock); // also, wrlock on dir mtime
wrlocks.insert(&dn->dir->inode->nestlock); // also, wrlock on dir mtime
- mds->locker->include_snap_rdlocks(rdlocks, mdr->ref);
+ mds->locker->include_snap_rdlocks(rdlocks, dn->dir->inode);
if (!mds->locker->acquire_locks(mdr, rdlocks, wrlocks, xlocks))
return 0;
CDentry *dn = rdlock_path_xlock_dentry(mdr, false, false);
if (!dn) return;
- snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_last_created();
mdr->now = g_clock.real_now();
CInode *newi = prepare_new_inode(mdr, dn->dir);
if (!dn) return;
// new inode
- snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_last_created();
mdr->now = g_clock.real_now();
CInode *newi = prepare_new_inode(mdr, dn->dir);
if (!dn) return;
mdr->now = g_clock.real_now();
- snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_last_created();
CInode *newi = prepare_new_inode(mdr, dn->dir);
assert(newi);
pi->ctime = mdr->now;
pi->version = tipv;
- snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_last_created();
dn->first = follows+1;
// log + wait
if (!destdn->is_null())
mdcache->journal_cow_dentry(metablob, destdn);
else
- destdn->first = destdn->dir->inode->find_snaprealm()->get_latest_snap()+1;
+ destdn->first = destdn->dir->inode->find_snaprealm()->get_last_created()+1;
metablob->add_remote_dentry(destdn, true, srcdn->get_remote_ino(), srcdn->get_remote_d_type());
mdcache->journal_cow_dentry(metablob, srcdn->inode->get_parent_dn());
ji = metablob->add_primary_dentry(srcdn->inode->get_parent_dn(), true, srcdn->inode, pi);
if (!destdn->is_null())
mdcache->journal_cow_dentry(metablob, destdn);
else
- destdn->first = destdn->dir->inode->find_snaprealm()->get_latest_snap()+1;
+ destdn->first = destdn->dir->inode->find_snaprealm()->get_last_created()+1;
metablob->add_primary_dentry(destdn, true, destdn->inode, pi);
}
} else if (srcdn->is_primary()) {
// project snap parent update?
bufferlist snapbl;
- if (destdn->is_auth() && srcdn->inode->snaprealm) {
+ if (!srcdn->inode->snaprealm)
+ srcdn->inode->open_snaprealm();
+ if (destdn->is_auth()) {
SnapRealm *realm = srcdn->inode->snaprealm;
- snapid_t oldlast = realm->parent->get_latest_snap();
- snapid_t newlast = destdn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t oldlast = realm->parent->get_newest_snap();
+ snapid_t newlast = destdn->dir->inode->find_snaprealm()->get_last_created();
snapid_t first = realm->current_parent_since;
snapid_t old_since = realm->current_parent_since;
if (!destdn->is_null())
mdcache->journal_cow_dentry(metablob, destdn);
else
- destdn->first = destdn->dir->inode->find_snaprealm()->get_latest_snap()+1;
+ destdn->first = destdn->dir->inode->find_snaprealm()->get_last_created()+1;
ji = metablob->add_primary_dentry(destdn, true, srcdn->inode, pi, 0, &snapbl);
}
destdn->inode->pop_and_dirty_projected_inode(mdr->ls);
// snap parent update?
- if (destdn->is_auth() && destdn->inode->snaprealm) {
+ if (destdn->inode->is_dir()) {
SnapRealm *realm = destdn->inode->snaprealm;
- snapid_t oldlast = srcdn->dir->inode->find_snaprealm()->get_latest_snap();
- snapid_t newlast = destdn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t oldlast = srcdn->dir->inode->find_snaprealm()->get_newest_snap();
+ snapid_t newlast = destdn->dir->inode->find_snaprealm()->get_last_created();
snapid_t first = realm->current_parent_since;
if (oldlast >= realm->current_parent_since) {
// create inode.
mdr->now = g_clock.real_now();
- snapid_t follows = dn->dir->inode->find_snaprealm()->get_latest_snap();
+ snapid_t follows = dn->dir->inode->find_snaprealm()->get_last_created();
CInode *in = prepare_new_inode(mdr, dn->dir);
assert(in);
// project the snaprealm.. hack!
bufferlist snapbl;
snapid_t old_seq = diri->snaprealm->seq;
+ snapid_t old_lc = diri->snaprealm->last_created;
diri->snaprealm->snaps[snapid] = info;
diri->snaprealm->seq = snapid;
+ diri->snaprealm->last_created = snapid;
diri->encode_snap_blob(snapbl);
diri->snaprealm->snaps.erase(snapid);
diri->snaprealm->seq = old_seq;
+ diri->snaprealm->last_created = old_lc;
le->metablob.add_primary_dentry(diri->get_projected_parent_dn(), true, 0, pi, 0, &snapbl);
mdlog->submit_entry(le, new C_MDS_mksnap_finish(mds, mdr, diri, info));
snapid_t snapid = info.snapid;
diri->snaprealm->snaps[snapid] = info;
diri->snaprealm->seq = snapid;
+ diri->snaprealm->last_created = snapid;
dout(10) << "snaprealm now " << *diri->snaprealm << dendl;
bufferlist snapbl;
dout(10) << " " << realm << " open_children are " << realm->open_children << dendl;
for (set<SnapRealm*>::iterator p = realm->open_children.begin();
p != realm->open_children.end();
- p++)
+ p++) {
+ (*p)->invalidate_cached_snaps();
q.push_back(*p);
+ }
}
// send
* get list of snaps for this realm. we must include parents' snaps
* for the intervals during which they were our parent.
*/
-void SnapRealm::build_snap_set(set<snapid_t> &s, snapid_t first, snapid_t last)
+void SnapRealm::build_snap_set(set<snapid_t> &s,
+ snapid_t& max_seq, snapid_t& max_last_created,
+ snapid_t first, snapid_t last)
{
dout(10) << "build_snap_set [" << first << "," << last << "] on " << *this << dendl;
+ if (seq > max_seq)
+ max_seq = seq;
+ if (last_created > max_last_created)
+ max_last_created = last_created;
+
// include my snaps within interval [first,last]
for (map<snapid_t, SnapInfo>::iterator p = snaps.lower_bound(first); // first element >= first
p != snaps.end() && p->first <= last;
assert(oldparent->snaprealm);
snapid_t thru = MIN(last, p->first);
- oldparent->snaprealm->build_snap_set(s,
+ oldparent->snaprealm->build_snap_set(s, max_seq, max_last_created,
MAX(first, p->second.first),
thru);
}
if (current_parent_since <= last && parent)
- parent->build_snap_set(s, current_parent_since, last);
+ parent->build_snap_set(s, max_seq, max_last_created, current_parent_since, last);
}
/*
* build vector in reverse sorted order
*/
+void SnapRealm::check_cache()
+{
+ if (cached_seq >= seq)
+ return;
+
+ cached_snaps.clear();
+ cached_snap_vec.clear();
+ cached_last_created = last_created;
+ cached_seq = seq;
+ build_snap_set(cached_snaps, cached_seq, cached_last_created, 0, CEPH_NOSNAP);
+
+ dout(10) << "check_cache " << cached_snaps
+ << " seq " << seq
+ << " cached_seq " << cached_seq
+ << " cached_last_created " << cached_last_created << ")"
+ << dendl;
+}
+
const set<snapid_t>& SnapRealm::get_snaps()
{
- if (cached_snaps.empty() || cached_snaps_seq < seq) {
- cached_snaps.clear();
- cached_snap_vec.clear();
- build_snap_set(cached_snaps, 0, CEPH_NOSNAP);
-
- dout(10) << "get_snaps " << cached_snaps
- << " (seq " << seq << ")"
- << dendl;
- } else {
- dout(10) << "get_snaps " << cached_snaps
- << " (seq " << seq << ")"
- << " (cached)"
- << dendl;
- }
+ check_cache();
+ dout(10) << "get_snaps " << cached_snaps
+ << " (seq " << seq << " cached_seq " << cached_seq << ")"
+ << dendl;
return cached_snaps;
}
const vector<snapid_t>& SnapRealm::get_snap_vector()
{
- get_snaps();
+ check_cache();
if (cached_snap_vec.empty()) {
cached_snap_vec.resize(cached_snaps.size());
SnapRealmInfo info;
info.ino = inode->ino();
info.seq = seq;
+ info.parent_since = current_parent_since;
if (parent) {
info.parent = parent->inode->ino();
if (!past_parents.empty()) {
snapid_t last = past_parents.rbegin()->first;
set<snapid_t> past;
- build_snap_set(past, 0, last);
+ snapid_t max_seq, max_last_created;
+ build_snap_set(past, max_seq, max_last_created, 0, last);
info.prior_parent_snaps.reserve(past.size());
for (set<snapid_t>::reverse_iterator p = past.rbegin(); p != past.rend(); p++)
info.prior_parent_snaps.push_back(*p);
- info.parent_since = last+1;
dout(10) << "build_snap_trace prior_parent_snaps from [1," << last << "] "
<< info.prior_parent_snaps << dendl;
- } else
- info.parent_since = 1;
+ }
} else
info.parent = 0;
struct SnapRealm {
// realm state
- snapid_t created, seq;
+ snapid_t created; // when this realm was created.
+ snapid_t last_created; // last snap created in _this_ realm.
+ snapid_t seq; // basically, a version/seq # for changes to _this_ realm.
snapid_t current_parent_since;
map<snapid_t, SnapInfo> snaps;
map<snapid_t, snaplink_t> past_parents; // key is "last" (or NOSNAP)
void encode(bufferlist& bl) const {
::encode(created, bl);
+ ::encode(last_created, bl);
::encode(seq, bl);
::encode(current_parent_since, bl);
::encode(snaps, bl);
}
void decode(bufferlist::iterator& p) {
::decode(created, p);
+ ::decode(last_created, p);
::decode(seq, p);
::decode(current_parent_since, p);
::decode(snaps, p);
set<SnapRealm*> open_children; // active children that are currently open
map<snapid_t,SnapRealm*> open_past_parents; // these are explicitly pinned.
- // caches?
- snapid_t cached_snaps_seq;
+ // cache
+ snapid_t cached_seq; // max seq over self and all past+present parents.
+ snapid_t cached_last_created; // max last_created over all past+present parents
set<snapid_t> cached_snaps;
vector<snapid_t> cached_snap_vec;
map<int, xlist<Capability*> > client_caps; // to identify clients who need snap notifications
SnapRealm(MDCache *c, CInode *in) :
- created(0), seq(0),
+ created(0), last_created(0), seq(0),
current_parent_since(1),
mdcache(c), inode(in),
parent(0)
}
bool open_parents(MDRequest *mdr);
- void build_snap_set(set<snapid_t>& s, snapid_t first, snapid_t last);
+ void build_snap_set(set<snapid_t>& s,
+ snapid_t& max_seq, snapid_t& max_last_created,
+ snapid_t first, snapid_t last);
void get_snap_info(map<snapid_t,SnapInfo*>& infomap, snapid_t first=0, snapid_t last=CEPH_NOSNAP);
void build_snap_trace(bufferlist& snapbl);
const string& get_snapname(snapid_t snapid, inodeno_t atino);
snapid_t resolve_snapname(const string &name, inodeno_t atino, snapid_t first=0, snapid_t last=CEPH_NOSNAP);
+ void check_cache();
const set<snapid_t>& get_snaps();
const vector<snapid_t>& get_snap_vector();
- snapid_t get_latest_snap() {
- const set<snapid_t> &snaps = get_snaps();
- if (snaps.empty())
+ void invalidate_cached_snaps() {
+ cached_seq = 0;
+ }
+ snapid_t get_last_created() {
+ check_cache();
+ return cached_last_created;
+ }
+ snapid_t get_newest_snap() {
+ check_cache();
+ if (cached_snaps.empty())
return 0;
else
- return *snaps.rbegin();
+ return *cached_snaps.rbegin();
}
void change_open_parent_to(SnapRealm *newp) {
inline ostream& operator<<(ostream& out, const SnapRealm &realm) {
out << "snaprealm(seq " << realm.seq
+ << " lc " << realm.last_created
<< " snaps=" << realm.snaps;
if (realm.past_parents.size()) {
out << " past_parents=(";