void PurgeItem::encode(bufferlist &bl) const
{
ENCODE_START(1, 1, bl);
+ ::encode((uint8_t)action, bl);
::encode(ino, bl);
::encode(size, bl);
::encode(layout, bl, CEPH_FEATURE_FS_FILE_LAYOUT_V2);
::encode(old_pools, bl);
::encode(snapc, bl);
+ ::encode(fragtree, bl);
ENCODE_FINISH(bl);
}
void PurgeItem::decode(bufferlist::iterator &p)
{
DECODE_START(1, p);
+ ::decode((uint8_t&)action, p);
::decode(ino, p);
::decode(size, p);
::decode(layout, p);
::decode(old_pools, p);
::decode(snapc, p);
+ ::decode(fragtree, p);
DECODE_FINISH(p);
}
journaler.write_head(fin);
}
+/**
+ * The `completion` context will always be called back via a Finisher
+ */
void PurgeQueue::push(const PurgeItem &pi, Context *completion)
{
dout(4) << "pushing inode 0x" << std::hex << pi.ino << std::dec << dendl;
in_flight[expire_to] = item;
- // TODO: handle things other than normal file purges
- // (directories, snapshot truncates)
+ SnapContext nullsnapc;
+
C_GatherBuilder gather(cct);
- if (item.size > 0) {
- uint64_t num = Striper::get_num_objects(item.layout, item.size);
- dout(10) << " 0~" << item.size << " objects 0~" << num
- << " snapc " << item.snapc << " on " << item.ino << dendl;
- filer.purge_range(item.ino, &item.layout, item.snapc,
- 0, num, ceph::real_clock::now(), 0,
- gather.new_sub());
- }
+ if (item.action == PurgeItem::PURGE_FILE) {
+ if (item.size > 0) {
+ uint64_t num = Striper::get_num_objects(item.layout, item.size);
+ dout(10) << " 0~" << item.size << " objects 0~" << num
+ << " snapc " << item.snapc << " on " << item.ino << dendl;
+ filer.purge_range(item.ino, &item.layout, item.snapc,
+ 0, num, ceph::real_clock::now(), 0,
+ gather.new_sub());
+ }
- // remove the backtrace object if it was not purged
- object_t oid = CInode::get_object_name(item.ino, frag_t(), "");
- if (!gather.has_subs() || !item.layout.pool_ns.empty()) {
- object_locator_t oloc(item.layout.pool_id);
- dout(10) << " remove backtrace object " << oid
- << " pool " << oloc.pool << " snapc " << item.snapc << dendl;
- objecter->remove(oid, oloc, item.snapc,
- ceph::real_clock::now(), 0,
- NULL, gather.new_sub());
- }
+ // remove the backtrace object if it was not purged
+ object_t oid = CInode::get_object_name(item.ino, frag_t(), "");
+ if (!gather.has_subs() || !item.layout.pool_ns.empty()) {
+ object_locator_t oloc(item.layout.pool_id);
+ dout(10) << " remove backtrace object " << oid
+ << " pool " << oloc.pool << " snapc " << item.snapc << dendl;
+ objecter->remove(oid, oloc, item.snapc,
+ ceph::real_clock::now(), 0,
+ NULL, gather.new_sub());
+ }
- // remove old backtrace objects
- for (const auto &p : item.old_pools) {
- object_locator_t oloc(p);
- dout(10) << " remove backtrace object " << oid
- << " old pool " << p << " snapc " << item.snapc << dendl;
- objecter->remove(oid, oloc, item.snapc,
- ceph::real_clock::now(), 0,
- NULL, gather.new_sub());
+ // remove old backtrace objects
+ for (const auto &p : item.old_pools) {
+ object_locator_t oloc(p);
+ dout(10) << " remove backtrace object " << oid
+ << " old pool " << p << " snapc " << item.snapc << dendl;
+ objecter->remove(oid, oloc, item.snapc,
+ ceph::real_clock::now(), 0,
+ NULL, gather.new_sub());
+ }
+ } else if (item.action == PurgeItem::PURGE_DIR) {
+ object_locator_t oloc(metadata_pool);
+ std::list<frag_t> frags;
+ if (!item.fragtree.is_leaf(frag_t()))
+ item.fragtree.get_leaves(frags);
+ frags.push_back(frag_t());
+ for (const auto &frag : frags) {
+ object_t oid = CInode::get_object_name(item.ino, frag, "");
+ dout(10) << " remove dirfrag " << oid << dendl;
+ objecter->remove(oid, oloc, nullsnapc,
+ ceph::real_clock::now(),
+ 0, NULL, gather.new_sub());
+ }
+ } else if (item.action == PurgeItem::TRUNCATE_FILE) {
+ const uint64_t num = Striper::get_num_objects(item.layout, item.size);
+ dout(10) << " 0~" << item.size << " objects 0~" << num
+ << " snapc " << item.snapc << " on " << item.ino << dendl;
+
+ // keep backtrace object
+ if (num > 1) {
+ filer.purge_range(item.ino, &item.layout, item.snapc,
+ 1, num - 1, ceph::real_clock::now(),
+ 0, gather.new_sub());
+ }
+ filer.zero(item.ino, &item.layout, item.snapc,
+ 0, item.layout.object_size,
+ ceph::real_clock::now(),
+ 0, true, NULL, gather.new_sub());
+ } else {
+ derr << "Invalid item (action=" << item.action << ") in purge queue, "
+ "dropping it" << dendl;
+ in_flight.erase(expire_to);
+ return;
}
assert(gather.has_subs());
class PurgeItem
{
public:
+ enum Action : uint8_t {
+ NONE = 0,
+ PURGE_FILE = 1,
+ TRUNCATE_FILE,
+ PURGE_DIR
+ };
+
+ Action action;
inodeno_t ino;
uint64_t size;
file_layout_t layout;
compact_set<int64_t> old_pools;
SnapContext snapc;
+ fragtree_t fragtree;
PurgeItem()
- : ino(0), size(0)
+ : action(NONE), ino(0), size(0)
{}
void encode(bufferlist &bl) const;
#include "common/perf_counters.h"
-#include "osdc/Objecter.h"
-#include "osdc/Filer.h"
#include "mds/MDSRank.h"
#include "mds/MDCache.h"
#include "mds/MDLog.h"
// dir. on recovery, we'll need to re-eval all strays anyway.
SnapContext nullsnapc;
- C_GatherBuilder gather(
- g_ceph_context,
- new C_OnFinisher(new C_IO_PurgeStrayPurged(
- this, dn, false), mds->finisher));
+ PurgeItem item;
+ item.ino = in->inode.ino;
if (in->is_dir()) {
- object_locator_t oloc(mds->mdsmap->get_metadata_pool());
- std::list<frag_t> ls;
- if (!in->dirfragtree.is_leaf(frag_t()))
- in->dirfragtree.get_leaves(ls);
- ls.push_back(frag_t());
- for (std::list<frag_t>::iterator p = ls.begin();
- p != ls.end();
- ++p) {
- object_t oid = CInode::get_object_name(in->inode.ino, *p, "");
- dout(10) << __func__ << " remove dirfrag " << oid << dendl;
- mds->objecter->remove(oid, oloc, nullsnapc,
- ceph::real_clock::now(),
- 0, gather.new_sub());
- }
- assert(gather.has_subs());
- gather.activate();
- return;
- }
-
- const SnapContext *snapc;
- SnapRealm *realm = in->find_snaprealm();
- if (realm) {
- dout(10) << " realm " << *realm << dendl;
- snapc = &realm->get_snap_context();
+ item.action = PurgeItem::PURGE_DIR;
+ item.fragtree = in->dirfragtree;
} else {
- dout(10) << " NO realm, using null context" << dendl;
- snapc = &nullsnapc;
- assert(in->last == CEPH_NOSNAP);
- }
+ item.action = PurgeItem::PURGE_FILE;
- uint64_t to = 0;
- if (in->is_file()) {
- to = in->inode.get_max_size();
- to = MAX(in->inode.size, to);
- // when truncating a file, the filer does not delete stripe objects that are
- // truncated to zero. so we need to purge stripe objects up to the max size
- // the file has ever been.
- to = MAX(in->inode.max_size_ever, to);
- }
+ const SnapContext *snapc;
+ SnapRealm *realm = in->find_snaprealm();
+ if (realm) {
+ dout(10) << " realm " << *realm << dendl;
+ snapc = &realm->get_snap_context();
+ } else {
+ dout(10) << " NO realm, using null context" << dendl;
+ snapc = &nullsnapc;
+ assert(in->last == CEPH_NOSNAP);
+ }
- inode_t *pi = in->get_projected_inode();
+ uint64_t to = 0;
+ if (in->is_file()) {
+ to = in->inode.get_max_size();
+ to = MAX(in->inode.size, to);
+ // when truncating a file, the filer does not delete stripe objects that are
+ // truncated to zero. so we need to purge stripe objects up to the max size
+ // the file has ever been.
+ to = MAX(in->inode.max_size_ever, to);
+ }
- PurgeItem item;
- item.ino = in->inode.ino;
- item.size = to;
- item.layout = pi->layout;
- item.old_pools = pi->old_pools;
- item.snapc = *snapc;
+ inode_t *pi = in->get_projected_inode();
- purge_queue.push(item, gather.new_sub());
+ item.size = to;
+ item.layout = pi->layout;
+ item.old_pools = pi->old_pools;
+ item.snapc = *snapc;
+ }
- assert(gather.has_subs());
- gather.activate();
+ purge_queue.push(item, new C_IO_PurgeStrayPurged(
+ this, dn, false));
}
class C_PurgeStrayLogged : public StrayManagerLogContext {
: delayed_eval_stray(member_offset(CDentry, item_stray)),
mds(mds), logger(NULL), started(false), num_strays(0),
num_strays_delayed(0), num_strays_enqueuing(0),
- filer(mds->objecter, mds->finisher), purge_queue(purge_queue_)
+ purge_queue(purge_queue_)
{
assert(mds != NULL);
}
void StrayManager::truncate(CDentry *dn)
{
- CDentry::linkage_t *dnl = dn->get_projected_linkage();
- CInode *in = dnl->get_inode();
+ const CDentry::linkage_t *dnl = dn->get_projected_linkage();
+ const CInode *in = dnl->get_inode();
assert(in);
dout(10) << __func__ << ": " << *dn << " " << *in << dendl;
assert(!dn->is_replicated());
- C_GatherBuilder gather(
- g_ceph_context,
- new C_OnFinisher(new C_IO_PurgeStrayPurged(this, dn, true),
- mds->finisher));
-
- SnapRealm *realm = in->find_snaprealm();
+ const SnapRealm *realm = in->find_snaprealm();
assert(realm);
dout(10) << " realm " << *realm << dendl;
const SnapContext *snapc = &realm->get_snap_context();
// truncated to zero. so we need to purge stripe objects up to the max size
// the file has ever been.
to = MAX(in->inode.max_size_ever, to);
- if (to > 0) {
- uint64_t num = Striper::get_num_objects(in->inode.layout, to);
- dout(10) << __func__ << " 0~" << to << " objects 0~" << num
- << " snapc " << snapc << " on " << *in << dendl;
-
- // keep backtrace object
- if (num > 1) {
- filer.purge_range(in->ino(), &in->inode.layout, *snapc,
- 1, num - 1, ceph::real_clock::now(),
- 0, gather.new_sub());
- }
- filer.zero(in->ino(), &in->inode.layout, *snapc,
- 0, in->inode.layout.object_size,
- ceph::real_clock::now(),
- 0, true, gather.new_sub());
- }
- assert(gather.has_subs());
- gather.activate();
+ assert(to > 0);
+
+ PurgeItem item;
+ item.ino = in->inode.ino;
+ item.layout = in->inode.layout;
+ item.snapc = *snapc;
+ item.size = to;
+
+ purge_queue.push(item, new C_IO_PurgeStrayPurged(
+ this, dn, true));
}
void StrayManager::_truncate_stray_logged(CDentry *dn, LogSegment *ls)
#include "include/elist.h"
#include <list>
-#include "osdc/Filer.h"
#include "mds/PurgeQueue.h"
class MDSRank;
// recorded by PurgeQueue yet
uint64_t num_strays_enqueuing;
- Filer filer;
-
PurgeQueue &purge_queue;
void truncate(CDentry *dn);