class Transaction {
public:
// 这里有点类似于设计了一套指令。
enum {
OP_NOP = 0,
OP_TOUCH = 9, // cid, oid
OP_WRITE = 10, // cid, oid, offset, len, bl
OP_ZERO = 11, // cid, oid, offset, len
OP_TRUNCATE = 12, // cid, oid, len
OP_REMOVE = 13, // cid, oid
OP_SETATTR = 14, // cid, oid, attrname, bl
OP_SETATTRS = 15, // cid, oid, attrset
OP_RMATTR = 16, // cid, oid, attrname
OP_CLONE = 17, // cid, oid, newoid
OP_CLONERANGE = 18, // cid, oid, newoid, offset, len
OP_CLONERANGE2 = 30, // cid, oid, newoid, srcoff, len, dstoff
OP_TRIMCACHE = 19, // cid, oid, offset, len **DEPRECATED**
OP_MKCOLL = 20, // cid
OP_RMCOLL = 21, // cid
OP_COLL_ADD = 22, // cid, oldcid, oid
OP_COLL_REMOVE = 23, // cid, oid
OP_COLL_SETATTR = 24, // cid, attrname, bl
OP_COLL_RMATTR = 25, // cid, attrname
OP_COLL_SETATTRS = 26, // cid, attrset
OP_COLL_MOVE = 8, // newcid, oldcid, oid
OP_RMATTRS = 28, // cid, oid
OP_COLL_RENAME = 29, // cid, newcid
OP_OMAP_CLEAR = 31, // cid
OP_OMAP_SETKEYS = 32, // cid, attrset
OP_OMAP_RMKEYS = 33, // cid, keyset
OP_OMAP_SETHEADER = 34, // cid, header
OP_SPLIT_COLLECTION = 35, // cid, bits, destination
OP_SPLIT_COLLECTION2 = 36, /* cid, bits, destination
doesn't create the destination */
OP_OMAP_RMKEYRANGE = 37, // cid, oid, firstkey, lastkey
OP_COLL_MOVE_RENAME = 38, // oldcid, oldoid, newcid, newoid
OP_SETALLOCHINT = 39, // cid, oid, object_size, write_size
OP_COLL_HINT = 40, // cid, type, bl
OP_TRY_RENAME = 41, // oldcid, oldoid, newoid
OP_COLL_SET_BITS = 42, // cid, bits
};
// Transaction hint type
enum {
COLL_HINT_EXPECTED_NUM_OBJECTS = 1,
};
// 真正的操作
struct Op {
__le32 op; // 这里用数字来表示操作的类型,也可以看做是指令的类型
__le32 cid;
__le32 oid;
__le64 off;
__le64 len;
__le32 dest_cid;
__le32 dest_oid; //OP_CLONE, OP_CLONERANGE
__le64 dest_off; //OP_CLONERANGE
union {
struct {
__le32 hint_type; //OP_COLL_HINT
};
struct {
__le32 alloc_hint_flags; //OP_SETALLOCHINT
};
};
__le64 expected_object_size; //OP_SETALLOCHINT
__le64 expected_write_size; //OP_SETALLOCHINT
__le32 split_bits; //OP_SPLIT_COLLECTION2,OP_COLL_SET_BITS,
//OP_MKCOLL
__le32 split_rem; //OP_SPLIT_COLLECTION2
} __attribute__ ((packed)) ;
//
struct TransactionData {
__le64 ops; // 这个应该是指的操作的数量
__le32 largest_data_len;
__le32 largest_data_off;
__le32 largest_data_off_in_data_bl;
__le32 fadvise_flags;
} __attribute__ ((packed)) ;
private:
TransactionData data;
map<coll_t, __le32> coll_index;
map<ghobject_t, __le32> object_index;
__le32 coll_id {0};
__le32 object_id {0};
bufferlist data_bl;
bufferlist op_bl;
bufferptr op_ptr;
list<Context *> on_applied;
list<Context *> on_commit;
list<Context *> on_applied_sync;
public:
void _update_op(Op* op,
vector<__le32> &cm,
vector<__le32> &om) {
// 根据情况来决定是否需要更新collection id
// 或者是object id
// 根据op的类型来决定
op->cid = cm[op->cid];
op->oid = om[op->oid];
op->dest_oid = om[op->dest_oid];
}
// bl里面是一个list
// list里面的每个元素都是一个Op结构
// 然后再通过_update_op(op_memory, cm, om)
// 来进行更新
void _update_op_bl(
bufferlist& bl,
vector<__le32> &cm,
vector<__le32> &om)
{
list<bufferptr> list = bl.buffers();
std::list<bufferptr>::iterator p;
for(p = list.begin(); p != list.end(); ++p) {
assert(p->length() % sizeof(Op) == 0);
char* raw_p = p->c_str();
char* raw_end = raw_p + p->length();
while (raw_p < raw_end) {
_update_op(reinterpret_cast<Op*>(raw_p), cm, om);
raw_p += sizeof(Op);
}
}
}
/// Append the operations of the parameter to this Transaction.
// Those operations are removed from the parameter Transaction
// 这里更加类似于两个事务的合并,注意:
// other.op_bl是深度复制了的。
// ohter.data_bl则是没有深度复制
// 可能是觉得other还会在别的地方会有用处
void append(Transaction& other) {
data.ops += other.data.ops;
if (other.data.largest_data_len > data.largest_data_len) {
data.largest_data_len = other.data.largest_data_len;
data.largest_data_off = other.data.largest_data_off;
data.largest_data_off_in_data_bl = data_bl.length() + other.data.largest_data_off_in_data_bl;
}
data.fadvise_flags |= other.data.fadvise_flags;
// splice的含义是把另外一个list放到on_applied/on_commit后面
// splice函数是说
// splice(Iterator position, list<T> l);
// 把l插入到postion位置。然后l里面的元素被move过去。所以
// 操作之后l变成空的了。
on_applied.splice(on_applied.end(), other.on_applied);
on_commit.splice(on_commit.end(), other.on_commit);
on_applied_sync.splice(on_applied_sync.end(), other.on_applied_sync);
//append coll_index & object_index
// cm新生成,后面用来更新
vector<__le32> cm(other.coll_index.size());
map<coll_t, __le32>::iterator coll_index_p;
for (coll_index_p = other.coll_index.begin();
coll_index_p != other.coll_index.end();
++coll_index_p) {
// 这里更新cm这个vector
cm[coll_index_p->second] = _get_coll_id(coll_index_p->first);
}
vector<__le32> om(other.object_index.size());
map<ghobject_t, __le32>::iterator object_index_p;
for (object_index_p = other.object_index.begin();
object_index_p != other.object_index.end();
++object_index_p) {
// 这里更新的是om这个vector
om[object_index_p->second] = _get_object_id(object_index_p->first);
}
// other.op_bl在这里是不能被更改的
//the other.op_bl SHOULD NOT be changes during append operation,
// 这里使用了另外一个bufferlist来处理这种case.
//we use additional bufferlist to avoid this problem
// 申请一个新的内存,长度为other.op_bl.length()
bufferptr other_op_bl_ptr(other.op_bl.length());
// 这里把other.op_bl里面的内容复制到新申请的内存里
other.op_bl.copy(0, other.op_bl.length(), other_op_bl_ptr.c_str());
bufferlist other_op_bl;
// 注意这里是一个list<bufferptr>, 所以这里用append把前面的内存缓冲区放进去
other_op_bl.append(other_op_bl_ptr);
//update other_op_bl with cm & om
//When the other is appended to current transaction, all coll_index and
//object_index in other.op_buffer should be updated by new index of the
//combined transaction
// 然后利用list<buffer>把当前的transaction更新一把
_update_op_bl(other_op_bl, cm, om);
//append op_bl
// 把other的op_bl list append到op_bl里面
// 完成两个事务的op的合并
op_bl.append(other_op_bl);
//append data_bl
// data bl也是需要合并
data_bl.append(other.data_bl);
}
/** Inquires about the Transaction as a whole. */
/// How big is the encoded Transaction buffer?
// 得到整个事务的长度
// 感觉这里不应该老是去计算
// 最好是有办法去优化
uint64_t get_encoded_bytes() {
//layout: data_bl + op_bl + coll_index + object_index + data
// coll_index size, object_index size and sizeof(transaction_data)
// all here, so they may be computed at compile-time
size_t final_size = sizeof(__u32) * 2 + sizeof(data);
// coll_index second and object_index second
final_size += (coll_index.size() + object_index.size()) * sizeof(__le32);
// coll_index first
for (auto p = coll_index.begin(); p != coll_index.end(); ++p) {
final_size += p->first.encoded_size();
}
// object_index first
for (auto p = object_index.begin(); p != object_index.end(); ++p) {
final_size += p->first.encoded_size();
}
return data_bl.length() +
op_bl.length() +
final_size;
}
uint64_t get_num_bytes() {
return get_encoded_bytes();
}
/// Size of largest data buffer to the "write" operation encountered so far
uint32_t get_data_length() {
return data.largest_data_len;
}
/// offset within the encoded buffer to the start of the largest data buffer that's encoded
uint32_t get_data_offset()
{
if (data.largest_data_off_in_data_bl) {
return data.largest_data_off_in_data_bl +
sizeof(__u8) + // encode struct_v
sizeof(__u8) + // encode compat_v
sizeof(__u32) + // encode len
sizeof(__u32); // data_bl len
}
return 0; // none
}
/// offset of buffer as aligned to destination within object.
int get_data_alignment()
{
if (!data.largest_data_len)
return 0;
return (0 - get_data_offset()) & ~CEPH_PAGE_MASK;
}
/// Is the Transaction empty (no operations)
bool empty()
{
// data里面的ops就是用来计数ops操作的数目
return !data.ops;
}
/// Number of operations in the transation
int get_num_ops()
{
return data.ops;
}
/**
* iterator
*
* Helper object to parse Transactions.
*
* ObjectStore instances use this object to step down the encoded
* buffer decoding operation codes and parameters as we go.
*
*/
class iterator
{
Transaction *t;
uint64_t ops;
char* op_buffer_p;
bufferlist::const_iterator data_bl_p;
public:
vector<coll_t> colls;
vector<ghobject_t> objects;
private:
explicit iterator(Transaction *t)
: t(t),
data_bl_p(t->data_bl.cbegin()),
colls(t->coll_index.size()),
objects(t->object_index.size())
{
ops = t->data.ops;
op_buffer_p = t->op_bl.get_contiguous(0, t->data.ops * sizeof(Op));
map<coll_t, __le32>::iterator coll_index_p;
for (coll_index_p = t->coll_index.begin();
coll_index_p != t->coll_index.end();
++coll_index_p) {
colls[coll_index_p->second] = coll_index_p->first;
}
map<ghobject_t, __le32>::iterator object_index_p;
for (object_index_p = t->object_index.begin();
object_index_p != t->object_index.end();
++object_index_p) {
objects[object_index_p->second] = object_index_p->first;
}
}
friend class Transaction;
public:
bool have_op()
{
return ops > 0;
}
Op* decode_op()
{
assert(ops > 0);
Op* op = reinterpret_cast<Op*>(op_buffer_p);
op_buffer_p += sizeof(Op);
ops--;
return op;
}
string decode_string()
{
using ceph::decode;
string s;
decode(s, data_bl_p);
return s;
}
void decode_bp(bufferptr& bp)
{
using ceph::decode;
decode(bp, data_bl_p);
}
void decode_bl(bufferlist& bl)
{
using ceph::decode;
decode(bl, data_bl_p);
}
void decode_attrset(map<string,bufferptr>& aset)
{
using ceph::decode;
decode(aset, data_bl_p);
}
void decode_attrset(map<string,bufferlist>& aset)
{
using ceph::decode;
decode(aset, data_bl_p);
}
void decode_attrset_bl(bufferlist *pbl)
{
decode_str_str_map_to_bl(data_bl_p, pbl);
}
void decode_keyset(set<string> &keys)
{
using ceph::decode;
decode(keys, data_bl_p);
}
void decode_keyset_bl(bufferlist *pbl)
{
decode_str_set_to_bl(data_bl_p, pbl);
}
const ghobject_t &get_oid(__le32 oid_id)
{
assert(oid_id < objects.size());
return objects[oid_id];
}
const coll_t &get_cid(__le32 cid_id)
{
assert(cid_id < colls.size());
return colls[cid_id];
}
uint32_t get_fadvise_flags() const
{
return t->get_fadvise_flags();
}
};
iterator begin()
{
return iterator(this);
}
private:
void _build_actions_from_tbl();
/**
* Helper functions to encode the various mutation elements of a
* transaction. These are 1:1 with the operation codes (see
* enumeration above). These routines ensure that the
* encoder/creator of a transaction gets the right data in the
* right place. Sadly, there's no corresponding version nor any
* form of seat belts for the decoder.
*/
Op* _get_next_op()
{
if (op_ptr.length() == 0 || op_ptr.offset() >= op_ptr.length()) {
op_ptr = bufferptr(sizeof(Op) * OPS_PER_PTR);
}
bufferptr ptr(op_ptr, 0, sizeof(Op));
op_bl.append(ptr);
op_ptr.set_offset(op_ptr.offset() + sizeof(Op));
char* p = ptr.c_str();
memset(p, 0, sizeof(Op));
return reinterpret_cast<Op*>(p);
}
__le32 _get_coll_id(const coll_t& coll)
{
map<coll_t, __le32>::iterator c = coll_index.find(coll);
if (c != coll_index.end())
return c->second;
__le32 index_id = coll_id++;
coll_index[coll] = index_id;
return index_id;
}
__le32 _get_object_id(const ghobject_t& oid)
{
map<ghobject_t, __le32>::iterator o = object_index.find(oid);
if (o != object_index.end())
return o->second;
__le32 index_id = object_id++;
object_index[oid] = index_id;
return index_id;
}
public:
// 接下来这里生成各种事务的参数,指令
/// noop. 'nuf said
void nop()
{
Op* _op = _get_next_op();
_op->op = OP_NOP;
data.ops++;
}
/**
* touch
*
* Ensure the existance of an object in a collection. Create an
* empty object if necessary
*/
void touch(const coll_t& cid, const ghobject_t& oid)
{
Op* _op = _get_next_op();
_op->op = OP_TOUCH;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
data.ops++;
}
/**
* Write data to an offset within an object. If the object is too
* small, it is expanded as needed. It is possible to specify an
* offset beyond the current end of an object and it will be
* expanded as needed. Simple implementations of ObjectStore will
* just zero the data between the old end of the object and the
* newly provided data. More sophisticated implementations of
* ObjectStore will omit the untouched data and store it as a
* "hole" in the file.
*
* Note that a 0-length write does not affect the size of the object.
*/
void write(const coll_t& cid, const ghobject_t& oid, uint64_t off, uint64_t len,
const bufferlist& write_data, uint32_t flags = 0)
{
using ceph::encode;
uint32_t orig_len = data_bl.length();
Op* _op = _get_next_op();
_op->op = OP_WRITE;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
_op->off = off;
_op->len = len;
encode(write_data, data_bl);
assert(len == write_data.length());
data.fadvise_flags = data.fadvise_flags | flags;
if (write_data.length() > data.largest_data_len) {
data.largest_data_len = write_data.length();
data.largest_data_off = off;
data.largest_data_off_in_data_bl = orig_len + sizeof(__u32); // we are about to
}
data.ops++;
}
/**
* zero out the indicated byte range within an object. Some
* ObjectStore instances may optimize this to release the
* underlying storage space.
*
* If the zero range extends beyond the end of the object, the object
* size is extended, just as if we were writing a buffer full of zeros.
* EXCEPT if the length is 0, in which case (just like a 0-length write)
* we do not adjust the object size.
*/
void zero(const coll_t& cid, const ghobject_t& oid, uint64_t off, uint64_t len)
{
Op* _op = _get_next_op();
_op->op = OP_ZERO;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
_op->off = off;
_op->len = len;
data.ops++;
}
/// Discard all data in the object beyond the specified size.
void truncate(const coll_t& cid, const ghobject_t& oid, uint64_t off)
{
Op* _op = _get_next_op();
_op->op = OP_TRUNCATE;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
_op->off = off;
data.ops++;
}
/// Remove an object. All four parts of the object are removed.
void remove(const coll_t& cid, const ghobject_t& oid)
{
Op* _op = _get_next_op();
_op->op = OP_REMOVE;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
data.ops++;
}
/// Set an xattr of an object
void setattr(const coll_t& cid, const ghobject_t& oid, const char* name, bufferlist& val)
{
string n(name);
setattr(cid, oid, n, val);
}
/// Set an xattr of an object
void setattr(const coll_t& cid, const ghobject_t& oid, const string& s, bufferlist& val)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_SETATTR;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(s, data_bl);
encode(val, data_bl);
data.ops++;
}
/// Set multiple xattrs of an object
void setattrs(const coll_t& cid, const ghobject_t& oid, const map<string,bufferptr>& attrset)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_SETATTRS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(attrset, data_bl);
data.ops++;
}
/// Set multiple xattrs of an object
void setattrs(const coll_t& cid, const ghobject_t& oid, const map<string,bufferlist>& attrset)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_SETATTRS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(attrset, data_bl);
data.ops++;
}
/// remove an xattr from an object
void rmattr(const coll_t& cid, const ghobject_t& oid, const char *name)
{
string n(name);
rmattr(cid, oid, n);
}
/// remove an xattr from an object
void rmattr(const coll_t& cid, const ghobject_t& oid, const string& s)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_RMATTR;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(s, data_bl);
data.ops++;
}
/// remove all xattrs from an object
void rmattrs(const coll_t& cid, const ghobject_t& oid)
{
Op* _op = _get_next_op();
_op->op = OP_RMATTRS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
data.ops++;
}
/**
* Clone an object into another object.
*
* Low-cost (e.g., O(1)) cloning (if supported) is best, but
* fallback to an O(n) copy is allowed. All four parts of the
* object are cloned (data, xattrs, omap header, omap
* entries).
*
* The destination named object may already exist, in
* which case its previous contents are discarded.
*/
void clone(const coll_t& cid, const ghobject_t& oid,
const ghobject_t& noid)
{
Op* _op = _get_next_op();
_op->op = OP_CLONE;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
_op->dest_oid = _get_object_id(noid);
data.ops++;
}
/**
* Clone a byte range from one object to another.
*
* The data portion of the destination object receives a copy of a
* portion of the data from the source object. None of the other
* three parts of an object is copied from the source.
*
* The destination object size may be extended to the dstoff + len.
*
* The source range *must* overlap with the source object data. If it does
* not the result is undefined.
*/
void clone_range(const coll_t& cid, const ghobject_t& oid,
const ghobject_t& noid,
uint64_t srcoff, uint64_t srclen, uint64_t dstoff)
{
Op* _op = _get_next_op();
_op->op = OP_CLONERANGE2;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
_op->dest_oid = _get_object_id(noid);
_op->off = srcoff;
_op->len = srclen;
_op->dest_off = dstoff;
data.ops++;
}
/// Create the collection
void create_collection(const coll_t& cid, int bits)
{
Op* _op = _get_next_op();
_op->op = OP_MKCOLL;
_op->cid = _get_coll_id(cid);
_op->split_bits = bits;
data.ops++;
}
/**
* Give the collection a hint.
*
* @param cid - collection id.
* @param type - hint type.
* @param hint - the hint payload, which contains the customized
* data along with the hint type.
*/
void collection_hint(const coll_t& cid, uint32_t type, const bufferlist& hint)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_COLL_HINT;
_op->cid = _get_coll_id(cid);
_op->hint_type = type;
encode(hint, data_bl);
data.ops++;
}
/// remove the collection, the collection must be empty
void remove_collection(const coll_t& cid)
{
Op* _op = _get_next_op();
_op->op = OP_RMCOLL;
_op->cid = _get_coll_id(cid);
data.ops++;
}
void collection_move(const coll_t& cid, const coll_t &oldcid, const ghobject_t& oid)
__attribute__ ((deprecated))
{
// NOTE: we encode this as a fixed combo of ADD + REMOVE. they
// always appear together, so this is effectively a single MOVE.
Op* _op = _get_next_op();
_op->op = OP_COLL_ADD;
_op->cid = _get_coll_id(oldcid);
_op->oid = _get_object_id(oid);
_op->dest_cid = _get_coll_id(cid);
data.ops++;
_op = _get_next_op();
_op->op = OP_COLL_REMOVE;
_op->cid = _get_coll_id(oldcid);
_op->oid = _get_object_id(oid);
data.ops++;
}
void collection_move_rename(const coll_t& oldcid, const ghobject_t& oldoid,
const coll_t &cid, const ghobject_t& oid)
{
Op* _op = _get_next_op();
_op->op = OP_COLL_MOVE_RENAME;
_op->cid = _get_coll_id(oldcid);
_op->oid = _get_object_id(oldoid);
_op->dest_cid = _get_coll_id(cid);
_op->dest_oid = _get_object_id(oid);
data.ops++;
}
void try_rename(const coll_t &cid, const ghobject_t& oldoid,
const ghobject_t& oid)
{
Op* _op = _get_next_op();
_op->op = OP_TRY_RENAME;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oldoid);
_op->dest_oid = _get_object_id(oid);
data.ops++;
}
/// Remove omap from oid
void omap_clear(
const coll_t &cid, ///< [in] Collection containing oid
const ghobject_t &oid ///< [in] Object from which to remove omap
)
{
Op* _op = _get_next_op();
_op->op = OP_OMAP_CLEAR;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
data.ops++;
}
/// Set keys on oid omap. Replaces duplicate keys.
void omap_setkeys(
const coll_t& cid, ///< [in] Collection containing oid
const ghobject_t &oid, ///< [in] Object to update
const map<string, bufferlist> &attrset ///< [in] Replacement keys and values
)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_OMAP_SETKEYS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(attrset, data_bl);
data.ops++;
}
/// Set keys on an oid omap (bufferlist variant).
void omap_setkeys(
const coll_t &cid, ///< [in] Collection containing oid
const ghobject_t &oid, ///< [in] Object to update
const bufferlist &attrset_bl ///< [in] Replacement keys and values
)
{
Op* _op = _get_next_op();
_op->op = OP_OMAP_SETKEYS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
data_bl.append(attrset_bl);
data.ops++;
}
/// Remove keys from oid omap
void omap_rmkeys(
const coll_t &cid, ///< [in] Collection containing oid
const ghobject_t &oid, ///< [in] Object from which to remove the omap
const set<string> &keys ///< [in] Keys to clear
)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_OMAP_RMKEYS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(keys, data_bl);
data.ops++;
}
/// Remove keys from oid omap
void omap_rmkeys(
const coll_t &cid, ///< [in] Collection containing oid
const ghobject_t &oid, ///< [in] Object from which to remove the omap
const bufferlist &keys_bl ///< [in] Keys to clear
)
{
Op* _op = _get_next_op();
_op->op = OP_OMAP_RMKEYS;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
data_bl.append(keys_bl);
data.ops++;
}
/// Remove key range from oid omap
void omap_rmkeyrange(
const coll_t &cid, ///< [in] Collection containing oid
const ghobject_t &oid, ///< [in] Object from which to remove the omap keys
const string& first, ///< [in] first key in range
const string& last ///< [in] first key past range, range is [first,last)
)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_OMAP_RMKEYRANGE;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(first, data_bl);
encode(last, data_bl);
data.ops++;
}
/// Set omap header
void omap_setheader(
const coll_t &cid, ///< [in] Collection containing oid
const ghobject_t &oid, ///< [in] Object
const bufferlist &bl ///< [in] Header value
)
{
using ceph::encode;
Op* _op = _get_next_op();
_op->op = OP_OMAP_SETHEADER;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
encode(bl, data_bl);
data.ops++;
}
/// Split collection based on given prefixes, objects matching the specified bits/rem are
/// moved to the new collection
void split_collection(
const coll_t &cid,
uint32_t bits,
uint32_t rem,
const coll_t &destination)
{
Op* _op = _get_next_op();
_op->op = OP_SPLIT_COLLECTION2;
_op->cid = _get_coll_id(cid);
_op->dest_cid = _get_coll_id(destination);
_op->split_bits = bits;
_op->split_rem = rem;
data.ops++;
}
void collection_set_bits(
const coll_t &cid,
int bits)
{
Op* _op = _get_next_op();
_op->op = OP_COLL_SET_BITS;
_op->cid = _get_coll_id(cid);
_op->split_bits = bits;
data.ops++;
}
/// Set allocation hint for an object
/// make 0 values(expected_object_size, expected_write_size) noops for all implementations
void set_alloc_hint(
const coll_t &cid,
const ghobject_t &oid,
uint64_t expected_object_size,
uint64_t expected_write_size,
uint32_t flags
)
{
Op* _op = _get_next_op();
_op->op = OP_SETALLOCHINT;
_op->cid = _get_coll_id(cid);
_op->oid = _get_object_id(oid);
_op->expected_object_size = expected_object_size;
_op->expected_write_size = expected_write_size;
_op->alloc_hint_flags = flags;
data.ops++;
}
};