Bug #5380 ยป 0001-osdc-re-calculate-truncate_size-for-strip-objects.patch
src/client/Client.cc | ||
---|---|---|
<< truncate_size << dendl;
|
||
in->truncate_size = truncate_size;
|
||
in->oset.truncate_size = truncate_size;
|
||
objectcacher->recalc_truncate_size(&in->oset, &in->layout);
|
||
} else {
|
||
ldout(cct, 0) << "Hmmm, truncate_seq && truncate_size changed on non-file inode!" << dendl;
|
||
}
|
||
... | ... | |
// invalidate our userspace inode cache
|
||
if (cct->_conf->client_oc) {
|
||
vector<ObjectExtent> ls;
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, off, len, ls);
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, off, len, in->truncate_size, ls);
|
||
objectcacher->discard_set(&in->oset, ls);
|
||
}
|
||
... | ... | |
Inode *in = f->inode;
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, off, 1, extents);
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, off, 1, in->truncate_size, extents);
|
||
assert(extents.size() == 1);
|
||
pg_t pg = osdmap->object_locator_to_pg(extents[0].oid, extents[0].oloc);
|
||
... | ... | |
// which object?
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, offset, 1, extents);
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, offset, 1, in->truncate_size, extents);
|
||
assert(extents.size() == 1);
|
||
// now we have the object and its 'layout'
|
||
... | ... | |
Inode *in = f->inode;
|
||
// map to a list of extents
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, offset, length, result);
|
||
Striper::file_to_extents(cct, in->ino, &in->layout, offset, length, in->truncate_size, result);
|
||
ldout(cct, 3) << "enumerate_layout(" << fd << ", " << length << ", " << offset << ") = 0" << dendl;
|
||
return 0;
|
src/librbd/ImageCtx.cc | ||
---|---|---|
snap_lock.get_read();
|
||
ObjectCacher::OSDRead *rd = object_cacher->prepare_read(snap_id, bl, 0);
|
||
snap_lock.put_read();
|
||
ObjectExtent extent(o, 0 /* a lie */, off, len);
|
||
ObjectExtent extent(o, 0 /* a lie */, off, len, 0);
|
||
extent.oloc.pool = data_ctx.get_id();
|
||
extent.buffer_extents.push_back(make_pair(0, len));
|
||
rd->extents.push_back(extent);
|
||
... | ... | |
ObjectCacher::OSDWrite *wr = object_cacher->prepare_write(snapc, bl,
|
||
utime_t(), 0);
|
||
snap_lock.put_read();
|
||
ObjectExtent extent(o, 0, off, len);
|
||
ObjectExtent extent(o, 0, off, len, 0);
|
||
extent.oloc.pool = data_ctx.get_id();
|
||
extent.buffer_extents.push_back(make_pair(0, len));
|
||
wr->extents.push_back(extent);
|
src/librbd/internal.cc | ||
---|---|---|
if (delete_off > newsize) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
|
||
newsize, delete_off - newsize, extents);
|
||
newsize, delete_off - newsize, 0, extents);
|
||
for (vector<ObjectExtent>::iterator p = extents.begin();
|
||
p != extents.end(); ++p) {
|
||
... | ... | |
// map to extents
|
||
map<object_t,vector<ObjectExtent> > object_extents;
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
|
||
off, read_len, object_extents, 0);
|
||
off, read_len, 0, object_extents, 0);
|
||
// get snap info for each object
|
||
for (map<object_t,vector<ObjectExtent> >::iterator p = object_extents.begin();
|
||
... | ... | |
// map
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, mylen, extents);
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, mylen, 0, extents);
|
||
c->get();
|
||
c->init_time(ictx, AIO_TYPE_WRITE);
|
||
... | ... | |
// map
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, len, extents);
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout, off, len, 0, extents);
|
||
c->get();
|
||
c->init_time(ictx, AIO_TYPE_DISCARD);
|
||
... | ... | |
return r;
|
||
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
|
||
p->first, len, object_extents, buffer_ofs);
|
||
p->first, len, 0, object_extents, buffer_ofs);
|
||
buffer_ofs += len;
|
||
}
|
||
src/osd/osd_types.h | ||
---|---|---|
uint64_t objectno;
|
||
uint64_t offset; // in object
|
||
uint64_t length; // in object
|
||
uint64_t truncate_size; // in object
|
||
object_locator_t oloc; // object locator (pool etc)
|
||
vector<pair<uint64_t,uint64_t> > buffer_extents; // off -> len. extents in buffer being mapped (may be fragmented bc of striping!)
|
||
|
||
ObjectExtent() : objectno(0), offset(0), length(0) {}
|
||
ObjectExtent(object_t o, uint64_t ono, uint64_t off, uint64_t l) : oid(o), objectno(ono), offset(off), length(l) { }
|
||
ObjectExtent() : objectno(0), offset(0), length(0), truncate_size(0) {}
|
||
ObjectExtent(object_t o, uint64_t ono, uint64_t off, uint64_t l, uint64_t ts) :
|
||
oid(o), objectno(ono), offset(off), length(l), truncate_size(ts) { }
|
||
};
|
||
inline ostream& operator<<(ostream& out, const ObjectExtent &ex)
|
src/osdc/Filer.cc | ||
---|---|---|
probe->known_size.clear();
|
||
probe->probing.clear();
|
||
Striper::file_to_extents(cct, probe->ino, &probe->layout,
|
||
probe->probing_off, probe->probing_len, probe->probing);
|
||
probe->probing_off, probe->probing_len, 0, probe->probing);
|
||
|
||
for (vector<ObjectExtent>::iterator p = probe->probing.begin();
|
||
p != probe->probing.end();
|
src/osdc/Filer.h | ||
---|---|---|
Context *onfinish) {
|
||
assert(snap); // (until there is a non-NOSNAP write)
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents);
|
||
objecter->sg_read(extents, snap, bl, flags, onfinish);
|
||
return 0;
|
||
}
|
||
... | ... | |
Context *onfinish) {
|
||
assert(snap); // (until there is a non-NOSNAP write)
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, truncate_size, extents);
|
||
objecter->sg_read_trunc(extents, snap, bl, flags,
|
||
truncate_size, truncate_seq, onfinish);
|
||
return 0;
|
||
... | ... | |
Context *onack,
|
||
Context *oncommit) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents);
|
||
objecter->sg_write(extents, snapc, bl, mtime, flags, onack, oncommit);
|
||
return 0;
|
||
}
|
||
... | ... | |
Context *onack,
|
||
Context *oncommit) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, truncate_size, extents);
|
||
objecter->sg_write_trunc(extents, snapc, bl, mtime, flags,
|
||
truncate_size, truncate_seq, onack, oncommit);
|
||
return 0;
|
||
... | ... | |
Context *onack,
|
||
Context *oncommit) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, offset, extents);
|
||
if (extents.size() == 1) {
|
||
vector<OSDOp> ops(1);
|
||
ops[0].op.op = CEPH_OSD_OP_TRIMTRUNC;
|
||
... | ... | |
Context *onack,
|
||
Context *oncommit) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, ino, layout, offset, len, offset, extents);
|
||
if (extents.size() == 1) {
|
||
if (extents[0].offset == 0 && extents[0].length == layout->fl_object_size)
|
||
objecter->remove(extents[0].oid, extents[0].oloc,
|
src/osdc/ObjectCacher.cc | ||
---|---|---|
/* private */
|
||
ObjectCacher::Object *ObjectCacher::get_object(sobject_t oid, ObjectSet *oset,
|
||
object_locator_t &l)
|
||
object_locator_t &l, uint64_t ts)
|
||
{
|
||
assert(lock.is_locked());
|
||
// have it?
|
||
... | ... | |
}
|
||
// create it.
|
||
Object *o = new Object(this, oid, oset, l);
|
||
Object *o = new Object(this, oid, oset, l, ts);
|
||
objects[l.pool][oid] = o;
|
||
ob_lru.lru_insert_top(o);
|
||
return o;
|
||
... | ... | |
// go
|
||
writeback_handler.read(bh->ob->get_oid(), bh->ob->get_oloc(),
|
||
bh->start(), bh->length(), bh->ob->get_snap(),
|
||
&onfinish->bl, oset->truncate_size, oset->truncate_seq,
|
||
&onfinish->bl, bh->ob->truncate_size, oset->truncate_seq,
|
||
onfinish);
|
||
++reads_outstanding;
|
||
}
|
||
... | ... | |
tid_t tid = writeback_handler.write(bh->ob->get_oid(), bh->ob->get_oloc(),
|
||
bh->start(), bh->length(),
|
||
bh->snapc, bh->bl, bh->last_write,
|
||
oset->truncate_size, oset->truncate_seq,
|
||
bh->ob->truncate_size, oset->truncate_seq,
|
||
oncommit);
|
||
ldout(cct, 20) << " tid " << tid << " on " << bh->ob->get_oid() << dendl;
|
||
... | ... | |
// get Object cache
|
||
sobject_t soid(ex_it->oid, rd->snap);
|
||
Object *o = get_object(soid, oset, ex_it->oloc);
|
||
Object *o = get_object(soid, oset, ex_it->oloc, ex_it->truncate_size);
|
||
touch_ob(o);
|
||
// does not exist and no hits?
|
||
... | ... | |
++ex_it) {
|
||
// get object cache
|
||
sobject_t soid(ex_it->oid, CEPH_NOSNAP);
|
||
Object *o = get_object(soid, oset, ex_it->oloc);
|
||
Object *o = get_object(soid, oset, ex_it->oloc, ex_it->truncate_size);
|
||
// map it all into a single bufferhead.
|
||
BufferHead *bh = o->map_write(wr);
|
||
... | ... | |
flush_set_callback(flush_set_callback_arg, oset);
|
||
}
|
||
void ObjectCacher::recalc_truncate_size(ObjectSet *oset, ceph_file_layout *layout)
|
||
{
|
||
assert(lock.is_locked());
|
||
ldout(cct, 10) << "recalc_truncate_size " << oset << dendl;
|
||
if (objects.size() <= (uint32_t)oset->poolid)
|
||
return;
|
||
for (hash_map<sobject_t, Object*>::iterator p = objects[oset->poolid].begin();
|
||
p != objects[oset->poolid].end();
|
||
++p) {
|
||
if (p->first.snap != CEPH_NOSNAP)
|
||
continue;
|
||
p->second->truncate_size = Striper::object_truncate_size(cct, layout, p->first.oid,
|
||
oset->truncate_size);
|
||
}
|
||
}
|
||
void ObjectCacher::verify_stats() const
|
||
{
|
||
assert(lock.is_locked());
|
src/osdc/ObjectCacher.h | ||
---|---|---|
ObjectSet *oset;
|
||
xlist<Object*>::item set_item;
|
||
object_locator_t oloc;
|
||
uint64_t truncate_size;
|
||
|
||
bool complete;
|
||
bool exists;
|
||
... | ... | |
Object(const Object& other);
|
||
const Object& operator=(const Object& other);
|
||
Object(ObjectCacher *_oc, sobject_t o, ObjectSet *os, object_locator_t& l) :
|
||
Object(ObjectCacher *_oc, sobject_t o, ObjectSet *os, object_locator_t& l, uint64_t ts) :
|
||
ref(0),
|
||
oc(_oc),
|
||
oid(o), oset(os), set_item(this), oloc(l),
|
||
oid(o), oset(os), set_item(this), oloc(l), truncate_size(ts),
|
||
complete(false), exists(true),
|
||
last_write_tid(0), last_commit_tid(0),
|
||
dirty_or_tx(0) {
|
||
... | ... | |
}
|
||
Object *get_object(sobject_t oid, ObjectSet *oset,
|
||
object_locator_t &l);
|
||
object_locator_t &l, uint64_t ts);
|
||
void close_object(Object *ob);
|
||
// bh stats
|
||
... | ... | |
// file functions
|
||
void recalc_truncate_size(ObjectSet *oset, ceph_file_layout *layout);
|
||
/*** async+caching (non-blocking) file interface ***/
|
||
int file_is_cached(ObjectSet *oset, ceph_file_layout *layout, snapid_t snapid,
|
||
loff_t offset, uint64_t len) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, extents);
|
||
return is_cached(oset, extents, snapid);
|
||
}
|
||
... | ... | |
int flags,
|
||
Context *onfinish) {
|
||
OSDRead *rd = prepare_read(snapid, bl, flags);
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, rd->extents);
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, rd->extents);
|
||
return readx(rd, oset, onfinish);
|
||
}
|
||
... | ... | |
bufferlist& bl, utime_t mtime, int flags,
|
||
Mutex& wait_on_lock) {
|
||
OSDWrite *wr = prepare_write(snapc, bl, mtime, flags);
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, wr->extents);
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, wr->extents);
|
||
return writex(wr, oset, wait_on_lock, NULL);
|
||
}
|
||
bool file_flush(ObjectSet *oset, ceph_file_layout *layout, const SnapContext& snapc,
|
||
loff_t offset, uint64_t len, Context *onfinish) {
|
||
vector<ObjectExtent> extents;
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, extents);
|
||
Striper::file_to_extents(cct, oset->ino, layout, offset, len, oset->truncate_size, extents);
|
||
return flush_set(oset, extents, onfinish);
|
||
}
|
||
};
|
src/osdc/Objecter.h | ||
---|---|---|
uint64_t trunc_size, __u32 trunc_seq, Context *onfinish) {
|
||
if (extents.size() == 1) {
|
||
read_trunc(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length,
|
||
snap, bl, flags, trunc_size, trunc_seq, onfinish);
|
||
snap, bl, flags, extents[0].truncate_size, trunc_seq, onfinish);
|
||
} else {
|
||
C_GatherBuilder gather(cct);
|
||
vector<bufferlist> resultbl(extents.size());
|
||
int i=0;
|
||
for (vector<ObjectExtent>::iterator p = extents.begin(); p != extents.end(); ++p) {
|
||
read_trunc(p->oid, p->oloc, p->offset, p->length,
|
||
snap, &resultbl[i++], flags, trunc_size, trunc_seq, gather.new_sub());
|
||
snap, &resultbl[i++], flags, p->truncate_size, trunc_seq, gather.new_sub());
|
||
}
|
||
gather.set_finisher(new C_SGRead(this, extents, resultbl, bl, onfinish));
|
||
gather.activate();
|
||
... | ... | |
Context *onack, Context *oncommit) {
|
||
if (extents.size() == 1) {
|
||
write_trunc(extents[0].oid, extents[0].oloc, extents[0].offset, extents[0].length,
|
||
snapc, bl, mtime, flags, trunc_size, trunc_seq, onack, oncommit);
|
||
snapc, bl, mtime, flags, extents[0].truncate_size, trunc_seq, onack, oncommit);
|
||
} else {
|
||
C_GatherBuilder gack(cct, onack);
|
||
C_GatherBuilder gcom(cct, oncommit);
|
||
... | ... | |
bl.copy(bit->first, bit->second, cur);
|
||
assert(cur.length() == p->length);
|
||
write_trunc(p->oid, p->oloc, p->offset, p->length,
|
||
snapc, cur, mtime, flags, trunc_size, trunc_seq,
|
||
snapc, cur, mtime, flags, p->truncate_size, trunc_seq,
|
||
onack ? gack.new_sub():0,
|
||
oncommit ? gcom.new_sub():0);
|
||
}
|
src/osdc/Striper.cc | ||
---|---|---|
void Striper::file_to_extents(CephContext *cct, const char *object_format,
|
||
ceph_file_layout *layout,
|
||
uint64_t offset, uint64_t len,
|
||
uint64_t offset, uint64_t len, uint64_t trunc_size,
|
||
vector<ObjectExtent>& extents,
|
||
uint64_t buffer_offset)
|
||
{
|
||
map<object_t,vector<ObjectExtent> > object_extents;
|
||
file_to_extents(cct, object_format, layout, offset, len, object_extents, buffer_offset);
|
||
file_to_extents(cct, object_format, layout, offset, len, trunc_size,
|
||
object_extents, buffer_offset);
|
||
assimilate_extents(object_extents, extents);
|
||
}
|
||
void Striper::file_to_extents(CephContext *cct, const char *object_format,
|
||
ceph_file_layout *layout,
|
||
uint64_t offset, uint64_t len,
|
||
uint64_t offset, uint64_t len, uint64_t trunc_size,
|
||
map<object_t,vector<ObjectExtent> >& object_extents,
|
||
uint64_t buffer_offset)
|
||
{
|
||
... | ... | |
ex->offset = x_offset;
|
||
ex->length = x_len;
|
||
ex->truncate_size = object_truncate_size(cct, layout, objectno, trunc_size);
|
||
ldout(cct, 20) << " added new " << *ex << dendl;
|
||
} else {
|
||
// add to extent
|
||
... | ... | |
}
|
||
}
|
||
uint64_t Striper::object_truncate_size(CephContext *cct, ceph_file_layout *layout,
|
||
uint64_t objectno, uint64_t trunc_size)
|
||
{
|
||
uint64_t obj_trunc_size;
|
||
if (trunc_size == 0 || trunc_size == (uint64_t)-1) {
|
||
obj_trunc_size = trunc_size;
|
||
} else {
|
||
__u32 object_size = layout->fl_object_size;
|
||
__u32 su = layout->fl_stripe_unit;
|
||
__u32 stripe_count = layout->fl_stripe_count;
|
||
assert(object_size >= su);
|
||
uint64_t stripes_per_object = object_size / su;
|
||
uint64_t objectsetno = objectno / stripe_count;
|
||
uint64_t trunc_objectsetno = trunc_size / object_size / stripe_count;
|
||
if (objectsetno > trunc_objectsetno)
|
||
obj_trunc_size = 0;
|
||
else if (objectsetno < trunc_objectsetno)
|
||
obj_trunc_size = object_size;
|
||
else {
|
||
uint64_t trunc_blockno = trunc_size / su;
|
||
uint64_t trunc_stripeno = trunc_blockno / stripe_count;
|
||
uint64_t trunc_stripepos = trunc_blockno % stripe_count;
|
||
uint64_t trunc_objectno = trunc_objectsetno * stripe_count + trunc_stripepos;
|
||
if (objectno < trunc_objectno)
|
||
obj_trunc_size = ((trunc_stripeno % stripes_per_object) + 1) * su;
|
||
else if (objectno > trunc_objectno)
|
||
obj_trunc_size = (trunc_stripeno % stripes_per_object) * su;
|
||
else
|
||
obj_trunc_size = (trunc_stripeno % stripes_per_object) * su + (trunc_size % su);
|
||
}
|
||
}
|
||
ldout(cct, 20) << "object_truncate_size " << objectno << " "
|
||
<< trunc_size << "->" << obj_trunc_size << dendl;
|
||
return obj_trunc_size;
|
||
}
|
||
// StripedReadResult
|
||
src/osdc/Striper.h | ||
---|---|---|
*/
|
||
static void file_to_extents(CephContext *cct, const char *object_format,
|
||
ceph_file_layout *layout,
|
||
uint64_t offset, uint64_t len,
|
||
uint64_t offset, uint64_t len, uint64_t trunc_size,
|
||
map<object_t, vector<ObjectExtent> >& extents,
|
||
uint64_t buffer_offset=0);
|
||
static void file_to_extents(CephContext *cct, const char *object_format,
|
||
ceph_file_layout *layout,
|
||
uint64_t offset, uint64_t len,
|
||
uint64_t offset, uint64_t len, uint64_t trunc_size,
|
||
vector<ObjectExtent>& extents,
|
||
uint64_t buffer_offset=0);
|
||
static void file_to_extents(CephContext *cct, inodeno_t ino,
|
||
ceph_file_layout *layout,
|
||
uint64_t offset, uint64_t len,
|
||
uint64_t offset, uint64_t len, uint64_t trunc_size,
|
||
vector<ObjectExtent>& extents) {
|
||
// generate prefix/format
|
||
char buf[32];
|
||
snprintf(buf, sizeof(buf), "%llx.%%08llx", (long long unsigned)ino);
|
||
file_to_extents(cct, buf, layout, offset, len, extents);
|
||
file_to_extents(cct, buf, layout, offset, len, trunc_size, extents);
|
||
}
|
||
static void assimilate_extents(map<object_t,vector<ObjectExtent> >& object_extents,
|
||
... | ... | |
uint64_t objectno, uint64_t off, uint64_t len,
|
||
vector<pair<uint64_t, uint64_t> >& extents);
|
||
static uint64_t object_truncate_size(CephContext *cct, ceph_file_layout *layout,
|
||
uint64_t objectno, uint64_t trunc_size);
|
||
static uint64_t object_truncate_size(CephContext *cct, ceph_file_layout *layout,
|
||
object_t oid, uint64_t trunc_size) {
|
||
uint64_t ino, objectno;
|
||
sscanf(oid.name.c_str(), "%llx.%08llx",
|
||
(long long unsigned*)&ino, (long long unsigned*)&objectno);
|
||
return object_truncate_size(cct, layout, objectno, trunc_size);
|
||
}
|
||
/*
|
||
* helper to assemble a striped result
|
||
*/
|
src/test/test_striper.cc | ||
---|---|---|
l.fl_stripe_count = 3;
|
||
vector<ObjectExtent> ex;
|
||
Striper::file_to_extents(g_ceph_context, 1, &l, 5006035, 46419, ex);
|
||
Striper::file_to_extents(g_ceph_context, 1, &l, 5006035, 46419, 5006035, ex);
|
||
cout << "result " << ex << std::endl;
|
||
ASSERT_EQ(3u, ex.size());
|
||
ASSERT_EQ(98304u, ex[0].truncate_size);
|
||
ASSERT_EQ(ex[1].offset, ex[1].truncate_size);
|
||
ASSERT_EQ(94208u, ex[2].truncate_size);
|
||
}
|
||