ceph/src/rgw/rgw_cache.h

529 lines
14 KiB
C
Raw Normal View History

2011-02-09 01:19:39 +00:00
#ifndef CEPH_RGWCACHE_H
#define CEPH_RGWCACHE_H
#include "rgw_rados.h"
2011-02-09 01:19:39 +00:00
#include <string>
#include <map>
#include "include/types.h"
#include "include/utime.h"
#include "include/assert.h"
2011-02-09 01:19:39 +00:00
2011-07-01 00:13:42 +00:00
enum {
2011-07-07 22:04:26 +00:00
UPDATE_OBJ,
REMOVE_OBJ,
2011-07-01 00:13:42 +00:00
};
2011-10-25 23:23:08 +00:00
#define CACHE_FLAG_DATA 0x1
#define CACHE_FLAG_XATTRS 0x2
#define CACHE_FLAG_META 0x4
#define CACHE_FLAG_MODIFY_XATTRS 0x8
2011-07-07 22:04:26 +00:00
#define mydout(v) lsubdout(T::cct, rgw, v)
2011-07-07 22:04:26 +00:00
struct ObjectMetaInfo {
uint64_t size;
time_t mtime;
ObjectMetaInfo() : size(0), mtime(0) {}
2011-07-07 22:04:26 +00:00
void encode(bufferlist& bl) const {
ENCODE_START(2, 2, bl);
2011-07-07 22:04:26 +00:00
::encode(size, bl);
utime_t t(mtime, 0);
::encode(t, bl);
ENCODE_FINISH(bl);
2011-07-07 22:04:26 +00:00
}
void decode(bufferlist::iterator& bl) {
DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
2011-07-07 22:04:26 +00:00
::decode(size, bl);
utime_t t;
::decode(t, bl);
mtime = t.sec();
DECODE_FINISH(bl);
2011-07-07 22:04:26 +00:00
}
void dump(Formatter *f) const;
static void generate_test_instances(list<ObjectMetaInfo*>& o);
2011-07-07 22:04:26 +00:00
};
WRITE_CLASS_ENCODER(ObjectMetaInfo)
struct ObjectCacheInfo {
int status;
uint32_t flags;
uint64_t epoch;
2011-07-07 22:04:26 +00:00
bufferlist data;
map<string, bufferlist> xattrs;
map<string, bufferlist> rm_xattrs;
2011-07-07 22:04:26 +00:00
ObjectMetaInfo meta;
ObjectCacheInfo() : status(0), flags(0), epoch(0) {}
2011-07-07 22:04:26 +00:00
void encode(bufferlist& bl) const {
ENCODE_START(4, 3, bl);
2011-07-07 22:04:26 +00:00
::encode(status, bl);
::encode(flags, bl);
::encode(data, bl);
::encode(xattrs, bl);
::encode(meta, bl);
::encode(rm_xattrs, bl);
::encode(epoch, bl);
ENCODE_FINISH(bl);
2011-07-07 22:04:26 +00:00
}
void decode(bufferlist::iterator& bl) {
DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
2011-07-07 22:04:26 +00:00
::decode(status, bl);
::decode(flags, bl);
::decode(data, bl);
::decode(xattrs, bl);
::decode(meta, bl);
if (struct_v >= 2)
::decode(rm_xattrs, bl);
if (struct_v >= 4)
::decode(epoch, bl);
DECODE_FINISH(bl);
2011-07-07 22:04:26 +00:00
}
void dump(Formatter *f) const;
static void generate_test_instances(list<ObjectCacheInfo*>& o);
2011-07-07 22:04:26 +00:00
};
WRITE_CLASS_ENCODER(ObjectCacheInfo)
2011-07-01 00:13:42 +00:00
struct RGWCacheNotifyInfo {
uint32_t op;
rgw_obj obj;
2011-07-07 22:04:26 +00:00
ObjectCacheInfo obj_info;
2011-07-01 00:13:42 +00:00
off_t ofs;
2011-07-07 22:04:26 +00:00
string ns;
2011-07-01 00:13:42 +00:00
RGWCacheNotifyInfo() : op(0), ofs(0) {}
2011-07-01 00:13:42 +00:00
void encode(bufferlist& obl) const {
ENCODE_START(2, 2, obl);
2011-07-01 00:13:42 +00:00
::encode(op, obl);
::encode(obj, obl);
2011-07-07 22:04:26 +00:00
::encode(obj_info, obl);
2011-07-01 00:13:42 +00:00
::encode(ofs, obl);
2011-07-07 22:04:26 +00:00
::encode(ns, obl);
ENCODE_FINISH(obl);
2011-07-01 00:13:42 +00:00
}
void decode(bufferlist::iterator& ibl) {
DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, ibl);
2011-07-01 00:13:42 +00:00
::decode(op, ibl);
::decode(obj, ibl);
2011-07-07 22:04:26 +00:00
::decode(obj_info, ibl);
2011-07-01 00:13:42 +00:00
::decode(ofs, ibl);
2011-07-07 22:04:26 +00:00
::decode(ns, ibl);
DECODE_FINISH(ibl);
2011-07-01 00:13:42 +00:00
}
void dump(Formatter *f) const;
static void generate_test_instances(list<RGWCacheNotifyInfo*>& o);
2011-07-01 00:13:42 +00:00
};
WRITE_CLASS_ENCODER(RGWCacheNotifyInfo)
2011-07-09 00:17:32 +00:00
struct ObjectCacheEntry {
ObjectCacheInfo info;
std::list<string>::iterator lru_iter;
};
2011-02-09 01:19:39 +00:00
class ObjectCache {
2011-07-09 00:17:32 +00:00
std::map<string, ObjectCacheEntry> cache_map;
std::list<string> lru;
Mutex lock;
CephContext *cct;
2011-02-09 01:19:39 +00:00
2011-07-09 00:17:32 +00:00
void touch_lru(string& name, std::list<string>::iterator& lru_iter);
void remove_lru(string& name, std::list<string>::iterator& lru_iter);
2011-02-09 01:19:39 +00:00
public:
ObjectCache() : lock("ObjectCache"), cct(NULL) { }
2011-07-07 22:04:26 +00:00
int get(std::string& name, ObjectCacheInfo& bl, uint32_t mask);
void put(std::string& name, ObjectCacheInfo& bl);
void remove(std::string& name);
void set_ctx(CephContext *_cct) { cct = _cct; }
2011-02-09 01:19:39 +00:00
};
template <class T>
class RGWCache : public T
{
ObjectCache cache;
int list_objects_raw_init(rgw_bucket& bucket, RGWAccessHandle *handle) {
return T::list_objects_raw_init(bucket, handle);
}
int list_objects_raw_next(RGWObjEnt& obj, RGWAccessHandle *handle) {
return T::list_objects_raw_next(obj, handle);
}
string normal_name(rgw_bucket& bucket, std::string& oid) {
string& bucket_name = bucket.name;
char buf[bucket_name.size() + 1 + oid.size() + 1];
const char *bucket_str = bucket_name.c_str();
2011-03-04 22:11:21 +00:00
const char *oid_str = oid.c_str();
2011-07-07 22:04:26 +00:00
sprintf(buf, "%s+%s", bucket_str, oid_str);
2011-02-09 01:19:39 +00:00
return string(buf);
}
void normalize_bucket_and_obj(rgw_bucket& src_bucket, string& src_obj, rgw_bucket& dst_bucket, string& dst_obj);
2011-07-11 21:26:16 +00:00
string normal_name(rgw_obj& obj) {
return normal_name(obj.bucket, obj.object);
}
int initialize() {
int ret;
cache.set_ctx(T::cct);
ret = T::initialize();
if (ret < 0)
return ret;
ret = T::init_watch();
return ret;
}
void finalize() {
T::finalize_watch();
T::finalize();
}
int distribute_cache(const string& normal_name, rgw_obj& obj, ObjectCacheInfo& obj_info, int op);
2011-07-01 00:13:42 +00:00
int watch_cb(int opcode, uint64_t ver, bufferlist& bl);
2011-02-09 01:19:39 +00:00
public:
RGWCache() {}
2011-10-25 23:23:08 +00:00
int set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl);
int set_attrs(void *ctx, rgw_obj& obj,
map<string, bufferlist>& attrs,
map<string, bufferlist>* rmattrs);
int put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime,
map<std::string, bufferlist>& attrs, RGWObjCategory category, int flags,
map<std::string, bufferlist>* rmattrs, const bufferlist *data,
RGWObjManifest *manifest, const string *ptag, list<string> *remove_objs);
2011-10-25 23:23:08 +00:00
int put_obj_data(void *ctx, rgw_obj& obj, const char *data,
off_t ofs, size_t len, bool exclusive);
2011-02-09 01:19:39 +00:00
int get_obj(void *ctx, void **handle, rgw_obj& obj, bufferlist& bl, off_t ofs, off_t end);
2011-02-09 01:19:39 +00:00
int obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime, uint64_t *epoch, map<string, bufferlist> *attrs, bufferlist *first_chunk);
2011-07-11 23:55:05 +00:00
int delete_obj(void *ctx, rgw_obj& obj);
2011-02-09 01:19:39 +00:00
};
template <class T>
void RGWCache<T>::normalize_bucket_and_obj(rgw_bucket& src_bucket, string& src_obj, rgw_bucket& dst_bucket, string& dst_obj)
{
if (src_obj.size()) {
dst_bucket = src_bucket;
dst_obj = src_obj;
} else {
dst_bucket = T::params.domain_root;
dst_obj = src_bucket.name;
}
}
2011-02-09 01:19:39 +00:00
2011-07-11 23:55:05 +00:00
template <class T>
int RGWCache<T>::delete_obj(void *ctx, rgw_obj& obj)
2011-07-11 23:55:05 +00:00
{
2011-10-25 23:23:08 +00:00
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
if (bucket.name[0] != '.')
return T::delete_obj(ctx, obj);
2011-07-11 23:55:05 +00:00
string name = normal_name(obj);
cache.remove(name);
ObjectCacheInfo info;
distribute_cache(name, obj, info, REMOVE_OBJ);
2011-07-11 23:55:05 +00:00
return T::delete_obj(ctx, obj);
2011-07-11 23:55:05 +00:00
}
2011-07-07 22:04:26 +00:00
2011-02-09 01:19:39 +00:00
template <class T>
int RGWCache<T>::get_obj(void *ctx, void **handle, rgw_obj& obj, bufferlist& obl, off_t ofs, off_t end)
2011-02-09 01:19:39 +00:00
{
2011-10-25 23:23:08 +00:00
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
if (bucket.name[0] != '.' || ofs != 0)
return T::get_obj(ctx, handle, obj, obl, ofs, end);
2011-02-09 01:19:39 +00:00
string name = normal_name(obj.bucket, oid);
2011-07-11 21:26:16 +00:00
2011-07-07 22:04:26 +00:00
ObjectCacheInfo info;
if (cache.get(name, info, CACHE_FLAG_DATA) == 0) {
if (info.status < 0)
return info.status;
bufferlist& bl = info.data;
bufferlist::iterator i = bl.begin();
obl.clear();
i.copy_all(obl);
2011-02-09 01:19:39 +00:00
return bl.length();
}
int r = T::get_obj(ctx, handle, obj, obl, ofs, end);
2011-07-07 22:04:26 +00:00
if (r < 0) {
if (r == -ENOENT) { // only update ENOENT, we'd rather retry other errors
info.status = r;
cache.put(name, info);
}
2011-02-09 01:19:39 +00:00
return r;
2011-07-07 22:04:26 +00:00
}
2011-02-09 01:19:39 +00:00
if (obl.length() == end + 1) {
/* in this case, most likely object contains more data, we can't cache it */
return r;
}
2011-02-09 01:19:39 +00:00
bufferptr p(r);
2011-07-07 22:04:26 +00:00
bufferlist& bl = info.data;
2011-02-09 01:19:39 +00:00
bl.clear();
bufferlist::iterator o = obl.begin();
o.copy_all(bl);
2011-07-07 22:04:26 +00:00
info.status = 0;
info.flags = CACHE_FLAG_DATA;
cache.put(name, info);
2011-02-09 01:19:39 +00:00
return r;
}
2011-10-25 23:23:08 +00:00
template <class T>
int RGWCache<T>::set_attr(void *ctx, rgw_obj& obj, const char *attr_name, bufferlist& bl)
{
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
ObjectCacheInfo info;
bool cacheable = false;
if (bucket.name[0] == '.') {
cacheable = true;
info.xattrs[attr_name] = bl;
info.status = 0;
info.flags = CACHE_FLAG_MODIFY_XATTRS;
2011-10-25 23:23:08 +00:00
}
int ret = T::set_attr(ctx, obj, attr_name, bl);
if (cacheable) {
string name = normal_name(bucket, oid);
if (ret >= 0) {
cache.put(name, info);
int r = distribute_cache(name, obj, info, UPDATE_OBJ);
2011-10-25 23:23:08 +00:00
if (r < 0)
mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl;
2011-10-25 23:23:08 +00:00
} else {
cache.remove(name);
}
}
return ret;
}
template <class T>
int RGWCache<T>::set_attrs(void *ctx, rgw_obj& obj,
map<string, bufferlist>& attrs,
map<string, bufferlist>* rmattrs)
{
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
ObjectCacheInfo info;
bool cacheable = false;
if (bucket.name[0] == '.') {
cacheable = true;
info.xattrs = attrs;
if (rmattrs)
info.rm_xattrs = *rmattrs;
info.status = 0;
info.flags = CACHE_FLAG_MODIFY_XATTRS;
}
int ret = T::set_attrs(ctx, obj, attrs, rmattrs);
if (cacheable) {
string name = normal_name(bucket, oid);
if (ret >= 0) {
cache.put(name, info);
int r = distribute_cache(name, obj, info, UPDATE_OBJ);
if (r < 0)
mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl;
} else {
cache.remove(name);
}
}
return ret;
}
2011-10-25 23:23:08 +00:00
template <class T>
int RGWCache<T>::put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime,
map<std::string, bufferlist>& attrs, RGWObjCategory category, int flags,
map<std::string, bufferlist>* rmattrs, const bufferlist *data,
RGWObjManifest *manifest, const string *ptag, list<string> *remove_objs)
2011-10-25 23:23:08 +00:00
{
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
ObjectCacheInfo info;
bool cacheable = false;
if (bucket.name[0] == '.') {
cacheable = true;
info.xattrs = attrs;
info.status = 0;
info.flags = CACHE_FLAG_XATTRS;
if (data) {
info.data = *data;
info.flags |= CACHE_FLAG_DATA;
}
2011-10-25 23:23:08 +00:00
}
int ret = T::put_obj_meta(ctx, obj, size, mtime, attrs, category, flags, rmattrs, data, manifest, ptag, remove_objs);
2011-10-25 23:23:08 +00:00
if (cacheable) {
string name = normal_name(bucket, oid);
if (ret >= 0) {
cache.put(name, info);
int r = distribute_cache(name, obj, info, UPDATE_OBJ);
2011-10-25 23:23:08 +00:00
if (r < 0)
mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl;
2011-10-25 23:23:08 +00:00
} else {
cache.remove(name);
}
}
return ret;
}
2011-02-09 01:19:39 +00:00
template <class T>
int RGWCache<T>::put_obj_data(void *ctx, rgw_obj& obj, const char *data,
off_t ofs, size_t len, bool exclusive)
2011-02-09 01:19:39 +00:00
{
2011-10-25 23:23:08 +00:00
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
2011-07-07 22:04:26 +00:00
ObjectCacheInfo info;
2011-07-01 00:13:42 +00:00
bool cacheable = false;
2011-10-25 23:23:08 +00:00
if ((bucket.name[0] == '.') && ((ofs == 0) || (ofs == -1))) {
2011-07-01 00:13:42 +00:00
cacheable = true;
2011-02-09 01:19:39 +00:00
bufferptr p(len);
memcpy(p.c_str(), data, len);
2011-07-07 22:04:26 +00:00
bufferlist& bl = info.data;
2011-02-09 01:19:39 +00:00
bl.append(p);
2011-07-07 22:04:26 +00:00
info.meta.size = bl.length();
info.status = 0;
info.flags = CACHE_FLAG_DATA;
2011-02-09 01:19:39 +00:00
}
int ret = T::put_obj_data(ctx, obj, data, ofs, len, exclusive);
2011-07-07 22:04:26 +00:00
if (cacheable) {
2011-10-25 23:23:08 +00:00
string name = normal_name(bucket, oid);
2011-07-07 22:04:26 +00:00
if (ret >= 0) {
cache.put(name, info);
int r = distribute_cache(name, obj, info, UPDATE_OBJ);
2011-07-07 22:04:26 +00:00
if (r < 0)
mydout(0) << "ERROR: failed to distribute cache for " << obj << dendl;
2011-07-07 22:04:26 +00:00
} else {
cache.remove(name);
}
2011-07-01 00:13:42 +00:00
}
return ret;
2011-02-09 01:19:39 +00:00
}
template <class T>
int RGWCache<T>::obj_stat(void *ctx, rgw_obj& obj, uint64_t *psize, time_t *pmtime,
uint64_t *pepoch, map<string, bufferlist> *attrs,
bufferlist *first_chunk)
2011-02-09 01:19:39 +00:00
{
2011-10-25 23:23:08 +00:00
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid);
if (bucket.name[0] != '.')
return T::obj_stat(ctx, obj, psize, pmtime, pepoch, attrs, first_chunk);
2011-02-09 01:19:39 +00:00
2011-10-25 23:23:08 +00:00
string name = normal_name(bucket, oid);
2011-02-09 01:19:39 +00:00
uint64_t size;
2011-02-09 01:19:39 +00:00
time_t mtime;
uint64_t epoch;
2011-02-09 01:19:39 +00:00
2011-07-07 22:04:26 +00:00
ObjectCacheInfo info;
2011-10-21 23:14:11 +00:00
int r = cache.get(name, info, CACHE_FLAG_META | CACHE_FLAG_XATTRS);
2011-02-09 01:19:39 +00:00
if (r == 0) {
2011-07-07 22:04:26 +00:00
if (info.status < 0)
return info.status;
size = info.meta.size;
mtime = info.meta.mtime;
epoch = info.epoch;
2011-02-09 01:19:39 +00:00
goto done;
}
r = T::obj_stat(ctx, obj, &size, &mtime, &epoch, &info.xattrs, first_chunk);
2011-07-07 22:04:26 +00:00
if (r < 0) {
if (r == -ENOENT) {
info.status = r;
cache.put(name, info);
}
2011-02-09 01:19:39 +00:00
return r;
2011-07-07 22:04:26 +00:00
}
info.status = 0;
info.epoch = epoch;
2011-07-07 22:04:26 +00:00
info.meta.mtime = mtime;
info.meta.size = size;
2011-10-21 23:14:11 +00:00
info.flags = CACHE_FLAG_META | CACHE_FLAG_XATTRS;
2011-07-07 22:04:26 +00:00
cache.put(name, info);
2011-02-09 01:19:39 +00:00
done:
if (psize)
*psize = size;
if (pmtime)
*pmtime = mtime;
if (pepoch)
*pepoch = epoch;
2011-10-21 23:14:11 +00:00
if (attrs)
*attrs = info.xattrs;
2011-02-09 01:19:39 +00:00
return 0;
}
2011-07-01 00:13:42 +00:00
template <class T>
int RGWCache<T>::distribute_cache(const string& normal_name, rgw_obj& obj, ObjectCacheInfo& obj_info, int op)
2011-07-01 00:13:42 +00:00
{
RGWCacheNotifyInfo info;
2011-07-11 23:55:05 +00:00
info.op = op;
2011-07-07 22:04:26 +00:00
info.obj_info = obj_info;
2011-07-01 00:13:42 +00:00
info.obj = obj;
2011-07-07 22:04:26 +00:00
bufferlist bl;
2011-07-01 00:13:42 +00:00
::encode(info, bl);
int ret = T::distribute(normal_name, bl);
2011-07-01 00:13:42 +00:00
return ret;
}
template <class T>
int RGWCache<T>::watch_cb(int opcode, uint64_t ver, bufferlist& bl)
{
RGWCacheNotifyInfo info;
try {
bufferlist::iterator iter = bl.begin();
::decode(info, iter);
} catch (buffer::end_of_buffer& err) {
mydout(0) << "ERROR: got bad notification" << dendl;
2011-07-01 00:13:42 +00:00
return -EIO;
} catch (buffer::error& err) {
mydout(0) << "ERROR: buffer::error" << dendl;
return -EIO;
2011-07-01 00:13:42 +00:00
}
rgw_bucket bucket;
string oid;
normalize_bucket_and_obj(info.obj.bucket, info.obj.object, bucket, oid);
string name = normal_name(bucket, oid);
2011-07-11 21:26:16 +00:00
2011-07-01 00:13:42 +00:00
switch (info.op) {
2011-07-07 22:04:26 +00:00
case UPDATE_OBJ:
2011-07-11 21:26:16 +00:00
cache.put(name, info.obj_info);
2011-07-01 00:13:42 +00:00
break;
2011-07-11 23:55:05 +00:00
case REMOVE_OBJ:
cache.remove(name);
break;
2011-07-01 00:13:42 +00:00
default:
mydout(0) << "WARNING: got unknown notification op: " << info.op << dendl;
2011-07-01 00:13:42 +00:00
return -EINVAL;
}
return 0;
}
2011-02-09 01:19:39 +00:00
#endif