declare -A pids
for f in \
- api_aio api_io api_asio api_list api_lock api_misc \
- api_tier api_pool api_snapshots api_stat api_watch_notify api_cmd \
- api_service \
+ api_aio api_aio_pp \
+ api_io api_io_pp \
+ api_asio api_list \
+ api_lock api_lock_pp \
+ api_misc api_misc_pp \
+ api_tier_pp \
+ api_pool \
+ api_snapshots api_snapshots_pp \
+ api_stat api_stat_pp \
+ api_watch_notify api_watch_notify_pp \
+ api_cmd api_cmd_pp \
+ api_service api_service_pp \
api_c_write_operations \
api_c_read_operations \
list_parallel \
#define CLS_LUA_CLIENT_HPP
#include <string>
-#include "include/buffer_fwd.h" // for bufferlist
+#include "include/rados/librados.hpp"
namespace librados {
class IoCtx;
#include "common/Mutex.h"
#include "include/buffer.h"
-#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
#include "include/xlist.h"
#include "osd/osd_types.h"
-add_library(librados_objs OBJECT
+add_library(librados_impl STATIC
IoCtxImpl.cc
RadosXattrIter.cc
- RadosClient.cc)
-add_library(librados_api_obj OBJECT
- librados.cc)
+ RadosClient.cc
+ librados_util.cc
+ librados_tp.cc
+ $<TARGET_OBJECTS:common_buffer_obj>)
+
+add_library(rados_c_api OBJECT
+ librados_c.cc)
+add_library(rados_cxx_api OBJECT
+ librados_cxx.cc)
+add_library(rados_cxx STATIC
+ $<TARGET_OBJECTS:rados_cxx_api>)
if(WITH_LTTNG)
- add_dependencies(librados_api_obj librados-tp)
+ add_dependencies(librados_impl librados-tp)
+ add_dependencies(rados_c_api librados-tp)
+ add_dependencies(rados_cxx_api librados-tp)
endif()
+
+# C API
+add_library(librados ${CEPH_SHARED}
+ $<TARGET_OBJECTS:rados_c_api>)
if(ENABLE_SHARED)
- add_library(librados ${CEPH_SHARED}
- $<TARGET_OBJECTS:librados_api_obj>
- $<TARGET_OBJECTS:librados_objs>
- $<TARGET_OBJECTS:common_buffer_obj>)
set_target_properties(librados PROPERTIES
OUTPUT_NAME rados
VERSION 2.0.0
set_property(TARGET librados APPEND_STRING PROPERTY
LINK_FLAGS " -Wl,--exclude-libs,ALL")
endif()
-else(ENABLE_SHARED)
- add_library(librados STATIC
- $<TARGET_OBJECTS:librados_api_obj>
- $<TARGET_OBJECTS:librados_objs>)
-endif(ENABLE_SHARED)
+ if(WITH_STATIC_LIBSTDCXX)
+ set_property(TARGET librados APPEND_STRING PROPERTY
+ LINK_FLAGS " -static-libstdc++ -static-libgcc")
+ endif()
+endif()
+
target_link_libraries(librados PRIVATE
+ rados_cxx librados_impl
osdc ceph-common cls_lock_client
${BLKID_LIBRARIES} ${CRYPTO_LIBS} ${EXTRALIBS})
-target_link_libraries(librados ${rados_libs})
install(TARGETS librados DESTINATION ${CMAKE_INSTALL_LIBDIR})
+# C++ API
+add_library(librados-cxx ${CEPH_SHARED}
+ $<TARGET_OBJECTS:rados_cxx_api>)
+if(ENABLE_SHARED)
+ set_target_properties(librados-cxx PROPERTIES
+ OUTPUT_NAME radospp
+ VERSION 1.0.0
+ SOVERSION 1
+ CXX_VISIBILITY_PRESET hidden
+ VISIBILITY_INLINES_HIDDEN ON)
+ if(NOT APPLE)
+ set_property(TARGET librados-cxx APPEND_STRING PROPERTY
+ LINK_FLAGS " -Wl,--exclude-libs,ALL")
+ endif()
+endif(ENABLE_SHARED)
+target_link_libraries(librados-cxx
+ PUBLIC
+ librados
+ PRIVATE
+ librados_impl cls_lock_client ceph-common)
+install(TARGETS librados-cxx DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
if(WITH_LTTNG AND WITH_EVENTTRACE)
add_dependencies(librados_api_obj eventtrace_tp)
endif()
#include "common/common_init.h"
#include "common/ceph_json.h"
#include "common/errno.h"
+#include "common/ceph_json.h"
#include "include/buffer.h"
#include "include/stringify.h"
#include "include/util.h"
}
int librados::RadosClient::get_inconsistent_pgs(int64_t pool_id,
- std::vector<std::string>* pgs)
+ std::vector<std::string>* pgs)
{
vector<string> cmd = {
"{\"prefix\": \"pg ls\","
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2012 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.
- *
- */
-
-#include <limits.h>
-
-#include "common/config.h"
-#include "common/errno.h"
-#include "common/ceph_argparse.h"
-#include "common/ceph_json.h"
-#include "common/common_init.h"
-#include "common/TracepointProvider.h"
-#include "common/hobject.h"
-#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
-#include "include/types.h"
-#include <include/stringify.h>
-
-#include "librados/AioCompletionImpl.h"
-#include "librados/IoCtxImpl.h"
-#include "librados/PoolAsyncCompletionImpl.h"
-#include "librados/RadosClient.h"
-#include "librados/RadosXattrIter.h"
-#include "librados/ListObjectImpl.h"
-#include <cls/lock/cls_lock_client.h>
-
-#include <string>
-#include <map>
-#include <set>
-#include <vector>
-#include <list>
-#include <stdexcept>
-
-#ifdef WITH_LTTNG
-#define TRACEPOINT_DEFINE
-#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
-#include "tracing/librados.h"
-#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
-#undef TRACEPOINT_DEFINE
-#else
-#define tracepoint(...)
-#endif
-
-using std::string;
-using std::map;
-using std::set;
-using std::vector;
-using std::list;
-using std::runtime_error;
-
-#define dout_subsys ceph_subsys_rados
-#undef dout_prefix
-#define dout_prefix *_dout << "librados: "
-
-#define RADOS_LIST_MAX_ENTRIES 1024
-
-namespace {
-
-TracepointProvider::Traits tracepoint_traits("librados_tp.so", "rados_tracing");
-
-uint8_t get_checksum_op_type(rados_checksum_type_t type) {
- switch (type) {
- case LIBRADOS_CHECKSUM_TYPE_XXHASH32:
- return CEPH_OSD_CHECKSUM_OP_TYPE_XXHASH32;
- case LIBRADOS_CHECKSUM_TYPE_XXHASH64:
- return CEPH_OSD_CHECKSUM_OP_TYPE_XXHASH64;
- case LIBRADOS_CHECKSUM_TYPE_CRC32C:
- return CEPH_OSD_CHECKSUM_OP_TYPE_CRC32C;
- default:
- return -1;
- }
-}
-
-} // anonymous namespace
-
-/*
- * Structure of this file
- *
- * RadosClient and the related classes are the internal implementation of librados.
- * Above that layer sits the C API, found in include/rados/librados.h, and
- * the C++ API, found in include/rados/librados.hpp
- *
- * The C++ API sometimes implements things in terms of the C API.
- * Both the C++ and C API rely on RadosClient.
- *
- * Visually:
- * +--------------------------------------+
- * | C++ API |
- * +--------------------+ |
- * | C API | |
- * +--------------------+-----------------+
- * | RadosClient |
- * +--------------------------------------+
- */
-
-namespace librados {
-
-struct ObjectOperationImpl {
- ::ObjectOperation o;
- real_time rt;
- real_time *prt;
-
- ObjectOperationImpl() : prt(NULL) {}
-};
-
-}
-
-size_t librados::ObjectOperation::size()
-{
- ::ObjectOperation *o = &impl->o;
- return o->size();
-}
-
-static void set_op_flags(::ObjectOperation *o, int flags)
-{
- int rados_flags = 0;
- if (flags & LIBRADOS_OP_FLAG_EXCL)
- rados_flags |= CEPH_OSD_OP_FLAG_EXCL;
- if (flags & LIBRADOS_OP_FLAG_FAILOK)
- rados_flags |= CEPH_OSD_OP_FLAG_FAILOK;
- if (flags & LIBRADOS_OP_FLAG_FADVISE_RANDOM)
- rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_RANDOM;
- if (flags & LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL)
- rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL;
- if (flags & LIBRADOS_OP_FLAG_FADVISE_WILLNEED)
- rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_WILLNEED;
- if (flags & LIBRADOS_OP_FLAG_FADVISE_DONTNEED)
- rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_DONTNEED;
- if (flags & LIBRADOS_OP_FLAG_FADVISE_NOCACHE)
- rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_NOCACHE;
- o->set_last_op_flags(rados_flags);
-}
-
-//deprcated
-void librados::ObjectOperation::set_op_flags(ObjectOperationFlags flags)
-{
- ::set_op_flags(&impl->o, (int)flags);
-}
-
-void librados::ObjectOperation::set_op_flags2(int flags)
-{
- ::ObjectOperation *o = &impl->o;
- ::set_op_flags(o, flags);
-}
-
-void librados::ObjectOperation::cmpext(uint64_t off,
- bufferlist &cmp_bl,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->cmpext(off, cmp_bl, prval);
-}
-
-void librados::ObjectOperation::cmpxattr(const char *name, uint8_t op, const bufferlist& v)
-{
- ::ObjectOperation *o = &impl->o;
- o->cmpxattr(name, op, CEPH_OSD_CMPXATTR_MODE_STRING, v);
-}
-
-void librados::ObjectOperation::cmpxattr(const char *name, uint8_t op, uint64_t v)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist bl;
- encode(v, bl);
- o->cmpxattr(name, op, CEPH_OSD_CMPXATTR_MODE_U64, bl);
-}
-
-void librados::ObjectOperation::assert_version(uint64_t ver)
-{
- ::ObjectOperation *o = &impl->o;
- o->assert_version(ver);
-}
-
-void librados::ObjectOperation::assert_exists()
-{
- ::ObjectOperation *o = &impl->o;
- o->stat(NULL, (ceph::real_time*) NULL, NULL);
-}
-
-void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl)
-{
- ::ObjectOperation *o = &impl->o;
- o->call(cls, method, inbl);
-}
-
-void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->call(cls, method, inbl, outbl, NULL, prval);
-}
-
-class ObjectOpCompletionCtx : public Context {
- librados::ObjectOperationCompletion *completion;
- bufferlist bl;
-public:
- explicit ObjectOpCompletionCtx(librados::ObjectOperationCompletion *c) : completion(c) {}
- void finish(int r) override {
- completion->handle_completion(r, bl);
- delete completion;
- }
-
- bufferlist *outbl() {
- return &bl;
- }
-};
-
-void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, librados::ObjectOperationCompletion *completion)
-{
- ::ObjectOperation *o = &impl->o;
-
- ObjectOpCompletionCtx *ctx = new ObjectOpCompletionCtx(completion);
-
- o->call(cls, method, inbl, ctx->outbl(), ctx, NULL);
-}
-
-void librados::ObjectReadOperation::stat(uint64_t *psize, time_t *pmtime, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->stat(psize, pmtime, prval);
-}
-
-void librados::ObjectReadOperation::stat2(uint64_t *psize, struct timespec *pts, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->stat(psize, pts, prval);
-}
-
-void librados::ObjectReadOperation::read(size_t off, uint64_t len, bufferlist *pbl, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->read(off, len, pbl, prval, NULL);
-}
-
-void librados::ObjectReadOperation::sparse_read(uint64_t off, uint64_t len,
- std::map<uint64_t,uint64_t> *m,
- bufferlist *data_bl, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->sparse_read(off, len, m, data_bl, prval);
-}
-
-void librados::ObjectReadOperation::checksum(rados_checksum_type_t type,
- const bufferlist &init_value_bl,
- uint64_t off, size_t len,
- size_t chunk_size, bufferlist *pbl,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->checksum(get_checksum_op_type(type), init_value_bl, off, len, chunk_size,
- pbl, prval, nullptr);
-}
-
-void librados::ObjectReadOperation::tmap_get(bufferlist *pbl, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->tmap_get(pbl, prval);
-}
-
-void librados::ObjectReadOperation::getxattr(const char *name, bufferlist *pbl, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->getxattr(name, pbl, prval);
-}
-
-void librados::ObjectReadOperation::omap_get_vals(
- const std::string &start_after,
- const std::string &filter_prefix,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_vals(start_after, filter_prefix, max_return, out_vals, nullptr,
- prval);
-}
-
-void librados::ObjectReadOperation::omap_get_vals2(
- const std::string &start_after,
- const std::string &filter_prefix,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals,
- bool *pmore,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_vals(start_after, filter_prefix, max_return, out_vals, pmore,
- prval);
-}
-
-void librados::ObjectReadOperation::omap_get_vals(
- const std::string &start_after,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_vals(start_after, "", max_return, out_vals, nullptr, prval);
-}
-
-void librados::ObjectReadOperation::omap_get_vals2(
- const std::string &start_after,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals,
- bool *pmore,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_vals(start_after, "", max_return, out_vals, pmore, prval);
-}
-
-void librados::ObjectReadOperation::omap_get_keys(
- const std::string &start_after,
- uint64_t max_return,
- std::set<std::string> *out_keys,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_keys(start_after, max_return, out_keys, nullptr, prval);
-}
-
-void librados::ObjectReadOperation::omap_get_keys2(
- const std::string &start_after,
- uint64_t max_return,
- std::set<std::string> *out_keys,
- bool *pmore,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_keys(start_after, max_return, out_keys, pmore, prval);
-}
-
-void librados::ObjectReadOperation::omap_get_header(bufferlist *bl, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_header(bl, prval);
-}
-
-void librados::ObjectReadOperation::omap_get_vals_by_keys(
- const std::set<std::string> &keys,
- std::map<std::string, bufferlist> *map,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_get_vals_by_keys(keys, map, prval);
-}
-
-void librados::ObjectOperation::omap_cmp(
- const std::map<std::string, pair<bufferlist, int> > &assertions,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_cmp(assertions, prval);
-}
-
-void librados::ObjectReadOperation::list_watchers(
- list<obj_watch_t> *out_watchers,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->list_watchers(out_watchers, prval);
-}
-
-void librados::ObjectReadOperation::list_snaps(
- snap_set_t *out_snaps,
- int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->list_snaps(out_snaps, prval);
-}
-
-void librados::ObjectReadOperation::is_dirty(bool *is_dirty, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->is_dirty(is_dirty, prval);
-}
-
-int librados::IoCtx::omap_get_vals(const std::string& oid,
- const std::string& orig_start_after,
- const std::string& filter_prefix,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals)
-{
- bool first = true;
- string start_after = orig_start_after;
- bool more = true;
- while (max_return > 0 && more) {
- std::map<std::string,bufferlist> out;
- ObjectReadOperation op;
- op.omap_get_vals2(start_after, filter_prefix, max_return, &out, &more,
- nullptr);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0) {
- return ret;
- }
- if (more) {
- if (out.empty()) {
- return -EINVAL; // wth
- }
- start_after = out.rbegin()->first;
- }
- if (out.size() <= max_return) {
- max_return -= out.size();
- } else {
- max_return = 0;
- }
- if (first) {
- out_vals->swap(out);
- first = false;
- } else {
- out_vals->insert(out.begin(), out.end());
- out.clear();
- }
- }
- return 0;
-}
-
-int librados::IoCtx::omap_get_vals2(
- const std::string& oid,
- const std::string& start_after,
- const std::string& filter_prefix,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals,
- bool *pmore)
-{
- ObjectReadOperation op;
- int r;
- op.omap_get_vals2(start_after, filter_prefix, max_return, out_vals, pmore, &r);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0)
- return ret;
- return r;
-}
-
-void librados::ObjectReadOperation::getxattrs(map<string, bufferlist> *pattrs, int *prval)
-{
- ::ObjectOperation *o = &impl->o;
- o->getxattrs(pattrs, prval);
-}
-
-void librados::ObjectWriteOperation::mtime(time_t *pt)
-{
- if (pt) {
- impl->rt = ceph::real_clock::from_time_t(*pt);
- impl->prt = &impl->rt;
- }
-}
-
-void librados::ObjectWriteOperation::mtime2(struct timespec *pts)
-{
- if (pts) {
- impl->rt = ceph::real_clock::from_timespec(*pts);
- impl->prt = &impl->rt;
- }
-}
-
-void librados::ObjectWriteOperation::create(bool exclusive)
-{
- ::ObjectOperation *o = &impl->o;
- o->create(exclusive);
-}
-
-void librados::ObjectWriteOperation::create(bool exclusive,
- const std::string& category) // unused
-{
- ::ObjectOperation *o = &impl->o;
- o->create(exclusive);
-}
-
-void librados::ObjectWriteOperation::write(uint64_t off, const bufferlist& bl)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist c = bl;
- o->write(off, c);
-}
-
-void librados::ObjectWriteOperation::write_full(const bufferlist& bl)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist c = bl;
- o->write_full(c);
-}
-
-void librados::ObjectWriteOperation::writesame(uint64_t off, uint64_t write_len,
- const bufferlist& bl)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist c = bl;
- o->writesame(off, write_len, c);
-}
-
-void librados::ObjectWriteOperation::append(const bufferlist& bl)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist c = bl;
- o->append(c);
-}
-
-void librados::ObjectWriteOperation::remove()
-{
- ::ObjectOperation *o = &impl->o;
- o->remove();
-}
-
-void librados::ObjectWriteOperation::truncate(uint64_t off)
-{
- ::ObjectOperation *o = &impl->o;
- o->truncate(off);
-}
-
-void librados::ObjectWriteOperation::zero(uint64_t off, uint64_t len)
-{
- ::ObjectOperation *o = &impl->o;
- o->zero(off, len);
-}
-
-void librados::ObjectWriteOperation::rmxattr(const char *name)
-{
- ::ObjectOperation *o = &impl->o;
- o->rmxattr(name);
-}
-
-void librados::ObjectWriteOperation::setxattr(const char *name, const bufferlist& v)
-{
- ::ObjectOperation *o = &impl->o;
- o->setxattr(name, v);
-}
-
-void librados::ObjectWriteOperation::omap_set(
- const map<string, bufferlist> &map)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_set(map);
-}
-
-void librados::ObjectWriteOperation::omap_set_header(const bufferlist &bl)
-{
- bufferlist c = bl;
- ::ObjectOperation *o = &impl->o;
- o->omap_set_header(c);
-}
-
-void librados::ObjectWriteOperation::omap_clear()
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_clear();
-}
-
-void librados::ObjectWriteOperation::omap_rm_keys(
- const std::set<std::string> &to_rm)
-{
- ::ObjectOperation *o = &impl->o;
- o->omap_rm_keys(to_rm);
-}
-
-void librados::ObjectWriteOperation::copy_from(const std::string& src,
- const IoCtx& src_ioctx,
- uint64_t src_version)
-{
- copy_from2(src, src_ioctx, src_version, 0);
-}
-
-void librados::ObjectWriteOperation::copy_from2(const std::string& src,
- const IoCtx& src_ioctx,
- uint64_t src_version,
- uint32_t src_fadvise_flags)
-{
- ::ObjectOperation *o = &impl->o;
- o->copy_from(object_t(src), src_ioctx.io_ctx_impl->snap_seq,
- src_ioctx.io_ctx_impl->oloc, src_version, 0, src_fadvise_flags);
-}
-
-void librados::ObjectWriteOperation::undirty()
-{
- ::ObjectOperation *o = &impl->o;
- o->undirty();
-}
-
-void librados::ObjectReadOperation::cache_flush()
-{
- ::ObjectOperation *o = &impl->o;
- o->cache_flush();
-}
-
-void librados::ObjectReadOperation::cache_try_flush()
-{
- ::ObjectOperation *o = &impl->o;
- o->cache_try_flush();
-}
-
-void librados::ObjectReadOperation::cache_evict()
-{
- ::ObjectOperation *o = &impl->o;
- o->cache_evict();
-}
-
-void librados::ObjectWriteOperation::set_redirect(const std::string& tgt_obj,
- const IoCtx& tgt_ioctx,
- uint64_t tgt_version,
- int flag)
-{
- ::ObjectOperation *o = &impl->o;
- o->set_redirect(object_t(tgt_obj), tgt_ioctx.io_ctx_impl->snap_seq,
- tgt_ioctx.io_ctx_impl->oloc, tgt_version, flag);
-}
-
-void librados::ObjectWriteOperation::set_chunk(uint64_t src_offset,
- uint64_t src_length,
- const IoCtx& tgt_ioctx,
- string tgt_oid,
- uint64_t tgt_offset,
- int flag)
-{
- ::ObjectOperation *o = &impl->o;
- o->set_chunk(src_offset, src_length,
- tgt_ioctx.io_ctx_impl->oloc, object_t(tgt_oid), tgt_offset, flag);
-}
-
-void librados::ObjectWriteOperation::tier_promote()
-{
- ::ObjectOperation *o = &impl->o;
- o->tier_promote();
-}
-
-void librados::ObjectWriteOperation::unset_manifest()
-{
- ::ObjectOperation *o = &impl->o;
- o->unset_manifest();
-}
-
-void librados::ObjectWriteOperation::tmap_put(const bufferlist &bl)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist c = bl;
- o->tmap_put(c);
-}
-
-void librados::ObjectWriteOperation::tmap_update(const bufferlist& cmdbl)
-{
- ::ObjectOperation *o = &impl->o;
- bufferlist c = cmdbl;
- o->tmap_update(c);
-}
-
-void librados::ObjectWriteOperation::selfmanaged_snap_rollback(snap_t snapid)
-{
- ::ObjectOperation *o = &impl->o;
- o->rollback(snapid);
-}
-
-// You must specify the snapid not the name normally used with pool snapshots
-void librados::ObjectWriteOperation::snap_rollback(snap_t snapid)
-{
- ::ObjectOperation *o = &impl->o;
- o->rollback(snapid);
-}
-
-void librados::ObjectWriteOperation::set_alloc_hint(
- uint64_t expected_object_size,
- uint64_t expected_write_size)
-{
- ::ObjectOperation *o = &impl->o;
- o->set_alloc_hint(expected_object_size, expected_write_size, 0);
-}
-void librados::ObjectWriteOperation::set_alloc_hint2(
- uint64_t expected_object_size,
- uint64_t expected_write_size,
- uint32_t flags)
-{
- ::ObjectOperation *o = &impl->o;
- o->set_alloc_hint(expected_object_size, expected_write_size, flags);
-}
-
-void librados::ObjectWriteOperation::cache_pin()
-{
- ::ObjectOperation *o = &impl->o;
- o->cache_pin();
-}
-
-void librados::ObjectWriteOperation::cache_unpin()
-{
- ::ObjectOperation *o = &impl->o;
- o->cache_unpin();
-}
-
-librados::WatchCtx::
-~WatchCtx()
-{
-}
-
-librados::WatchCtx2::
-~WatchCtx2()
-{
-}
-
-
-struct librados::ObjListCtx {
- librados::IoCtxImpl dupctx;
- librados::IoCtxImpl *ctx;
- Objecter::NListContext *nlc;
- bool legacy_list_api;
-
- ObjListCtx(IoCtxImpl *c, Objecter::NListContext *nl, bool legacy=false)
- : nlc(nl),
- legacy_list_api(legacy) {
- // Get our own private IoCtxImpl so that namespace setting isn't
- // changed by caller between uses.
- ctx = &dupctx;
- dupctx.dup(*c);
- }
- ~ObjListCtx() {
- ctx = NULL;
- delete nlc;
- }
-};
-
-///////////////////////////// NObjectIteratorImpl /////////////////////////////
-librados::NObjectIteratorImpl::NObjectIteratorImpl(ObjListCtx *ctx_)
- : ctx(ctx_)
-{
-}
-
-librados::NObjectIteratorImpl::~NObjectIteratorImpl()
-{
- ctx.reset();
-}
-
-librados::NObjectIteratorImpl::NObjectIteratorImpl(const NObjectIteratorImpl &rhs)
-{
- *this = rhs;
-}
-
-librados::NObjectIteratorImpl& librados::NObjectIteratorImpl::operator=(const librados::NObjectIteratorImpl &rhs)
-{
- if (&rhs == this)
- return *this;
- if (rhs.ctx.get() == NULL) {
- ctx.reset();
- return *this;
- }
- Objecter::NListContext *list_ctx = new Objecter::NListContext(*rhs.ctx->nlc);
- ctx.reset(new ObjListCtx(rhs.ctx->ctx, list_ctx));
- cur_obj = rhs.cur_obj;
- return *this;
-}
-
-bool librados::NObjectIteratorImpl::operator==(const librados::NObjectIteratorImpl& rhs) const {
-
- if (ctx.get() == NULL) {
- if (rhs.ctx.get() == NULL)
- return true;
- return rhs.ctx->nlc->at_end();
- }
- if (rhs.ctx.get() == NULL) {
- // Redundant but same as ObjectIterator version
- if (ctx.get() == NULL)
- return true;
- return ctx->nlc->at_end();
- }
- return ctx.get() == rhs.ctx.get();
-}
-
-bool librados::NObjectIteratorImpl::operator!=(const librados::NObjectIteratorImpl& rhs) const {
- return !(*this == rhs);
-}
-
-const librados::ListObject& librados::NObjectIteratorImpl::operator*() const {
- return cur_obj;
-}
-
-const librados::ListObject* librados::NObjectIteratorImpl::operator->() const {
- return &cur_obj;
-}
-
-librados::NObjectIteratorImpl& librados::NObjectIteratorImpl::operator++()
-{
- get_next();
- return *this;
-}
-
-librados::NObjectIteratorImpl librados::NObjectIteratorImpl::operator++(int)
-{
- librados::NObjectIteratorImpl ret(*this);
- get_next();
- return ret;
-}
-
-uint32_t librados::NObjectIteratorImpl::seek(uint32_t pos)
-{
- uint32_t r = rados_nobjects_list_seek(ctx.get(), pos);
- get_next();
- return r;
-}
-
-uint32_t librados::NObjectIteratorImpl::seek(const ObjectCursor& cursor)
-{
- uint32_t r = rados_nobjects_list_seek_cursor(ctx.get(), (rados_object_list_cursor)cursor.c_cursor);
- get_next();
- return r;
-}
-
-librados::ObjectCursor librados::NObjectIteratorImpl::get_cursor()
-{
- librados::ObjListCtx *lh = (librados::ObjListCtx *)ctx.get();
- librados::ObjectCursor oc;
- oc.set(lh->ctx->nlist_get_cursor(lh->nlc));
- return oc;
-}
-
-void librados::NObjectIteratorImpl::set_filter(const bufferlist &bl)
-{
- ceph_assert(ctx);
- ctx->nlc->filter = bl;
-}
-
-void librados::NObjectIteratorImpl::get_next()
-{
- const char *entry, *key, *nspace;
- if (ctx->nlc->at_end())
- return;
- int ret = rados_nobjects_list_next(ctx.get(), &entry, &key, &nspace);
- if (ret == -ENOENT) {
- return;
- }
- else if (ret) {
- ostringstream oss;
- oss << "rados returned " << cpp_strerror(ret);
- throw std::runtime_error(oss.str());
- }
-
- if (cur_obj.impl == NULL)
- cur_obj.impl = new ListObjectImpl();
- cur_obj.impl->nspace = nspace;
- cur_obj.impl->oid = entry;
- cur_obj.impl->locator = key ? key : string();
-}
-
-uint32_t librados::NObjectIteratorImpl::get_pg_hash_position() const
-{
- return ctx->nlc->get_pg_hash_position();
-}
-
-///////////////////////////// NObjectIterator /////////////////////////////
-librados::NObjectIterator::NObjectIterator(ObjListCtx *ctx_)
-{
- impl = new NObjectIteratorImpl(ctx_);
-}
-
-librados::NObjectIterator::~NObjectIterator()
-{
- delete impl;
-}
-
-librados::NObjectIterator::NObjectIterator(const NObjectIterator &rhs)
-{
- if (rhs.impl == NULL) {
- impl = NULL;
- return;
- }
- impl = new NObjectIteratorImpl();
- *impl = *(rhs.impl);
-}
-
-librados::NObjectIterator& librados::NObjectIterator::operator=(const librados::NObjectIterator &rhs)
-{
- if (rhs.impl == NULL) {
- delete impl;
- impl = NULL;
- return *this;
- }
- if (impl == NULL)
- impl = new NObjectIteratorImpl();
- *impl = *(rhs.impl);
- return *this;
-}
-
-bool librados::NObjectIterator::operator==(const librados::NObjectIterator& rhs) const
-{
- if (impl && rhs.impl) {
- return *impl == *(rhs.impl);
- } else {
- return impl == rhs.impl;
- }
-}
-
-bool librados::NObjectIterator::operator!=(const librados::NObjectIterator& rhs) const
-{
- return !(*this == rhs);
-}
-
-const librados::ListObject& librados::NObjectIterator::operator*() const {
- ceph_assert(impl);
- return *(impl->get_listobjectp());
-}
-
-const librados::ListObject* librados::NObjectIterator::operator->() const {
- ceph_assert(impl);
- return impl->get_listobjectp();
-}
-
-librados::NObjectIterator& librados::NObjectIterator::operator++()
-{
- ceph_assert(impl);
- impl->get_next();
- return *this;
-}
-
-librados::NObjectIterator librados::NObjectIterator::operator++(int)
-{
- librados::NObjectIterator ret(*this);
- impl->get_next();
- return ret;
-}
-
-uint32_t librados::NObjectIterator::seek(uint32_t pos)
-{
- ceph_assert(impl);
- return impl->seek(pos);
-}
-
-uint32_t librados::NObjectIterator::seek(const ObjectCursor& cursor)
-{
- ceph_assert(impl);
- return impl->seek(cursor);
-}
-
-librados::ObjectCursor librados::NObjectIterator::get_cursor()
-{
- ceph_assert(impl);
- return impl->get_cursor();
-}
-
-void librados::NObjectIterator::set_filter(const bufferlist &bl)
-{
- impl->set_filter(bl);
-}
-
-void librados::NObjectIterator::get_next()
-{
- ceph_assert(impl);
- impl->get_next();
-}
-
-uint32_t librados::NObjectIterator::get_pg_hash_position() const
-{
- ceph_assert(impl);
- return impl->get_pg_hash_position();
-}
-
-const librados::NObjectIterator librados::NObjectIterator::__EndObjectIterator(NULL);
-
-///////////////////////////// PoolAsyncCompletion //////////////////////////////
-int librados::PoolAsyncCompletion::PoolAsyncCompletion::set_callback(void *cb_arg,
- rados_callback_t cb)
-{
- PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
- return c->set_callback(cb_arg, cb);
-}
-
-int librados::PoolAsyncCompletion::PoolAsyncCompletion::wait()
-{
- PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
- return c->wait();
-}
-
-bool librados::PoolAsyncCompletion::PoolAsyncCompletion::is_complete()
-{
- PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
- return c->is_complete();
-}
-
-int librados::PoolAsyncCompletion::PoolAsyncCompletion::get_return_value()
-{
- PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
- return c->get_return_value();
-}
-
-void librados::PoolAsyncCompletion::PoolAsyncCompletion::release()
-{
- PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
- c->release();
- delete this;
-}
-
-///////////////////////////// AioCompletion //////////////////////////////
-int librados::AioCompletion::AioCompletion::set_complete_callback(void *cb_arg, rados_callback_t cb)
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->set_complete_callback(cb_arg, cb);
-}
-
-int librados::AioCompletion::AioCompletion::set_safe_callback(void *cb_arg, rados_callback_t cb)
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->set_safe_callback(cb_arg, cb);
-}
-
-int librados::AioCompletion::AioCompletion::wait_for_complete()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->wait_for_complete();
-}
-
-int librados::AioCompletion::AioCompletion::wait_for_safe()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->wait_for_safe();
-}
-
-bool librados::AioCompletion::AioCompletion::is_complete()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->is_complete();
-}
-
-bool librados::AioCompletion::AioCompletion::is_safe()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->is_safe();
-}
-
-int librados::AioCompletion::AioCompletion::wait_for_complete_and_cb()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->wait_for_complete_and_cb();
-}
-
-int librados::AioCompletion::AioCompletion::wait_for_safe_and_cb()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->wait_for_safe_and_cb();
-}
-
-bool librados::AioCompletion::AioCompletion::is_complete_and_cb()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->is_complete_and_cb();
-}
-
-bool librados::AioCompletion::AioCompletion::is_safe_and_cb()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->is_safe_and_cb();
-}
-
-int librados::AioCompletion::AioCompletion::get_return_value()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->get_return_value();
-}
-
-int librados::AioCompletion::AioCompletion::get_version()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->get_version();
-}
-
-uint64_t librados::AioCompletion::AioCompletion::get_version64()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- return c->get_version();
-}
-
-void librados::AioCompletion::AioCompletion::release()
-{
- AioCompletionImpl *c = (AioCompletionImpl *)pc;
- c->release();
- delete this;
-}
-
-///////////////////////////// IoCtx //////////////////////////////
-librados::IoCtx::IoCtx() : io_ctx_impl(NULL)
-{
-}
-
-void librados::IoCtx::from_rados_ioctx_t(rados_ioctx_t p, IoCtx &io)
-{
- IoCtxImpl *io_ctx_impl = (IoCtxImpl*)p;
-
- io.io_ctx_impl = io_ctx_impl;
- if (io_ctx_impl) {
- io_ctx_impl->get();
- }
-}
-
-librados::IoCtx::IoCtx(const IoCtx& rhs)
-{
- io_ctx_impl = rhs.io_ctx_impl;
- if (io_ctx_impl) {
- io_ctx_impl->get();
- }
-}
-
-librados::IoCtx& librados::IoCtx::operator=(const IoCtx& rhs)
-{
- if (io_ctx_impl)
- io_ctx_impl->put();
- io_ctx_impl = rhs.io_ctx_impl;
- io_ctx_impl->get();
- return *this;
-}
-
-librados::IoCtx::~IoCtx()
-{
- close();
-}
-
-void librados::IoCtx::close()
-{
- if (io_ctx_impl)
- io_ctx_impl->put();
- io_ctx_impl = 0;
-}
-
-void librados::IoCtx::dup(const IoCtx& rhs)
-{
- if (io_ctx_impl)
- io_ctx_impl->put();
- io_ctx_impl = new IoCtxImpl();
- io_ctx_impl->get();
- io_ctx_impl->dup(*rhs.io_ctx_impl);
-}
-
-int librados::IoCtx::set_auid(uint64_t auid_)
-{
- return -EOPNOTSUPP;
-}
-
-int librados::IoCtx::set_auid_async(uint64_t auid_, PoolAsyncCompletion *c)
-{
- return -EOPNOTSUPP;
-}
-
-int librados::IoCtx::get_auid(uint64_t *auid_)
-{
- return -EOPNOTSUPP;
-}
-
-bool librados::IoCtx::pool_requires_alignment()
-{
- return io_ctx_impl->client->pool_requires_alignment(get_id());
-}
-
-int librados::IoCtx::pool_requires_alignment2(bool *requires)
-{
- return io_ctx_impl->client->pool_requires_alignment2(get_id(), requires);
-}
-
-uint64_t librados::IoCtx::pool_required_alignment()
-{
- return io_ctx_impl->client->pool_required_alignment(get_id());
-}
-
-int librados::IoCtx::pool_required_alignment2(uint64_t *alignment)
-{
- return io_ctx_impl->client->pool_required_alignment2(get_id(), alignment);
-}
-
-std::string librados::IoCtx::get_pool_name()
-{
- std::string s;
- io_ctx_impl->client->pool_get_name(get_id(), &s);
- return s;
-}
-
-std::string librados::IoCtx::get_pool_name() const
-{
- return io_ctx_impl->get_cached_pool_name();
-}
-
-uint64_t librados::IoCtx::get_instance_id() const
-{
- return io_ctx_impl->client->get_instance_id();
-}
-
-int librados::IoCtx::create(const std::string& oid, bool exclusive)
-{
- object_t obj(oid);
- return io_ctx_impl->create(obj, exclusive);
-}
-
-int librados::IoCtx::create(const std::string& oid, bool exclusive,
- const std::string& category) // unused
-{
- object_t obj(oid);
- return io_ctx_impl->create(obj, exclusive);
-}
-
-int librados::IoCtx::write(const std::string& oid, bufferlist& bl, size_t len, uint64_t off)
-{
- object_t obj(oid);
- return io_ctx_impl->write(obj, bl, len, off);
-}
-
-int librados::IoCtx::append(const std::string& oid, bufferlist& bl, size_t len)
-{
- object_t obj(oid);
- return io_ctx_impl->append(obj, bl, len);
-}
-
-int librados::IoCtx::write_full(const std::string& oid, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->write_full(obj, bl);
-}
-
-int librados::IoCtx::writesame(const std::string& oid, bufferlist& bl,
- size_t write_len, uint64_t off)
-{
- object_t obj(oid);
- return io_ctx_impl->writesame(obj, bl, write_len, off);
-}
-
-
-int librados::IoCtx::read(const std::string& oid, bufferlist& bl, size_t len, uint64_t off)
-{
- object_t obj(oid);
- return io_ctx_impl->read(obj, bl, len, off);
-}
-
-int librados::IoCtx::checksum(const std::string& oid,
- rados_checksum_type_t type,
- const bufferlist &init_value_bl, size_t len,
- uint64_t off, size_t chunk_size, bufferlist *pbl)
-{
- object_t obj(oid);
- return io_ctx_impl->checksum(obj, get_checksum_op_type(type), init_value_bl,
- len, off, chunk_size, pbl);
-}
-
-int librados::IoCtx::remove(const std::string& oid)
-{
- object_t obj(oid);
- return io_ctx_impl->remove(obj);
-}
-
-int librados::IoCtx::remove(const std::string& oid, int flags)
-{
- object_t obj(oid);
- return io_ctx_impl->remove(obj, flags);
-}
-
-int librados::IoCtx::trunc(const std::string& oid, uint64_t size)
-{
- object_t obj(oid);
- return io_ctx_impl->trunc(obj, size);
-}
-
-int librados::IoCtx::mapext(const std::string& oid, uint64_t off, size_t len,
- std::map<uint64_t,uint64_t>& m)
-{
- object_t obj(oid);
- return io_ctx_impl->mapext(obj, off, len, m);
-}
-
-int librados::IoCtx::cmpext(const std::string& oid, uint64_t off, bufferlist& cmp_bl)
-{
- object_t obj(oid);
- return io_ctx_impl->cmpext(obj, off, cmp_bl);
-}
-
-int librados::IoCtx::sparse_read(const std::string& oid, std::map<uint64_t,uint64_t>& m,
- bufferlist& bl, size_t len, uint64_t off)
-{
- object_t obj(oid);
- return io_ctx_impl->sparse_read(obj, m, bl, len, off);
-}
-
-int librados::IoCtx::getxattr(const std::string& oid, const char *name, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->getxattr(obj, name, bl);
-}
-
-int librados::IoCtx::getxattrs(const std::string& oid, map<std::string, bufferlist>& attrset)
-{
- object_t obj(oid);
- return io_ctx_impl->getxattrs(obj, attrset);
-}
-
-int librados::IoCtx::setxattr(const std::string& oid, const char *name, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->setxattr(obj, name, bl);
-}
-
-int librados::IoCtx::rmxattr(const std::string& oid, const char *name)
-{
- object_t obj(oid);
- return io_ctx_impl->rmxattr(obj, name);
-}
-
-int librados::IoCtx::stat(const std::string& oid, uint64_t *psize, time_t *pmtime)
-{
- object_t obj(oid);
- return io_ctx_impl->stat(obj, psize, pmtime);
-}
-
-int librados::IoCtx::stat2(const std::string& oid, uint64_t *psize, struct timespec *pts)
-{
- object_t obj(oid);
- return io_ctx_impl->stat2(obj, psize, pts);
-}
-
-int librados::IoCtx::exec(const std::string& oid, const char *cls, const char *method,
- bufferlist& inbl, bufferlist& outbl)
-{
- object_t obj(oid);
- return io_ctx_impl->exec(obj, cls, method, inbl, outbl);
-}
-
-int librados::IoCtx::tmap_update(const std::string& oid, bufferlist& cmdbl)
-{
- object_t obj(oid);
- return io_ctx_impl->tmap_update(obj, cmdbl);
-}
-
-int librados::IoCtx::tmap_put(const std::string& oid, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->tmap_put(obj, bl);
-}
-
-int librados::IoCtx::tmap_get(const std::string& oid, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->tmap_get(obj, bl);
-}
-
-int librados::IoCtx::tmap_to_omap(const std::string& oid, bool nullok)
-{
- object_t obj(oid);
- return io_ctx_impl->tmap_to_omap(obj, nullok);
-}
-
-int librados::IoCtx::omap_get_vals(const std::string& oid,
- const std::string& start_after,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals)
-{
- return omap_get_vals(oid, start_after, string(), max_return, out_vals);
-}
-
-int librados::IoCtx::omap_get_vals2(
- const std::string& oid,
- const std::string& start_after,
- uint64_t max_return,
- std::map<std::string, bufferlist> *out_vals,
- bool *pmore)
-{
- ObjectReadOperation op;
- int r;
- op.omap_get_vals2(start_after, max_return, out_vals, pmore, &r);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0)
- return ret;
- return r;
-}
-
-int librados::IoCtx::omap_get_keys(const std::string& oid,
- const std::string& orig_start_after,
- uint64_t max_return,
- std::set<std::string> *out_keys)
-{
- bool first = true;
- string start_after = orig_start_after;
- bool more = true;
- while (max_return > 0 && more) {
- std::set<std::string> out;
- ObjectReadOperation op;
- op.omap_get_keys2(start_after, max_return, &out, &more, nullptr);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0) {
- return ret;
- }
- if (more) {
- if (out.empty()) {
- return -EINVAL; // wth
- }
- start_after = *out.rbegin();
- }
- if (out.size() <= max_return) {
- max_return -= out.size();
- } else {
- max_return = 0;
- }
- if (first) {
- out_keys->swap(out);
- first = false;
- } else {
- out_keys->insert(out.begin(), out.end());
- out.clear();
- }
- }
- return 0;
-}
-
-int librados::IoCtx::omap_get_keys2(
- const std::string& oid,
- const std::string& start_after,
- uint64_t max_return,
- std::set<std::string> *out_keys,
- bool *pmore)
-{
- ObjectReadOperation op;
- int r;
- op.omap_get_keys2(start_after, max_return, out_keys, pmore, &r);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0)
- return ret;
- return r;
-}
-
-int librados::IoCtx::omap_get_header(const std::string& oid,
- bufferlist *bl)
-{
- ObjectReadOperation op;
- int r;
- op.omap_get_header(bl, &r);
- bufferlist b;
- int ret = operate(oid, &op, &b);
- if (ret < 0)
- return ret;
-
- return r;
-}
-
-int librados::IoCtx::omap_get_vals_by_keys(const std::string& oid,
- const std::set<std::string>& keys,
- std::map<std::string, bufferlist> *vals)
-{
- ObjectReadOperation op;
- int r;
- bufferlist bl;
- op.omap_get_vals_by_keys(keys, vals, &r);
- int ret = operate(oid, &op, &bl);
- if (ret < 0)
- return ret;
-
- return r;
-}
-
-int librados::IoCtx::omap_set(const std::string& oid,
- const map<string, bufferlist>& m)
-{
- ObjectWriteOperation op;
- op.omap_set(m);
- return operate(oid, &op);
-}
-
-int librados::IoCtx::omap_set_header(const std::string& oid,
- const bufferlist& bl)
-{
- ObjectWriteOperation op;
- op.omap_set_header(bl);
- return operate(oid, &op);
-}
-
-int librados::IoCtx::omap_clear(const std::string& oid)
-{
- ObjectWriteOperation op;
- op.omap_clear();
- return operate(oid, &op);
-}
-
-int librados::IoCtx::omap_rm_keys(const std::string& oid,
- const std::set<std::string>& keys)
-{
- ObjectWriteOperation op;
- op.omap_rm_keys(keys);
- return operate(oid, &op);
-}
-
-
-
-static int translate_flags(int flags)
-{
- int op_flags = 0;
- if (flags & librados::OPERATION_BALANCE_READS)
- op_flags |= CEPH_OSD_FLAG_BALANCE_READS;
- if (flags & librados::OPERATION_LOCALIZE_READS)
- op_flags |= CEPH_OSD_FLAG_LOCALIZE_READS;
- if (flags & librados::OPERATION_ORDER_READS_WRITES)
- op_flags |= CEPH_OSD_FLAG_RWORDERED;
- if (flags & librados::OPERATION_IGNORE_CACHE)
- op_flags |= CEPH_OSD_FLAG_IGNORE_CACHE;
- if (flags & librados::OPERATION_SKIPRWLOCKS)
- op_flags |= CEPH_OSD_FLAG_SKIPRWLOCKS;
- if (flags & librados::OPERATION_IGNORE_OVERLAY)
- op_flags |= CEPH_OSD_FLAG_IGNORE_OVERLAY;
- if (flags & librados::OPERATION_FULL_TRY)
- op_flags |= CEPH_OSD_FLAG_FULL_TRY;
- if (flags & librados::OPERATION_FULL_FORCE)
- op_flags |= CEPH_OSD_FLAG_FULL_FORCE;
- if (flags & librados::OPERATION_IGNORE_REDIRECT)
- op_flags |= CEPH_OSD_FLAG_IGNORE_REDIRECT;
- if (flags & librados::OPERATION_ORDERSNAP)
- op_flags |= CEPH_OSD_FLAG_ORDERSNAP;
-
- return op_flags;
-}
-
-int librados::IoCtx::operate(const std::string& oid, librados::ObjectWriteOperation *o)
-{
- object_t obj(oid);
- return io_ctx_impl->operate(obj, &o->impl->o, (ceph::real_time *)o->impl->prt);
-}
-
-int librados::IoCtx::operate(const std::string& oid, librados::ObjectReadOperation *o, bufferlist *pbl)
-{
- object_t obj(oid);
- return io_ctx_impl->operate_read(obj, &o->impl->o, pbl);
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectWriteOperation *o)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
- io_ctx_impl->snapc, 0);
-}
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- ObjectWriteOperation *o, int flags)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
- io_ctx_impl->snapc,
- translate_flags(flags));
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectWriteOperation *o,
- snap_t snap_seq, std::vector<snap_t>& snaps)
-{
- object_t obj(oid);
- vector<snapid_t> snv;
- snv.resize(snaps.size());
- for (size_t i = 0; i < snaps.size(); ++i)
- snv[i] = snaps[i];
- SnapContext snapc(snap_seq, snv);
- return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
- snapc, 0);
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectWriteOperation *o,
- snap_t snap_seq, std::vector<snap_t>& snaps,
- const blkin_trace_info *trace_info)
-{
- object_t obj(oid);
- vector<snapid_t> snv;
- snv.resize(snaps.size());
- for (size_t i = 0; i < snaps.size(); ++i)
- snv[i] = snaps[i];
- SnapContext snapc(snap_seq, snv);
- return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
- snapc, 0, trace_info);
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectWriteOperation *o,
- snap_t snap_seq, std::vector<snap_t>& snaps, int flags,
- const blkin_trace_info *trace_info)
-{
- object_t obj(oid);
- vector<snapid_t> snv;
- snv.resize(snaps.size());
- for (size_t i = 0; i < snaps.size(); ++i)
- snv[i] = snaps[i];
- SnapContext snapc(snap_seq, snv);
- return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc, snapc,
- translate_flags(flags), trace_info);
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectReadOperation *o,
- bufferlist *pbl)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
- 0, pbl);
-}
-
-// deprecated
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectReadOperation *o,
- snap_t snapid_unused_deprecated,
- int flags, bufferlist *pbl)
-{
- object_t obj(oid);
- int op_flags = 0;
- if (flags & OPERATION_BALANCE_READS)
- op_flags |= CEPH_OSD_FLAG_BALANCE_READS;
- if (flags & OPERATION_LOCALIZE_READS)
- op_flags |= CEPH_OSD_FLAG_LOCALIZE_READS;
- if (flags & OPERATION_ORDER_READS_WRITES)
- op_flags |= CEPH_OSD_FLAG_RWORDERED;
-
- return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
- op_flags, pbl);
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectReadOperation *o,
- int flags, bufferlist *pbl)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
- translate_flags(flags), pbl);
-}
-
-int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
- librados::ObjectReadOperation *o,
- int flags, bufferlist *pbl, const blkin_trace_info *trace_info)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
- translate_flags(flags), pbl, trace_info);
-}
-
-void librados::IoCtx::snap_set_read(snap_t seq)
-{
- io_ctx_impl->set_snap_read(seq);
-}
-
-int librados::IoCtx::selfmanaged_snap_set_write_ctx(snap_t seq, vector<snap_t>& snaps)
-{
- vector<snapid_t> snv;
- snv.resize(snaps.size());
- for (unsigned i=0; i<snaps.size(); i++)
- snv[i] = snaps[i];
- return io_ctx_impl->set_snap_write_context(seq, snv);
-}
-
-int librados::IoCtx::snap_create(const char *snapname)
-{
- return io_ctx_impl->snap_create(snapname);
-}
-
-int librados::IoCtx::snap_lookup(const char *name, snap_t *snapid)
-{
- return io_ctx_impl->snap_lookup(name, snapid);
-}
-
-int librados::IoCtx::snap_get_stamp(snap_t snapid, time_t *t)
-{
- return io_ctx_impl->snap_get_stamp(snapid, t);
-}
-
-int librados::IoCtx::snap_get_name(snap_t snapid, std::string *s)
-{
- return io_ctx_impl->snap_get_name(snapid, s);
-}
-
-int librados::IoCtx::snap_remove(const char *snapname)
-{
- return io_ctx_impl->snap_remove(snapname);
-}
-
-int librados::IoCtx::snap_list(std::vector<snap_t> *snaps)
-{
- return io_ctx_impl->snap_list(snaps);
-}
-
-int librados::IoCtx::snap_rollback(const std::string& oid, const char *snapname)
-{
- return io_ctx_impl->rollback(oid, snapname);
-}
-
-// Deprecated name kept for backward compatibility
-int librados::IoCtx::rollback(const std::string& oid, const char *snapname)
-{
- return snap_rollback(oid, snapname);
-}
-
-int librados::IoCtx::selfmanaged_snap_create(uint64_t *snapid)
-{
- return io_ctx_impl->selfmanaged_snap_create(snapid);
-}
-
-void librados::IoCtx::aio_selfmanaged_snap_create(uint64_t *snapid,
- AioCompletion *c)
-{
- io_ctx_impl->aio_selfmanaged_snap_create(snapid, c->pc);
-}
-
-int librados::IoCtx::selfmanaged_snap_remove(uint64_t snapid)
-{
- return io_ctx_impl->selfmanaged_snap_remove(snapid);
-}
-
-void librados::IoCtx::aio_selfmanaged_snap_remove(uint64_t snapid,
- AioCompletion *c)
-{
- io_ctx_impl->aio_selfmanaged_snap_remove(snapid, c->pc);
-}
-
-int librados::IoCtx::selfmanaged_snap_rollback(const std::string& oid, uint64_t snapid)
-{
- return io_ctx_impl->selfmanaged_snap_rollback_object(oid,
- io_ctx_impl->snapc,
- snapid);
-}
-
-int librados::IoCtx::lock_exclusive(const std::string &oid, const std::string &name,
- const std::string &cookie,
- const std::string &description,
- struct timeval * duration, uint8_t flags)
-{
- utime_t dur = utime_t();
- if (duration)
- dur.set_from_timeval(duration);
-
- return rados::cls::lock::lock(this, oid, name, LOCK_EXCLUSIVE, cookie, "",
- description, dur, flags);
-}
-
-int librados::IoCtx::lock_shared(const std::string &oid, const std::string &name,
- const std::string &cookie, const std::string &tag,
- const std::string &description,
- struct timeval * duration, uint8_t flags)
-{
- utime_t dur = utime_t();
- if (duration)
- dur.set_from_timeval(duration);
-
- return rados::cls::lock::lock(this, oid, name, LOCK_SHARED, cookie, tag,
- description, dur, flags);
-}
-
-int librados::IoCtx::unlock(const std::string &oid, const std::string &name,
- const std::string &cookie)
-{
- return rados::cls::lock::unlock(this, oid, name, cookie);
-}
-
-struct AioUnlockCompletion : public librados::ObjectOperationCompletion {
- librados::AioCompletionImpl *completion;
- AioUnlockCompletion(librados::AioCompletion *c) : completion(c->pc) {
- completion->get();
- };
- void handle_completion(int r, bufferlist& outbl) override {
- rados_callback_t cb = completion->callback_complete;
- void *cb_arg = completion->callback_complete_arg;
- cb(completion, cb_arg);
- completion->lock.Lock();
- completion->callback_complete = NULL;
- completion->cond.Signal();
- completion->put_unlock();
- }
-};
-
-int librados::IoCtx::aio_unlock(const std::string &oid, const std::string &name,
- const std::string &cookie, AioCompletion *c)
-{
- return rados::cls::lock::aio_unlock(this, oid, name, cookie, c);
-}
-
-int librados::IoCtx::break_lock(const std::string &oid, const std::string &name,
- const std::string &client, const std::string &cookie)
-{
- entity_name_t locker;
- if (!locker.parse(client))
- return -EINVAL;
- return rados::cls::lock::break_lock(this, oid, name, cookie, locker);
-}
-
-int librados::IoCtx::list_lockers(const std::string &oid, const std::string &name,
- int *exclusive,
- std::string *tag,
- std::list<librados::locker_t> *lockers)
-{
- std::list<librados::locker_t> tmp_lockers;
- map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t> rados_lockers;
- std::string tmp_tag;
- ClsLockType tmp_type;
- int r = rados::cls::lock::get_lock_info(this, oid, name, &rados_lockers, &tmp_type, &tmp_tag);
- if (r < 0)
- return r;
-
- map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t>::iterator map_it;
- for (map_it = rados_lockers.begin(); map_it != rados_lockers.end(); ++map_it) {
- librados::locker_t locker;
- locker.client = stringify(map_it->first.locker);
- locker.cookie = map_it->first.cookie;
- locker.address = stringify(map_it->second.addr);
- tmp_lockers.push_back(locker);
- }
-
- if (lockers)
- *lockers = tmp_lockers;
- if (tag)
- *tag = tmp_tag;
- if (exclusive) {
- if (tmp_type == LOCK_EXCLUSIVE)
- *exclusive = 1;
- else
- *exclusive = 0;
- }
-
- return tmp_lockers.size();
-}
-
-librados::NObjectIterator librados::IoCtx::nobjects_begin()
-{
- bufferlist bl;
- return nobjects_begin(bl);
-}
-
-librados::NObjectIterator librados::IoCtx::nobjects_begin(
- const bufferlist &filter)
-{
- rados_list_ctx_t listh;
- rados_nobjects_list_open(io_ctx_impl, &listh);
- NObjectIterator iter((ObjListCtx*)listh);
- if (filter.length() > 0) {
- iter.set_filter(filter);
- }
- iter.get_next();
- return iter;
-}
-
-librados::NObjectIterator librados::IoCtx::nobjects_begin(uint32_t pos)
-{
- bufferlist bl;
- return nobjects_begin(pos, bl);
-}
-
-librados::NObjectIterator librados::IoCtx::nobjects_begin(
- uint32_t pos, const bufferlist &filter)
-{
- rados_list_ctx_t listh;
- rados_nobjects_list_open(io_ctx_impl, &listh);
- NObjectIterator iter((ObjListCtx*)listh);
- if (filter.length() > 0) {
- iter.set_filter(filter);
- }
- iter.seek(pos);
- return iter;
-}
-
-librados::NObjectIterator librados::IoCtx::nobjects_begin(const ObjectCursor& cursor)
-{
- bufferlist bl;
- return nobjects_begin(cursor, bl);
-}
-
-librados::NObjectIterator librados::IoCtx::nobjects_begin(
- const ObjectCursor& cursor, const bufferlist &filter)
-{
- rados_list_ctx_t listh;
- rados_nobjects_list_open(io_ctx_impl, &listh);
- NObjectIterator iter((ObjListCtx*)listh);
- if (filter.length() > 0) {
- iter.set_filter(filter);
- }
- iter.seek(cursor);
- return iter;
-}
-
-const librados::NObjectIterator& librados::IoCtx::nobjects_end() const
-{
- return NObjectIterator::__EndObjectIterator;
-}
-
-int librados::IoCtx::hit_set_list(uint32_t hash, AioCompletion *c,
- std::list< std::pair<time_t, time_t> > *pls)
-{
- return io_ctx_impl->hit_set_list(hash, c->pc, pls);
-}
-
-int librados::IoCtx::hit_set_get(uint32_t hash, AioCompletion *c, time_t stamp,
- bufferlist *pbl)
-{
- return io_ctx_impl->hit_set_get(hash, c->pc, stamp, pbl);
-}
-
-
-
-uint64_t librados::IoCtx::get_last_version()
-{
- return io_ctx_impl->last_version();
-}
-
-int librados::IoCtx::aio_read(const std::string& oid, librados::AioCompletion *c,
- bufferlist *pbl, size_t len, uint64_t off)
-{
- return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off,
- io_ctx_impl->snap_seq);
-}
-
-int librados::IoCtx::aio_read(const std::string& oid, librados::AioCompletion *c,
- bufferlist *pbl, size_t len, uint64_t off,
- uint64_t snapid)
-{
- return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off, snapid);
-}
-
-int librados::IoCtx::aio_exec(const std::string& oid,
- librados::AioCompletion *c, const char *cls,
- const char *method, bufferlist& inbl,
- bufferlist *outbl)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_exec(obj, c->pc, cls, method, inbl, outbl);
-}
-
-int librados::IoCtx::aio_cmpext(const std::string& oid,
- librados::AioCompletion *c,
- uint64_t off,
- bufferlist& cmp_bl)
-{
- return io_ctx_impl->aio_cmpext(oid, c->pc, off, cmp_bl);
-}
-
-int librados::IoCtx::aio_sparse_read(const std::string& oid, librados::AioCompletion *c,
- std::map<uint64_t,uint64_t> *m, bufferlist *data_bl,
- size_t len, uint64_t off)
-{
- return io_ctx_impl->aio_sparse_read(oid, c->pc,
- m, data_bl, len, off,
- io_ctx_impl->snap_seq);
-}
-
-int librados::IoCtx::aio_sparse_read(const std::string& oid, librados::AioCompletion *c,
- std::map<uint64_t,uint64_t> *m, bufferlist *data_bl,
- size_t len, uint64_t off, uint64_t snapid)
-{
- return io_ctx_impl->aio_sparse_read(oid, c->pc,
- m, data_bl, len, off, snapid);
-}
-
-int librados::IoCtx::aio_write(const std::string& oid, librados::AioCompletion *c,
- const bufferlist& bl, size_t len, uint64_t off)
-{
- return io_ctx_impl->aio_write(oid, c->pc, bl, len, off);
-}
-
-int librados::IoCtx::aio_append(const std::string& oid, librados::AioCompletion *c,
- const bufferlist& bl, size_t len)
-{
- return io_ctx_impl->aio_append(oid, c->pc, bl, len);
-}
-
-int librados::IoCtx::aio_write_full(const std::string& oid, librados::AioCompletion *c,
- const bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_write_full(obj, c->pc, bl);
-}
-
-int librados::IoCtx::aio_writesame(const std::string& oid, librados::AioCompletion *c,
- const bufferlist& bl, size_t write_len,
- uint64_t off)
-{
- return io_ctx_impl->aio_writesame(oid, c->pc, bl, write_len, off);
-}
-
-
-int librados::IoCtx::aio_remove(const std::string& oid, librados::AioCompletion *c)
-{
- return io_ctx_impl->aio_remove(oid, c->pc);
-}
-
-int librados::IoCtx::aio_remove(const std::string& oid, librados::AioCompletion *c, int flags)
-{
- return io_ctx_impl->aio_remove(oid, c->pc, flags);
-}
-
-int librados::IoCtx::aio_flush_async(librados::AioCompletion *c)
-{
- io_ctx_impl->flush_aio_writes_async(c->pc);
- return 0;
-}
-
-int librados::IoCtx::aio_flush()
-{
- io_ctx_impl->flush_aio_writes();
- return 0;
-}
-
-struct AioGetxattrDataPP {
- AioGetxattrDataPP(librados::AioCompletionImpl *c, bufferlist *_bl) :
- bl(_bl), completion(c) {}
- bufferlist *bl;
- struct librados::C_AioCompleteAndSafe completion;
-};
-
-static void rados_aio_getxattr_completepp(rados_completion_t c, void *arg) {
- AioGetxattrDataPP *cdata = reinterpret_cast<AioGetxattrDataPP*>(arg);
- int rc = rados_aio_get_return_value(c);
- if (rc >= 0) {
- rc = cdata->bl->length();
- }
- cdata->completion.finish(rc);
- delete cdata;
-}
-
-int librados::IoCtx::aio_getxattr(const std::string& oid, librados::AioCompletion *c,
- const char *name, bufferlist& bl)
-{
- // create data object to be passed to async callback
- AioGetxattrDataPP *cdata = new AioGetxattrDataPP(c->pc, &bl);
- if (!cdata) {
- return -ENOMEM;
- }
- // create completion callback
- librados::AioCompletionImpl *comp = new librados::AioCompletionImpl;
- comp->set_complete_callback(cdata, rados_aio_getxattr_completepp);
- // call actual getxattr from IoCtxImpl
- object_t obj(oid);
- return io_ctx_impl->aio_getxattr(obj, comp, name, bl);
-}
-
-int librados::IoCtx::aio_getxattrs(const std::string& oid, AioCompletion *c,
- map<std::string, bufferlist>& attrset)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_getxattrs(obj, c->pc, attrset);
-}
-
-int librados::IoCtx::aio_setxattr(const std::string& oid, AioCompletion *c,
- const char *name, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_setxattr(obj, c->pc, name, bl);
-}
-
-int librados::IoCtx::aio_rmxattr(const std::string& oid, AioCompletion *c,
- const char *name)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_rmxattr(obj, c->pc, name);
-}
-
-int librados::IoCtx::aio_stat(const std::string& oid, librados::AioCompletion *c,
- uint64_t *psize, time_t *pmtime)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_stat(obj, c->pc, psize, pmtime);
-}
-
-int librados::IoCtx::aio_cancel(librados::AioCompletion *c)
-{
- return io_ctx_impl->aio_cancel(c->pc);
-}
-
-int librados::IoCtx::watch(const string& oid, uint64_t ver, uint64_t *cookie,
- librados::WatchCtx *ctx)
-{
- object_t obj(oid);
- return io_ctx_impl->watch(obj, cookie, ctx, NULL);
-}
-
-int librados::IoCtx::watch2(const string& oid, uint64_t *cookie,
- librados::WatchCtx2 *ctx2)
-{
- object_t obj(oid);
- return io_ctx_impl->watch(obj, cookie, NULL, ctx2);
-}
-
-int librados::IoCtx::watch3(const string& oid, uint64_t *cookie,
- librados::WatchCtx2 *ctx2, uint32_t timeout)
-{
- object_t obj(oid);
- return io_ctx_impl->watch(obj, cookie, NULL, ctx2, timeout);
-}
-
-int librados::IoCtx::aio_watch(const string& oid, AioCompletion *c,
- uint64_t *cookie,
- librados::WatchCtx2 *ctx2)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_watch(obj, c->pc, cookie, NULL, ctx2);
-}
-
-int librados::IoCtx::aio_watch2(const string& oid, AioCompletion *c,
- uint64_t *cookie,
- librados::WatchCtx2 *ctx2,
- uint32_t timeout)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_watch(obj, c->pc, cookie, NULL, ctx2, timeout);
-}
-
-int librados::IoCtx::unwatch(const string& oid, uint64_t handle)
-{
- return io_ctx_impl->unwatch(handle);
-}
-
-int librados::IoCtx::unwatch2(uint64_t handle)
-{
- return io_ctx_impl->unwatch(handle);
-}
-
-int librados::IoCtx::aio_unwatch(uint64_t handle, AioCompletion *c)
-{
- return io_ctx_impl->aio_unwatch(handle, c->pc);
-}
-
-int librados::IoCtx::watch_check(uint64_t handle)
-{
- return io_ctx_impl->watch_check(handle);
-}
-
-int librados::IoCtx::notify(const string& oid, uint64_t ver, bufferlist& bl)
-{
- object_t obj(oid);
- return io_ctx_impl->notify(obj, bl, 0, NULL, NULL, NULL);
-}
-
-int librados::IoCtx::notify2(const string& oid, bufferlist& bl,
- uint64_t timeout_ms, bufferlist *preplybl)
-{
- object_t obj(oid);
- return io_ctx_impl->notify(obj, bl, timeout_ms, preplybl, NULL, NULL);
-}
-
-int librados::IoCtx::aio_notify(const string& oid, AioCompletion *c,
- bufferlist& bl, uint64_t timeout_ms,
- bufferlist *preplybl)
-{
- object_t obj(oid);
- return io_ctx_impl->aio_notify(obj, c->pc, bl, timeout_ms, preplybl, NULL,
- NULL);
-}
-
-void librados::IoCtx::notify_ack(const std::string& o,
- uint64_t notify_id, uint64_t handle,
- bufferlist& bl)
-{
- io_ctx_impl->notify_ack(o, notify_id, handle, bl);
-}
-
-int librados::IoCtx::list_watchers(const std::string& oid,
- std::list<obj_watch_t> *out_watchers)
-{
- ObjectReadOperation op;
- int r;
- op.list_watchers(out_watchers, &r);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0)
- return ret;
-
- return r;
-}
-
-int librados::IoCtx::list_snaps(const std::string& oid,
- snap_set_t *out_snaps)
-{
- ObjectReadOperation op;
- int r;
- if (io_ctx_impl->snap_seq != CEPH_SNAPDIR)
- return -EINVAL;
- op.list_snaps(out_snaps, &r);
- bufferlist bl;
- int ret = operate(oid, &op, &bl);
- if (ret < 0)
- return ret;
-
- return r;
-}
-
-void librados::IoCtx::set_notify_timeout(uint32_t timeout)
-{
- io_ctx_impl->set_notify_timeout(timeout);
-}
-
-int librados::IoCtx::set_alloc_hint(const std::string& o,
- uint64_t expected_object_size,
- uint64_t expected_write_size)
-{
- object_t oid(o);
- return io_ctx_impl->set_alloc_hint(oid, expected_object_size,
- expected_write_size, 0);
-}
-
-int librados::IoCtx::set_alloc_hint2(const std::string& o,
- uint64_t expected_object_size,
- uint64_t expected_write_size,
- uint32_t flags)
-{
- object_t oid(o);
- return io_ctx_impl->set_alloc_hint(oid, expected_object_size,
- expected_write_size, flags);
-}
-
-void librados::IoCtx::set_assert_version(uint64_t ver)
-{
- io_ctx_impl->set_assert_version(ver);
-}
-
-void librados::IoCtx::locator_set_key(const string& key)
-{
- io_ctx_impl->oloc.key = key;
-}
-
-void librados::IoCtx::set_namespace(const string& nspace)
-{
- io_ctx_impl->oloc.nspace = nspace;
-}
-
-std::string librados::IoCtx::get_namespace() const
-{
- return io_ctx_impl->oloc.nspace;
-}
-
-int64_t librados::IoCtx::get_id()
-{
- return io_ctx_impl->get_id();
-}
-
-uint32_t librados::IoCtx::get_object_hash_position(const std::string& oid)
-{
- uint32_t hash;
- int r = io_ctx_impl->get_object_hash_position(oid, &hash);
- if (r < 0)
- hash = 0;
- return hash;
-}
-
-uint32_t librados::IoCtx::get_object_pg_hash_position(const std::string& oid)
-{
- uint32_t hash;
- int r = io_ctx_impl->get_object_pg_hash_position(oid, &hash);
- if (r < 0)
- hash = 0;
- return hash;
-}
-
-int librados::IoCtx::get_object_hash_position2(
- const std::string& oid, uint32_t *hash_position)
-{
- return io_ctx_impl->get_object_hash_position(oid, hash_position);
-}
-
-int librados::IoCtx::get_object_pg_hash_position2(
- const std::string& oid, uint32_t *pg_hash_position)
-{
- return io_ctx_impl->get_object_pg_hash_position(oid, pg_hash_position);
-}
-
-librados::config_t librados::IoCtx::cct()
-{
- return (config_t)io_ctx_impl->client->cct;
-}
-
-librados::IoCtx::IoCtx(IoCtxImpl *io_ctx_impl_)
- : io_ctx_impl(io_ctx_impl_)
-{
-}
-
-void librados::IoCtx::set_osdmap_full_try()
-{
- io_ctx_impl->objecter->set_osdmap_full_try();
-}
-
-void librados::IoCtx::unset_osdmap_full_try()
-{
- io_ctx_impl->objecter->unset_osdmap_full_try();
-}
-
-///////////////////////////// Rados //////////////////////////////
-void librados::Rados::version(int *major, int *minor, int *extra)
-{
- rados_version(major, minor, extra);
-}
-
-librados::Rados::Rados() : client(NULL)
-{
-}
-
-librados::Rados::Rados(IoCtx &ioctx)
-{
- client = ioctx.io_ctx_impl->client;
- ceph_assert(client != NULL);
- client->get();
-}
-
-librados::Rados::~Rados()
-{
- shutdown();
-}
-
-int librados::Rados::init(const char * const id)
-{
- return rados_create((rados_t *)&client, id);
-}
-
-int librados::Rados::init2(const char * const name,
- const char * const clustername, uint64_t flags)
-{
- return rados_create2((rados_t *)&client, clustername, name, flags);
-}
-
-int librados::Rados::init_with_context(config_t cct_)
-{
- return rados_create_with_context((rados_t *)&client, (rados_config_t)cct_);
-}
-
-int librados::Rados::connect()
-{
- return client->connect();
-}
-
-librados::config_t librados::Rados::cct()
-{
- return (config_t)client->cct;
-}
-
-int librados::Rados::watch_flush()
-{
- if (!client)
- return -EINVAL;
- return client->watch_flush();
-}
-
-int librados::Rados::aio_watch_flush(AioCompletion *c)
-{
- if (!client)
- return -EINVAL;
- return client->async_watch_flush(c->pc);
-}
-
-void librados::Rados::shutdown()
-{
- if (!client)
- return;
- if (client->put()) {
- client->shutdown();
- delete client;
- client = NULL;
- }
-}
-
-uint64_t librados::Rados::get_instance_id()
-{
- return client->get_instance_id();
-}
-
-int librados::Rados::get_min_compatible_osd(int8_t* require_osd_release)
-{
- return client->get_min_compatible_osd(require_osd_release);
-}
-
-int librados::Rados::get_min_compatible_client(int8_t* min_compat_client,
- int8_t* require_min_compat_client)
-{
- return client->get_min_compatible_client(min_compat_client,
- require_min_compat_client);
-}
-
-int librados::Rados::conf_read_file(const char * const path) const
-{
- return rados_conf_read_file((rados_t)client, path);
-}
-
-int librados::Rados::conf_parse_argv(int argc, const char ** argv) const
-{
- return rados_conf_parse_argv((rados_t)client, argc, argv);
-}
-
-int librados::Rados::conf_parse_argv_remainder(int argc, const char ** argv,
- const char ** remargv) const
-{
- return rados_conf_parse_argv_remainder((rados_t)client, argc, argv, remargv);
-}
-
-int librados::Rados::conf_parse_env(const char *name) const
-{
- return rados_conf_parse_env((rados_t)client, name);
-}
-
-int librados::Rados::conf_set(const char *option, const char *value)
-{
- return rados_conf_set((rados_t)client, option, value);
-}
-
-int librados::Rados::conf_get(const char *option, std::string &val)
-{
- char *str = NULL;
- const auto& conf = client->cct->_conf;
- int ret = conf.get_val(option, &str, -1);
- if (ret) {
- free(str);
- return ret;
- }
- val = str;
- free(str);
- return 0;
-}
-
-int librados::Rados::service_daemon_register(
- const std::string& service, ///< service name (e.g., 'rgw')
- const std::string& name, ///< daemon name (e.g., 'gwfoo')
- const std::map<std::string,std::string>& metadata) ///< static metadata about daemon
-{
- return client->service_daemon_register(service, name, metadata);
-}
-
-int librados::Rados::service_daemon_update_status(
- std::map<std::string,std::string>&& status)
-{
- return client->service_daemon_update_status(std::move(status));
-}
-
-int librados::Rados::pool_create(const char *name)
-{
- string str(name);
- return client->pool_create(str);
-}
-
-int librados::Rados::pool_create(const char *name, uint64_t auid)
-{
- if (auid != CEPH_AUTH_UID_DEFAULT) {
- return -EINVAL;
- }
- string str(name);
- return client->pool_create(str);
-}
-
-int librados::Rados::pool_create(const char *name, uint64_t auid, __u8 crush_rule)
-{
- if (auid != CEPH_AUTH_UID_DEFAULT) {
- return -EINVAL;
- }
- string str(name);
- return client->pool_create(str, crush_rule);
-}
-
-int librados::Rados::pool_create_with_rule(const char *name, __u8 crush_rule)
-{
- string str(name);
- return client->pool_create(str, crush_rule);
-}
-
-int librados::Rados::pool_create_async(const char *name, PoolAsyncCompletion *c)
-{
- string str(name);
- return client->pool_create_async(str, c->pc);
-}
-
-int librados::Rados::pool_create_async(const char *name, uint64_t auid, PoolAsyncCompletion *c)
-{
- if (auid != CEPH_AUTH_UID_DEFAULT) {
- return -EINVAL;
- }
- string str(name);
- return client->pool_create_async(str, c->pc);
-}
-
-int librados::Rados::pool_create_async(const char *name, uint64_t auid, __u8 crush_rule,
- PoolAsyncCompletion *c)
-{
- if (auid != CEPH_AUTH_UID_DEFAULT) {
- return -EINVAL;
- }
- string str(name);
- return client->pool_create_async(str, c->pc, crush_rule);
-}
-
-int librados::Rados::pool_create_with_rule_async(
- const char *name, __u8 crush_rule,
- PoolAsyncCompletion *c)
-{
- string str(name);
- return client->pool_create_async(str, c->pc, crush_rule);
-}
-
-int librados::Rados::pool_get_base_tier(int64_t pool_id, int64_t* base_tier)
-{
- tracepoint(librados, rados_pool_get_base_tier_enter, (rados_t)client, pool_id);
- int retval = client->pool_get_base_tier(pool_id, base_tier);
- tracepoint(librados, rados_pool_get_base_tier_exit, retval, *base_tier);
- return retval;
-}
-
-int librados::Rados::pool_delete(const char *name)
-{
- return client->pool_delete(name);
-}
-
-int librados::Rados::pool_delete_async(const char *name, PoolAsyncCompletion *c)
-{
- return client->pool_delete_async(name, c->pc);
-}
-
-int librados::Rados::pool_list(std::list<std::string>& v)
-{
- std::list<std::pair<int64_t, std::string> > pools;
- int r = client->pool_list(pools);
- if (r < 0) {
- return r;
- }
-
- v.clear();
- for (std::list<std::pair<int64_t, std::string> >::iterator it = pools.begin();
- it != pools.end(); ++it) {
- v.push_back(it->second);
- }
- return 0;
-}
-
-int librados::Rados::pool_list2(std::list<std::pair<int64_t, std::string> >& v)
-{
- return client->pool_list(v);
-}
-
-int64_t librados::Rados::pool_lookup(const char *name)
-{
- return client->lookup_pool(name);
-}
-
-int librados::Rados::pool_reverse_lookup(int64_t id, std::string *name)
-{
- return client->pool_get_name(id, name);
-}
-
-int librados::Rados::mon_command(string cmd, const bufferlist& inbl,
- bufferlist *outbl, string *outs)
-{
- vector<string> cmdvec;
- cmdvec.push_back(cmd);
- return client->mon_command(cmdvec, inbl, outbl, outs);
-}
-
-int librados::Rados::osd_command(int osdid, std::string cmd, const bufferlist& inbl,
- bufferlist *outbl, std::string *outs)
-{
- vector<string> cmdvec;
- cmdvec.push_back(cmd);
- return client->osd_command(osdid, cmdvec, inbl, outbl, outs);
-}
-
-int librados::Rados::mgr_command(std::string cmd, const bufferlist& inbl,
- bufferlist *outbl, std::string *outs)
-{
- vector<string> cmdvec;
- cmdvec.push_back(cmd);
- return client->mgr_command(cmdvec, inbl, outbl, outs);
-}
-
-
-
-int librados::Rados::pg_command(const char *pgstr, std::string cmd, const bufferlist& inbl,
- bufferlist *outbl, std::string *outs)
-{
- vector<string> cmdvec;
- cmdvec.push_back(cmd);
-
- pg_t pgid;
- if (!pgid.parse(pgstr))
- return -EINVAL;
-
- return client->pg_command(pgid, cmdvec, inbl, outbl, outs);
-}
-
-int librados::Rados::ioctx_create(const char *name, IoCtx &io)
-{
- rados_ioctx_t p;
- int ret = rados_ioctx_create((rados_t)client, name, &p);
- if (ret)
- return ret;
- io.close();
- io.io_ctx_impl = (IoCtxImpl*)p;
- return 0;
-}
-
-int librados::Rados::ioctx_create2(int64_t pool_id, IoCtx &io)
-{
- rados_ioctx_t p;
- int ret = rados_ioctx_create2((rados_t)client, pool_id, &p);
- if (ret)
- return ret;
- io.close();
- io.io_ctx_impl = (IoCtxImpl*)p;
- return 0;
-}
-
-void librados::Rados::test_blacklist_self(bool set)
-{
- client->blacklist_self(set);
-}
-
-int librados::Rados::get_pool_stats(std::list<string>& v,
- stats_map& result)
-{
- map<string,::pool_stat_t> rawresult;
- int r = client->get_pool_stats(v, rawresult);
- for (map<string,::pool_stat_t>::iterator p = rawresult.begin();
- p != rawresult.end();
- ++p) {
- pool_stat_t& pv = result[p->first];
- object_stat_sum_t *sum = &p->second.stats.sum;
- pv.num_kb = shift_round_up(sum->num_bytes, 10);
- pv.num_bytes = sum->num_bytes;
- pv.num_objects = sum->num_objects;
- pv.num_object_clones = sum->num_object_clones;
- pv.num_object_copies = sum->num_object_copies;
- pv.num_objects_missing_on_primary = sum->num_objects_missing_on_primary;
- pv.num_objects_unfound = sum->num_objects_unfound;
- pv.num_objects_degraded = sum->num_objects_degraded;
- pv.num_rd = sum->num_rd;
- pv.num_rd_kb = sum->num_rd_kb;
- pv.num_wr = sum->num_wr;
- pv.num_wr_kb = sum->num_wr_kb;
- }
- return r;
-}
-
-int librados::Rados::get_pool_stats(std::list<string>& v,
- std::map<string, stats_map>& result)
-{
- stats_map m;
- int r = get_pool_stats(v, m);
- if (r < 0)
- return r;
- for (map<string,pool_stat_t>::iterator p = m.begin();
- p != m.end();
- ++p) {
- result[p->first][string()] = p->second;
- }
- return r;
-}
-
-int librados::Rados::get_pool_stats(std::list<string>& v,
- string& category, // unused
- std::map<string, stats_map>& result)
-{
- return -EOPNOTSUPP;
-}
-
-bool librados::Rados::get_pool_is_selfmanaged_snaps_mode(const std::string& pool)
-{
- return client->get_pool_is_selfmanaged_snaps_mode(pool);
-}
-
-int librados::Rados::cluster_stat(cluster_stat_t& result)
-{
- ceph_statfs stats;
- int r = client->get_fs_stats(stats);
- result.kb = stats.kb;
- result.kb_used = stats.kb_used;
- result.kb_avail = stats.kb_avail;
- result.num_objects = stats.num_objects;
- return r;
-}
-
-int librados::Rados::cluster_fsid(string *fsid)
-{
- return client->get_fsid(fsid);
-}
-
-namespace librados {
- struct PlacementGroupImpl {
- pg_t pgid;
- };
-
- PlacementGroup::PlacementGroup()
- : impl{new PlacementGroupImpl}
- {}
-
- PlacementGroup::PlacementGroup(const PlacementGroup& pg)
- : impl{new PlacementGroupImpl}
- {
- impl->pgid = pg.impl->pgid;
- }
-
- PlacementGroup::~PlacementGroup()
- {}
-
- bool PlacementGroup::parse(const char* s)
- {
- return impl->pgid.parse(s);
- }
-}
-
-std::ostream& librados::operator<<(std::ostream& out,
- const librados::PlacementGroup& pg)
-{
- return out << pg.impl->pgid;
-}
-
-int librados::Rados::get_inconsistent_pgs(int64_t pool_id,
- std::vector<PlacementGroup>* pgs)
-{
- std::vector<string> pgids;
- if (auto ret = client->get_inconsistent_pgs(pool_id, &pgids); ret) {
- return ret;
- }
- for (const auto& pgid : pgids) {
- librados::PlacementGroup pg;
- if (!pg.parse(pgid.c_str())) {
- return -EINVAL;
- }
- pgs->emplace_back(std::move(pg));
- }
- return 0;
-}
-
-int librados::Rados::get_inconsistent_objects(const PlacementGroup& pg,
- const object_id_t &start_after,
- unsigned max_return,
- AioCompletion *c,
- std::vector<inconsistent_obj_t>* objects,
- uint32_t* interval)
-{
- IoCtx ioctx;
- const pg_t pgid = pg.impl->pgid;
- int r = ioctx_create2(pgid.pool(), ioctx);
- if (r < 0) {
- return r;
- }
-
- return ioctx.io_ctx_impl->get_inconsistent_objects(pgid,
- start_after,
- max_return,
- c->pc,
- objects,
- interval);
-}
-
-int librados::Rados::get_inconsistent_snapsets(const PlacementGroup& pg,
- const object_id_t &start_after,
- unsigned max_return,
- AioCompletion *c,
- std::vector<inconsistent_snapset_t>* snapsets,
- uint32_t* interval)
-{
- IoCtx ioctx;
- const pg_t pgid = pg.impl->pgid;
- int r = ioctx_create2(pgid.pool(), ioctx);
- if (r < 0) {
- return r;
- }
-
- return ioctx.io_ctx_impl->get_inconsistent_snapsets(pgid,
- start_after,
- max_return,
- c->pc,
- snapsets,
- interval);
-}
-
-int librados::Rados::wait_for_latest_osdmap()
-{
- return client->wait_for_latest_osdmap();
-}
-
-int librados::Rados::blacklist_add(const std::string& client_address,
- uint32_t expire_seconds)
-{
- return client->blacklist_add(client_address, expire_seconds);
-}
-
-librados::PoolAsyncCompletion *librados::Rados::pool_async_create_completion()
-{
- PoolAsyncCompletionImpl *c = new PoolAsyncCompletionImpl;
- return new PoolAsyncCompletion(c);
-}
-
-librados::AioCompletion *librados::Rados::aio_create_completion()
-{
- AioCompletionImpl *c = new AioCompletionImpl;
- return new AioCompletion(c);
-}
-
-librados::AioCompletion *librados::Rados::aio_create_completion(void *cb_arg,
- callback_t cb_complete,
- callback_t cb_safe)
-{
- AioCompletionImpl *c;
- int r = rados_aio_create_completion(cb_arg, cb_complete, cb_safe, (void**)&c);
- ceph_assert(r == 0);
- return new AioCompletion(c);
-}
-
-librados::ObjectOperation::ObjectOperation()
-{
- impl = new ObjectOperationImpl;
-}
-
-librados::ObjectOperation::~ObjectOperation()
-{
- delete impl;
-}
-
-///////////////////////////// C API //////////////////////////////
-
-static CephContext *rados_create_cct(const char * const clustername,
- CephInitParameters *iparams)
-{
- // missing things compared to global_init:
- // g_ceph_context, g_conf, g_lockdep, signal handlers
- CephContext *cct = common_preinit(*iparams, CODE_ENVIRONMENT_LIBRARY, 0);
- if (clustername)
- cct->_conf->cluster = clustername;
- cct->_conf.parse_env(); // environment variables override
- cct->_conf.apply_changes(nullptr);
-
- TracepointProvider::initialize<tracepoint_traits>(cct);
- return cct;
-}
-
-extern "C" int rados_create(rados_t *pcluster, const char * const id)
-{
- CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
- if (id) {
- iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id);
- }
- CephContext *cct = rados_create_cct("", &iparams);
-
- tracepoint(librados, rados_create_enter, id);
- *pcluster = reinterpret_cast<rados_t>(new librados::RadosClient(cct));
- tracepoint(librados, rados_create_exit, 0, *pcluster);
-
- cct->put();
- return 0;
-}
-
-// as above, but
-// 1) don't assume 'client.'; name is a full type.id namestr
-// 2) allow setting clustername
-// 3) flags is for future expansion (maybe some of the global_init()
-// behavior is appropriate for some consumers of librados, for instance)
-
-extern "C" int rados_create2(rados_t *pcluster, const char *const clustername,
- const char * const name, uint64_t flags)
-{
- // client is assumed, but from_str will override
- int retval = 0;
- CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
- if (!name || !iparams.name.from_str(name)) {
- retval = -EINVAL;
- }
-
- CephContext *cct = rados_create_cct(clustername, &iparams);
- tracepoint(librados, rados_create2_enter, clustername, name, flags);
- if (retval == 0) {
- *pcluster = reinterpret_cast<rados_t>(new librados::RadosClient(cct));
- }
- tracepoint(librados, rados_create2_exit, retval, *pcluster);
-
- cct->put();
- return retval;
-}
-
-/* This function is intended for use by Ceph daemons. These daemons have
- * already called global_init and want to use that particular configuration for
- * their cluster.
- */
-extern "C" int rados_create_with_context(rados_t *pcluster, rados_config_t cct_)
-{
- CephContext *cct = (CephContext *)cct_;
- TracepointProvider::initialize<tracepoint_traits>(cct);
-
- tracepoint(librados, rados_create_with_context_enter, cct_);
- librados::RadosClient *radosp = new librados::RadosClient(cct);
- *pcluster = (void *)radosp;
- tracepoint(librados, rados_create_with_context_exit, 0, *pcluster);
- return 0;
-}
-
-extern "C" rados_config_t rados_cct(rados_t cluster)
-{
- tracepoint(librados, rados_cct_enter, cluster);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- rados_config_t retval = (rados_config_t)client->cct;
- tracepoint(librados, rados_cct_exit, retval);
- return retval;
-}
-
-extern "C" int rados_connect(rados_t cluster)
-{
- tracepoint(librados, rados_connect_enter, cluster);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- int retval = client->connect();
- tracepoint(librados, rados_connect_exit, retval);
- return retval;
-}
-
-extern "C" void rados_shutdown(rados_t cluster)
-{
- tracepoint(librados, rados_shutdown_enter, cluster);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- radosp->shutdown();
- delete radosp;
- tracepoint(librados, rados_shutdown_exit);
-}
-
-extern "C" uint64_t rados_get_instance_id(rados_t cluster)
-{
- tracepoint(librados, rados_get_instance_id_enter, cluster);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- uint64_t retval = client->get_instance_id();
- tracepoint(librados, rados_get_instance_id_exit, retval);
- return retval;
-}
-
-extern "C" int rados_get_min_compatible_osd(rados_t cluster,
- int8_t* require_osd_release)
-{
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- return client->get_min_compatible_osd(require_osd_release);
-}
-
-extern "C" int rados_get_min_compatible_client(rados_t cluster,
- int8_t* min_compat_client,
- int8_t* require_min_compat_client)
-{
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- return client->get_min_compatible_client(min_compat_client,
- require_min_compat_client);
-}
-
-extern "C" void rados_version(int *major, int *minor, int *extra)
-{
- tracepoint(librados, rados_version_enter, major, minor, extra);
- if (major)
- *major = LIBRADOS_VER_MAJOR;
- if (minor)
- *minor = LIBRADOS_VER_MINOR;
- if (extra)
- *extra = LIBRADOS_VER_EXTRA;
- tracepoint(librados, rados_version_exit, LIBRADOS_VER_MAJOR, LIBRADOS_VER_MINOR, LIBRADOS_VER_EXTRA);
-}
-
-
-// -- config --
-extern "C" int rados_conf_read_file(rados_t cluster, const char *path_list)
-{
- tracepoint(librados, rados_conf_read_file_enter, cluster, path_list);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- auto& conf = client->cct->_conf;
- ostringstream warnings;
- int ret = conf.parse_config_files(path_list, &warnings, 0);
- if (ret) {
- if (warnings.tellp() > 0)
- lderr(client->cct) << warnings.str() << dendl;
- client->cct->_conf.complain_about_parse_errors(client->cct);
- tracepoint(librados, rados_conf_read_file_exit, ret);
- return ret;
- }
- conf.parse_env(); // environment variables override
-
- conf.apply_changes(nullptr);
- client->cct->_conf.complain_about_parse_errors(client->cct);
- tracepoint(librados, rados_conf_read_file_exit, 0);
- return 0;
-}
-
-extern "C" int rados_conf_parse_argv(rados_t cluster, int argc, const char **argv)
-{
- tracepoint(librados, rados_conf_parse_argv_enter, cluster, argc);
- int i;
- for(i = 0; i < argc; i++) {
- tracepoint(librados, rados_conf_parse_argv_arg, argv[i]);
- }
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- auto& conf = client->cct->_conf;
- vector<const char*> args;
- argv_to_vec(argc, argv, args);
- int ret = conf.parse_argv(args);
- if (ret) {
- tracepoint(librados, rados_conf_parse_argv_exit, ret);
- return ret;
- }
- conf.apply_changes(nullptr);
- tracepoint(librados, rados_conf_parse_argv_exit, 0);
- return 0;
-}
-
-// like above, but return the remainder of argv to contain remaining
-// unparsed args. Must be allocated to at least argc by caller.
-// remargv will contain n <= argc pointers to original argv[], the end
-// of which may be NULL
-
-extern "C" int rados_conf_parse_argv_remainder(rados_t cluster, int argc,
- const char **argv,
- const char **remargv)
-{
- tracepoint(librados, rados_conf_parse_argv_remainder_enter, cluster, argc);
- unsigned int i;
- for(i = 0; i < (unsigned int) argc; i++) {
- tracepoint(librados, rados_conf_parse_argv_remainder_arg, argv[i]);
- }
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- auto& conf = client->cct->_conf;
- vector<const char*> args;
- for (int i=0; i<argc; i++)
- args.push_back(argv[i]);
- int ret = conf.parse_argv(args);
- if (ret) {
- tracepoint(librados, rados_conf_parse_argv_remainder_exit, ret);
- return ret;
- }
- conf.apply_changes(NULL);
- ceph_assert(args.size() <= (unsigned int)argc);
- for (i = 0; i < (unsigned int)argc; ++i) {
- if (i < args.size())
- remargv[i] = args[i];
- else
- remargv[i] = (const char *)NULL;
- tracepoint(librados, rados_conf_parse_argv_remainder_remarg, remargv[i]);
- }
- tracepoint(librados, rados_conf_parse_argv_remainder_exit, 0);
- return 0;
-}
-
-extern "C" int rados_conf_parse_env(rados_t cluster, const char *env)
-{
- tracepoint(librados, rados_conf_parse_env_enter, cluster, env);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- auto& conf = client->cct->_conf;
- conf.parse_env(env);
- conf.apply_changes(nullptr);
- tracepoint(librados, rados_conf_parse_env_exit, 0);
- return 0;
-}
-
-extern "C" int rados_conf_set(rados_t cluster, const char *option, const char *value)
-{
- tracepoint(librados, rados_conf_set_enter, cluster, option, value);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- auto& conf = client->cct->_conf;
- int ret = conf.set_val(option, value);
- if (ret) {
- tracepoint(librados, rados_conf_set_exit, ret);
- return ret;
- }
- conf.apply_changes(nullptr);
- tracepoint(librados, rados_conf_set_exit, 0);
- return 0;
-}
-
-/* cluster info */
-extern "C" int rados_cluster_stat(rados_t cluster, rados_cluster_stat_t *result)
-{
- tracepoint(librados, rados_cluster_stat_enter, cluster);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
-
- ceph_statfs stats;
- int r = client->get_fs_stats(stats);
- result->kb = stats.kb;
- result->kb_used = stats.kb_used;
- result->kb_avail = stats.kb_avail;
- result->num_objects = stats.num_objects;
- tracepoint(librados, rados_cluster_stat_exit, r, result->kb, result->kb_used, result->kb_avail, result->num_objects);
- return r;
-}
-
-extern "C" int rados_conf_get(rados_t cluster, const char *option, char *buf, size_t len)
-{
- tracepoint(librados, rados_conf_get_enter, cluster, option, len);
- char *tmp = buf;
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- const auto& conf = client->cct->_conf;
- int retval = conf.get_val(option, &tmp, len);
- tracepoint(librados, rados_conf_get_exit, retval, retval ? "" : option);
- return retval;
-}
-
-extern "C" int64_t rados_pool_lookup(rados_t cluster, const char *name)
-{
- tracepoint(librados, rados_pool_lookup_enter, cluster, name);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- int64_t retval = radosp->lookup_pool(name);
- tracepoint(librados, rados_pool_lookup_exit, retval);
- return retval;
-}
-
-extern "C" int rados_pool_reverse_lookup(rados_t cluster, int64_t id,
- char *buf, size_t maxlen)
-{
- tracepoint(librados, rados_pool_reverse_lookup_enter, cluster, id, maxlen);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- std::string name;
- int r = radosp->pool_get_name(id, &name);
- if (r < 0) {
- tracepoint(librados, rados_pool_reverse_lookup_exit, r, "");
- return r;
- }
- if (name.length() >= maxlen) {
- tracepoint(librados, rados_pool_reverse_lookup_exit, -ERANGE, "");
- return -ERANGE;
- }
- strcpy(buf, name.c_str());
- int retval = name.length();
- tracepoint(librados, rados_pool_reverse_lookup_exit, retval, buf);
- return retval;
-}
-
-extern "C" int rados_cluster_fsid(rados_t cluster, char *buf,
- size_t maxlen)
-{
- tracepoint(librados, rados_cluster_fsid_enter, cluster, maxlen);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- std::string fsid;
- radosp->get_fsid(&fsid);
- if (fsid.length() >= maxlen) {
- tracepoint(librados, rados_cluster_fsid_exit, -ERANGE, "");
- return -ERANGE;
- }
- strcpy(buf, fsid.c_str());
- int retval = fsid.length();
- tracepoint(librados, rados_cluster_fsid_exit, retval, buf);
- return retval;
-}
-
-extern "C" int rados_wait_for_latest_osdmap(rados_t cluster)
-{
- tracepoint(librados, rados_wait_for_latest_osdmap_enter, cluster);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- int retval = radosp->wait_for_latest_osdmap();
- tracepoint(librados, rados_wait_for_latest_osdmap_exit, retval);
- return retval;
-}
-
-extern "C" int rados_blacklist_add(rados_t cluster, char *client_address,
- uint32_t expire_seconds)
-{
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- return radosp->blacklist_add(client_address, expire_seconds);
-}
-
-extern "C" void rados_set_osdmap_full_try(rados_ioctx_t io)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- ctx->objecter->set_osdmap_full_try();
-}
-
-extern "C" void rados_unset_osdmap_full_try(rados_ioctx_t io)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- ctx->objecter->unset_osdmap_full_try();
-}
-
-extern "C" int rados_application_enable(rados_ioctx_t io, const char *app_name,
- int force)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- return ctx->application_enable(app_name, force != 0);
-}
-
-extern "C" int rados_application_list(rados_ioctx_t io, char *values,
- size_t *values_len)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- std::set<std::string> app_names;
- int r = ctx->application_list(&app_names);
- if (r < 0) {
- return r;
- }
-
- size_t total_len = 0;
- for (auto app_name : app_names) {
- total_len += app_name.size() + 1;
- }
-
- if (*values_len < total_len) {
- *values_len = total_len;
- return -ERANGE;
- }
-
- char *values_p = values;
- for (auto app_name : app_names) {
- size_t len = app_name.size() + 1;
- strncpy(values_p, app_name.c_str(), len);
- values_p += len;
- }
- *values_p = '\0';
- *values_len = total_len;
- return 0;
-}
-
-extern "C" int rados_application_metadata_get(rados_ioctx_t io,
- const char *app_name,
- const char *key, char *value,
- size_t *value_len)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- std::string value_str;
- int r = ctx->application_metadata_get(app_name, key, &value_str);
- if (r < 0) {
- return r;
- }
-
- size_t len = value_str.size() + 1;
- if (*value_len < len) {
- *value_len = len;
- return -ERANGE;
- }
-
- strncpy(value, value_str.c_str(), len);
- *value_len = len;
- return 0;
-}
-
-extern "C" int rados_application_metadata_set(rados_ioctx_t io,
- const char *app_name,
- const char *key,
- const char *value)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- return ctx->application_metadata_set(app_name, key, value);
-}
-
-extern "C" int rados_application_metadata_remove(rados_ioctx_t io,
- const char *app_name,
- const char *key)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- return ctx->application_metadata_remove(app_name, key);
-}
-
-extern "C" int rados_application_metadata_list(rados_ioctx_t io,
- const char *app_name,
- char *keys, size_t *keys_len,
- char *values, size_t *vals_len)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- std::map<std::string, std::string> metadata;
- int r = ctx->application_metadata_list(app_name, &metadata);
- if (r < 0) {
- return r;
- }
-
- size_t total_key_len = 0;
- size_t total_val_len = 0;
- for (auto pair : metadata) {
- total_key_len += pair.first.size() + 1;
- total_val_len += pair.second.size() + 1;
- }
-
- if (*keys_len < total_key_len || *vals_len < total_val_len) {
- *keys_len = total_key_len;
- *vals_len = total_val_len;
- return -ERANGE;
- }
-
- char *keys_p = keys;
- char *vals_p = values;
- for (auto pair : metadata) {
- size_t key_len = pair.first.size() + 1;
- strncpy(keys_p, pair.first.c_str(), key_len);
- keys_p += key_len;
-
- size_t val_len = pair.second.size() + 1;
- strncpy(vals_p, pair.second.c_str(), val_len);
- vals_p += val_len;
- }
- *keys_p = '\0';
- *keys_len = total_key_len;
-
- *vals_p = '\0';
- *vals_len = total_val_len;
- return 0;
-}
-
-extern "C" int rados_pool_list(rados_t cluster, char *buf, size_t len)
-{
- tracepoint(librados, rados_pool_list_enter, cluster, len);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- std::list<std::pair<int64_t, std::string> > pools;
- int r = client->pool_list(pools);
- if (r < 0) {
- tracepoint(librados, rados_pool_list_exit, r);
- return r;
- }
-
- if (len > 0 && !buf) {
- tracepoint(librados, rados_pool_list_exit, -EINVAL);
- return -EINVAL;
- }
-
- char *b = buf;
- if (b)
- memset(b, 0, len);
- int needed = 0;
- std::list<std::pair<int64_t, std::string> >::const_iterator i = pools.begin();
- std::list<std::pair<int64_t, std::string> >::const_iterator p_end =
- pools.end();
- for (; i != p_end; ++i) {
- int rl = i->second.length() + 1;
- if (len < (unsigned)rl)
- break;
- const char* pool = i->second.c_str();
- tracepoint(librados, rados_pool_list_pool, pool);
- if (b) {
- strncat(b, pool, rl);
- b += rl;
- }
- needed += rl;
- len -= rl;
- }
- for (; i != p_end; ++i) {
- int rl = i->second.length() + 1;
- needed += rl;
- }
- int retval = needed + 1;
- tracepoint(librados, rados_pool_list_exit, retval);
- return retval;
-}
-
-CEPH_RADOS_API int rados_inconsistent_pg_list(rados_t cluster, int64_t pool_id,
- char *buf, size_t len)
-{
- tracepoint(librados, rados_inconsistent_pg_list_enter, cluster, pool_id, len);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- std::vector<std::string> pgs;
- if (int r = client->get_inconsistent_pgs(pool_id, &pgs); r < 0) {
- tracepoint(librados, rados_inconsistent_pg_list_exit, r);
- return r;
- }
-
- if (len > 0 && !buf) {
- tracepoint(librados, rados_inconsistent_pg_list_exit, -EINVAL);
- return -EINVAL;
- }
-
- char *b = buf;
- if (b)
- memset(b, 0, len);
- int needed = 0;
- for (const auto& s : pgs) {
- unsigned rl = s.length() + 1;
- if (b && len >= rl) {
- tracepoint(librados, rados_inconsistent_pg_list_pg, s.c_str());
- strncat(b, s.c_str(), rl);
- b += rl;
- len -= rl;
- }
- needed += rl;
- }
- int retval = needed + 1;
- tracepoint(librados, rados_inconsistent_pg_list_exit, retval);
- return retval;
-}
-
-
-static void dict_to_map(const char *dict,
- std::map<std::string, std::string>* dict_map)
-{
- while (*dict != '\0') {
- const char* key = dict;
- dict += strlen(key) + 1;
- const char* value = dict;
- dict += strlen(value) + 1;
- (*dict_map)[key] = value;
- }
-}
-
-CEPH_RADOS_API int rados_service_register(rados_t cluster, const char *service,
- const char *daemon,
- const char *metadata_dict)
-{
- librados::RadosClient *client = (librados::RadosClient *)cluster;
-
- std::map<std::string, std::string> metadata;
- dict_to_map(metadata_dict, &metadata);
-
- return client->service_daemon_register(service, daemon, metadata);
-}
-
-CEPH_RADOS_API int rados_service_update_status(rados_t cluster,
- const char *status_dict)
-{
- librados::RadosClient *client = (librados::RadosClient *)cluster;
-
- std::map<std::string, std::string> status;
- dict_to_map(status_dict, &status);
-
- return client->service_daemon_update_status(std::move(status));
-}
-
-static void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen)
-{
- if (outbuf) {
- if (outbl.length() > 0) {
- *outbuf = (char *)malloc(outbl.length());
- memcpy(*outbuf, outbl.c_str(), outbl.length());
- } else {
- *outbuf = NULL;
- }
- }
- if (outbuflen)
- *outbuflen = outbl.length();
-}
-
-static void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen)
-{
- if (outbuf) {
- if (outbl.length() > 0) {
- *outbuf = (char *)malloc(outbl.length());
- memcpy(*outbuf, outbl.c_str(), outbl.length());
- } else {
- *outbuf = NULL;
- }
- }
- if (outbuflen)
- *outbuflen = outbl.length();
-}
-
-extern "C" int rados_ping_monitor(rados_t cluster, const char *mon_id,
- char **outstr, size_t *outstrlen)
-{
- tracepoint(librados, rados_ping_monitor_enter, cluster, mon_id);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- string str;
-
- if (!mon_id) {
- tracepoint(librados, rados_ping_monitor_exit, -EINVAL, NULL, NULL);
- return -EINVAL;
- }
-
- int ret = client->ping_monitor(mon_id, &str);
- if (ret == 0) {
- do_out_buffer(str, outstr, outstrlen);
- }
- tracepoint(librados, rados_ping_monitor_exit, ret, ret < 0 ? NULL : outstr, ret < 0 ? NULL : outstrlen);
- return ret;
-}
-
-extern "C" int rados_mon_command(rados_t cluster, const char **cmd,
- size_t cmdlen,
- const char *inbuf, size_t inbuflen,
- char **outbuf, size_t *outbuflen,
- char **outs, size_t *outslen)
-{
- tracepoint(librados, rados_mon_command_enter, cluster, cmdlen, inbuf, inbuflen);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- bufferlist inbl;
- bufferlist outbl;
- string outstring;
- vector<string> cmdvec;
-
- for (size_t i = 0; i < cmdlen; i++) {
- tracepoint(librados, rados_mon_command_cmd, cmd[i]);
- cmdvec.push_back(cmd[i]);
- }
-
- inbl.append(inbuf, inbuflen);
- int ret = client->mon_command(cmdvec, inbl, &outbl, &outstring);
-
- do_out_buffer(outbl, outbuf, outbuflen);
- do_out_buffer(outstring, outs, outslen);
- tracepoint(librados, rados_mon_command_exit, ret, outbuf, outbuflen, outs, outslen);
- return ret;
-}
-
-extern "C" int rados_mon_command_target(rados_t cluster, const char *name,
- const char **cmd,
- size_t cmdlen,
- const char *inbuf, size_t inbuflen,
- char **outbuf, size_t *outbuflen,
- char **outs, size_t *outslen)
-{
- tracepoint(librados, rados_mon_command_target_enter, cluster, name, cmdlen, inbuf, inbuflen);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- bufferlist inbl;
- bufferlist outbl;
- string outstring;
- vector<string> cmdvec;
-
- // is this a numeric id?
- char *endptr;
- errno = 0;
- long rank = strtol(name, &endptr, 10);
- if ((errno == ERANGE && (rank == LONG_MAX || rank == LONG_MIN)) ||
- (errno != 0 && rank == 0) ||
- endptr == name || // no digits
- *endptr != '\0') { // extra characters
- rank = -1;
- }
-
- for (size_t i = 0; i < cmdlen; i++) {
- tracepoint(librados, rados_mon_command_target_cmd, cmd[i]);
- cmdvec.push_back(cmd[i]);
- }
-
- inbl.append(inbuf, inbuflen);
- int ret;
- if (rank >= 0)
- ret = client->mon_command(rank, cmdvec, inbl, &outbl, &outstring);
- else
- ret = client->mon_command(name, cmdvec, inbl, &outbl, &outstring);
-
- do_out_buffer(outbl, outbuf, outbuflen);
- do_out_buffer(outstring, outs, outslen);
- tracepoint(librados, rados_mon_command_target_exit, ret, outbuf, outbuflen, outs, outslen);
- return ret;
-}
-
-extern "C" int rados_osd_command(rados_t cluster, int osdid, const char **cmd,
- size_t cmdlen,
- const char *inbuf, size_t inbuflen,
- char **outbuf, size_t *outbuflen,
- char **outs, size_t *outslen)
-{
- tracepoint(librados, rados_osd_command_enter, cluster, osdid, cmdlen, inbuf, inbuflen);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- bufferlist inbl;
- bufferlist outbl;
- string outstring;
- vector<string> cmdvec;
-
- for (size_t i = 0; i < cmdlen; i++) {
- tracepoint(librados, rados_osd_command_cmd, cmd[i]);
- cmdvec.push_back(cmd[i]);
- }
-
- inbl.append(inbuf, inbuflen);
- int ret = client->osd_command(osdid, cmdvec, inbl, &outbl, &outstring);
-
- do_out_buffer(outbl, outbuf, outbuflen);
- do_out_buffer(outstring, outs, outslen);
- tracepoint(librados, rados_osd_command_exit, ret, outbuf, outbuflen, outs, outslen);
- return ret;
-}
-
-extern "C" int rados_mgr_command(rados_t cluster, const char **cmd,
- size_t cmdlen,
- const char *inbuf, size_t inbuflen,
- char **outbuf, size_t *outbuflen,
- char **outs, size_t *outslen)
-{
- tracepoint(librados, rados_mgr_command_enter, cluster, cmdlen, inbuf,
- inbuflen);
-
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- bufferlist inbl;
- bufferlist outbl;
- string outstring;
- vector<string> cmdvec;
-
- for (size_t i = 0; i < cmdlen; i++) {
- tracepoint(librados, rados_mgr_command_cmd, cmd[i]);
- cmdvec.push_back(cmd[i]);
- }
-
- inbl.append(inbuf, inbuflen);
- int ret = client->mgr_command(cmdvec, inbl, &outbl, &outstring);
-
- do_out_buffer(outbl, outbuf, outbuflen);
- do_out_buffer(outstring, outs, outslen);
- tracepoint(librados, rados_mgr_command_exit, ret, outbuf, outbuflen, outs,
- outslen);
- return ret;
-}
-
-extern "C" int rados_pg_command(rados_t cluster, const char *pgstr,
- const char **cmd, size_t cmdlen,
- const char *inbuf, size_t inbuflen,
- char **outbuf, size_t *outbuflen,
- char **outs, size_t *outslen)
-{
- tracepoint(librados, rados_pg_command_enter, cluster, pgstr, cmdlen, inbuf, inbuflen);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- bufferlist inbl;
- bufferlist outbl;
- string outstring;
- pg_t pgid;
- vector<string> cmdvec;
-
- for (size_t i = 0; i < cmdlen; i++) {
- tracepoint(librados, rados_pg_command_cmd, cmd[i]);
- cmdvec.push_back(cmd[i]);
- }
-
- inbl.append(inbuf, inbuflen);
- if (!pgid.parse(pgstr))
- return -EINVAL;
-
- int ret = client->pg_command(pgid, cmdvec, inbl, &outbl, &outstring);
-
- do_out_buffer(outbl, outbuf, outbuflen);
- do_out_buffer(outstring, outs, outslen);
- tracepoint(librados, rados_pg_command_exit, ret, outbuf, outbuflen, outs, outslen);
- return ret;
-}
-
-extern "C" void rados_buffer_free(char *buf)
-{
- tracepoint(librados, rados_buffer_free_enter, buf);
- if (buf)
- free(buf);
- tracepoint(librados, rados_buffer_free_exit);
-}
-
-extern "C" int rados_monitor_log(rados_t cluster, const char *level, rados_log_callback_t cb, void *arg)
-{
- tracepoint(librados, rados_monitor_log_enter, cluster, level, cb, arg);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- int retval = client->monitor_log(level, cb, nullptr, arg);
- tracepoint(librados, rados_monitor_log_exit, retval);
- return retval;
-}
-
-extern "C" int rados_monitor_log2(rados_t cluster, const char *level,
- rados_log_callback2_t cb, void *arg)
-{
- tracepoint(librados, rados_monitor_log2_enter, cluster, level, cb, arg);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- int retval = client->monitor_log(level, nullptr, cb, arg);
- tracepoint(librados, rados_monitor_log2_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_create(rados_t cluster, const char *name, rados_ioctx_t *io)
-{
- tracepoint(librados, rados_ioctx_create_enter, cluster, name);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- librados::IoCtxImpl *ctx;
-
- int r = client->create_ioctx(name, &ctx);
- if (r < 0) {
- tracepoint(librados, rados_ioctx_create_exit, r, NULL);
- return r;
- }
-
- *io = ctx;
- ctx->get();
- tracepoint(librados, rados_ioctx_create_exit, 0, ctx);
- return 0;
-}
-
-extern "C" int rados_ioctx_create2(rados_t cluster, int64_t pool_id,
- rados_ioctx_t *io)
-{
- tracepoint(librados, rados_ioctx_create2_enter, cluster, pool_id);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- librados::IoCtxImpl *ctx;
-
- int r = client->create_ioctx(pool_id, &ctx);
- if (r < 0) {
- tracepoint(librados, rados_ioctx_create2_exit, r, NULL);
- return r;
- }
-
- *io = ctx;
- ctx->get();
- tracepoint(librados, rados_ioctx_create2_exit, 0, ctx);
- return 0;
-}
-
-extern "C" void rados_ioctx_destroy(rados_ioctx_t io)
-{
- tracepoint(librados, rados_ioctx_destroy_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- ctx->put();
- tracepoint(librados, rados_ioctx_destroy_exit);
-}
-
-extern "C" int rados_ioctx_pool_stat(rados_ioctx_t io, struct rados_pool_stat_t *stats)
-{
- tracepoint(librados, rados_ioctx_pool_stat_enter, io);
- librados::IoCtxImpl *io_ctx_impl = (librados::IoCtxImpl *)io;
- list<string> ls;
- std::string pool_name;
-
- int err = io_ctx_impl->client->pool_get_name(io_ctx_impl->get_id(), &pool_name);
- if (err) {
- tracepoint(librados, rados_ioctx_pool_stat_exit, err, stats);
- return err;
- }
- ls.push_back(pool_name);
-
- map<string, ::pool_stat_t> rawresult;
- err = io_ctx_impl->client->get_pool_stats(ls, rawresult);
- if (err) {
- tracepoint(librados, rados_ioctx_pool_stat_exit, err, stats);
- return err;
- }
-
- ::pool_stat_t& r = rawresult[pool_name];
- stats->num_kb = shift_round_up(r.stats.sum.num_bytes, 10);
- stats->num_bytes = r.stats.sum.num_bytes;
- stats->num_objects = r.stats.sum.num_objects;
- stats->num_object_clones = r.stats.sum.num_object_clones;
- stats->num_object_copies = r.stats.sum.num_object_copies;
- stats->num_objects_missing_on_primary = r.stats.sum.num_objects_missing_on_primary;
- stats->num_objects_unfound = r.stats.sum.num_objects_unfound;
- stats->num_objects_degraded =
- r.stats.sum.num_objects_degraded +
- r.stats.sum.num_objects_misplaced; // FIXME: this is imprecise
- stats->num_rd = r.stats.sum.num_rd;
- stats->num_rd_kb = r.stats.sum.num_rd_kb;
- stats->num_wr = r.stats.sum.num_wr;
- stats->num_wr_kb = r.stats.sum.num_wr_kb;
- tracepoint(librados, rados_ioctx_pool_stat_exit, 0, stats);
- return 0;
-}
-
-extern "C" rados_config_t rados_ioctx_cct(rados_ioctx_t io)
-{
- tracepoint(librados, rados_ioctx_cct_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- rados_config_t retval = (rados_config_t)ctx->client->cct;
- tracepoint(librados, rados_ioctx_cct_exit, retval);
- return retval;
-}
-
-extern "C" void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t seq)
-{
- tracepoint(librados, rados_ioctx_snap_set_read_enter, io, seq);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- ctx->set_snap_read((snapid_t)seq);
- tracepoint(librados, rados_ioctx_snap_set_read_exit);
-}
-
-extern "C" int rados_ioctx_selfmanaged_snap_set_write_ctx(rados_ioctx_t io,
- rados_snap_t seq, rados_snap_t *snaps, int num_snaps)
-{
- tracepoint(librados, rados_ioctx_selfmanaged_snap_set_write_ctx_enter, io, seq, snaps, num_snaps);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- vector<snapid_t> snv;
- snv.resize(num_snaps);
- for (int i=0; i<num_snaps; i++) {
- snv[i] = (snapid_t)snaps[i];
- }
- int retval = ctx->set_snap_write_context((snapid_t)seq, snv);
- tracepoint(librados, rados_ioctx_selfmanaged_snap_set_write_ctx_exit, retval);
- return retval;
-}
-
-extern "C" int rados_write(rados_ioctx_t io, const char *o, const char *buf, size_t len, uint64_t off)
-{
- tracepoint(librados, rados_write_enter, io, o, buf, len, off);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->write(oid, bl, len, off);
- tracepoint(librados, rados_write_exit, retval);
- return retval;
-}
-
-extern "C" int rados_append(rados_ioctx_t io, const char *o, const char *buf, size_t len)
-{
- tracepoint(librados, rados_append_enter, io, o, buf, len);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->append(oid, bl, len);
- tracepoint(librados, rados_append_exit, retval);
- return retval;
-}
-
-extern "C" int rados_write_full(rados_ioctx_t io, const char *o, const char *buf, size_t len)
-{
- tracepoint(librados, rados_write_full_enter, io, o, buf, len);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->write_full(oid, bl);
- tracepoint(librados, rados_write_full_exit, retval);
- return retval;
-}
-
-extern "C" int rados_writesame(rados_ioctx_t io,
- const char *o,
- const char *buf,
- size_t data_len,
- size_t write_len,
- uint64_t off)
-{
- tracepoint(librados, rados_writesame_enter, io, o, buf, data_len, write_len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, data_len);
- int retval = ctx->writesame(oid, bl, write_len, off);
- tracepoint(librados, rados_writesame_exit, retval);
- return retval;
-}
-
-extern "C" int rados_trunc(rados_ioctx_t io, const char *o, uint64_t size)
-{
- tracepoint(librados, rados_trunc_enter, io, o, size);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->trunc(oid, size);
- tracepoint(librados, rados_trunc_exit, retval);
- return retval;
-}
-
-extern "C" int rados_remove(rados_ioctx_t io, const char *o)
-{
- tracepoint(librados, rados_remove_enter, io, o);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->remove(oid);
- tracepoint(librados, rados_remove_exit, retval);
- return retval;
-}
-
-extern "C" int rados_read(rados_ioctx_t io, const char *o, char *buf, size_t len, uint64_t off)
-{
- tracepoint(librados, rados_read_enter, io, o, buf, len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int ret;
- object_t oid(o);
-
- bufferlist bl;
- bufferptr bp = buffer::create_static(len, buf);
- bl.push_back(bp);
-
- ret = ctx->read(oid, bl, len, off);
- if (ret >= 0) {
- if (bl.length() > len) {
- tracepoint(librados, rados_read_exit, -ERANGE, NULL);
- return -ERANGE;
- }
- if (!bl.is_provided_buffer(buf))
- bl.copy(0, bl.length(), buf);
- ret = bl.length(); // hrm :/
- }
-
- tracepoint(librados, rados_read_exit, ret, buf);
- return ret;
-}
-
-extern "C" int rados_checksum(rados_ioctx_t io, const char *o,
- rados_checksum_type_t type,
- const char *init_value, size_t init_value_len,
- size_t len, uint64_t off, size_t chunk_size,
- char *pchecksum, size_t checksum_len)
-{
- tracepoint(librados, rados_checksum_enter, io, o, type, init_value,
- init_value_len, len, off, chunk_size);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
-
- bufferlist init_value_bl;
- init_value_bl.append(init_value, init_value_len);
-
- bufferlist checksum_bl;
-
- int retval = ctx->checksum(oid, get_checksum_op_type(type), init_value_bl,
- len, off, chunk_size, &checksum_bl);
- if (retval >= 0) {
- if (checksum_bl.length() > checksum_len) {
- tracepoint(librados, rados_checksum_exit, -ERANGE, NULL, 0);
- return -ERANGE;
- }
-
- checksum_bl.copy(0, checksum_bl.length(), pchecksum);
- }
- tracepoint(librados, rados_checksum_exit, retval, pchecksum, checksum_len);
- return retval;
-}
-
-extern "C" uint64_t rados_get_last_version(rados_ioctx_t io)
-{
- tracepoint(librados, rados_get_last_version_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- uint64_t retval = ctx->last_version();
- tracepoint(librados, rados_get_last_version_exit, retval);
- return retval;
-}
-
-extern "C" int rados_pool_create(rados_t cluster, const char *name)
-{
- tracepoint(librados, rados_pool_create_enter, cluster, name);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- string sname(name);
- int retval = radosp->pool_create(sname);
- tracepoint(librados, rados_pool_create_exit, retval);
- return retval;
-}
-
-extern "C" int rados_pool_create_with_auid(rados_t cluster, const char *name,
- uint64_t auid)
-{
- tracepoint(librados, rados_pool_create_with_auid_enter, cluster, name, auid);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- string sname(name);
- int retval = 0;
- if (auid != CEPH_AUTH_UID_DEFAULT) {
- retval = -EINVAL;
- } else {
- retval = radosp->pool_create(sname);
- }
- tracepoint(librados, rados_pool_create_with_auid_exit, retval);
- return retval;
-}
-
-extern "C" int rados_pool_create_with_crush_rule(rados_t cluster, const char *name,
- __u8 crush_rule_num)
-{
- tracepoint(librados, rados_pool_create_with_crush_rule_enter, cluster, name, crush_rule_num);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- string sname(name);
- int retval = radosp->pool_create(sname, crush_rule_num);
- tracepoint(librados, rados_pool_create_with_crush_rule_exit, retval);
- return retval;
-}
-
-extern "C" int rados_pool_create_with_all(rados_t cluster, const char *name,
- uint64_t auid, __u8 crush_rule_num)
-{
- tracepoint(librados, rados_pool_create_with_all_enter, cluster, name, auid, crush_rule_num);
- librados::RadosClient *radosp = (librados::RadosClient *)cluster;
- string sname(name);
- int retval = 0;
- if (auid != CEPH_AUTH_UID_DEFAULT) {
- retval = -EINVAL;
- } else {
- retval = radosp->pool_create(sname, crush_rule_num);
- }
- tracepoint(librados, rados_pool_create_with_all_exit, retval);
- return retval;
-}
-
-extern "C" int rados_pool_get_base_tier(rados_t cluster, int64_t pool_id, int64_t* base_tier)
-{
- tracepoint(librados, rados_pool_get_base_tier_enter, cluster, pool_id);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- int retval = client->pool_get_base_tier(pool_id, base_tier);
- tracepoint(librados, rados_pool_get_base_tier_exit, retval, *base_tier);
- return retval;
-}
-
-extern "C" int rados_pool_delete(rados_t cluster, const char *pool_name)
-{
- tracepoint(librados, rados_pool_delete_enter, cluster, pool_name);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- int retval = client->pool_delete(pool_name);
- tracepoint(librados, rados_pool_delete_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid)
-{
- tracepoint(librados, rados_ioctx_pool_set_auid_enter, io, auid);
- int retval = -EOPNOTSUPP;
- tracepoint(librados, rados_ioctx_pool_set_auid_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_pool_get_auid(rados_ioctx_t io, uint64_t *auid)
-{
- tracepoint(librados, rados_ioctx_pool_get_auid_enter, io);
- int retval = -EOPNOTSUPP;
- tracepoint(librados, rados_ioctx_pool_get_auid_exit, retval, *auid);
- return retval;
-}
-
-extern "C" int rados_ioctx_pool_requires_alignment(rados_ioctx_t io)
-{
- tracepoint(librados, rados_ioctx_pool_requires_alignment_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->client->pool_requires_alignment(ctx->get_id());
- tracepoint(librados, rados_ioctx_pool_requires_alignment_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_pool_requires_alignment2(rados_ioctx_t io,
- int *requires)
-{
- tracepoint(librados, rados_ioctx_pool_requires_alignment_enter2, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- bool requires_alignment;
- int retval = ctx->client->pool_requires_alignment2(ctx->get_id(),
- &requires_alignment);
- tracepoint(librados, rados_ioctx_pool_requires_alignment_exit2, retval,
- requires_alignment);
- if (requires)
- *requires = requires_alignment;
- return retval;
-}
-
-extern "C" uint64_t rados_ioctx_pool_required_alignment(rados_ioctx_t io)
-{
- tracepoint(librados, rados_ioctx_pool_required_alignment_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- uint64_t retval = ctx->client->pool_required_alignment(ctx->get_id());
- tracepoint(librados, rados_ioctx_pool_required_alignment_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_pool_required_alignment2(rados_ioctx_t io,
- uint64_t *alignment)
-{
- tracepoint(librados, rados_ioctx_pool_required_alignment_enter2, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->client->pool_required_alignment2(ctx->get_id(),
- alignment);
- tracepoint(librados, rados_ioctx_pool_required_alignment_exit2, retval,
- *alignment);
- return retval;
-}
-
-extern "C" void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key)
-{
- tracepoint(librados, rados_ioctx_locator_set_key_enter, io, key);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- if (key)
- ctx->oloc.key = key;
- else
- ctx->oloc.key = "";
- tracepoint(librados, rados_ioctx_locator_set_key_exit);
-}
-
-extern "C" void rados_ioctx_set_namespace(rados_ioctx_t io, const char *nspace)
-{
- tracepoint(librados, rados_ioctx_set_namespace_enter, io, nspace);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- if (nspace)
- ctx->oloc.nspace = nspace;
- else
- ctx->oloc.nspace = "";
- tracepoint(librados, rados_ioctx_set_namespace_exit);
-}
-
-extern "C" int rados_ioctx_get_namespace(rados_ioctx_t io, char *s,
- unsigned maxlen)
-{
- tracepoint(librados, rados_ioctx_get_namespace_enter, io, maxlen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- auto length = ctx->oloc.nspace.length();
- if (length >= maxlen) {
- tracepoint(librados, rados_ioctx_get_namespace_exit, -ERANGE, "");
- return -ERANGE;
- }
- strcpy(s, ctx->oloc.nspace.c_str());
- int retval = (int)length;
- tracepoint(librados, rados_ioctx_get_namespace_exit, retval, s);
- return retval;
-}
-
-extern "C" rados_t rados_ioctx_get_cluster(rados_ioctx_t io)
-{
- tracepoint(librados, rados_ioctx_get_cluster_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- rados_t retval = (rados_t)ctx->client;
- tracepoint(librados, rados_ioctx_get_cluster_exit, retval);
- return retval;
-}
-
-extern "C" int64_t rados_ioctx_get_id(rados_ioctx_t io)
-{
- tracepoint(librados, rados_ioctx_get_id_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int64_t retval = ctx->get_id();
- tracepoint(librados, rados_ioctx_get_id_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_get_pool_name(rados_ioctx_t io, char *s, unsigned maxlen)
-{
- tracepoint(librados, rados_ioctx_get_pool_name_enter, io, maxlen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- std::string pool_name;
-
- int err = ctx->client->pool_get_name(ctx->get_id(), &pool_name);
- if (err) {
- tracepoint(librados, rados_ioctx_get_pool_name_exit, err, "");
- return err;
- }
- if (pool_name.length() >= maxlen) {
- tracepoint(librados, rados_ioctx_get_pool_name_exit, -ERANGE, "");
- return -ERANGE;
- }
- strcpy(s, pool_name.c_str());
- int retval = pool_name.length();
- tracepoint(librados, rados_ioctx_get_pool_name_exit, retval, s);
- return retval;
-}
-
-// snaps
-
-extern "C" int rados_ioctx_snap_create(rados_ioctx_t io, const char *snapname)
-{
- tracepoint(librados, rados_ioctx_snap_create_enter, io, snapname);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->snap_create(snapname);
- tracepoint(librados, rados_ioctx_snap_create_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_snap_remove(rados_ioctx_t io, const char *snapname)
-{
- tracepoint(librados, rados_ioctx_snap_remove_enter, io, snapname);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->snap_remove(snapname);
- tracepoint(librados, rados_ioctx_snap_remove_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_snap_rollback(rados_ioctx_t io, const char *oid,
- const char *snapname)
-{
- tracepoint(librados, rados_ioctx_snap_rollback_enter, io, oid, snapname);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->rollback(oid, snapname);
- tracepoint(librados, rados_ioctx_snap_rollback_exit, retval);
- return retval;
-}
-
-// Deprecated name kept for backward compatibility
-extern "C" int rados_rollback(rados_ioctx_t io, const char *oid,
- const char *snapname)
-{
- return rados_ioctx_snap_rollback(io, oid, snapname);
-}
-
-extern "C" int rados_ioctx_selfmanaged_snap_create(rados_ioctx_t io,
- uint64_t *snapid)
-{
- tracepoint(librados, rados_ioctx_selfmanaged_snap_create_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->selfmanaged_snap_create(snapid);
- tracepoint(librados, rados_ioctx_selfmanaged_snap_create_exit, retval, *snapid);
- return retval;
-}
-
-extern "C" void
-rados_aio_ioctx_selfmanaged_snap_create(rados_ioctx_t io,
- rados_snap_t *snapid,
- rados_completion_t completion)
-{
- tracepoint(librados, rados_ioctx_selfmanaged_snap_create_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
- ctx->aio_selfmanaged_snap_create(snapid, c);
- tracepoint(librados, rados_ioctx_selfmanaged_snap_create_exit, 0, 0);
-}
-
-extern "C" int rados_ioctx_selfmanaged_snap_remove(rados_ioctx_t io,
- uint64_t snapid)
-{
- tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_enter, io, snapid);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->selfmanaged_snap_remove(snapid);
- tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_exit, retval);
- return retval;
-}
-
-extern "C" void
-rados_aio_ioctx_selfmanaged_snap_remove(rados_ioctx_t io,
- rados_snap_t snapid,
- rados_completion_t completion)
-{
- tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_enter, io, snapid);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
- ctx->aio_selfmanaged_snap_remove(snapid, c);
- tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_exit, 0);
-}
-
-extern "C" int rados_ioctx_selfmanaged_snap_rollback(rados_ioctx_t io,
- const char *oid,
- uint64_t snapid)
-{
- tracepoint(librados, rados_ioctx_selfmanaged_snap_rollback_enter, io, oid, snapid);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->selfmanaged_snap_rollback_object(oid, ctx->snapc, snapid);
- tracepoint(librados, rados_ioctx_selfmanaged_snap_rollback_exit, retval);
- return retval;
-}
-
-extern "C" int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t *snaps,
- int maxlen)
-{
- tracepoint(librados, rados_ioctx_snap_list_enter, io, maxlen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- vector<uint64_t> snapvec;
- int r = ctx->snap_list(&snapvec);
- if (r < 0) {
- tracepoint(librados, rados_ioctx_snap_list_exit, r, snaps, 0);
- return r;
- }
- if ((int)snapvec.size() <= maxlen) {
- for (unsigned i=0; i<snapvec.size(); i++) {
- snaps[i] = snapvec[i];
- }
- int retval = snapvec.size();
- tracepoint(librados, rados_ioctx_snap_list_exit, retval, snaps, retval);
- return retval;
- }
- int retval = -ERANGE;
- tracepoint(librados, rados_ioctx_snap_list_exit, retval, snaps, 0);
- return retval;
-}
-
-extern "C" int rados_ioctx_snap_lookup(rados_ioctx_t io, const char *name,
- rados_snap_t *id)
-{
- tracepoint(librados, rados_ioctx_snap_lookup_enter, io, name);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->snap_lookup(name, (uint64_t *)id);
- tracepoint(librados, rados_ioctx_snap_lookup_exit, retval, *id);
- return retval;
-}
-
-extern "C" int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id,
- char *name, int maxlen)
-{
- tracepoint(librados, rados_ioctx_snap_get_name_enter, io, id, maxlen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- std::string sname;
- int r = ctx->snap_get_name(id, &sname);
- if (r < 0) {
- tracepoint(librados, rados_ioctx_snap_get_name_exit, r, "");
- return r;
- }
- if ((int)sname.length() >= maxlen) {
- int retval = -ERANGE;
- tracepoint(librados, rados_ioctx_snap_get_name_exit, retval, "");
- return retval;
- }
- strncpy(name, sname.c_str(), maxlen);
- tracepoint(librados, rados_ioctx_snap_get_name_exit, 0, name);
- return 0;
-}
-
-extern "C" int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t *t)
-{
- tracepoint(librados, rados_ioctx_snap_get_stamp_enter, io, id);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->snap_get_stamp(id, t);
- tracepoint(librados, rados_ioctx_snap_get_stamp_exit, retval, *t);
- return retval;
-}
-
-extern "C" int rados_cmpext(rados_ioctx_t io, const char *o,
- const char *cmp_buf, size_t cmp_len, uint64_t off)
-{
- tracepoint(librados, rados_cmpext_enter, io, o, cmp_buf, cmp_len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int ret;
- object_t oid(o);
-
- bufferlist cmp_bl;
- cmp_bl.append(cmp_buf, cmp_len);
-
- ret = ctx->cmpext(oid, off, cmp_bl);
- tracepoint(librados, rados_cmpext_exit, ret);
-
- return ret;
-}
-
-extern "C" int rados_getxattr(rados_ioctx_t io, const char *o, const char *name,
- char *buf, size_t len)
-{
- tracepoint(librados, rados_getxattr_enter, io, o, name, len);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int ret;
- object_t oid(o);
- bufferlist bl;
- bl.push_back(buffer::create_static(len, buf));
- ret = ctx->getxattr(oid, name, bl);
- if (ret >= 0) {
- if (bl.length() > len) {
- tracepoint(librados, rados_getxattr_exit, -ERANGE, buf, 0);
- return -ERANGE;
- }
- if (!bl.is_provided_buffer(buf))
- bl.copy(0, bl.length(), buf);
- ret = bl.length();
- }
-
- tracepoint(librados, rados_getxattr_exit, ret, buf, ret);
- return ret;
-}
-
-extern "C" int rados_getxattrs(rados_ioctx_t io, const char *oid,
- rados_xattrs_iter_t *iter)
-{
- tracepoint(librados, rados_getxattrs_enter, io, oid);
- librados::RadosXattrsIter *it = new librados::RadosXattrsIter();
- if (!it) {
- tracepoint(librados, rados_getxattrs_exit, -ENOMEM, NULL);
- return -ENOMEM;
- }
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t obj(oid);
- int ret = ctx->getxattrs(obj, it->attrset);
- if (ret) {
- delete it;
- tracepoint(librados, rados_getxattrs_exit, ret, NULL);
- return ret;
- }
- it->i = it->attrset.begin();
-
- *iter = it;
- tracepoint(librados, rados_getxattrs_exit, 0, *iter);
- return 0;
-}
-
-extern "C" int rados_getxattrs_next(rados_xattrs_iter_t iter,
- const char **name, const char **val, size_t *len)
-{
- tracepoint(librados, rados_getxattrs_next_enter, iter);
- librados::RadosXattrsIter *it = static_cast<librados::RadosXattrsIter*>(iter);
- if (it->val) {
- free(it->val);
- it->val = NULL;
- }
- if (it->i == it->attrset.end()) {
- *name = NULL;
- *val = NULL;
- *len = 0;
- tracepoint(librados, rados_getxattrs_next_exit, 0, NULL, NULL, 0);
- return 0;
- }
- const std::string &s(it->i->first);
- *name = s.c_str();
- bufferlist &bl(it->i->second);
- size_t bl_len = bl.length();
- if (!bl_len) {
- // malloc(0) is not guaranteed to return a valid pointer
- *val = (char *)NULL;
- } else {
- it->val = (char*)malloc(bl_len);
- if (!it->val) {
- tracepoint(librados, rados_getxattrs_next_exit, -ENOMEM, *name, NULL, 0);
- return -ENOMEM;
- }
- memcpy(it->val, bl.c_str(), bl_len);
- *val = it->val;
- }
- *len = bl_len;
- ++it->i;
- tracepoint(librados, rados_getxattrs_next_exit, 0, *name, *val, *len);
- return 0;
-}
-
-extern "C" void rados_getxattrs_end(rados_xattrs_iter_t iter)
-{
- tracepoint(librados, rados_getxattrs_end_enter, iter);
- librados::RadosXattrsIter *it = static_cast<librados::RadosXattrsIter*>(iter);
- delete it;
- tracepoint(librados, rados_getxattrs_end_exit);
-}
-
-extern "C" int rados_setxattr(rados_ioctx_t io, const char *o, const char *name, const char *buf, size_t len)
-{
- tracepoint(librados, rados_setxattr_enter, io, o, name, buf, len);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->setxattr(oid, name, bl);
- tracepoint(librados, rados_setxattr_exit, retval);
- return retval;
-}
-
-extern "C" int rados_rmxattr(rados_ioctx_t io, const char *o, const char *name)
-{
- tracepoint(librados, rados_rmxattr_enter, io, o, name);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->rmxattr(oid, name);
- tracepoint(librados, rados_rmxattr_exit, retval);
- return retval;
-}
-
-extern "C" int rados_stat(rados_ioctx_t io, const char *o, uint64_t *psize, time_t *pmtime)
-{
- tracepoint(librados, rados_stat_enter, io, o);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->stat(oid, psize, pmtime);
- tracepoint(librados, rados_stat_exit, retval, psize, pmtime);
- return retval;
-}
-
-extern "C" int rados_tmap_update(rados_ioctx_t io, const char *o, const char *cmdbuf, size_t cmdbuflen)
-{
- tracepoint(librados, rados_tmap_update_enter, io, o, cmdbuf, cmdbuflen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist cmdbl;
- cmdbl.append(cmdbuf, cmdbuflen);
- int retval = ctx->tmap_update(oid, cmdbl);
- tracepoint(librados, rados_tmap_update_exit, retval);
- return retval;
-}
-
-extern "C" int rados_tmap_put(rados_ioctx_t io, const char *o, const char *buf, size_t buflen)
-{
- tracepoint(librados, rados_tmap_put_enter, io, o, buf, buflen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, buflen);
- int retval = ctx->tmap_put(oid, bl);
- tracepoint(librados, rados_tmap_put_exit, retval);
- return retval;
-}
-
-extern "C" int rados_tmap_get(rados_ioctx_t io, const char *o, char *buf, size_t buflen)
-{
- tracepoint(librados, rados_tmap_get_enter, io, o, buflen);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- int r = ctx->tmap_get(oid, bl);
- if (r < 0) {
- tracepoint(librados, rados_tmap_get_exit, r, buf, 0);
- return r;
- }
- if (bl.length() > buflen) {
- tracepoint(librados, rados_tmap_get_exit, -ERANGE, buf, 0);
- return -ERANGE;
- }
- bl.copy(0, bl.length(), buf);
- int retval = bl.length();
- tracepoint(librados, rados_tmap_get_exit, retval, buf, retval);
- return retval;
-}
-
-extern "C" int rados_tmap_to_omap(rados_ioctx_t io, const char *o, bool nullok)
-{
- tracepoint(librados, rados_tmap_to_omap_enter, io, o, nullok);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->tmap_to_omap(oid, nullok);
- tracepoint(librados, rados_tmap_to_omap_exit, retval);
- return retval;
-}
-
-extern "C" int rados_exec(rados_ioctx_t io, const char *o, const char *cls, const char *method,
- const char *inbuf, size_t in_len, char *buf, size_t out_len)
-{
- tracepoint(librados, rados_exec_enter, io, o, cls, method, inbuf, in_len, out_len);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist inbl, outbl;
- int ret;
- inbl.append(inbuf, in_len);
- ret = ctx->exec(oid, cls, method, inbl, outbl);
- if (ret >= 0) {
- if (outbl.length()) {
- if (outbl.length() > out_len) {
- tracepoint(librados, rados_exec_exit, -ERANGE, buf, 0);
- return -ERANGE;
- }
- outbl.copy(0, outbl.length(), buf);
- ret = outbl.length(); // hrm :/
- }
- }
- tracepoint(librados, rados_exec_exit, ret, buf, ret);
- return ret;
-}
-
-extern "C" rados_object_list_cursor rados_object_list_begin(rados_ioctx_t io)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- hobject_t *result = new hobject_t(ctx->objecter->enumerate_objects_begin());
- return (rados_object_list_cursor)result;
-}
-
-extern "C" rados_object_list_cursor rados_object_list_end(rados_ioctx_t io)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- hobject_t *result = new hobject_t(ctx->objecter->enumerate_objects_end());
- return (rados_object_list_cursor)result;
-}
-
-extern "C" int rados_object_list_is_end(
- rados_ioctx_t io, rados_object_list_cursor cur)
-{
- hobject_t *hobj = (hobject_t*)cur;
- return hobj->is_max();
-}
-
-extern "C" void rados_object_list_cursor_free(
- rados_ioctx_t io, rados_object_list_cursor cur)
-{
- hobject_t *hobj = (hobject_t*)cur;
- delete hobj;
-}
-
-extern "C" int rados_object_list_cursor_cmp(
- rados_ioctx_t io,
- rados_object_list_cursor lhs_cur,
- rados_object_list_cursor rhs_cur)
-{
- hobject_t *lhs = (hobject_t*)lhs_cur;
- hobject_t *rhs = (hobject_t*)rhs_cur;
- return cmp(*lhs, *rhs);
-}
-
-extern "C" int rados_object_list(rados_ioctx_t io,
- const rados_object_list_cursor start,
- const rados_object_list_cursor finish,
- const size_t result_item_count,
- const char *filter_buf,
- const size_t filter_buf_len,
- rados_object_list_item *result_items,
- rados_object_list_cursor *next)
-{
- ceph_assert(next);
-
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- // Zero out items so that they will be safe to free later
- memset(result_items, 0, sizeof(rados_object_list_item) * result_item_count);
-
- std::list<librados::ListObjectImpl> result;
- hobject_t next_hash;
-
- bufferlist filter_bl;
- if (filter_buf != nullptr) {
- filter_bl.append(filter_buf, filter_buf_len);
- }
-
- C_SaferCond cond;
- ctx->objecter->enumerate_objects(
- ctx->poolid,
- ctx->oloc.nspace,
- *((hobject_t*)start),
- *((hobject_t*)finish),
- result_item_count,
- filter_bl,
- &result,
- &next_hash,
- &cond);
-
- hobject_t *next_hobj = (hobject_t*)(*next);
- ceph_assert(next_hobj);
-
- int r = cond.wait();
- if (r < 0) {
- *next_hobj = hobject_t::get_max();
- return r;
- }
-
- ceph_assert(result.size() <= result_item_count); // Don't overflow!
-
- int k = 0;
- for (std::list<librados::ListObjectImpl>::iterator i = result.begin();
- i != result.end(); ++i) {
- rados_object_list_item &item = result_items[k++];
- do_out_buffer(i->oid, &item.oid, &item.oid_length);
- do_out_buffer(i->nspace, &item.nspace, &item.nspace_length);
- do_out_buffer(i->locator, &item.locator, &item.locator_length);
- }
-
- *next_hobj = next_hash;
-
- return result.size();
-}
-
-extern "C" void rados_object_list_free(
- const size_t result_size,
- rados_object_list_item *results)
-{
- ceph_assert(results);
-
- for (unsigned int i = 0; i < result_size; ++i) {
- rados_buffer_free(results[i].oid);
- rados_buffer_free(results[i].locator);
- rados_buffer_free(results[i].nspace);
- }
-}
-
-/* list objects */
-
-extern "C" int rados_nobjects_list_open(rados_ioctx_t io, rados_list_ctx_t *listh)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- tracepoint(librados, rados_nobjects_list_open_enter, io);
-
- Objecter::NListContext *h = new Objecter::NListContext;
- h->pool_id = ctx->poolid;
- h->pool_snap_seq = ctx->snap_seq;
- h->nspace = ctx->oloc.nspace; // After dropping compatibility need nspace
- *listh = (void *)new librados::ObjListCtx(ctx, h);
- tracepoint(librados, rados_nobjects_list_open_exit, 0, *listh);
- return 0;
-}
-
-extern "C" void rados_nobjects_list_close(rados_list_ctx_t h)
-{
- tracepoint(librados, rados_nobjects_list_close_enter, h);
- librados::ObjListCtx *lh = (librados::ObjListCtx *)h;
- delete lh;
- tracepoint(librados, rados_nobjects_list_close_exit);
-}
-
-extern "C" uint32_t rados_nobjects_list_seek(rados_list_ctx_t listctx,
- uint32_t pos)
-{
- librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
- tracepoint(librados, rados_nobjects_list_seek_enter, listctx, pos);
- uint32_t r = lh->ctx->nlist_seek(lh->nlc, pos);
- tracepoint(librados, rados_nobjects_list_seek_exit, r);
- return r;
-}
-
-extern "C" uint32_t rados_nobjects_list_seek_cursor(rados_list_ctx_t listctx,
- rados_object_list_cursor cursor)
-{
- librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
-
- tracepoint(librados, rados_nobjects_list_seek_cursor_enter, listctx);
- uint32_t r = lh->ctx->nlist_seek(lh->nlc, cursor);
- tracepoint(librados, rados_nobjects_list_seek_cursor_exit, r);
- return r;
-}
-
-extern "C" int rados_nobjects_list_get_cursor(rados_list_ctx_t listctx,
- rados_object_list_cursor *cursor)
-{
- librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
-
- tracepoint(librados, rados_nobjects_list_get_cursor_enter, listctx);
- *cursor = lh->ctx->nlist_get_cursor(lh->nlc);
- tracepoint(librados, rados_nobjects_list_get_cursor_exit, 0);
- return 0;
-}
-
-extern "C" uint32_t rados_nobjects_list_get_pg_hash_position(
- rados_list_ctx_t listctx)
-{
- librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
- tracepoint(librados, rados_nobjects_list_get_pg_hash_position_enter, listctx);
- uint32_t retval = lh->nlc->get_pg_hash_position();
- tracepoint(librados, rados_nobjects_list_get_pg_hash_position_exit, retval);
- return retval;
-}
-
-extern "C" int rados_nobjects_list_next(rados_list_ctx_t listctx, const char **entry, const char **key, const char **nspace)
-{
- tracepoint(librados, rados_nobjects_list_next_enter, listctx);
- librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
- Objecter::NListContext *h = lh->nlc;
-
- // if the list is non-empty, this method has been called before
- if (!h->list.empty())
- // so let's kill the previously-returned object
- h->list.pop_front();
-
- if (h->list.empty()) {
- int ret = lh->ctx->nlist(lh->nlc, RADOS_LIST_MAX_ENTRIES);
- if (ret < 0) {
- tracepoint(librados, rados_nobjects_list_next_exit, ret, NULL, NULL, NULL);
- return ret;
- }
- if (h->list.empty()) {
- tracepoint(librados, rados_nobjects_list_next_exit, -ENOENT, NULL, NULL, NULL);
- return -ENOENT;
- }
- }
-
- *entry = h->list.front().oid.c_str();
-
- if (key) {
- if (h->list.front().locator.size())
- *key = h->list.front().locator.c_str();
- else
- *key = NULL;
- }
- if (nspace)
- *nspace = h->list.front().nspace.c_str();
- tracepoint(librados, rados_nobjects_list_next_exit, 0, *entry, key, nspace);
- return 0;
-}
-
-
-/*
- * removed legacy v2 list objects stubs
- *
- * thse return -ENOTSUP where possible.
- */
-extern "C" int rados_objects_list_open(
- rados_ioctx_t io,
- rados_list_ctx_t *ctx)
-{
- return -ENOTSUP;
-}
-
-extern "C" uint32_t rados_objects_list_get_pg_hash_position(
- rados_list_ctx_t ctx)
-{
- return 0;
-}
-
-extern "C" uint32_t rados_objects_list_seek(
- rados_list_ctx_t ctx,
- uint32_t pos)
-{
- return 0;
-}
-
-extern "C" int rados_objects_list_next(
- rados_list_ctx_t ctx,
- const char **entry,
- const char **key)
-{
- return -ENOTSUP;
-}
-
-extern "C" void rados_objects_list_close(
- rados_list_ctx_t ctx)
-{
-}
-
-
-// -------------------------
-// aio
-
-extern "C" int rados_aio_create_completion(void *cb_arg,
- rados_callback_t cb_complete,
- rados_callback_t cb_safe,
- rados_completion_t *pc)
-{
- tracepoint(librados, rados_aio_create_completion_enter, cb_arg, cb_complete, cb_safe);
- librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
- if (cb_complete)
- c->set_complete_callback(cb_arg, cb_complete);
- if (cb_safe)
- c->set_safe_callback(cb_arg, cb_safe);
- *pc = c;
- tracepoint(librados, rados_aio_create_completion_exit, 0, *pc);
- return 0;
-}
-
-extern "C" int rados_aio_wait_for_complete(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_wait_for_complete_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->wait_for_complete();
- tracepoint(librados, rados_aio_wait_for_complete_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_wait_for_safe(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_wait_for_safe_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->wait_for_safe();
- tracepoint(librados, rados_aio_wait_for_safe_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_is_complete(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_is_complete_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->is_complete();
- tracepoint(librados, rados_aio_is_complete_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_is_safe(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_is_safe_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->is_safe();
- tracepoint(librados, rados_aio_is_safe_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_wait_for_complete_and_cb(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_wait_for_complete_and_cb_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->wait_for_complete_and_cb();
- tracepoint(librados, rados_aio_wait_for_complete_and_cb_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_wait_for_safe_and_cb(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_wait_for_safe_and_cb_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->wait_for_safe_and_cb();
- tracepoint(librados, rados_aio_wait_for_safe_and_cb_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_is_complete_and_cb(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_is_complete_and_cb_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->is_complete_and_cb();
- tracepoint(librados, rados_aio_is_complete_and_cb_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_is_safe_and_cb(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_is_safe_and_cb_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->is_safe_and_cb();
- tracepoint(librados, rados_aio_is_safe_and_cb_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_get_return_value(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_get_return_value_enter, c);
- int retval = ((librados::AioCompletionImpl*)c)->get_return_value();
- tracepoint(librados, rados_aio_get_return_value_exit, retval);
- return retval;
-}
-
-extern "C" uint64_t rados_aio_get_version(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_get_version_enter, c);
- uint64_t retval = ((librados::AioCompletionImpl*)c)->get_version();
- tracepoint(librados, rados_aio_get_version_exit, retval);
- return retval;
-}
-
-extern "C" void rados_aio_release(rados_completion_t c)
-{
- tracepoint(librados, rados_aio_release_enter, c);
- ((librados::AioCompletionImpl*)c)->put();
- tracepoint(librados, rados_aio_release_exit);
-}
-
-extern "C" int rados_aio_read(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- char *buf, size_t len, uint64_t off)
-{
- tracepoint(librados, rados_aio_read_enter, io, o, completion, len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->aio_read(oid, (librados::AioCompletionImpl*)completion,
- buf, len, off, ctx->snap_seq);
- tracepoint(librados, rados_aio_read_exit, retval);
- return retval;
-}
-
-#ifdef WITH_BLKIN
-extern "C" int rados_aio_read_traced(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- char *buf, size_t len, uint64_t off,
- struct blkin_trace_info *info)
-{
- tracepoint(librados, rados_aio_read_enter, io, o, completion, len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->aio_read(oid, (librados::AioCompletionImpl*)completion,
- buf, len, off, ctx->snap_seq, info);
- tracepoint(librados, rados_aio_read_exit, retval);
- return retval;
-}
-#endif
-
-extern "C" int rados_aio_write(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *buf, size_t len, uint64_t off)
-{
- tracepoint(librados, rados_aio_write_enter, io, o, completion, buf, len, off);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->aio_write(oid, (librados::AioCompletionImpl*)completion,
- bl, len, off);
- tracepoint(librados, rados_aio_write_exit, retval);
- return retval;
-}
-
-#ifdef WITH_BLKIN
-extern "C" int rados_aio_write_traced(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *buf, size_t len, uint64_t off,
- struct blkin_trace_info *info)
-{
- tracepoint(librados, rados_aio_write_enter, io, o, completion, buf, len, off);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->aio_write(oid, (librados::AioCompletionImpl*)completion,
- bl, len, off, info);
- tracepoint(librados, rados_aio_write_exit, retval);
- return retval;
-}
-#endif
-
-extern "C" int rados_aio_append(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *buf, size_t len)
-{
- tracepoint(librados, rados_aio_append_enter, io, o, completion, buf, len);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->aio_append(oid, (librados::AioCompletionImpl*)completion,
- bl, len);
- tracepoint(librados, rados_aio_append_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_write_full(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *buf, size_t len)
-{
- tracepoint(librados, rados_aio_write_full_enter, io, o, completion, buf, len);
- if (len > UINT_MAX/2)
- return -E2BIG;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->aio_write_full(oid, (librados::AioCompletionImpl*)completion, bl);
- tracepoint(librados, rados_aio_write_full_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_writesame(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *buf, size_t data_len,
- size_t write_len, uint64_t off)
-{
- tracepoint(librados, rados_aio_writesame_enter, io, o, completion, buf,
- data_len, write_len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, data_len);
- int retval = ctx->aio_writesame(o, (librados::AioCompletionImpl*)completion,
- bl, write_len, off);
- tracepoint(librados, rados_aio_writesame_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_remove(rados_ioctx_t io, const char *o,
- rados_completion_t completion)
-{
- tracepoint(librados, rados_aio_remove_enter, io, o, completion);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->aio_remove(oid, (librados::AioCompletionImpl*)completion);
- tracepoint(librados, rados_aio_remove_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_flush_async(rados_ioctx_t io,
- rados_completion_t completion)
-{
- tracepoint(librados, rados_aio_flush_async_enter, io, completion);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- ctx->flush_aio_writes_async((librados::AioCompletionImpl*)completion);
- tracepoint(librados, rados_aio_flush_async_exit, 0);
- return 0;
-}
-
-extern "C" int rados_aio_flush(rados_ioctx_t io)
-{
- tracepoint(librados, rados_aio_flush_enter, io);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- ctx->flush_aio_writes();
- tracepoint(librados, rados_aio_flush_exit, 0);
- return 0;
-}
-
-struct AioGetxattrData {
- AioGetxattrData(char* buf, rados_completion_t c, size_t l) :
- user_buf(buf), len(l), user_completion((librados::AioCompletionImpl*)c) {}
- bufferlist bl;
- char* user_buf;
- size_t len;
- struct librados::C_AioCompleteAndSafe user_completion;
-};
-
-static void rados_aio_getxattr_complete(rados_completion_t c, void *arg) {
- AioGetxattrData *cdata = reinterpret_cast<AioGetxattrData*>(arg);
- int rc = rados_aio_get_return_value(c);
- if (rc >= 0) {
- if (cdata->bl.length() > cdata->len) {
- rc = -ERANGE;
- } else {
- if (!cdata->bl.is_provided_buffer(cdata->user_buf))
- cdata->bl.copy(0, cdata->bl.length(), cdata->user_buf);
- rc = cdata->bl.length();
- }
- }
- cdata->user_completion.finish(rc);
- delete cdata;
-}
-
-extern "C" int rados_aio_getxattr(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *name, char *buf, size_t len)
-{
- tracepoint(librados, rados_aio_getxattr_enter, io, o, completion, name, len);
- // create data object to be passed to async callback
- AioGetxattrData *cdata = new AioGetxattrData(buf, completion, len);
- if (!cdata) {
- tracepoint(librados, rados_aio_getxattr_exit, -ENOMEM, NULL, 0);
- return -ENOMEM;
- }
- cdata->bl.push_back(buffer::create_static(len, buf));
- // create completion callback
- librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
- c->set_complete_callback(cdata, rados_aio_getxattr_complete);
- // call async getxattr of IoCtx
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int ret = ctx->aio_getxattr(oid, c, name, cdata->bl);
- tracepoint(librados, rados_aio_getxattr_exit, ret, buf, ret);
- return ret;
-}
-
-namespace {
-struct AioGetxattrsData {
- AioGetxattrsData(rados_completion_t c, rados_xattrs_iter_t *_iter) :
- iter(_iter), user_completion((librados::AioCompletionImpl*)c) {
- it = new librados::RadosXattrsIter();
- }
- ~AioGetxattrsData() {
- if (it) delete it;
- }
- librados::RadosXattrsIter *it;
- rados_xattrs_iter_t *iter;
- struct librados::C_AioCompleteAndSafe user_completion;
-};
-}
-
-static void rados_aio_getxattrs_complete(rados_completion_t c, void *arg) {
- AioGetxattrsData *cdata = reinterpret_cast<AioGetxattrsData*>(arg);
- int rc = rados_aio_get_return_value(c);
- if (rc) {
- cdata->user_completion.finish(rc);
- } else {
- cdata->it->i = cdata->it->attrset.begin();
- *cdata->iter = cdata->it;
- cdata->it = 0;
- cdata->user_completion.finish(0);
- }
- delete cdata;
-}
-
-extern "C" int rados_aio_getxattrs(rados_ioctx_t io, const char *oid,
- rados_completion_t completion,
- rados_xattrs_iter_t *iter)
-{
- tracepoint(librados, rados_aio_getxattrs_enter, io, oid, completion);
- // create data object to be passed to async callback
- AioGetxattrsData *cdata = new AioGetxattrsData(completion, iter);
- if (!cdata) {
- tracepoint(librados, rados_getxattrs_exit, -ENOMEM, NULL);
- return -ENOMEM;
- }
- // create completion callback
- librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
- c->set_complete_callback(cdata, rados_aio_getxattrs_complete);
- // call async getxattrs of IoCtx
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t obj(oid);
- int ret = ctx->aio_getxattrs(obj, c, cdata->it->attrset);
- tracepoint(librados, rados_aio_getxattrs_exit, ret, cdata->it);
- return ret;
-}
-
-extern "C" int rados_aio_setxattr(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *name, const char *buf, size_t len)
-{
- tracepoint(librados, rados_aio_setxattr_enter, io, o, completion, name, buf, len);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- bl.append(buf, len);
- int retval = ctx->aio_setxattr(oid, (librados::AioCompletionImpl*)completion, name, bl);
- tracepoint(librados, rados_aio_setxattr_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_rmxattr(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *name)
-{
- tracepoint(librados, rados_aio_rmxattr_enter, io, o, completion, name);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->aio_rmxattr(oid, (librados::AioCompletionImpl*)completion, name);
- tracepoint(librados, rados_aio_rmxattr_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_stat(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- uint64_t *psize, time_t *pmtime)
-{
- tracepoint(librados, rados_aio_stat_enter, io, o, completion);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->aio_stat(oid, (librados::AioCompletionImpl*)completion,
- psize, pmtime);
- tracepoint(librados, rados_aio_stat_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_cmpext(rados_ioctx_t io, const char *o,
- rados_completion_t completion, const char *cmp_buf,
- size_t cmp_len, uint64_t off)
-{
- tracepoint(librados, rados_aio_cmpext_enter, io, o, completion, cmp_buf,
- cmp_len, off);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->aio_cmpext(oid, (librados::AioCompletionImpl*)completion,
- cmp_buf, cmp_len, off);
- tracepoint(librados, rados_aio_cmpext_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_cancel(rados_ioctx_t io, rados_completion_t completion)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- return ctx->aio_cancel((librados::AioCompletionImpl*)completion);
-}
-
-extern "C" int rados_aio_exec(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *cls, const char *method,
- const char *inbuf, size_t in_len,
- char *buf, size_t out_len)
-{
- tracepoint(librados, rados_aio_exec_enter, io, o, completion);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist inbl;
- inbl.append(inbuf, in_len);
- int retval = ctx->aio_exec(oid, (librados::AioCompletionImpl*)completion,
- cls, method, inbl, buf, out_len);
- tracepoint(librados, rados_aio_exec_exit, retval);
- return retval;
-}
-
-struct C_WatchCB : public librados::WatchCtx {
- rados_watchcb_t wcb;
- void *arg;
- C_WatchCB(rados_watchcb_t _wcb, void *_arg) : wcb(_wcb), arg(_arg) {}
- void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) override {
- wcb(opcode, ver, arg);
- }
-};
-
-extern "C" int rados_watch(rados_ioctx_t io, const char *o, uint64_t ver,
- uint64_t *handle,
- rados_watchcb_t watchcb, void *arg)
-{
- tracepoint(librados, rados_watch_enter, io, o, ver, watchcb, arg);
- uint64_t *cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- C_WatchCB *wc = new C_WatchCB(watchcb, arg);
- int retval = ctx->watch(oid, cookie, wc, NULL, true);
- tracepoint(librados, rados_watch_exit, retval, *handle);
- return retval;
-}
-
-struct C_WatchCB2 : public librados::WatchCtx2 {
- rados_watchcb2_t wcb;
- rados_watcherrcb_t errcb;
- void *arg;
- C_WatchCB2(rados_watchcb2_t _wcb,
- rados_watcherrcb_t _errcb,
- void *_arg) : wcb(_wcb), errcb(_errcb), arg(_arg) {}
- void handle_notify(uint64_t notify_id,
- uint64_t cookie,
- uint64_t notifier_gid,
- bufferlist& bl) override {
- wcb(arg, notify_id, cookie, notifier_gid, bl.c_str(), bl.length());
- }
- void handle_error(uint64_t cookie, int err) override {
- if (errcb)
- errcb(arg, cookie, err);
- }
-};
-
-extern "C" int rados_watch2(rados_ioctx_t io, const char *o, uint64_t *handle,
- rados_watchcb2_t watchcb,
- rados_watcherrcb_t watcherrcb,
- void *arg) {
- return rados_watch3(io, o, handle, watchcb, watcherrcb, 0, arg);
-}
-
-extern "C" int rados_watch3(rados_ioctx_t io, const char *o, uint64_t *handle,
- rados_watchcb2_t watchcb,
- rados_watcherrcb_t watcherrcb,
- uint32_t timeout,
- void *arg)
-{
- tracepoint(librados, rados_watch3_enter, io, o, handle, watchcb, timeout, arg);
- int ret;
- if (!watchcb || !o || !handle) {
- ret = -EINVAL;
- } else {
- uint64_t *cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- C_WatchCB2 *wc = new C_WatchCB2(watchcb, watcherrcb, arg);
- ret = ctx->watch(oid, cookie, NULL, wc, timeout, true);
- }
- tracepoint(librados, rados_watch3_exit, ret, handle ? *handle : 0);
- return ret;
-}
-
-extern "C" int rados_aio_watch(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- uint64_t *handle,
- rados_watchcb2_t watchcb,
- rados_watcherrcb_t watcherrcb, void *arg) {
- return rados_aio_watch2(io, o, completion, handle, watchcb, watcherrcb, 0, arg);
-}
-
-extern "C" int rados_aio_watch2(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- uint64_t *handle,
- rados_watchcb2_t watchcb,
- rados_watcherrcb_t watcherrcb,
- uint32_t timeout, void *arg)
-{
- tracepoint(librados, rados_aio_watch2_enter, io, o, completion, handle, watchcb, timeout, arg);
- int ret;
- if (!completion || !watchcb || !o || !handle) {
- ret = -EINVAL;
- } else {
- uint64_t *cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- librados::AioCompletionImpl *c =
- reinterpret_cast<librados::AioCompletionImpl*>(completion);
- C_WatchCB2 *wc = new C_WatchCB2(watchcb, watcherrcb, arg);
- ret = ctx->aio_watch(oid, c, cookie, NULL, wc, timeout, true);
- }
- tracepoint(librados, rados_aio_watch2_exit, ret, handle ? *handle : 0);
- return ret;
-}
-
-
-extern "C" int rados_unwatch(rados_ioctx_t io, const char *o, uint64_t handle)
-{
- tracepoint(librados, rados_unwatch_enter, io, o, handle);
- uint64_t cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->unwatch(cookie);
- tracepoint(librados, rados_unwatch_exit, retval);
- return retval;
-}
-
-extern "C" int rados_unwatch2(rados_ioctx_t io, uint64_t handle)
-{
- tracepoint(librados, rados_unwatch2_enter, io, handle);
- uint64_t cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->unwatch(cookie);
- tracepoint(librados, rados_unwatch2_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_unwatch(rados_ioctx_t io, uint64_t handle,
- rados_completion_t completion)
-{
- tracepoint(librados, rados_aio_unwatch_enter, io, handle, completion);
- uint64_t cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- librados::AioCompletionImpl *c =
- reinterpret_cast<librados::AioCompletionImpl*>(completion);
- int retval = ctx->aio_unwatch(cookie, c);
- tracepoint(librados, rados_aio_unwatch_exit, retval);
- return retval;
-}
-
-extern "C" int rados_watch_check(rados_ioctx_t io, uint64_t handle)
-{
- tracepoint(librados, rados_watch_check_enter, io, handle);
- uint64_t cookie = handle;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->watch_check(cookie);
- tracepoint(librados, rados_watch_check_exit, retval);
- return retval;
-}
-
-extern "C" int rados_notify(rados_ioctx_t io, const char *o,
- uint64_t ver, const char *buf, int buf_len)
-{
- tracepoint(librados, rados_notify_enter, io, o, ver, buf, buf_len);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- if (buf) {
- bufferptr p = buffer::create(buf_len);
- memcpy(p.c_str(), buf, buf_len);
- bl.push_back(p);
- }
- int retval = ctx->notify(oid, bl, 0, NULL, NULL, NULL);
- tracepoint(librados, rados_notify_exit, retval);
- return retval;
-}
-
-extern "C" int rados_notify2(rados_ioctx_t io, const char *o,
- const char *buf, int buf_len,
- uint64_t timeout_ms,
- char **reply_buffer,
- size_t *reply_buffer_len)
-{
- tracepoint(librados, rados_notify2_enter, io, o, buf, buf_len, timeout_ms);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- if (buf) {
- bufferptr p = buffer::create(buf_len);
- memcpy(p.c_str(), buf, buf_len);
- bl.push_back(p);
- }
- int ret = ctx->notify(oid, bl, timeout_ms, NULL, reply_buffer, reply_buffer_len);
- tracepoint(librados, rados_notify2_exit, ret);
- return ret;
-}
-
-extern "C" int rados_aio_notify(rados_ioctx_t io, const char *o,
- rados_completion_t completion,
- const char *buf, int buf_len,
- uint64_t timeout_ms, char **reply_buffer,
- size_t *reply_buffer_len)
-{
- tracepoint(librados, rados_aio_notify_enter, io, o, completion, buf, buf_len,
- timeout_ms);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- if (buf) {
- bl.push_back(buffer::copy(buf, buf_len));
- }
- librados::AioCompletionImpl *c =
- reinterpret_cast<librados::AioCompletionImpl*>(completion);
- int ret = ctx->aio_notify(oid, c, bl, timeout_ms, NULL, reply_buffer,
- reply_buffer_len);
- tracepoint(librados, rados_aio_notify_exit, ret);
- return ret;
-}
-
-extern "C" int rados_notify_ack(rados_ioctx_t io, const char *o,
- uint64_t notify_id, uint64_t handle,
- const char *buf, int buf_len)
-{
- tracepoint(librados, rados_notify_ack_enter, io, o, notify_id, handle, buf, buf_len);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- bufferlist bl;
- if (buf) {
- bufferptr p = buffer::create(buf_len);
- memcpy(p.c_str(), buf, buf_len);
- bl.push_back(p);
- }
- ctx->notify_ack(oid, notify_id, handle, bl);
- tracepoint(librados, rados_notify_ack_exit, 0);
- return 0;
-}
-
-extern "C" int rados_watch_flush(rados_t cluster)
-{
- tracepoint(librados, rados_watch_flush_enter, cluster);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- int retval = client->watch_flush();
- tracepoint(librados, rados_watch_flush_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_watch_flush(rados_t cluster, rados_completion_t completion)
-{
- tracepoint(librados, rados_aio_watch_flush_enter, cluster, completion);
- librados::RadosClient *client = (librados::RadosClient *)cluster;
- librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
- int retval = client->async_watch_flush(c);
- tracepoint(librados, rados_aio_watch_flush_exit, retval);
- return retval;
-}
-
-extern "C" int rados_set_alloc_hint(rados_ioctx_t io, const char *o,
- uint64_t expected_object_size,
- uint64_t expected_write_size)
-{
- tracepoint(librados, rados_set_alloc_hint_enter, io, o, expected_object_size, expected_write_size);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->set_alloc_hint(oid, expected_object_size,
- expected_write_size, 0);
- tracepoint(librados, rados_set_alloc_hint_exit, retval);
- return retval;
-}
-
-extern "C" int rados_set_alloc_hint2(rados_ioctx_t io, const char *o,
- uint64_t expected_object_size,
- uint64_t expected_write_size,
- uint32_t flags)
-{
- tracepoint(librados, rados_set_alloc_hint2_enter, io, o, expected_object_size, expected_write_size, flags);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->set_alloc_hint(oid, expected_object_size,
- expected_write_size, flags);
- tracepoint(librados, rados_set_alloc_hint2_exit, retval);
- return retval;
-}
-
-extern "C" int rados_lock_exclusive(rados_ioctx_t io, const char * o,
- const char * name, const char * cookie,
- const char * desc, struct timeval * duration,
- uint8_t flags)
-{
- tracepoint(librados, rados_lock_exclusive_enter, io, o, name, cookie, desc, duration, flags);
- librados::IoCtx ctx;
- librados::IoCtx::from_rados_ioctx_t(io, ctx);
-
- int retval = ctx.lock_exclusive(o, name, cookie, desc, duration, flags);
- tracepoint(librados, rados_lock_exclusive_exit, retval);
- return retval;
-}
-
-extern "C" int rados_lock_shared(rados_ioctx_t io, const char * o,
- const char * name, const char * cookie,
- const char * tag, const char * desc,
- struct timeval * duration, uint8_t flags)
-{
- tracepoint(librados, rados_lock_shared_enter, io, o, name, cookie, tag, desc, duration, flags);
- librados::IoCtx ctx;
- librados::IoCtx::from_rados_ioctx_t(io, ctx);
-
- int retval = ctx.lock_shared(o, name, cookie, tag, desc, duration, flags);
- tracepoint(librados, rados_lock_shared_exit, retval);
- return retval;
-}
-extern "C" int rados_unlock(rados_ioctx_t io, const char *o, const char *name,
- const char *cookie)
-{
- tracepoint(librados, rados_unlock_enter, io, o, name, cookie);
- librados::IoCtx ctx;
- librados::IoCtx::from_rados_ioctx_t(io, ctx);
-
- int retval = ctx.unlock(o, name, cookie);
- tracepoint(librados, rados_unlock_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_unlock(rados_ioctx_t io, const char *o, const char *name,
- const char *cookie, rados_completion_t completion)
-{
- tracepoint(librados, rados_aio_unlock_enter, io, o, name, cookie, completion);
- librados::IoCtx ctx;
- librados::IoCtx::from_rados_ioctx_t(io, ctx);
- librados::AioCompletionImpl *comp = (librados::AioCompletionImpl*)completion;
- librados::AioCompletion c(comp);
- int retval = ctx.aio_unlock(o, name, cookie, &c);
- tracepoint(librados, rados_aio_unlock_exit, retval);
- return retval;
-}
-
-extern "C" ssize_t rados_list_lockers(rados_ioctx_t io, const char *o,
- const char *name, int *exclusive,
- char *tag, size_t *tag_len,
- char *clients, size_t *clients_len,
- char *cookies, size_t *cookies_len,
- char *addrs, size_t *addrs_len)
-{
- tracepoint(librados, rados_list_lockers_enter, io, o, name, *tag_len, *clients_len, *cookies_len, *addrs_len);
- librados::IoCtx ctx;
- librados::IoCtx::from_rados_ioctx_t(io, ctx);
- std::string name_str = name;
- std::string oid = o;
- std::string tag_str;
- int tmp_exclusive;
- std::list<librados::locker_t> lockers;
- int r = ctx.list_lockers(oid, name_str, &tmp_exclusive, &tag_str, &lockers);
- if (r < 0) {
- tracepoint(librados, rados_list_lockers_exit, r, *exclusive, "", *tag_len, *clients_len, *cookies_len, *addrs_len);
- return r;
- }
-
- size_t clients_total = 0;
- size_t cookies_total = 0;
- size_t addrs_total = 0;
- list<librados::locker_t>::const_iterator it;
- for (it = lockers.begin(); it != lockers.end(); ++it) {
- clients_total += it->client.length() + 1;
- cookies_total += it->cookie.length() + 1;
- addrs_total += it->address.length() + 1;
- }
-
- bool too_short = ((clients_total > *clients_len) ||
- (cookies_total > *cookies_len) ||
- (addrs_total > *addrs_len) ||
- (tag_str.length() + 1 > *tag_len));
- *clients_len = clients_total;
- *cookies_len = cookies_total;
- *addrs_len = addrs_total;
- *tag_len = tag_str.length() + 1;
- if (too_short) {
- tracepoint(librados, rados_list_lockers_exit, -ERANGE, *exclusive, "", *tag_len, *clients_len, *cookies_len, *addrs_len);
- return -ERANGE;
- }
-
- strcpy(tag, tag_str.c_str());
- char *clients_p = clients;
- char *cookies_p = cookies;
- char *addrs_p = addrs;
- for (it = lockers.begin(); it != lockers.end(); ++it) {
- strcpy(clients_p, it->client.c_str());
- strcpy(cookies_p, it->cookie.c_str());
- strcpy(addrs_p, it->address.c_str());
- tracepoint(librados, rados_list_lockers_locker, clients_p, cookies_p, addrs_p);
- clients_p += it->client.length() + 1;
- cookies_p += it->cookie.length() + 1;
- addrs_p += it->address.length() + 1;
- }
- if (tmp_exclusive)
- *exclusive = 1;
- else
- *exclusive = 0;
-
- int retval = lockers.size();
- tracepoint(librados, rados_list_lockers_exit, retval, *exclusive, tag, *tag_len, *clients_len, *cookies_len, *addrs_len);
- return retval;
-}
-
-extern "C" int rados_break_lock(rados_ioctx_t io, const char *o,
- const char *name, const char *client,
- const char *cookie)
-{
- tracepoint(librados, rados_break_lock_enter, io, o, name, client, cookie);
- librados::IoCtx ctx;
- librados::IoCtx::from_rados_ioctx_t(io, ctx);
-
- int retval = ctx.break_lock(o, name, client, cookie);
- tracepoint(librados, rados_break_lock_exit, retval);
- return retval;
-}
-
-extern "C" rados_write_op_t rados_create_write_op()
-{
- tracepoint(librados, rados_create_write_op_enter);
- rados_write_op_t retval = new (std::nothrow)::ObjectOperation;
- tracepoint(librados, rados_create_write_op_exit, retval);
- return retval;
-}
-
-extern "C" void rados_release_write_op(rados_write_op_t write_op)
-{
- tracepoint(librados, rados_release_write_op_enter, write_op);
- delete (::ObjectOperation*)write_op;
- tracepoint(librados, rados_release_write_op_exit);
-}
-
-extern "C" void rados_write_op_set_flags(rados_write_op_t write_op, int flags)
-{
- tracepoint(librados, rados_write_op_set_flags_enter, write_op, flags);
- set_op_flags((::ObjectOperation *)write_op, flags);
- tracepoint(librados, rados_write_op_set_flags_exit);
-}
-
-extern "C" void rados_write_op_assert_version(rados_write_op_t write_op, uint64_t ver)
-{
- tracepoint(librados, rados_write_op_assert_version_enter, write_op, ver);
- ((::ObjectOperation *)write_op)->assert_version(ver);
- tracepoint(librados, rados_write_op_assert_version_exit);
-}
-
-extern "C" void rados_write_op_assert_exists(rados_write_op_t write_op)
-{
- tracepoint(librados, rados_write_op_assert_exists_enter, write_op);
- ((::ObjectOperation *)write_op)->stat(NULL, (ceph::real_time *)NULL, NULL);
- tracepoint(librados, rados_write_op_assert_exists_exit);
-}
-
-extern "C" void rados_write_op_cmpext(rados_write_op_t write_op,
- const char *cmp_buf,
- size_t cmp_len,
- uint64_t off,
- int *prval)
-{
- tracepoint(librados, rados_write_op_cmpext_enter, write_op, cmp_buf,
- cmp_len, off, prval);
- ((::ObjectOperation *)write_op)->cmpext(off, cmp_len, cmp_buf, prval);
- tracepoint(librados, rados_write_op_cmpext_exit);
-}
-
-extern "C" void rados_write_op_cmpxattr(rados_write_op_t write_op,
- const char *name,
- uint8_t comparison_operator,
- const char *value,
- size_t value_len)
-{
- tracepoint(librados, rados_write_op_cmpxattr_enter, write_op, name, comparison_operator, value, value_len);
- bufferlist bl;
- bl.append(value, value_len);
- ((::ObjectOperation *)write_op)->cmpxattr(name,
- comparison_operator,
- CEPH_OSD_CMPXATTR_MODE_STRING,
- bl);
- tracepoint(librados, rados_write_op_cmpxattr_exit);
-}
-
-static void rados_c_omap_cmp(ObjectOperation *op,
- const char *key,
- uint8_t comparison_operator,
- const char *val,
- size_t key_len,
- size_t val_len,
- int *prval)
-{
- bufferlist bl;
- bl.append(val, val_len);
- std::map<std::string, pair<bufferlist, int> > assertions;
- string lkey = string(key, key_len);
-
- assertions[lkey] = std::make_pair(bl, comparison_operator);
- op->omap_cmp(assertions, prval);
-}
-
-extern "C" void rados_write_op_omap_cmp(rados_write_op_t write_op,
- const char *key,
- uint8_t comparison_operator,
- const char *val,
- size_t val_len,
- int *prval)
-{
- tracepoint(librados, rados_write_op_omap_cmp_enter, write_op, key, comparison_operator, val, val_len, prval);
- rados_c_omap_cmp((::ObjectOperation *)write_op, key, comparison_operator,
- val, strlen(key), val_len, prval);
- tracepoint(librados, rados_write_op_omap_cmp_exit);
-}
-
-extern "C" void rados_write_op_omap_cmp2(rados_write_op_t write_op,
- const char *key,
- uint8_t comparison_operator,
- const char *val,
- size_t key_len,
- size_t val_len,
- int *prval)
-{
- tracepoint(librados, rados_write_op_omap_cmp_enter, write_op, key, comparison_operator, val, val_len, prval);
- rados_c_omap_cmp((::ObjectOperation *)write_op, key, comparison_operator,
- val, key_len, val_len, prval);
- tracepoint(librados, rados_write_op_omap_cmp_exit);
-}
-
-extern "C" void rados_write_op_setxattr(rados_write_op_t write_op,
- const char *name,
- const char *value,
- size_t value_len)
-{
- tracepoint(librados, rados_write_op_setxattr_enter, write_op, name, value, value_len);
- bufferlist bl;
- bl.append(value, value_len);
- ((::ObjectOperation *)write_op)->setxattr(name, bl);
- tracepoint(librados, rados_write_op_setxattr_exit);
-}
-
-extern "C" void rados_write_op_rmxattr(rados_write_op_t write_op,
- const char *name)
-{
- tracepoint(librados, rados_write_op_rmxattr_enter, write_op, name);
- ((::ObjectOperation *)write_op)->rmxattr(name);
- tracepoint(librados, rados_write_op_rmxattr_exit);
-}
-
-extern "C" void rados_write_op_create(rados_write_op_t write_op,
- int exclusive,
- const char* category) // unused
-{
- tracepoint(librados, rados_write_op_create_enter, write_op, exclusive);
- ::ObjectOperation *oo = (::ObjectOperation *) write_op;
- oo->create(!!exclusive);
- tracepoint(librados, rados_write_op_create_exit);
-}
-
-extern "C" void rados_write_op_write(rados_write_op_t write_op,
- const char *buffer,
- size_t len,
- uint64_t offset)
-{
- tracepoint(librados, rados_write_op_write_enter, write_op, buffer, len, offset);
- bufferlist bl;
- bl.append(buffer,len);
- ((::ObjectOperation *)write_op)->write(offset, bl);
- tracepoint(librados, rados_write_op_write_exit);
-}
-
-extern "C" void rados_write_op_write_full(rados_write_op_t write_op,
- const char *buffer,
- size_t len)
-{
- tracepoint(librados, rados_write_op_write_full_enter, write_op, buffer, len);
- bufferlist bl;
- bl.append(buffer,len);
- ((::ObjectOperation *)write_op)->write_full(bl);
- tracepoint(librados, rados_write_op_write_full_exit);
-}
-
-extern "C" void rados_write_op_writesame(rados_write_op_t write_op,
- const char *buffer,
- size_t data_len,
- size_t write_len,
- uint64_t offset)
-{
- tracepoint(librados, rados_write_op_writesame_enter, write_op, buffer, data_len, write_len, offset);
- bufferlist bl;
- bl.append(buffer, data_len);
- ((::ObjectOperation *)write_op)->writesame(offset, write_len, bl);
- tracepoint(librados, rados_write_op_writesame_exit);
-}
-
-extern "C" void rados_write_op_append(rados_write_op_t write_op,
- const char *buffer,
- size_t len)
-{
- tracepoint(librados, rados_write_op_append_enter, write_op, buffer, len);
- bufferlist bl;
- bl.append(buffer,len);
- ((::ObjectOperation *)write_op)->append(bl);
- tracepoint(librados, rados_write_op_append_exit);
-}
-
-extern "C" void rados_write_op_remove(rados_write_op_t write_op)
-{
- tracepoint(librados, rados_write_op_remove_enter, write_op);
- ((::ObjectOperation *)write_op)->remove();
- tracepoint(librados, rados_write_op_remove_exit);
-}
-
-extern "C" void rados_write_op_truncate(rados_write_op_t write_op,
- uint64_t offset)
-{
- tracepoint(librados, rados_write_op_truncate_enter, write_op, offset);
- ((::ObjectOperation *)write_op)->truncate(offset);
- tracepoint(librados, rados_write_op_truncate_exit);
-}
-
-extern "C" void rados_write_op_zero(rados_write_op_t write_op,
- uint64_t offset,
- uint64_t len)
-{
- tracepoint(librados, rados_write_op_zero_enter, write_op, offset, len);
- ((::ObjectOperation *)write_op)->zero(offset, len);
- tracepoint(librados, rados_write_op_zero_exit);
-}
-
-extern "C" void rados_write_op_exec(rados_write_op_t write_op,
- const char *cls,
- const char *method,
- const char *in_buf,
- size_t in_len,
- int *prval)
-{
- tracepoint(librados, rados_write_op_exec_enter, write_op, cls, method, in_buf, in_len, prval);
- bufferlist inbl;
- inbl.append(in_buf, in_len);
- ((::ObjectOperation *)write_op)->call(cls, method, inbl, NULL, NULL, prval);
- tracepoint(librados, rados_write_op_exec_exit);
-}
-
-extern "C" void rados_write_op_omap_set(rados_write_op_t write_op,
- char const* const* keys,
- char const* const* vals,
- const size_t *lens,
- size_t num)
-{
- tracepoint(librados, rados_write_op_omap_set_enter, write_op, num);
- std::map<std::string, bufferlist> entries;
- for (size_t i = 0; i < num; ++i) {
- tracepoint(librados, rados_write_op_omap_set_entry, keys[i], vals[i], lens[i]);
- bufferlist bl(lens[i]);
- bl.append(vals[i], lens[i]);
- entries[keys[i]] = bl;
- }
- ((::ObjectOperation *)write_op)->omap_set(entries);
- tracepoint(librados, rados_write_op_omap_set_exit);
-}
-
-extern "C" void rados_write_op_omap_set2(rados_write_op_t write_op,
- char const* const* keys,
- char const* const* vals,
- const size_t *key_lens,
- const size_t *val_lens,
- size_t num)
-{
- tracepoint(librados, rados_write_op_omap_set_enter, write_op, num);
- std::map<std::string, bufferlist> entries;
- for (size_t i = 0; i < num; ++i) {
- bufferlist bl(val_lens[i]);
- bl.append(vals[i], val_lens[i]);
- string key(keys[i], key_lens[i]);
- entries[key] = bl;
- }
- ((::ObjectOperation *)write_op)->omap_set(entries);
- tracepoint(librados, rados_write_op_omap_set_exit);
-}
-
-extern "C" void rados_write_op_omap_rm_keys(rados_write_op_t write_op,
- char const* const* keys,
- size_t keys_len)
-{
- tracepoint(librados, rados_write_op_omap_rm_keys_enter, write_op, keys_len);
- for(size_t i = 0; i < keys_len; i++) {
- tracepoint(librados, rados_write_op_omap_rm_keys_entry, keys[i]);
- }
- std::set<std::string> to_remove(keys, keys + keys_len);
- ((::ObjectOperation *)write_op)->omap_rm_keys(to_remove);
- tracepoint(librados, rados_write_op_omap_rm_keys_exit);
-}
-
-extern "C" void rados_write_op_omap_rm_keys2(rados_write_op_t write_op,
- char const* const* keys,
- const size_t* key_lens,
- size_t keys_len)
-{
- tracepoint(librados, rados_write_op_omap_rm_keys_enter, write_op, keys_len);
- std::set<std::string> to_remove;
- for(size_t i = 0; i < keys_len; i++) {
- to_remove.emplace(keys[i], key_lens[i]);
- }
- ((::ObjectOperation *)write_op)->omap_rm_keys(to_remove);
- tracepoint(librados, rados_write_op_omap_rm_keys_exit);
-}
-
-extern "C" void rados_write_op_omap_clear(rados_write_op_t write_op)
-{
- tracepoint(librados, rados_write_op_omap_clear_enter, write_op);
- ((::ObjectOperation *)write_op)->omap_clear();
- tracepoint(librados, rados_write_op_omap_clear_exit);
-}
-
-extern "C" void rados_write_op_set_alloc_hint(rados_write_op_t write_op,
- uint64_t expected_object_size,
- uint64_t expected_write_size)
-{
- tracepoint(librados, rados_write_op_set_alloc_hint_enter, write_op, expected_object_size, expected_write_size);
- ((::ObjectOperation *)write_op)->set_alloc_hint(expected_object_size,
- expected_write_size, 0);
- tracepoint(librados, rados_write_op_set_alloc_hint_exit);
-}
-
-extern "C" void rados_write_op_set_alloc_hint2(rados_write_op_t write_op,
- uint64_t expected_object_size,
- uint64_t expected_write_size,
- uint32_t flags)
-{
- tracepoint(librados, rados_write_op_set_alloc_hint2_enter, write_op, expected_object_size, expected_write_size, flags);
- ((::ObjectOperation *)write_op)->set_alloc_hint(expected_object_size,
- expected_write_size,
- flags);
- tracepoint(librados, rados_write_op_set_alloc_hint2_exit);
-}
-
-extern "C" int rados_write_op_operate(rados_write_op_t write_op,
- rados_ioctx_t io,
- const char *oid,
- time_t *mtime,
- int flags)
-{
- tracepoint(librados, rados_write_op_operate_enter, write_op, io, oid, mtime, flags);
- object_t obj(oid);
- ::ObjectOperation *oo = (::ObjectOperation *) write_op;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- ceph::real_time *prt = NULL;
- ceph::real_time rt;
-
- if (mtime) {
- rt = ceph::real_clock::from_time_t(*mtime);
- prt = &rt;
- }
-
- int retval = ctx->operate(obj, oo, prt, translate_flags(flags));
- tracepoint(librados, rados_write_op_operate_exit, retval);
- return retval;
-}
-
-extern "C" int rados_write_op_operate2(rados_write_op_t write_op,
- rados_ioctx_t io,
- const char *oid,
- struct timespec *ts,
- int flags)
-{
- tracepoint(librados, rados_write_op_operate2_enter, write_op, io, oid, ts, flags);
- object_t obj(oid);
- ::ObjectOperation *oo = (::ObjectOperation *) write_op;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- ceph::real_time *prt = NULL;
- ceph::real_time rt;
-
- if (ts) {
- rt = ceph::real_clock::from_timespec(*ts);
- prt = &rt;
- }
-
- int retval = ctx->operate(obj, oo, prt, translate_flags(flags));
- tracepoint(librados, rados_write_op_operate_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_write_op_operate(rados_write_op_t write_op,
- rados_ioctx_t io,
- rados_completion_t completion,
- const char *oid,
- time_t *mtime,
- int flags)
-{
- tracepoint(librados, rados_aio_write_op_operate_enter, write_op, io, completion, oid, mtime, flags);
- object_t obj(oid);
- ::ObjectOperation *oo = (::ObjectOperation *) write_op;
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
- int retval = ctx->aio_operate(obj, oo, c, ctx->snapc, translate_flags(flags));
- tracepoint(librados, rados_aio_write_op_operate_exit, retval);
- return retval;
-}
-
-extern "C" rados_read_op_t rados_create_read_op()
-{
- tracepoint(librados, rados_create_read_op_enter);
- rados_read_op_t retval = new (std::nothrow)::ObjectOperation;
- tracepoint(librados, rados_create_read_op_exit, retval);
- return retval;
-}
-
-extern "C" void rados_release_read_op(rados_read_op_t read_op)
-{
- tracepoint(librados, rados_release_read_op_enter, read_op);
- delete (::ObjectOperation *)read_op;
- tracepoint(librados, rados_release_read_op_exit);
-}
-
-extern "C" void rados_read_op_set_flags(rados_read_op_t read_op, int flags)
-{
- tracepoint(librados, rados_read_op_set_flags_enter, read_op, flags);
- set_op_flags((::ObjectOperation *)read_op, flags);
- tracepoint(librados, rados_read_op_set_flags_exit);
-}
-
-extern "C" void rados_read_op_assert_version(rados_read_op_t read_op, uint64_t ver)
-{
- tracepoint(librados, rados_read_op_assert_version_enter, read_op, ver);
- ((::ObjectOperation *)read_op)->assert_version(ver);
- tracepoint(librados, rados_read_op_assert_version_exit);
-}
-
-extern "C" void rados_read_op_assert_exists(rados_read_op_t read_op)
-{
- tracepoint(librados, rados_read_op_assert_exists_enter, read_op);
- ((::ObjectOperation *)read_op)->stat(NULL, (ceph::real_time *)NULL, NULL);
- tracepoint(librados, rados_read_op_assert_exists_exit);
-}
-
-extern "C" void rados_read_op_cmpext(rados_read_op_t read_op,
- const char *cmp_buf,
- size_t cmp_len,
- uint64_t off,
- int *prval)
-{
- tracepoint(librados, rados_read_op_cmpext_enter, read_op, cmp_buf,
- cmp_len, off, prval);
- ((::ObjectOperation *)read_op)->cmpext(off, cmp_len, cmp_buf, prval);
- tracepoint(librados, rados_read_op_cmpext_exit);
-}
-
-extern "C" void rados_read_op_cmpxattr(rados_read_op_t read_op,
- const char *name,
- uint8_t comparison_operator,
- const char *value,
- size_t value_len)
-{
- tracepoint(librados, rados_read_op_cmpxattr_enter, read_op, name, comparison_operator, value, value_len);
- bufferlist bl;
- bl.append(value, value_len);
- ((::ObjectOperation *)read_op)->cmpxattr(name,
- comparison_operator,
- CEPH_OSD_CMPXATTR_MODE_STRING,
- bl);
- tracepoint(librados, rados_read_op_cmpxattr_exit);
-}
-
-extern "C" void rados_read_op_omap_cmp(rados_read_op_t read_op,
- const char *key,
- uint8_t comparison_operator,
- const char *val,
- size_t val_len,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_cmp_enter, read_op, key, comparison_operator, val, val_len, prval);
- rados_c_omap_cmp((::ObjectOperation *)read_op, key, comparison_operator,
- val, strlen(key), val_len, prval);
- tracepoint(librados, rados_read_op_omap_cmp_exit);
-}
-
-extern "C" void rados_read_op_omap_cmp2(rados_read_op_t read_op,
- const char *key,
- uint8_t comparison_operator,
- const char *val,
- size_t key_len,
- size_t val_len,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_cmp_enter, read_op, key, comparison_operator, val, val_len, prval);
- rados_c_omap_cmp((::ObjectOperation *)read_op, key, comparison_operator,
- val, key_len, val_len, prval);
- tracepoint(librados, rados_read_op_omap_cmp_exit);
-}
-
-extern "C" void rados_read_op_stat(rados_read_op_t read_op,
- uint64_t *psize,
- time_t *pmtime,
- int *prval)
-{
- tracepoint(librados, rados_read_op_stat_enter, read_op, psize, pmtime, prval);
- ((::ObjectOperation *)read_op)->stat(psize, pmtime, prval);
- tracepoint(librados, rados_read_op_stat_exit);
-}
-
-class C_bl_to_buf : public Context {
- char *out_buf;
- size_t out_len;
- size_t *bytes_read;
- int *prval;
-public:
- bufferlist out_bl;
- C_bl_to_buf(char *out_buf,
- size_t out_len,
- size_t *bytes_read,
- int *prval) : out_buf(out_buf), out_len(out_len),
- bytes_read(bytes_read), prval(prval) {}
- void finish(int r) override {
- if (out_bl.length() > out_len) {
- if (prval)
- *prval = -ERANGE;
- if (bytes_read)
- *bytes_read = 0;
- return;
- }
- if (bytes_read)
- *bytes_read = out_bl.length();
- if (out_buf && !out_bl.is_provided_buffer(out_buf))
- out_bl.copy(0, out_bl.length(), out_buf);
- }
-};
-
-extern "C" void rados_read_op_read(rados_read_op_t read_op,
- uint64_t offset,
- size_t len,
- char *buf,
- size_t *bytes_read,
- int *prval)
-{
- tracepoint(librados, rados_read_op_read_enter, read_op, offset, len, buf, bytes_read, prval);
- C_bl_to_buf *ctx = new C_bl_to_buf(buf, len, bytes_read, prval);
- ctx->out_bl.push_back(buffer::create_static(len, buf));
- ((::ObjectOperation *)read_op)->read(offset, len, &ctx->out_bl, prval, ctx);
- tracepoint(librados, rados_read_op_read_exit);
-}
-
-extern "C" void rados_read_op_checksum(rados_read_op_t read_op,
- rados_checksum_type_t type,
- const char *init_value,
- size_t init_value_len,
- uint64_t offset, size_t len,
- size_t chunk_size, char *pchecksum,
- size_t checksum_len, int *prval)
-{
- tracepoint(librados, rados_read_op_checksum_enter, read_op, type, init_value,
- init_value_len, offset, len, chunk_size);
- bufferlist init_value_bl;
- init_value_bl.append(init_value, init_value_len);
-
- C_bl_to_buf *ctx = nullptr;
- if (pchecksum != nullptr) {
- ctx = new C_bl_to_buf(pchecksum, checksum_len, nullptr, prval);
- }
- ((::ObjectOperation *)read_op)->checksum(get_checksum_op_type(type),
- init_value_bl, offset, len,
- chunk_size,
- (ctx ? &ctx->out_bl : nullptr),
- prval, ctx);
- tracepoint(librados, rados_read_op_checksum_exit);
-}
-
-class C_out_buffer : public Context {
- char **out_buf;
- size_t *out_len;
-public:
- bufferlist out_bl;
- C_out_buffer(char **out_buf, size_t *out_len) : out_buf(out_buf),
- out_len(out_len) {}
- void finish(int r) override {
- // ignore r since we don't know the meaning of return values
- // from custom class methods
- do_out_buffer(out_bl, out_buf, out_len);
- }
-};
-
-extern "C" void rados_read_op_exec(rados_read_op_t read_op,
- const char *cls,
- const char *method,
- const char *in_buf,
- size_t in_len,
- char **out_buf,
- size_t *out_len,
- int *prval)
-{
- tracepoint(librados, rados_read_op_exec_enter, read_op, cls, method, in_buf, in_len, out_buf, out_len, prval);
- bufferlist inbl;
- inbl.append(in_buf, in_len);
- C_out_buffer *ctx = new C_out_buffer(out_buf, out_len);
- ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
- prval);
- tracepoint(librados, rados_read_op_exec_exit);
-}
-
-extern "C" void rados_read_op_exec_user_buf(rados_read_op_t read_op,
- const char *cls,
- const char *method,
- const char *in_buf,
- size_t in_len,
- char *out_buf,
- size_t out_len,
- size_t *used_len,
- int *prval)
-{
- tracepoint(librados, rados_read_op_exec_user_buf_enter, read_op, cls, method, in_buf, in_len, out_buf, out_len, used_len, prval);
- C_bl_to_buf *ctx = new C_bl_to_buf(out_buf, out_len, used_len, prval);
- bufferlist inbl;
- inbl.append(in_buf, in_len);
- ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
- prval);
- tracepoint(librados, rados_read_op_exec_user_buf_exit);
-}
-
-struct RadosOmapIter {
- std::map<std::string, bufferlist> values;
- std::map<std::string, bufferlist>::iterator i;
-};
-
-class C_OmapIter : public Context {
- RadosOmapIter *iter;
-public:
- explicit C_OmapIter(RadosOmapIter *iter) : iter(iter) {}
- void finish(int r) override {
- iter->i = iter->values.begin();
- }
-};
-
-class C_XattrsIter : public Context {
- librados::RadosXattrsIter *iter;
-public:
- explicit C_XattrsIter(librados::RadosXattrsIter *iter) : iter(iter) {}
- void finish(int r) override {
- iter->i = iter->attrset.begin();
- }
-};
-
-extern "C" void rados_read_op_getxattrs(rados_read_op_t read_op,
- rados_xattrs_iter_t *iter,
- int *prval)
-{
- tracepoint(librados, rados_read_op_getxattrs_enter, read_op, prval);
- librados::RadosXattrsIter *xattrs_iter = new librados::RadosXattrsIter;
- ((::ObjectOperation *)read_op)->getxattrs(&xattrs_iter->attrset, prval);
- ((::ObjectOperation *)read_op)->add_handler(new C_XattrsIter(xattrs_iter));
- *iter = xattrs_iter;
- tracepoint(librados, rados_read_op_getxattrs_exit, *iter);
-}
-
-extern "C" void rados_read_op_omap_get_vals(rados_read_op_t read_op,
- const char *start_after,
- const char *filter_prefix,
- uint64_t max_return,
- rados_omap_iter_t *iter,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_get_vals_enter, read_op, start_after, filter_prefix, max_return, prval);
- RadosOmapIter *omap_iter = new RadosOmapIter;
- const char *start = start_after ? start_after : "";
- const char *filter = filter_prefix ? filter_prefix : "";
- ((::ObjectOperation *)read_op)->omap_get_vals(
- start,
- filter,
- max_return,
- &omap_iter->values,
- nullptr,
- prval);
- ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter));
- *iter = omap_iter;
- tracepoint(librados, rados_read_op_omap_get_vals_exit, *iter);
-}
-
-extern "C" void rados_read_op_omap_get_vals2(rados_read_op_t read_op,
- const char *start_after,
- const char *filter_prefix,
- uint64_t max_return,
- rados_omap_iter_t *iter,
- unsigned char *pmore,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_get_vals_enter, read_op, start_after, filter_prefix, max_return, prval);
- RadosOmapIter *omap_iter = new RadosOmapIter;
- const char *start = start_after ? start_after : "";
- const char *filter = filter_prefix ? filter_prefix : "";
- ((::ObjectOperation *)read_op)->omap_get_vals(
- start,
- filter,
- max_return,
- &omap_iter->values,
- (bool*)pmore,
- prval);
- ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter));
- *iter = omap_iter;
- tracepoint(librados, rados_read_op_omap_get_vals_exit, *iter);
-}
-
-struct C_OmapKeysIter : public Context {
- RadosOmapIter *iter;
- std::set<std::string> keys;
- explicit C_OmapKeysIter(RadosOmapIter *iter) : iter(iter) {}
- void finish(int r) override {
- // map each key to an empty bl
- for (std::set<std::string>::const_iterator i = keys.begin();
- i != keys.end(); ++i) {
- iter->values[*i];
- }
- iter->i = iter->values.begin();
- }
-};
-
-extern "C" void rados_read_op_omap_get_keys(rados_read_op_t read_op,
- const char *start_after,
- uint64_t max_return,
- rados_omap_iter_t *iter,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_get_keys_enter, read_op, start_after, max_return, prval);
- RadosOmapIter *omap_iter = new RadosOmapIter;
- C_OmapKeysIter *ctx = new C_OmapKeysIter(omap_iter);
- ((::ObjectOperation *)read_op)->omap_get_keys(
- start_after ? start_after : "",
- max_return, &ctx->keys, nullptr, prval);
- ((::ObjectOperation *)read_op)->add_handler(ctx);
- *iter = omap_iter;
- tracepoint(librados, rados_read_op_omap_get_keys_exit, *iter);
-}
-
-extern "C" void rados_read_op_omap_get_keys2(rados_read_op_t read_op,
- const char *start_after,
- uint64_t max_return,
- rados_omap_iter_t *iter,
- unsigned char *pmore,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_get_keys_enter, read_op, start_after, max_return, prval);
- RadosOmapIter *omap_iter = new RadosOmapIter;
- C_OmapKeysIter *ctx = new C_OmapKeysIter(omap_iter);
- ((::ObjectOperation *)read_op)->omap_get_keys(
- start_after ? start_after : "",
- max_return, &ctx->keys,
- (bool*)pmore, prval);
- ((::ObjectOperation *)read_op)->add_handler(ctx);
- *iter = omap_iter;
- tracepoint(librados, rados_read_op_omap_get_keys_exit, *iter);
-}
-
-void internal_rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op,
- set<string>& to_get,
- rados_omap_iter_t *iter,
- int *prval)
-{
- RadosOmapIter *omap_iter = new RadosOmapIter;
- ((::ObjectOperation *)read_op)->omap_get_vals_by_keys(to_get,
- &omap_iter->values,
- prval);
- ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter));
- *iter = omap_iter;
-}
-
-extern "C" void rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op,
- char const* const* keys,
- size_t keys_len,
- rados_omap_iter_t *iter,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_get_vals_by_keys_enter, read_op, keys, keys_len, iter, prval);
- std::set<std::string> to_get(keys, keys + keys_len);
- internal_rados_read_op_omap_get_vals_by_keys(read_op, to_get, iter, prval);
- tracepoint(librados, rados_read_op_omap_get_vals_by_keys_exit, *iter);
-}
-
-extern "C" void rados_read_op_omap_get_vals_by_keys2(rados_read_op_t read_op,
- char const* const* keys,
- size_t num_keys,
- const size_t* key_lens,
- rados_omap_iter_t *iter,
- int *prval)
-{
- tracepoint(librados, rados_read_op_omap_get_vals_by_keys_enter, read_op, keys, num_keys, iter, prval);
- std::set<std::string> to_get;
- for (size_t i = 0; i < num_keys; i++) {
- to_get.emplace(keys[i], key_lens[i]);
- }
- internal_rados_read_op_omap_get_vals_by_keys(read_op, to_get, iter, prval);
- tracepoint(librados, rados_read_op_omap_get_vals_by_keys_exit, *iter);
-}
-
-extern "C" int rados_omap_get_next(rados_omap_iter_t iter,
- char **key,
- char **val,
- size_t *len)
-{
- return rados_omap_get_next2(iter, key, val, nullptr, len);
-}
-
-extern "C" int rados_omap_get_next2(rados_omap_iter_t iter,
- char **key,
- char **val,
- size_t *key_len,
- size_t *val_len)
-{
- tracepoint(librados, rados_omap_get_next_enter, iter);
- RadosOmapIter *it = static_cast<RadosOmapIter *>(iter);
- if (it->i == it->values.end()) {
- if (key)
- *key = NULL;
- if (val)
- *val = NULL;
- if (key_len)
- *key_len = 0;
- if (val_len)
- *val_len = 0;
- tracepoint(librados, rados_omap_get_next_exit, 0, key, val, val_len);
- return 0;
- }
- if (key)
- *key = (char*)it->i->first.c_str();
- if (val)
- *val = it->i->second.c_str();
- if (key_len)
- *key_len = it->i->first.length();
- if (val_len)
- *val_len = it->i->second.length();
- ++it->i;
- tracepoint(librados, rados_omap_get_next_exit, 0, key, val, val_len);
- return 0;
-}
-
-extern "C" unsigned int rados_omap_iter_size(rados_omap_iter_t iter)
-{
- RadosOmapIter *it = static_cast<RadosOmapIter *>(iter);
- return it->values.size();
-}
-
-extern "C" void rados_omap_get_end(rados_omap_iter_t iter)
-{
- tracepoint(librados, rados_omap_get_end_enter, iter);
- RadosOmapIter *it = static_cast<RadosOmapIter *>(iter);
- delete it;
- tracepoint(librados, rados_omap_get_end_exit);
-}
-
-extern "C" int rados_read_op_operate(rados_read_op_t read_op,
- rados_ioctx_t io,
- const char *oid,
- int flags)
-{
- tracepoint(librados, rados_read_op_operate_enter, read_op, io, oid, flags);
- object_t obj(oid);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- int retval = ctx->operate_read(obj, (::ObjectOperation *)read_op, NULL,
- translate_flags(flags));
- tracepoint(librados, rados_read_op_operate_exit, retval);
- return retval;
-}
-
-extern "C" int rados_aio_read_op_operate(rados_read_op_t read_op,
- rados_ioctx_t io,
- rados_completion_t completion,
- const char *oid,
- int flags)
-{
- tracepoint(librados, rados_aio_read_op_operate_enter, read_op, io, completion, oid, flags);
- object_t obj(oid);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
- int retval = ctx->aio_operate_read(obj, (::ObjectOperation *)read_op,
- c, translate_flags(flags), NULL);
- tracepoint(librados, rados_aio_read_op_operate_exit, retval);
- return retval;
-}
-
-extern "C" int rados_cache_pin(rados_ioctx_t io, const char *o)
-{
- tracepoint(librados, rados_cache_pin_enter, io, o);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->cache_pin(oid);
- tracepoint(librados, rados_cache_pin_exit, retval);
- return retval;
-}
-
-extern "C" int rados_cache_unpin(rados_ioctx_t io, const char *o)
-{
- tracepoint(librados, rados_cache_unpin_enter, io, o);
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
- object_t oid(o);
- int retval = ctx->cache_unpin(oid);
- tracepoint(librados, rados_cache_unpin_exit, retval);
- return retval;
-}
-
-
-///////////////////////////// ListObject //////////////////////////////
-librados::ListObject::ListObject() : impl(NULL)
-{
-}
-
-librados::ListObject::ListObject(librados::ListObjectImpl *i): impl(i)
-{
-}
-
-librados::ListObject::ListObject(const ListObject& rhs)
-{
- if (rhs.impl == NULL) {
- impl = NULL;
- return;
- }
- impl = new ListObjectImpl();
- *impl = *(rhs.impl);
-}
-
-librados::ListObject& librados::ListObject::operator=(const ListObject& rhs)
-{
- if (rhs.impl == NULL) {
- delete impl;
- impl = NULL;
- return *this;
- }
- if (impl == NULL)
- impl = new ListObjectImpl();
- *impl = *(rhs.impl);
- return *this;
-}
-
-librados::ListObject::~ListObject()
-{
- if (impl)
- delete impl;
- impl = NULL;
-}
-
-const std::string& librados::ListObject::get_nspace() const
-{
- return impl->get_nspace();
-}
-
-const std::string& librados::ListObject::get_oid() const
-{
- return impl->get_oid();
-}
-
-const std::string& librados::ListObject::get_locator() const
-{
- return impl->get_locator();
-}
-
-std::ostream& librados::operator<<(std::ostream& out, const librados::ListObject& lop)
-{
- out << *(lop.impl);
- return out;
-}
-
-CEPH_RADOS_API void rados_object_list_slice(
- rados_ioctx_t io,
- const rados_object_list_cursor start,
- const rados_object_list_cursor finish,
- const size_t n,
- const size_t m,
- rados_object_list_cursor *split_start,
- rados_object_list_cursor *split_finish)
-{
- librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
-
- ceph_assert(split_start);
- ceph_assert(split_finish);
- hobject_t *split_start_hobj = (hobject_t*)(*split_start);
- hobject_t *split_finish_hobj = (hobject_t*)(*split_finish);
- ceph_assert(split_start_hobj);
- ceph_assert(split_finish_hobj);
- hobject_t *start_hobj = (hobject_t*)(start);
- hobject_t *finish_hobj = (hobject_t*)(finish);
-
- ctx->object_list_slice(
- *start_hobj,
- *finish_hobj,
- n,
- m,
- split_start_hobj,
- split_finish_hobj);
-}
-
-librados::ObjectCursor::ObjectCursor()
-{
- c_cursor = (rados_object_list_cursor)new hobject_t();
-}
-
-librados::ObjectCursor::~ObjectCursor()
-{
- hobject_t *h = (hobject_t *)c_cursor;
- delete h;
-}
-
-librados::ObjectCursor::ObjectCursor(rados_object_list_cursor c)
-{
- if (!c) {
- c_cursor = nullptr;
- } else {
- c_cursor = (rados_object_list_cursor)new hobject_t(*(hobject_t *)c);
- }
-}
-
-librados::ObjectCursor& librados::ObjectCursor::operator=(const librados::ObjectCursor& rhs)
-{
- if (rhs.c_cursor != nullptr) {
- hobject_t *h = (hobject_t*)rhs.c_cursor;
- c_cursor = (rados_object_list_cursor)(new hobject_t(*h));
- } else {
- c_cursor = nullptr;
- }
- return *this;
-}
-
-bool librados::ObjectCursor::operator<(const librados::ObjectCursor &rhs) const
-{
- const hobject_t lhs_hobj = (c_cursor == nullptr) ? hobject_t() : *((hobject_t*)c_cursor);
- const hobject_t rhs_hobj = (rhs.c_cursor == nullptr) ? hobject_t() : *((hobject_t*)(rhs.c_cursor));
- return lhs_hobj < rhs_hobj;
-}
-
-bool librados::ObjectCursor::operator==(const librados::ObjectCursor &rhs) const
-{
- const hobject_t lhs_hobj = (c_cursor == nullptr) ? hobject_t() : *((hobject_t*)c_cursor);
- const hobject_t rhs_hobj = (rhs.c_cursor == nullptr) ? hobject_t() : *((hobject_t*)(rhs.c_cursor));
- return cmp(lhs_hobj, rhs_hobj) == 0;
-}
-librados::ObjectCursor::ObjectCursor(const librados::ObjectCursor &rhs)
-{
- *this = rhs;
-}
-
-librados::ObjectCursor librados::IoCtx::object_list_begin()
-{
- hobject_t *h = new hobject_t(io_ctx_impl->objecter->enumerate_objects_begin());
- ObjectCursor oc;
- oc.set((rados_object_list_cursor)h);
- return oc;
-}
-
-
-librados::ObjectCursor librados::IoCtx::object_list_end()
-{
- hobject_t *h = new hobject_t(io_ctx_impl->objecter->enumerate_objects_end());
- librados::ObjectCursor oc;
- oc.set((rados_object_list_cursor)h);
- return oc;
-}
-
-
-void librados::ObjectCursor::set(rados_object_list_cursor c)
-{
- delete (hobject_t*)c_cursor;
- c_cursor = c;
-}
-
-string librados::ObjectCursor::to_str() const
-{
- stringstream ss;
- ss << *(hobject_t *)c_cursor;
- return ss.str();
-}
-
-bool librados::ObjectCursor::from_str(const string& s)
-{
- if (s.empty()) {
- *(hobject_t *)c_cursor = hobject_t();
- return true;
- }
- return ((hobject_t *)c_cursor)->parse(s);
-}
-
-CEPH_RADOS_API std::ostream& librados::operator<<(std::ostream& os, const librados::ObjectCursor& oc)
-{
- if (oc.c_cursor) {
- os << *(hobject_t *)oc.c_cursor;
- } else {
- os << hobject_t();
- }
- return os;
-}
-
-bool librados::IoCtx::object_list_is_end(const ObjectCursor &oc)
-{
- hobject_t *h = (hobject_t *)oc.c_cursor;
- return h->is_max();
-}
-
-int librados::IoCtx::object_list(const ObjectCursor &start,
- const ObjectCursor &finish,
- const size_t result_item_count,
- const bufferlist &filter,
- std::vector<ObjectItem> *result,
- ObjectCursor *next)
-{
- ceph_assert(result != nullptr);
- ceph_assert(next != nullptr);
- result->clear();
-
- C_SaferCond cond;
- hobject_t next_hash;
- std::list<librados::ListObjectImpl> obj_result;
- io_ctx_impl->objecter->enumerate_objects(
- io_ctx_impl->poolid,
- io_ctx_impl->oloc.nspace,
- *((hobject_t*)start.c_cursor),
- *((hobject_t*)finish.c_cursor),
- result_item_count,
- filter,
- &obj_result,
- &next_hash,
- &cond);
-
- int r = cond.wait();
- if (r < 0) {
- next->set((rados_object_list_cursor)(new hobject_t(hobject_t::get_max())));
- return r;
- }
-
- next->set((rados_object_list_cursor)(new hobject_t(next_hash)));
-
- for (std::list<librados::ListObjectImpl>::iterator i = obj_result.begin();
- i != obj_result.end(); ++i) {
- ObjectItem oi;
- oi.oid = i->oid;
- oi.nspace = i->nspace;
- oi.locator = i->locator;
- result->push_back(oi);
- }
-
- return obj_result.size();
-}
-
-void librados::IoCtx::object_list_slice(
- const ObjectCursor start,
- const ObjectCursor finish,
- const size_t n,
- const size_t m,
- ObjectCursor *split_start,
- ObjectCursor *split_finish)
-{
- ceph_assert(split_start != nullptr);
- ceph_assert(split_finish != nullptr);
-
- io_ctx_impl->object_list_slice(
- *((hobject_t*)(start.c_cursor)),
- *((hobject_t*)(finish.c_cursor)),
- n,
- m,
- (hobject_t*)(split_start->c_cursor),
- (hobject_t*)(split_finish->c_cursor));
-}
-
-int librados::IoCtx::application_enable(const std::string& app_name,
- bool force)
-{
- return io_ctx_impl->application_enable(app_name, force);
-}
-
-int librados::IoCtx::application_enable_async(const std::string& app_name,
- bool force,
- PoolAsyncCompletion *c)
-{
- io_ctx_impl->application_enable_async(app_name, force, c->pc);
- return 0;
-}
-
-int librados::IoCtx::application_list(std::set<std::string> *app_names)
-{
- return io_ctx_impl->application_list(app_names);
-}
-
-int librados::IoCtx::application_metadata_get(const std::string& app_name,
- const std::string &key,
- std::string* value)
-{
- return io_ctx_impl->application_metadata_get(app_name, key, value);
-}
-
-int librados::IoCtx::application_metadata_set(const std::string& app_name,
- const std::string &key,
- const std::string& value)
-{
- return io_ctx_impl->application_metadata_set(app_name, key, value);
-}
-
-int librados::IoCtx::application_metadata_remove(const std::string& app_name,
- const std::string &key)
-{
- return io_ctx_impl->application_metadata_remove(app_name, key);
-}
-
-int librados::IoCtx::application_metadata_list(const std::string& app_name,
- std::map<std::string, std::string> *values)
-{
- return io_ctx_impl->application_metadata_list(app_name, values);
-}
-
-
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <limits.h>
+
+#include "common/config.h"
+#include "common/errno.h"
+#include "common/ceph_argparse.h"
+#include "common/ceph_json.h"
+#include "common/common_init.h"
+#include "common/TracepointProvider.h"
+#include "common/hobject.h"
+#include "include/rados/librados.h"
+#include "include/types.h"
+#include <include/stringify.h>
+
+#include "librados/AioCompletionImpl.h"
+#include "librados/IoCtxImpl.h"
+#include "librados/PoolAsyncCompletionImpl.h"
+#include "librados/RadosClient.h"
+#include "librados/RadosXattrIter.h"
+#include "librados/ListObjectImpl.h"
+#include "librados/librados_util.h"
+#include <cls/lock/cls_lock_client.h>
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <list>
+#include <stdexcept>
+
+#ifdef WITH_LTTNG
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#include "tracing/librados.h"
+#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#undef TRACEPOINT_DEFINE
+#else
+#define tracepoint(...)
+#endif
+
+using std::string;
+using std::map;
+using std::set;
+using std::vector;
+using std::list;
+using std::runtime_error;
+
+#define dout_subsys ceph_subsys_rados
+#undef dout_prefix
+#define dout_prefix *_dout << "librados: "
+
+#define RADOS_LIST_MAX_ENTRIES 1024
+
+static TracepointProvider::Traits tracepoint_traits("librados_tp.so", "rados_tracing");
+
+/*
+ * Structure of this file
+ *
+ * RadosClient and the related classes are the internal implementation of librados.
+ * Above that layer sits the C API, found in include/rados/librados.h, and
+ * the C++ API, found in include/rados/librados.hpp
+ *
+ * The C++ API sometimes implements things in terms of the C API.
+ * Both the C++ and C API rely on RadosClient.
+ *
+ * Visually:
+ * +--------------------------------------+
+ * | C++ API |
+ * +--------------------+ |
+ * | C API | |
+ * +--------------------+-----------------+
+ * | RadosClient |
+ * +--------------------------------------+
+ */
+
+///////////////////////////// C API //////////////////////////////
+
+static CephContext *rados_create_cct(const char * const clustername,
+ CephInitParameters *iparams)
+{
+ // missing things compared to global_init:
+ // g_ceph_context, g_conf, g_lockdep, signal handlers
+ CephContext *cct = common_preinit(*iparams, CODE_ENVIRONMENT_LIBRARY, 0);
+ if (clustername)
+ cct->_conf->cluster = clustername;
+ cct->_conf.parse_env(); // environment variables override
+ cct->_conf.apply_changes(nullptr);
+
+ TracepointProvider::initialize<tracepoint_traits>(cct);
+ return cct;
+}
+
+extern "C" int rados_create(rados_t *pcluster, const char * const id)
+{
+ CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
+ if (id) {
+ iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id);
+ }
+ CephContext *cct = rados_create_cct("", &iparams);
+
+ tracepoint(librados, rados_create_enter, id);
+ *pcluster = reinterpret_cast<rados_t>(new librados::RadosClient(cct));
+ tracepoint(librados, rados_create_exit, 0, *pcluster);
+
+ cct->put();
+ return 0;
+}
+
+// as above, but
+// 1) don't assume 'client.'; name is a full type.id namestr
+// 2) allow setting clustername
+// 3) flags is for future expansion (maybe some of the global_init()
+// behavior is appropriate for some consumers of librados, for instance)
+
+extern "C" int rados_create2(rados_t *pcluster, const char *const clustername,
+ const char * const name, uint64_t flags)
+{
+ // client is assumed, but from_str will override
+ int retval = 0;
+ CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
+ if (!name || !iparams.name.from_str(name)) {
+ retval = -EINVAL;
+ }
+
+ CephContext *cct = rados_create_cct(clustername, &iparams);
+ tracepoint(librados, rados_create2_enter, clustername, name, flags);
+ if (retval == 0) {
+ *pcluster = reinterpret_cast<rados_t>(new librados::RadosClient(cct));
+ }
+ tracepoint(librados, rados_create2_exit, retval, *pcluster);
+
+ cct->put();
+ return retval;
+}
+
+/* This function is intended for use by Ceph daemons. These daemons have
+ * already called global_init and want to use that particular configuration for
+ * their cluster.
+ */
+extern "C" int rados_create_with_context(rados_t *pcluster, rados_config_t cct_)
+{
+ CephContext *cct = (CephContext *)cct_;
+ TracepointProvider::initialize<tracepoint_traits>(cct);
+
+ tracepoint(librados, rados_create_with_context_enter, cct_);
+ librados::RadosClient *radosp = new librados::RadosClient(cct);
+ *pcluster = (void *)radosp;
+ tracepoint(librados, rados_create_with_context_exit, 0, *pcluster);
+ return 0;
+}
+
+extern "C" rados_config_t rados_cct(rados_t cluster)
+{
+ tracepoint(librados, rados_cct_enter, cluster);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ rados_config_t retval = (rados_config_t)client->cct;
+ tracepoint(librados, rados_cct_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_connect(rados_t cluster)
+{
+ tracepoint(librados, rados_connect_enter, cluster);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ int retval = client->connect();
+ tracepoint(librados, rados_connect_exit, retval);
+ return retval;
+}
+
+extern "C" void rados_shutdown(rados_t cluster)
+{
+ tracepoint(librados, rados_shutdown_enter, cluster);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ radosp->shutdown();
+ delete radosp;
+ tracepoint(librados, rados_shutdown_exit);
+}
+
+extern "C" uint64_t rados_get_instance_id(rados_t cluster)
+{
+ tracepoint(librados, rados_get_instance_id_enter, cluster);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ uint64_t retval = client->get_instance_id();
+ tracepoint(librados, rados_get_instance_id_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_get_min_compatible_osd(rados_t cluster,
+ int8_t* require_osd_release)
+{
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ return client->get_min_compatible_osd(require_osd_release);
+}
+
+extern "C" int rados_get_min_compatible_client(rados_t cluster,
+ int8_t* min_compat_client,
+ int8_t* require_min_compat_client)
+{
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ return client->get_min_compatible_client(min_compat_client,
+ require_min_compat_client);
+}
+
+extern "C" void rados_version(int *major, int *minor, int *extra)
+{
+ tracepoint(librados, rados_version_enter, major, minor, extra);
+ if (major)
+ *major = LIBRADOS_VER_MAJOR;
+ if (minor)
+ *minor = LIBRADOS_VER_MINOR;
+ if (extra)
+ *extra = LIBRADOS_VER_EXTRA;
+ tracepoint(librados, rados_version_exit, LIBRADOS_VER_MAJOR, LIBRADOS_VER_MINOR, LIBRADOS_VER_EXTRA);
+}
+
+
+// -- config --
+extern "C" int rados_conf_read_file(rados_t cluster, const char *path_list)
+{
+ tracepoint(librados, rados_conf_read_file_enter, cluster, path_list);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ auto& conf = client->cct->_conf;
+ ostringstream warnings;
+ int ret = conf.parse_config_files(path_list, &warnings, 0);
+ if (ret) {
+ if (warnings.tellp() > 0)
+ lderr(client->cct) << warnings.str() << dendl;
+ client->cct->_conf.complain_about_parse_errors(client->cct);
+ tracepoint(librados, rados_conf_read_file_exit, ret);
+ return ret;
+ }
+ conf.parse_env(); // environment variables override
+
+ conf.apply_changes(nullptr);
+ client->cct->_conf.complain_about_parse_errors(client->cct);
+ tracepoint(librados, rados_conf_read_file_exit, 0);
+ return 0;
+}
+
+extern "C" int rados_conf_parse_argv(rados_t cluster, int argc, const char **argv)
+{
+ tracepoint(librados, rados_conf_parse_argv_enter, cluster, argc);
+ int i;
+ for(i = 0; i < argc; i++) {
+ tracepoint(librados, rados_conf_parse_argv_arg, argv[i]);
+ }
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ auto& conf = client->cct->_conf;
+ vector<const char*> args;
+ argv_to_vec(argc, argv, args);
+ int ret = conf.parse_argv(args);
+ if (ret) {
+ tracepoint(librados, rados_conf_parse_argv_exit, ret);
+ return ret;
+ }
+ conf.apply_changes(nullptr);
+ tracepoint(librados, rados_conf_parse_argv_exit, 0);
+ return 0;
+}
+
+// like above, but return the remainder of argv to contain remaining
+// unparsed args. Must be allocated to at least argc by caller.
+// remargv will contain n <= argc pointers to original argv[], the end
+// of which may be NULL
+
+extern "C" int rados_conf_parse_argv_remainder(rados_t cluster, int argc,
+ const char **argv,
+ const char **remargv)
+{
+ tracepoint(librados, rados_conf_parse_argv_remainder_enter, cluster, argc);
+ unsigned int i;
+ for(i = 0; i < (unsigned int) argc; i++) {
+ tracepoint(librados, rados_conf_parse_argv_remainder_arg, argv[i]);
+ }
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ auto& conf = client->cct->_conf;
+ vector<const char*> args;
+ for (int i=0; i<argc; i++)
+ args.push_back(argv[i]);
+ int ret = conf.parse_argv(args);
+ if (ret) {
+ tracepoint(librados, rados_conf_parse_argv_remainder_exit, ret);
+ return ret;
+ }
+ conf.apply_changes(NULL);
+ ceph_assert(args.size() <= (unsigned int)argc);
+ for (i = 0; i < (unsigned int)argc; ++i) {
+ if (i < args.size())
+ remargv[i] = args[i];
+ else
+ remargv[i] = (const char *)NULL;
+ tracepoint(librados, rados_conf_parse_argv_remainder_remarg, remargv[i]);
+ }
+ tracepoint(librados, rados_conf_parse_argv_remainder_exit, 0);
+ return 0;
+}
+
+extern "C" int rados_conf_parse_env(rados_t cluster, const char *env)
+{
+ tracepoint(librados, rados_conf_parse_env_enter, cluster, env);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ auto& conf = client->cct->_conf;
+ conf.parse_env(env);
+ conf.apply_changes(nullptr);
+ tracepoint(librados, rados_conf_parse_env_exit, 0);
+ return 0;
+}
+
+extern "C" int rados_conf_set(rados_t cluster, const char *option, const char *value)
+{
+ tracepoint(librados, rados_conf_set_enter, cluster, option, value);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ auto& conf = client->cct->_conf;
+ int ret = conf.set_val(option, value);
+ if (ret) {
+ tracepoint(librados, rados_conf_set_exit, ret);
+ return ret;
+ }
+ conf.apply_changes(nullptr);
+ tracepoint(librados, rados_conf_set_exit, 0);
+ return 0;
+}
+
+/* cluster info */
+extern "C" int rados_cluster_stat(rados_t cluster, rados_cluster_stat_t *result)
+{
+ tracepoint(librados, rados_cluster_stat_enter, cluster);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+
+ ceph_statfs stats;
+ int r = client->get_fs_stats(stats);
+ result->kb = stats.kb;
+ result->kb_used = stats.kb_used;
+ result->kb_avail = stats.kb_avail;
+ result->num_objects = stats.num_objects;
+ tracepoint(librados, rados_cluster_stat_exit, r, result->kb, result->kb_used, result->kb_avail, result->num_objects);
+ return r;
+}
+
+extern "C" int rados_conf_get(rados_t cluster, const char *option, char *buf, size_t len)
+{
+ tracepoint(librados, rados_conf_get_enter, cluster, option, len);
+ char *tmp = buf;
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ const auto& conf = client->cct->_conf;
+ int retval = conf.get_val(option, &tmp, len);
+ tracepoint(librados, rados_conf_get_exit, retval, retval ? "" : option);
+ return retval;
+}
+
+extern "C" int64_t rados_pool_lookup(rados_t cluster, const char *name)
+{
+ tracepoint(librados, rados_pool_lookup_enter, cluster, name);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ int64_t retval = radosp->lookup_pool(name);
+ tracepoint(librados, rados_pool_lookup_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_pool_reverse_lookup(rados_t cluster, int64_t id,
+ char *buf, size_t maxlen)
+{
+ tracepoint(librados, rados_pool_reverse_lookup_enter, cluster, id, maxlen);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ std::string name;
+ int r = radosp->pool_get_name(id, &name);
+ if (r < 0) {
+ tracepoint(librados, rados_pool_reverse_lookup_exit, r, "");
+ return r;
+ }
+ if (name.length() >= maxlen) {
+ tracepoint(librados, rados_pool_reverse_lookup_exit, -ERANGE, "");
+ return -ERANGE;
+ }
+ strcpy(buf, name.c_str());
+ int retval = name.length();
+ tracepoint(librados, rados_pool_reverse_lookup_exit, retval, buf);
+ return retval;
+}
+
+extern "C" int rados_cluster_fsid(rados_t cluster, char *buf,
+ size_t maxlen)
+{
+ tracepoint(librados, rados_cluster_fsid_enter, cluster, maxlen);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ std::string fsid;
+ radosp->get_fsid(&fsid);
+ if (fsid.length() >= maxlen) {
+ tracepoint(librados, rados_cluster_fsid_exit, -ERANGE, "");
+ return -ERANGE;
+ }
+ strcpy(buf, fsid.c_str());
+ int retval = fsid.length();
+ tracepoint(librados, rados_cluster_fsid_exit, retval, buf);
+ return retval;
+}
+
+extern "C" int rados_wait_for_latest_osdmap(rados_t cluster)
+{
+ tracepoint(librados, rados_wait_for_latest_osdmap_enter, cluster);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ int retval = radosp->wait_for_latest_osdmap();
+ tracepoint(librados, rados_wait_for_latest_osdmap_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_blacklist_add(rados_t cluster, char *client_address,
+ uint32_t expire_seconds)
+{
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ return radosp->blacklist_add(client_address, expire_seconds);
+}
+
+extern "C" void rados_set_osdmap_full_try(rados_ioctx_t io)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ ctx->objecter->set_osdmap_full_try();
+}
+
+extern "C" void rados_unset_osdmap_full_try(rados_ioctx_t io)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ ctx->objecter->unset_osdmap_full_try();
+}
+
+extern "C" int rados_application_enable(rados_ioctx_t io, const char *app_name,
+ int force)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ return ctx->application_enable(app_name, force != 0);
+}
+
+extern "C" int rados_application_list(rados_ioctx_t io, char *values,
+ size_t *values_len)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ std::set<std::string> app_names;
+ int r = ctx->application_list(&app_names);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t total_len = 0;
+ for (auto app_name : app_names) {
+ total_len += app_name.size() + 1;
+ }
+
+ if (*values_len < total_len) {
+ *values_len = total_len;
+ return -ERANGE;
+ }
+
+ char *values_p = values;
+ for (auto app_name : app_names) {
+ size_t len = app_name.size() + 1;
+ strncpy(values_p, app_name.c_str(), len);
+ values_p += len;
+ }
+ *values_p = '\0';
+ *values_len = total_len;
+ return 0;
+}
+
+extern "C" int rados_application_metadata_get(rados_ioctx_t io,
+ const char *app_name,
+ const char *key, char *value,
+ size_t *value_len)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ std::string value_str;
+ int r = ctx->application_metadata_get(app_name, key, &value_str);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t len = value_str.size() + 1;
+ if (*value_len < len) {
+ *value_len = len;
+ return -ERANGE;
+ }
+
+ strncpy(value, value_str.c_str(), len);
+ *value_len = len;
+ return 0;
+}
+
+extern "C" int rados_application_metadata_set(rados_ioctx_t io,
+ const char *app_name,
+ const char *key,
+ const char *value)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ return ctx->application_metadata_set(app_name, key, value);
+}
+
+extern "C" int rados_application_metadata_remove(rados_ioctx_t io,
+ const char *app_name,
+ const char *key)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ return ctx->application_metadata_remove(app_name, key);
+}
+
+extern "C" int rados_application_metadata_list(rados_ioctx_t io,
+ const char *app_name,
+ char *keys, size_t *keys_len,
+ char *values, size_t *vals_len)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ std::map<std::string, std::string> metadata;
+ int r = ctx->application_metadata_list(app_name, &metadata);
+ if (r < 0) {
+ return r;
+ }
+
+ size_t total_key_len = 0;
+ size_t total_val_len = 0;
+ for (auto pair : metadata) {
+ total_key_len += pair.first.size() + 1;
+ total_val_len += pair.second.size() + 1;
+ }
+
+ if (*keys_len < total_key_len || *vals_len < total_val_len) {
+ *keys_len = total_key_len;
+ *vals_len = total_val_len;
+ return -ERANGE;
+ }
+
+ char *keys_p = keys;
+ char *vals_p = values;
+ for (auto pair : metadata) {
+ size_t key_len = pair.first.size() + 1;
+ strncpy(keys_p, pair.first.c_str(), key_len);
+ keys_p += key_len;
+
+ size_t val_len = pair.second.size() + 1;
+ strncpy(vals_p, pair.second.c_str(), val_len);
+ vals_p += val_len;
+ }
+ *keys_p = '\0';
+ *keys_len = total_key_len;
+
+ *vals_p = '\0';
+ *vals_len = total_val_len;
+ return 0;
+}
+
+extern "C" int rados_pool_list(rados_t cluster, char *buf, size_t len)
+{
+ tracepoint(librados, rados_pool_list_enter, cluster, len);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ std::list<std::pair<int64_t, std::string> > pools;
+ int r = client->pool_list(pools);
+ if (r < 0) {
+ tracepoint(librados, rados_pool_list_exit, r);
+ return r;
+ }
+
+ if (len > 0 && !buf) {
+ tracepoint(librados, rados_pool_list_exit, -EINVAL);
+ return -EINVAL;
+ }
+
+ char *b = buf;
+ if (b)
+ memset(b, 0, len);
+ int needed = 0;
+ std::list<std::pair<int64_t, std::string> >::const_iterator i = pools.begin();
+ std::list<std::pair<int64_t, std::string> >::const_iterator p_end =
+ pools.end();
+ for (; i != p_end; ++i) {
+ int rl = i->second.length() + 1;
+ if (len < (unsigned)rl)
+ break;
+ const char* pool = i->second.c_str();
+ tracepoint(librados, rados_pool_list_pool, pool);
+ if (b) {
+ strncat(b, pool, rl);
+ b += rl;
+ }
+ needed += rl;
+ len -= rl;
+ }
+ for (; i != p_end; ++i) {
+ int rl = i->second.length() + 1;
+ needed += rl;
+ }
+ int retval = needed + 1;
+ tracepoint(librados, rados_pool_list_exit, retval);
+ return retval;
+}
+
+CEPH_RADOS_API int rados_inconsistent_pg_list(rados_t cluster, int64_t pool_id,
+ char *buf, size_t len)
+{
+ tracepoint(librados, rados_inconsistent_pg_list_enter, cluster, pool_id, len);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ std::vector<std::string> pgs;
+ if (int r = client->get_inconsistent_pgs(pool_id, &pgs); r < 0) {
+ tracepoint(librados, rados_inconsistent_pg_list_exit, r);
+ return r;
+ }
+
+ if (len > 0 && !buf) {
+ tracepoint(librados, rados_inconsistent_pg_list_exit, -EINVAL);
+ return -EINVAL;
+ }
+
+ char *b = buf;
+ if (b)
+ memset(b, 0, len);
+ int needed = 0;
+ for (const auto& s : pgs) {
+ unsigned rl = s.length() + 1;
+ if (b && len >= rl) {
+ tracepoint(librados, rados_inconsistent_pg_list_pg, s.c_str());
+ strncat(b, s.c_str(), rl);
+ b += rl;
+ len -= rl;
+ }
+ needed += rl;
+ }
+ int retval = needed + 1;
+ tracepoint(librados, rados_inconsistent_pg_list_exit, retval);
+ return retval;
+}
+
+
+static void dict_to_map(const char *dict,
+ std::map<std::string, std::string>* dict_map)
+{
+ while (*dict != '\0') {
+ const char* key = dict;
+ dict += strlen(key) + 1;
+ const char* value = dict;
+ dict += strlen(value) + 1;
+ (*dict_map)[key] = value;
+ }
+}
+
+CEPH_RADOS_API int rados_service_register(rados_t cluster, const char *service,
+ const char *daemon,
+ const char *metadata_dict)
+{
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+
+ std::map<std::string, std::string> metadata;
+ dict_to_map(metadata_dict, &metadata);
+
+ return client->service_daemon_register(service, daemon, metadata);
+}
+
+CEPH_RADOS_API int rados_service_update_status(rados_t cluster,
+ const char *status_dict)
+{
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+
+ std::map<std::string, std::string> status;
+ dict_to_map(status_dict, &status);
+
+ return client->service_daemon_update_status(std::move(status));
+}
+
+static void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen)
+{
+ if (outbuf) {
+ if (outbl.length() > 0) {
+ *outbuf = (char *)malloc(outbl.length());
+ memcpy(*outbuf, outbl.c_str(), outbl.length());
+ } else {
+ *outbuf = NULL;
+ }
+ }
+ if (outbuflen)
+ *outbuflen = outbl.length();
+}
+
+static void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen)
+{
+ if (outbuf) {
+ if (outbl.length() > 0) {
+ *outbuf = (char *)malloc(outbl.length());
+ memcpy(*outbuf, outbl.c_str(), outbl.length());
+ } else {
+ *outbuf = NULL;
+ }
+ }
+ if (outbuflen)
+ *outbuflen = outbl.length();
+}
+
+extern "C" int rados_ping_monitor(rados_t cluster, const char *mon_id,
+ char **outstr, size_t *outstrlen)
+{
+ tracepoint(librados, rados_ping_monitor_enter, cluster, mon_id);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ string str;
+
+ if (!mon_id) {
+ tracepoint(librados, rados_ping_monitor_exit, -EINVAL, NULL, NULL);
+ return -EINVAL;
+ }
+
+ int ret = client->ping_monitor(mon_id, &str);
+ if (ret == 0) {
+ do_out_buffer(str, outstr, outstrlen);
+ }
+ tracepoint(librados, rados_ping_monitor_exit, ret, ret < 0 ? NULL : outstr, ret < 0 ? NULL : outstrlen);
+ return ret;
+}
+
+extern "C" int rados_mon_command(rados_t cluster, const char **cmd,
+ size_t cmdlen,
+ const char *inbuf, size_t inbuflen,
+ char **outbuf, size_t *outbuflen,
+ char **outs, size_t *outslen)
+{
+ tracepoint(librados, rados_mon_command_enter, cluster, cmdlen, inbuf, inbuflen);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ bufferlist inbl;
+ bufferlist outbl;
+ string outstring;
+ vector<string> cmdvec;
+
+ for (size_t i = 0; i < cmdlen; i++) {
+ tracepoint(librados, rados_mon_command_cmd, cmd[i]);
+ cmdvec.push_back(cmd[i]);
+ }
+
+ inbl.append(inbuf, inbuflen);
+ int ret = client->mon_command(cmdvec, inbl, &outbl, &outstring);
+
+ do_out_buffer(outbl, outbuf, outbuflen);
+ do_out_buffer(outstring, outs, outslen);
+ tracepoint(librados, rados_mon_command_exit, ret, outbuf, outbuflen, outs, outslen);
+ return ret;
+}
+
+extern "C" int rados_mon_command_target(rados_t cluster, const char *name,
+ const char **cmd,
+ size_t cmdlen,
+ const char *inbuf, size_t inbuflen,
+ char **outbuf, size_t *outbuflen,
+ char **outs, size_t *outslen)
+{
+ tracepoint(librados, rados_mon_command_target_enter, cluster, name, cmdlen, inbuf, inbuflen);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ bufferlist inbl;
+ bufferlist outbl;
+ string outstring;
+ vector<string> cmdvec;
+
+ // is this a numeric id?
+ char *endptr;
+ errno = 0;
+ long rank = strtol(name, &endptr, 10);
+ if ((errno == ERANGE && (rank == LONG_MAX || rank == LONG_MIN)) ||
+ (errno != 0 && rank == 0) ||
+ endptr == name || // no digits
+ *endptr != '\0') { // extra characters
+ rank = -1;
+ }
+
+ for (size_t i = 0; i < cmdlen; i++) {
+ tracepoint(librados, rados_mon_command_target_cmd, cmd[i]);
+ cmdvec.push_back(cmd[i]);
+ }
+
+ inbl.append(inbuf, inbuflen);
+ int ret;
+ if (rank >= 0)
+ ret = client->mon_command(rank, cmdvec, inbl, &outbl, &outstring);
+ else
+ ret = client->mon_command(name, cmdvec, inbl, &outbl, &outstring);
+
+ do_out_buffer(outbl, outbuf, outbuflen);
+ do_out_buffer(outstring, outs, outslen);
+ tracepoint(librados, rados_mon_command_target_exit, ret, outbuf, outbuflen, outs, outslen);
+ return ret;
+}
+
+extern "C" int rados_osd_command(rados_t cluster, int osdid, const char **cmd,
+ size_t cmdlen,
+ const char *inbuf, size_t inbuflen,
+ char **outbuf, size_t *outbuflen,
+ char **outs, size_t *outslen)
+{
+ tracepoint(librados, rados_osd_command_enter, cluster, osdid, cmdlen, inbuf, inbuflen);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ bufferlist inbl;
+ bufferlist outbl;
+ string outstring;
+ vector<string> cmdvec;
+
+ for (size_t i = 0; i < cmdlen; i++) {
+ tracepoint(librados, rados_osd_command_cmd, cmd[i]);
+ cmdvec.push_back(cmd[i]);
+ }
+
+ inbl.append(inbuf, inbuflen);
+ int ret = client->osd_command(osdid, cmdvec, inbl, &outbl, &outstring);
+
+ do_out_buffer(outbl, outbuf, outbuflen);
+ do_out_buffer(outstring, outs, outslen);
+ tracepoint(librados, rados_osd_command_exit, ret, outbuf, outbuflen, outs, outslen);
+ return ret;
+}
+
+extern "C" int rados_mgr_command(rados_t cluster, const char **cmd,
+ size_t cmdlen,
+ const char *inbuf, size_t inbuflen,
+ char **outbuf, size_t *outbuflen,
+ char **outs, size_t *outslen)
+{
+ tracepoint(librados, rados_mgr_command_enter, cluster, cmdlen, inbuf,
+ inbuflen);
+
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ bufferlist inbl;
+ bufferlist outbl;
+ string outstring;
+ vector<string> cmdvec;
+
+ for (size_t i = 0; i < cmdlen; i++) {
+ tracepoint(librados, rados_mgr_command_cmd, cmd[i]);
+ cmdvec.push_back(cmd[i]);
+ }
+
+ inbl.append(inbuf, inbuflen);
+ int ret = client->mgr_command(cmdvec, inbl, &outbl, &outstring);
+
+ do_out_buffer(outbl, outbuf, outbuflen);
+ do_out_buffer(outstring, outs, outslen);
+ tracepoint(librados, rados_mgr_command_exit, ret, outbuf, outbuflen, outs,
+ outslen);
+ return ret;
+}
+
+extern "C" int rados_pg_command(rados_t cluster, const char *pgstr,
+ const char **cmd, size_t cmdlen,
+ const char *inbuf, size_t inbuflen,
+ char **outbuf, size_t *outbuflen,
+ char **outs, size_t *outslen)
+{
+ tracepoint(librados, rados_pg_command_enter, cluster, pgstr, cmdlen, inbuf, inbuflen);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ bufferlist inbl;
+ bufferlist outbl;
+ string outstring;
+ pg_t pgid;
+ vector<string> cmdvec;
+
+ for (size_t i = 0; i < cmdlen; i++) {
+ tracepoint(librados, rados_pg_command_cmd, cmd[i]);
+ cmdvec.push_back(cmd[i]);
+ }
+
+ inbl.append(inbuf, inbuflen);
+ if (!pgid.parse(pgstr))
+ return -EINVAL;
+
+ int ret = client->pg_command(pgid, cmdvec, inbl, &outbl, &outstring);
+
+ do_out_buffer(outbl, outbuf, outbuflen);
+ do_out_buffer(outstring, outs, outslen);
+ tracepoint(librados, rados_pg_command_exit, ret, outbuf, outbuflen, outs, outslen);
+ return ret;
+}
+
+extern "C" void rados_buffer_free(char *buf)
+{
+ tracepoint(librados, rados_buffer_free_enter, buf);
+ if (buf)
+ free(buf);
+ tracepoint(librados, rados_buffer_free_exit);
+}
+
+extern "C" int rados_monitor_log(rados_t cluster, const char *level, rados_log_callback_t cb, void *arg)
+{
+ tracepoint(librados, rados_monitor_log_enter, cluster, level, cb, arg);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ int retval = client->monitor_log(level, cb, nullptr, arg);
+ tracepoint(librados, rados_monitor_log_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_monitor_log2(rados_t cluster, const char *level,
+ rados_log_callback2_t cb, void *arg)
+{
+ tracepoint(librados, rados_monitor_log2_enter, cluster, level, cb, arg);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ int retval = client->monitor_log(level, nullptr, cb, arg);
+ tracepoint(librados, rados_monitor_log2_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_create(rados_t cluster, const char *name, rados_ioctx_t *io)
+{
+ tracepoint(librados, rados_ioctx_create_enter, cluster, name);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ librados::IoCtxImpl *ctx;
+
+ int r = client->create_ioctx(name, &ctx);
+ if (r < 0) {
+ tracepoint(librados, rados_ioctx_create_exit, r, NULL);
+ return r;
+ }
+
+ *io = ctx;
+ ctx->get();
+ tracepoint(librados, rados_ioctx_create_exit, 0, ctx);
+ return 0;
+}
+
+extern "C" int rados_ioctx_create2(rados_t cluster, int64_t pool_id,
+ rados_ioctx_t *io)
+{
+ tracepoint(librados, rados_ioctx_create2_enter, cluster, pool_id);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ librados::IoCtxImpl *ctx;
+
+ int r = client->create_ioctx(pool_id, &ctx);
+ if (r < 0) {
+ tracepoint(librados, rados_ioctx_create2_exit, r, NULL);
+ return r;
+ }
+
+ *io = ctx;
+ ctx->get();
+ tracepoint(librados, rados_ioctx_create2_exit, 0, ctx);
+ return 0;
+}
+
+extern "C" void rados_ioctx_destroy(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_ioctx_destroy_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ ctx->put();
+ tracepoint(librados, rados_ioctx_destroy_exit);
+}
+
+extern "C" int rados_ioctx_pool_stat(rados_ioctx_t io, struct rados_pool_stat_t *stats)
+{
+ tracepoint(librados, rados_ioctx_pool_stat_enter, io);
+ librados::IoCtxImpl *io_ctx_impl = (librados::IoCtxImpl *)io;
+ list<string> ls;
+ std::string pool_name;
+
+ int err = io_ctx_impl->client->pool_get_name(io_ctx_impl->get_id(), &pool_name);
+ if (err) {
+ tracepoint(librados, rados_ioctx_pool_stat_exit, err, stats);
+ return err;
+ }
+ ls.push_back(pool_name);
+
+ map<string, ::pool_stat_t> rawresult;
+ err = io_ctx_impl->client->get_pool_stats(ls, rawresult);
+ if (err) {
+ tracepoint(librados, rados_ioctx_pool_stat_exit, err, stats);
+ return err;
+ }
+
+ ::pool_stat_t& r = rawresult[pool_name];
+ stats->num_kb = shift_round_up(r.stats.sum.num_bytes, 10);
+ stats->num_bytes = r.stats.sum.num_bytes;
+ stats->num_objects = r.stats.sum.num_objects;
+ stats->num_object_clones = r.stats.sum.num_object_clones;
+ stats->num_object_copies = r.stats.sum.num_object_copies;
+ stats->num_objects_missing_on_primary = r.stats.sum.num_objects_missing_on_primary;
+ stats->num_objects_unfound = r.stats.sum.num_objects_unfound;
+ stats->num_objects_degraded =
+ r.stats.sum.num_objects_degraded +
+ r.stats.sum.num_objects_misplaced; // FIXME: this is imprecise
+ stats->num_rd = r.stats.sum.num_rd;
+ stats->num_rd_kb = r.stats.sum.num_rd_kb;
+ stats->num_wr = r.stats.sum.num_wr;
+ stats->num_wr_kb = r.stats.sum.num_wr_kb;
+ tracepoint(librados, rados_ioctx_pool_stat_exit, 0, stats);
+ return 0;
+}
+
+extern "C" rados_config_t rados_ioctx_cct(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_ioctx_cct_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ rados_config_t retval = (rados_config_t)ctx->client->cct;
+ tracepoint(librados, rados_ioctx_cct_exit, retval);
+ return retval;
+}
+
+extern "C" void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t seq)
+{
+ tracepoint(librados, rados_ioctx_snap_set_read_enter, io, seq);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ ctx->set_snap_read((snapid_t)seq);
+ tracepoint(librados, rados_ioctx_snap_set_read_exit);
+}
+
+extern "C" int rados_ioctx_selfmanaged_snap_set_write_ctx(rados_ioctx_t io,
+ rados_snap_t seq, rados_snap_t *snaps, int num_snaps)
+{
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_set_write_ctx_enter, io, seq, snaps, num_snaps);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ vector<snapid_t> snv;
+ snv.resize(num_snaps);
+ for (int i=0; i<num_snaps; i++) {
+ snv[i] = (snapid_t)snaps[i];
+ }
+ int retval = ctx->set_snap_write_context((snapid_t)seq, snv);
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_set_write_ctx_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_write(rados_ioctx_t io, const char *o, const char *buf, size_t len, uint64_t off)
+{
+ tracepoint(librados, rados_write_enter, io, o, buf, len, off);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->write(oid, bl, len, off);
+ tracepoint(librados, rados_write_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_append(rados_ioctx_t io, const char *o, const char *buf, size_t len)
+{
+ tracepoint(librados, rados_append_enter, io, o, buf, len);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->append(oid, bl, len);
+ tracepoint(librados, rados_append_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_write_full(rados_ioctx_t io, const char *o, const char *buf, size_t len)
+{
+ tracepoint(librados, rados_write_full_enter, io, o, buf, len);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->write_full(oid, bl);
+ tracepoint(librados, rados_write_full_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_writesame(rados_ioctx_t io,
+ const char *o,
+ const char *buf,
+ size_t data_len,
+ size_t write_len,
+ uint64_t off)
+{
+ tracepoint(librados, rados_writesame_enter, io, o, buf, data_len, write_len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, data_len);
+ int retval = ctx->writesame(oid, bl, write_len, off);
+ tracepoint(librados, rados_writesame_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_trunc(rados_ioctx_t io, const char *o, uint64_t size)
+{
+ tracepoint(librados, rados_trunc_enter, io, o, size);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->trunc(oid, size);
+ tracepoint(librados, rados_trunc_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_remove(rados_ioctx_t io, const char *o)
+{
+ tracepoint(librados, rados_remove_enter, io, o);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->remove(oid);
+ tracepoint(librados, rados_remove_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_read(rados_ioctx_t io, const char *o, char *buf, size_t len, uint64_t off)
+{
+ tracepoint(librados, rados_read_enter, io, o, buf, len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int ret;
+ object_t oid(o);
+
+ bufferlist bl;
+ bufferptr bp = buffer::create_static(len, buf);
+ bl.push_back(bp);
+
+ ret = ctx->read(oid, bl, len, off);
+ if (ret >= 0) {
+ if (bl.length() > len) {
+ tracepoint(librados, rados_read_exit, -ERANGE, NULL);
+ return -ERANGE;
+ }
+ if (!bl.is_provided_buffer(buf))
+ bl.copy(0, bl.length(), buf);
+ ret = bl.length(); // hrm :/
+ }
+
+ tracepoint(librados, rados_read_exit, ret, buf);
+ return ret;
+}
+
+extern "C" int rados_checksum(rados_ioctx_t io, const char *o,
+ rados_checksum_type_t type,
+ const char *init_value, size_t init_value_len,
+ size_t len, uint64_t off, size_t chunk_size,
+ char *pchecksum, size_t checksum_len)
+{
+ tracepoint(librados, rados_checksum_enter, io, o, type, init_value,
+ init_value_len, len, off, chunk_size);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+
+ bufferlist init_value_bl;
+ init_value_bl.append(init_value, init_value_len);
+
+ bufferlist checksum_bl;
+
+ int retval = ctx->checksum(oid, get_checksum_op_type(type), init_value_bl,
+ len, off, chunk_size, &checksum_bl);
+ if (retval >= 0) {
+ if (checksum_bl.length() > checksum_len) {
+ tracepoint(librados, rados_checksum_exit, -ERANGE, NULL, 0);
+ return -ERANGE;
+ }
+
+ checksum_bl.copy(0, checksum_bl.length(), pchecksum);
+ }
+ tracepoint(librados, rados_checksum_exit, retval, pchecksum, checksum_len);
+ return retval;
+}
+
+extern "C" uint64_t rados_get_last_version(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_get_last_version_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ uint64_t retval = ctx->last_version();
+ tracepoint(librados, rados_get_last_version_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_pool_create(rados_t cluster, const char *name)
+{
+ tracepoint(librados, rados_pool_create_enter, cluster, name);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ string sname(name);
+ int retval = radosp->pool_create(sname);
+ tracepoint(librados, rados_pool_create_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_pool_create_with_auid(rados_t cluster, const char *name,
+ uint64_t auid)
+{
+ tracepoint(librados, rados_pool_create_with_auid_enter, cluster, name, auid);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ string sname(name);
+ int retval = 0;
+ if (auid != CEPH_AUTH_UID_DEFAULT) {
+ retval = -EINVAL;
+ } else {
+ retval = radosp->pool_create(sname);
+ }
+ tracepoint(librados, rados_pool_create_with_auid_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_pool_create_with_crush_rule(rados_t cluster, const char *name,
+ __u8 crush_rule_num)
+{
+ tracepoint(librados, rados_pool_create_with_crush_rule_enter, cluster, name, crush_rule_num);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ string sname(name);
+ int retval = radosp->pool_create(sname, crush_rule_num);
+ tracepoint(librados, rados_pool_create_with_crush_rule_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_pool_create_with_all(rados_t cluster, const char *name,
+ uint64_t auid, __u8 crush_rule_num)
+{
+ tracepoint(librados, rados_pool_create_with_all_enter, cluster, name, auid, crush_rule_num);
+ librados::RadosClient *radosp = (librados::RadosClient *)cluster;
+ string sname(name);
+ int retval = 0;
+ if (auid != CEPH_AUTH_UID_DEFAULT) {
+ retval = -EINVAL;
+ } else {
+ retval = radosp->pool_create(sname, crush_rule_num);
+ }
+ tracepoint(librados, rados_pool_create_with_all_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_pool_get_base_tier(rados_t cluster, int64_t pool_id, int64_t* base_tier)
+{
+ tracepoint(librados, rados_pool_get_base_tier_enter, cluster, pool_id);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ int retval = client->pool_get_base_tier(pool_id, base_tier);
+ tracepoint(librados, rados_pool_get_base_tier_exit, retval, *base_tier);
+ return retval;
+}
+
+extern "C" int rados_pool_delete(rados_t cluster, const char *pool_name)
+{
+ tracepoint(librados, rados_pool_delete_enter, cluster, pool_name);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ int retval = client->pool_delete(pool_name);
+ tracepoint(librados, rados_pool_delete_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid)
+{
+ tracepoint(librados, rados_ioctx_pool_set_auid_enter, io, auid);
+ int retval = -EOPNOTSUPP;
+ tracepoint(librados, rados_ioctx_pool_set_auid_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_pool_get_auid(rados_ioctx_t io, uint64_t *auid)
+{
+ tracepoint(librados, rados_ioctx_pool_get_auid_enter, io);
+ int retval = -EOPNOTSUPP;
+ tracepoint(librados, rados_ioctx_pool_get_auid_exit, retval, *auid);
+ return retval;
+}
+
+extern "C" int rados_ioctx_pool_requires_alignment(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_ioctx_pool_requires_alignment_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->client->pool_requires_alignment(ctx->get_id());
+ tracepoint(librados, rados_ioctx_pool_requires_alignment_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_pool_requires_alignment2(rados_ioctx_t io,
+ int *requires)
+{
+ tracepoint(librados, rados_ioctx_pool_requires_alignment_enter2, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ bool requires_alignment;
+ int retval = ctx->client->pool_requires_alignment2(ctx->get_id(),
+ &requires_alignment);
+ tracepoint(librados, rados_ioctx_pool_requires_alignment_exit2, retval,
+ requires_alignment);
+ if (requires)
+ *requires = requires_alignment;
+ return retval;
+}
+
+extern "C" uint64_t rados_ioctx_pool_required_alignment(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_ioctx_pool_required_alignment_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ uint64_t retval = ctx->client->pool_required_alignment(ctx->get_id());
+ tracepoint(librados, rados_ioctx_pool_required_alignment_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_pool_required_alignment2(rados_ioctx_t io,
+ uint64_t *alignment)
+{
+ tracepoint(librados, rados_ioctx_pool_required_alignment_enter2, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->client->pool_required_alignment2(ctx->get_id(),
+ alignment);
+ tracepoint(librados, rados_ioctx_pool_required_alignment_exit2, retval,
+ *alignment);
+ return retval;
+}
+
+extern "C" void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key)
+{
+ tracepoint(librados, rados_ioctx_locator_set_key_enter, io, key);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ if (key)
+ ctx->oloc.key = key;
+ else
+ ctx->oloc.key = "";
+ tracepoint(librados, rados_ioctx_locator_set_key_exit);
+}
+
+extern "C" void rados_ioctx_set_namespace(rados_ioctx_t io, const char *nspace)
+{
+ tracepoint(librados, rados_ioctx_set_namespace_enter, io, nspace);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ if (nspace)
+ ctx->oloc.nspace = nspace;
+ else
+ ctx->oloc.nspace = "";
+ tracepoint(librados, rados_ioctx_set_namespace_exit);
+}
+
+extern "C" int rados_ioctx_get_namespace(rados_ioctx_t io, char *s,
+ unsigned maxlen)
+{
+ tracepoint(librados, rados_ioctx_get_namespace_enter, io, maxlen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ auto length = ctx->oloc.nspace.length();
+ if (length >= maxlen) {
+ tracepoint(librados, rados_ioctx_get_namespace_exit, -ERANGE, "");
+ return -ERANGE;
+ }
+ strcpy(s, ctx->oloc.nspace.c_str());
+ int retval = (int)length;
+ tracepoint(librados, rados_ioctx_get_namespace_exit, retval, s);
+ return retval;
+}
+
+extern "C" rados_t rados_ioctx_get_cluster(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_ioctx_get_cluster_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ rados_t retval = (rados_t)ctx->client;
+ tracepoint(librados, rados_ioctx_get_cluster_exit, retval);
+ return retval;
+}
+
+extern "C" int64_t rados_ioctx_get_id(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_ioctx_get_id_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int64_t retval = ctx->get_id();
+ tracepoint(librados, rados_ioctx_get_id_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_get_pool_name(rados_ioctx_t io, char *s, unsigned maxlen)
+{
+ tracepoint(librados, rados_ioctx_get_pool_name_enter, io, maxlen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ std::string pool_name;
+
+ int err = ctx->client->pool_get_name(ctx->get_id(), &pool_name);
+ if (err) {
+ tracepoint(librados, rados_ioctx_get_pool_name_exit, err, "");
+ return err;
+ }
+ if (pool_name.length() >= maxlen) {
+ tracepoint(librados, rados_ioctx_get_pool_name_exit, -ERANGE, "");
+ return -ERANGE;
+ }
+ strcpy(s, pool_name.c_str());
+ int retval = pool_name.length();
+ tracepoint(librados, rados_ioctx_get_pool_name_exit, retval, s);
+ return retval;
+}
+
+// snaps
+
+extern "C" int rados_ioctx_snap_create(rados_ioctx_t io, const char *snapname)
+{
+ tracepoint(librados, rados_ioctx_snap_create_enter, io, snapname);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->snap_create(snapname);
+ tracepoint(librados, rados_ioctx_snap_create_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_snap_remove(rados_ioctx_t io, const char *snapname)
+{
+ tracepoint(librados, rados_ioctx_snap_remove_enter, io, snapname);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->snap_remove(snapname);
+ tracepoint(librados, rados_ioctx_snap_remove_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_snap_rollback(rados_ioctx_t io, const char *oid,
+ const char *snapname)
+{
+ tracepoint(librados, rados_ioctx_snap_rollback_enter, io, oid, snapname);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->rollback(oid, snapname);
+ tracepoint(librados, rados_ioctx_snap_rollback_exit, retval);
+ return retval;
+}
+
+// Deprecated name kept for backward compatibility
+extern "C" int rados_rollback(rados_ioctx_t io, const char *oid,
+ const char *snapname)
+{
+ return rados_ioctx_snap_rollback(io, oid, snapname);
+}
+
+extern "C" int rados_ioctx_selfmanaged_snap_create(rados_ioctx_t io,
+ uint64_t *snapid)
+{
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_create_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->selfmanaged_snap_create(snapid);
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_create_exit, retval, *snapid);
+ return retval;
+}
+
+extern "C" void
+rados_aio_ioctx_selfmanaged_snap_create(rados_ioctx_t io,
+ rados_snap_t *snapid,
+ rados_completion_t completion)
+{
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_create_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
+ ctx->aio_selfmanaged_snap_create(snapid, c);
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_create_exit, 0, 0);
+}
+
+extern "C" int rados_ioctx_selfmanaged_snap_remove(rados_ioctx_t io,
+ uint64_t snapid)
+{
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_enter, io, snapid);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->selfmanaged_snap_remove(snapid);
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_exit, retval);
+ return retval;
+}
+
+extern "C" void
+rados_aio_ioctx_selfmanaged_snap_remove(rados_ioctx_t io,
+ rados_snap_t snapid,
+ rados_completion_t completion)
+{
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_enter, io, snapid);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
+ ctx->aio_selfmanaged_snap_remove(snapid, c);
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_remove_exit, 0);
+}
+
+extern "C" int rados_ioctx_selfmanaged_snap_rollback(rados_ioctx_t io,
+ const char *oid,
+ uint64_t snapid)
+{
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_rollback_enter, io, oid, snapid);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->selfmanaged_snap_rollback_object(oid, ctx->snapc, snapid);
+ tracepoint(librados, rados_ioctx_selfmanaged_snap_rollback_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t *snaps,
+ int maxlen)
+{
+ tracepoint(librados, rados_ioctx_snap_list_enter, io, maxlen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ vector<uint64_t> snapvec;
+ int r = ctx->snap_list(&snapvec);
+ if (r < 0) {
+ tracepoint(librados, rados_ioctx_snap_list_exit, r, snaps, 0);
+ return r;
+ }
+ if ((int)snapvec.size() <= maxlen) {
+ for (unsigned i=0; i<snapvec.size(); i++) {
+ snaps[i] = snapvec[i];
+ }
+ int retval = snapvec.size();
+ tracepoint(librados, rados_ioctx_snap_list_exit, retval, snaps, retval);
+ return retval;
+ }
+ int retval = -ERANGE;
+ tracepoint(librados, rados_ioctx_snap_list_exit, retval, snaps, 0);
+ return retval;
+}
+
+extern "C" int rados_ioctx_snap_lookup(rados_ioctx_t io, const char *name,
+ rados_snap_t *id)
+{
+ tracepoint(librados, rados_ioctx_snap_lookup_enter, io, name);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->snap_lookup(name, (uint64_t *)id);
+ tracepoint(librados, rados_ioctx_snap_lookup_exit, retval, *id);
+ return retval;
+}
+
+extern "C" int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id,
+ char *name, int maxlen)
+{
+ tracepoint(librados, rados_ioctx_snap_get_name_enter, io, id, maxlen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ std::string sname;
+ int r = ctx->snap_get_name(id, &sname);
+ if (r < 0) {
+ tracepoint(librados, rados_ioctx_snap_get_name_exit, r, "");
+ return r;
+ }
+ if ((int)sname.length() >= maxlen) {
+ int retval = -ERANGE;
+ tracepoint(librados, rados_ioctx_snap_get_name_exit, retval, "");
+ return retval;
+ }
+ strncpy(name, sname.c_str(), maxlen);
+ tracepoint(librados, rados_ioctx_snap_get_name_exit, 0, name);
+ return 0;
+}
+
+extern "C" int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t *t)
+{
+ tracepoint(librados, rados_ioctx_snap_get_stamp_enter, io, id);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->snap_get_stamp(id, t);
+ tracepoint(librados, rados_ioctx_snap_get_stamp_exit, retval, *t);
+ return retval;
+}
+
+extern "C" int rados_cmpext(rados_ioctx_t io, const char *o,
+ const char *cmp_buf, size_t cmp_len, uint64_t off)
+{
+ tracepoint(librados, rados_cmpext_enter, io, o, cmp_buf, cmp_len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int ret;
+ object_t oid(o);
+
+ bufferlist cmp_bl;
+ cmp_bl.append(cmp_buf, cmp_len);
+
+ ret = ctx->cmpext(oid, off, cmp_bl);
+ tracepoint(librados, rados_cmpext_exit, ret);
+
+ return ret;
+}
+
+extern "C" int rados_getxattr(rados_ioctx_t io, const char *o, const char *name,
+ char *buf, size_t len)
+{
+ tracepoint(librados, rados_getxattr_enter, io, o, name, len);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int ret;
+ object_t oid(o);
+ bufferlist bl;
+ bl.push_back(buffer::create_static(len, buf));
+ ret = ctx->getxattr(oid, name, bl);
+ if (ret >= 0) {
+ if (bl.length() > len) {
+ tracepoint(librados, rados_getxattr_exit, -ERANGE, buf, 0);
+ return -ERANGE;
+ }
+ if (!bl.is_provided_buffer(buf))
+ bl.copy(0, bl.length(), buf);
+ ret = bl.length();
+ }
+
+ tracepoint(librados, rados_getxattr_exit, ret, buf, ret);
+ return ret;
+}
+
+extern "C" int rados_getxattrs(rados_ioctx_t io, const char *oid,
+ rados_xattrs_iter_t *iter)
+{
+ tracepoint(librados, rados_getxattrs_enter, io, oid);
+ librados::RadosXattrsIter *it = new librados::RadosXattrsIter();
+ if (!it) {
+ tracepoint(librados, rados_getxattrs_exit, -ENOMEM, NULL);
+ return -ENOMEM;
+ }
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t obj(oid);
+ int ret = ctx->getxattrs(obj, it->attrset);
+ if (ret) {
+ delete it;
+ tracepoint(librados, rados_getxattrs_exit, ret, NULL);
+ return ret;
+ }
+ it->i = it->attrset.begin();
+
+ *iter = it;
+ tracepoint(librados, rados_getxattrs_exit, 0, *iter);
+ return 0;
+}
+
+extern "C" int rados_getxattrs_next(rados_xattrs_iter_t iter,
+ const char **name, const char **val, size_t *len)
+{
+ tracepoint(librados, rados_getxattrs_next_enter, iter);
+ librados::RadosXattrsIter *it = static_cast<librados::RadosXattrsIter*>(iter);
+ if (it->val) {
+ free(it->val);
+ it->val = NULL;
+ }
+ if (it->i == it->attrset.end()) {
+ *name = NULL;
+ *val = NULL;
+ *len = 0;
+ tracepoint(librados, rados_getxattrs_next_exit, 0, NULL, NULL, 0);
+ return 0;
+ }
+ const std::string &s(it->i->first);
+ *name = s.c_str();
+ bufferlist &bl(it->i->second);
+ size_t bl_len = bl.length();
+ if (!bl_len) {
+ // malloc(0) is not guaranteed to return a valid pointer
+ *val = (char *)NULL;
+ } else {
+ it->val = (char*)malloc(bl_len);
+ if (!it->val) {
+ tracepoint(librados, rados_getxattrs_next_exit, -ENOMEM, *name, NULL, 0);
+ return -ENOMEM;
+ }
+ memcpy(it->val, bl.c_str(), bl_len);
+ *val = it->val;
+ }
+ *len = bl_len;
+ ++it->i;
+ tracepoint(librados, rados_getxattrs_next_exit, 0, *name, *val, *len);
+ return 0;
+}
+
+extern "C" void rados_getxattrs_end(rados_xattrs_iter_t iter)
+{
+ tracepoint(librados, rados_getxattrs_end_enter, iter);
+ librados::RadosXattrsIter *it = static_cast<librados::RadosXattrsIter*>(iter);
+ delete it;
+ tracepoint(librados, rados_getxattrs_end_exit);
+}
+
+extern "C" int rados_setxattr(rados_ioctx_t io, const char *o, const char *name, const char *buf, size_t len)
+{
+ tracepoint(librados, rados_setxattr_enter, io, o, name, buf, len);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->setxattr(oid, name, bl);
+ tracepoint(librados, rados_setxattr_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_rmxattr(rados_ioctx_t io, const char *o, const char *name)
+{
+ tracepoint(librados, rados_rmxattr_enter, io, o, name);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->rmxattr(oid, name);
+ tracepoint(librados, rados_rmxattr_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_stat(rados_ioctx_t io, const char *o, uint64_t *psize, time_t *pmtime)
+{
+ tracepoint(librados, rados_stat_enter, io, o);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->stat(oid, psize, pmtime);
+ tracepoint(librados, rados_stat_exit, retval, psize, pmtime);
+ return retval;
+}
+
+extern "C" int rados_tmap_update(rados_ioctx_t io, const char *o, const char *cmdbuf, size_t cmdbuflen)
+{
+ tracepoint(librados, rados_tmap_update_enter, io, o, cmdbuf, cmdbuflen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist cmdbl;
+ cmdbl.append(cmdbuf, cmdbuflen);
+ int retval = ctx->tmap_update(oid, cmdbl);
+ tracepoint(librados, rados_tmap_update_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_tmap_put(rados_ioctx_t io, const char *o, const char *buf, size_t buflen)
+{
+ tracepoint(librados, rados_tmap_put_enter, io, o, buf, buflen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, buflen);
+ int retval = ctx->tmap_put(oid, bl);
+ tracepoint(librados, rados_tmap_put_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_tmap_get(rados_ioctx_t io, const char *o, char *buf, size_t buflen)
+{
+ tracepoint(librados, rados_tmap_get_enter, io, o, buflen);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ int r = ctx->tmap_get(oid, bl);
+ if (r < 0) {
+ tracepoint(librados, rados_tmap_get_exit, r, buf, 0);
+ return r;
+ }
+ if (bl.length() > buflen) {
+ tracepoint(librados, rados_tmap_get_exit, -ERANGE, buf, 0);
+ return -ERANGE;
+ }
+ bl.copy(0, bl.length(), buf);
+ int retval = bl.length();
+ tracepoint(librados, rados_tmap_get_exit, retval, buf, retval);
+ return retval;
+}
+
+extern "C" int rados_tmap_to_omap(rados_ioctx_t io, const char *o, bool nullok)
+{
+ tracepoint(librados, rados_tmap_to_omap_enter, io, o, nullok);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->tmap_to_omap(oid, nullok);
+ tracepoint(librados, rados_tmap_to_omap_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_exec(rados_ioctx_t io, const char *o, const char *cls, const char *method,
+ const char *inbuf, size_t in_len, char *buf, size_t out_len)
+{
+ tracepoint(librados, rados_exec_enter, io, o, cls, method, inbuf, in_len, out_len);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist inbl, outbl;
+ int ret;
+ inbl.append(inbuf, in_len);
+ ret = ctx->exec(oid, cls, method, inbl, outbl);
+ if (ret >= 0) {
+ if (outbl.length()) {
+ if (outbl.length() > out_len) {
+ tracepoint(librados, rados_exec_exit, -ERANGE, buf, 0);
+ return -ERANGE;
+ }
+ outbl.copy(0, outbl.length(), buf);
+ ret = outbl.length(); // hrm :/
+ }
+ }
+ tracepoint(librados, rados_exec_exit, ret, buf, ret);
+ return ret;
+}
+
+extern "C" rados_object_list_cursor rados_object_list_begin(rados_ioctx_t io)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ hobject_t *result = new hobject_t(ctx->objecter->enumerate_objects_begin());
+ return (rados_object_list_cursor)result;
+}
+
+extern "C" rados_object_list_cursor rados_object_list_end(rados_ioctx_t io)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ hobject_t *result = new hobject_t(ctx->objecter->enumerate_objects_end());
+ return (rados_object_list_cursor)result;
+}
+
+extern "C" int rados_object_list_is_end(
+ rados_ioctx_t io, rados_object_list_cursor cur)
+{
+ hobject_t *hobj = (hobject_t*)cur;
+ return hobj->is_max();
+}
+
+extern "C" void rados_object_list_cursor_free(
+ rados_ioctx_t io, rados_object_list_cursor cur)
+{
+ hobject_t *hobj = (hobject_t*)cur;
+ delete hobj;
+}
+
+extern "C" int rados_object_list_cursor_cmp(
+ rados_ioctx_t io,
+ rados_object_list_cursor lhs_cur,
+ rados_object_list_cursor rhs_cur)
+{
+ hobject_t *lhs = (hobject_t*)lhs_cur;
+ hobject_t *rhs = (hobject_t*)rhs_cur;
+ return cmp(*lhs, *rhs);
+}
+
+extern "C" int rados_object_list(rados_ioctx_t io,
+ const rados_object_list_cursor start,
+ const rados_object_list_cursor finish,
+ const size_t result_item_count,
+ const char *filter_buf,
+ const size_t filter_buf_len,
+ rados_object_list_item *result_items,
+ rados_object_list_cursor *next)
+{
+ ceph_assert(next);
+
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ // Zero out items so that they will be safe to free later
+ memset(result_items, 0, sizeof(rados_object_list_item) * result_item_count);
+
+ std::list<librados::ListObjectImpl> result;
+ hobject_t next_hash;
+
+ bufferlist filter_bl;
+ if (filter_buf != nullptr) {
+ filter_bl.append(filter_buf, filter_buf_len);
+ }
+
+ C_SaferCond cond;
+ ctx->objecter->enumerate_objects(
+ ctx->poolid,
+ ctx->oloc.nspace,
+ *((hobject_t*)start),
+ *((hobject_t*)finish),
+ result_item_count,
+ filter_bl,
+ &result,
+ &next_hash,
+ &cond);
+
+ hobject_t *next_hobj = (hobject_t*)(*next);
+ ceph_assert(next_hobj);
+
+ int r = cond.wait();
+ if (r < 0) {
+ *next_hobj = hobject_t::get_max();
+ return r;
+ }
+
+ ceph_assert(result.size() <= result_item_count); // Don't overflow!
+
+ int k = 0;
+ for (std::list<librados::ListObjectImpl>::iterator i = result.begin();
+ i != result.end(); ++i) {
+ rados_object_list_item &item = result_items[k++];
+ do_out_buffer(i->oid, &item.oid, &item.oid_length);
+ do_out_buffer(i->nspace, &item.nspace, &item.nspace_length);
+ do_out_buffer(i->locator, &item.locator, &item.locator_length);
+ }
+
+ *next_hobj = next_hash;
+
+ return result.size();
+}
+
+extern "C" void rados_object_list_free(
+ const size_t result_size,
+ rados_object_list_item *results)
+{
+ ceph_assert(results);
+
+ for (unsigned int i = 0; i < result_size; ++i) {
+ rados_buffer_free(results[i].oid);
+ rados_buffer_free(results[i].locator);
+ rados_buffer_free(results[i].nspace);
+ }
+}
+
+/* list objects */
+
+extern "C" int rados_nobjects_list_open(rados_ioctx_t io, rados_list_ctx_t *listh)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ tracepoint(librados, rados_nobjects_list_open_enter, io);
+
+ Objecter::NListContext *h = new Objecter::NListContext;
+ h->pool_id = ctx->poolid;
+ h->pool_snap_seq = ctx->snap_seq;
+ h->nspace = ctx->oloc.nspace; // After dropping compatibility need nspace
+ *listh = (void *)new librados::ObjListCtx(ctx, h);
+ tracepoint(librados, rados_nobjects_list_open_exit, 0, *listh);
+ return 0;
+}
+
+extern "C" void rados_nobjects_list_close(rados_list_ctx_t h)
+{
+ tracepoint(librados, rados_nobjects_list_close_enter, h);
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)h;
+ delete lh;
+ tracepoint(librados, rados_nobjects_list_close_exit);
+}
+
+extern "C" uint32_t rados_nobjects_list_seek(rados_list_ctx_t listctx,
+ uint32_t pos)
+{
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
+ tracepoint(librados, rados_nobjects_list_seek_enter, listctx, pos);
+ uint32_t r = lh->ctx->nlist_seek(lh->nlc, pos);
+ tracepoint(librados, rados_nobjects_list_seek_exit, r);
+ return r;
+}
+
+extern "C" uint32_t rados_nobjects_list_seek_cursor(rados_list_ctx_t listctx,
+ rados_object_list_cursor cursor)
+{
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
+
+ tracepoint(librados, rados_nobjects_list_seek_cursor_enter, listctx);
+ uint32_t r = lh->ctx->nlist_seek(lh->nlc, cursor);
+ tracepoint(librados, rados_nobjects_list_seek_cursor_exit, r);
+ return r;
+}
+
+extern "C" int rados_nobjects_list_get_cursor(rados_list_ctx_t listctx,
+ rados_object_list_cursor *cursor)
+{
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
+
+ tracepoint(librados, rados_nobjects_list_get_cursor_enter, listctx);
+ *cursor = lh->ctx->nlist_get_cursor(lh->nlc);
+ tracepoint(librados, rados_nobjects_list_get_cursor_exit, 0);
+ return 0;
+}
+
+extern "C" uint32_t rados_nobjects_list_get_pg_hash_position(
+ rados_list_ctx_t listctx)
+{
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
+ tracepoint(librados, rados_nobjects_list_get_pg_hash_position_enter, listctx);
+ uint32_t retval = lh->nlc->get_pg_hash_position();
+ tracepoint(librados, rados_nobjects_list_get_pg_hash_position_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_nobjects_list_next(rados_list_ctx_t listctx, const char **entry, const char **key, const char **nspace)
+{
+ tracepoint(librados, rados_nobjects_list_next_enter, listctx);
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)listctx;
+ Objecter::NListContext *h = lh->nlc;
+
+ // if the list is non-empty, this method has been called before
+ if (!h->list.empty())
+ // so let's kill the previously-returned object
+ h->list.pop_front();
+
+ if (h->list.empty()) {
+ int ret = lh->ctx->nlist(lh->nlc, RADOS_LIST_MAX_ENTRIES);
+ if (ret < 0) {
+ tracepoint(librados, rados_nobjects_list_next_exit, ret, NULL, NULL, NULL);
+ return ret;
+ }
+ if (h->list.empty()) {
+ tracepoint(librados, rados_nobjects_list_next_exit, -ENOENT, NULL, NULL, NULL);
+ return -ENOENT;
+ }
+ }
+
+ *entry = h->list.front().oid.c_str();
+
+ if (key) {
+ if (h->list.front().locator.size())
+ *key = h->list.front().locator.c_str();
+ else
+ *key = NULL;
+ }
+ if (nspace)
+ *nspace = h->list.front().nspace.c_str();
+ tracepoint(librados, rados_nobjects_list_next_exit, 0, *entry, key, nspace);
+ return 0;
+}
+
+
+/*
+ * removed legacy v2 list objects stubs
+ *
+ * thse return -ENOTSUP where possible.
+ */
+extern "C" int rados_objects_list_open(
+ rados_ioctx_t io,
+ rados_list_ctx_t *ctx)
+{
+ return -ENOTSUP;
+}
+
+extern "C" uint32_t rados_objects_list_get_pg_hash_position(
+ rados_list_ctx_t ctx)
+{
+ return 0;
+}
+
+extern "C" uint32_t rados_objects_list_seek(
+ rados_list_ctx_t ctx,
+ uint32_t pos)
+{
+ return 0;
+}
+
+extern "C" int rados_objects_list_next(
+ rados_list_ctx_t ctx,
+ const char **entry,
+ const char **key)
+{
+ return -ENOTSUP;
+}
+
+extern "C" void rados_objects_list_close(
+ rados_list_ctx_t ctx)
+{
+}
+
+
+// -------------------------
+// aio
+
+extern "C" int rados_aio_create_completion(void *cb_arg,
+ rados_callback_t cb_complete,
+ rados_callback_t cb_safe,
+ rados_completion_t *pc)
+{
+ tracepoint(librados, rados_aio_create_completion_enter, cb_arg, cb_complete, cb_safe);
+ librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
+ if (cb_complete)
+ c->set_complete_callback(cb_arg, cb_complete);
+ if (cb_safe)
+ c->set_safe_callback(cb_arg, cb_safe);
+ *pc = c;
+ tracepoint(librados, rados_aio_create_completion_exit, 0, *pc);
+ return 0;
+}
+
+extern "C" int rados_aio_wait_for_complete(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_wait_for_complete_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->wait_for_complete();
+ tracepoint(librados, rados_aio_wait_for_complete_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_wait_for_safe(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_wait_for_safe_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->wait_for_safe();
+ tracepoint(librados, rados_aio_wait_for_safe_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_is_complete(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_is_complete_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->is_complete();
+ tracepoint(librados, rados_aio_is_complete_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_is_safe(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_is_safe_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->is_safe();
+ tracepoint(librados, rados_aio_is_safe_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_wait_for_complete_and_cb(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_wait_for_complete_and_cb_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->wait_for_complete_and_cb();
+ tracepoint(librados, rados_aio_wait_for_complete_and_cb_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_wait_for_safe_and_cb(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_wait_for_safe_and_cb_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->wait_for_safe_and_cb();
+ tracepoint(librados, rados_aio_wait_for_safe_and_cb_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_is_complete_and_cb(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_is_complete_and_cb_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->is_complete_and_cb();
+ tracepoint(librados, rados_aio_is_complete_and_cb_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_is_safe_and_cb(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_is_safe_and_cb_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->is_safe_and_cb();
+ tracepoint(librados, rados_aio_is_safe_and_cb_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_get_return_value(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_get_return_value_enter, c);
+ int retval = ((librados::AioCompletionImpl*)c)->get_return_value();
+ tracepoint(librados, rados_aio_get_return_value_exit, retval);
+ return retval;
+}
+
+extern "C" uint64_t rados_aio_get_version(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_get_version_enter, c);
+ uint64_t retval = ((librados::AioCompletionImpl*)c)->get_version();
+ tracepoint(librados, rados_aio_get_version_exit, retval);
+ return retval;
+}
+
+extern "C" void rados_aio_release(rados_completion_t c)
+{
+ tracepoint(librados, rados_aio_release_enter, c);
+ ((librados::AioCompletionImpl*)c)->put();
+ tracepoint(librados, rados_aio_release_exit);
+}
+
+extern "C" int rados_aio_read(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ char *buf, size_t len, uint64_t off)
+{
+ tracepoint(librados, rados_aio_read_enter, io, o, completion, len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->aio_read(oid, (librados::AioCompletionImpl*)completion,
+ buf, len, off, ctx->snap_seq);
+ tracepoint(librados, rados_aio_read_exit, retval);
+ return retval;
+}
+
+#ifdef WITH_BLKIN
+extern "C" int rados_aio_read_traced(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ char *buf, size_t len, uint64_t off,
+ struct blkin_trace_info *info)
+{
+ tracepoint(librados, rados_aio_read_enter, io, o, completion, len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->aio_read(oid, (librados::AioCompletionImpl*)completion,
+ buf, len, off, ctx->snap_seq, info);
+ tracepoint(librados, rados_aio_read_exit, retval);
+ return retval;
+}
+#endif
+
+extern "C" int rados_aio_write(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *buf, size_t len, uint64_t off)
+{
+ tracepoint(librados, rados_aio_write_enter, io, o, completion, buf, len, off);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->aio_write(oid, (librados::AioCompletionImpl*)completion,
+ bl, len, off);
+ tracepoint(librados, rados_aio_write_exit, retval);
+ return retval;
+}
+
+#ifdef WITH_BLKIN
+extern "C" int rados_aio_write_traced(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *buf, size_t len, uint64_t off,
+ struct blkin_trace_info *info)
+{
+ tracepoint(librados, rados_aio_write_enter, io, o, completion, buf, len, off);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->aio_write(oid, (librados::AioCompletionImpl*)completion,
+ bl, len, off, info);
+ tracepoint(librados, rados_aio_write_exit, retval);
+ return retval;
+}
+#endif
+
+extern "C" int rados_aio_append(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *buf, size_t len)
+{
+ tracepoint(librados, rados_aio_append_enter, io, o, completion, buf, len);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->aio_append(oid, (librados::AioCompletionImpl*)completion,
+ bl, len);
+ tracepoint(librados, rados_aio_append_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_write_full(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *buf, size_t len)
+{
+ tracepoint(librados, rados_aio_write_full_enter, io, o, completion, buf, len);
+ if (len > UINT_MAX/2)
+ return -E2BIG;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->aio_write_full(oid, (librados::AioCompletionImpl*)completion, bl);
+ tracepoint(librados, rados_aio_write_full_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_writesame(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *buf, size_t data_len,
+ size_t write_len, uint64_t off)
+{
+ tracepoint(librados, rados_aio_writesame_enter, io, o, completion, buf,
+ data_len, write_len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, data_len);
+ int retval = ctx->aio_writesame(o, (librados::AioCompletionImpl*)completion,
+ bl, write_len, off);
+ tracepoint(librados, rados_aio_writesame_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_remove(rados_ioctx_t io, const char *o,
+ rados_completion_t completion)
+{
+ tracepoint(librados, rados_aio_remove_enter, io, o, completion);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->aio_remove(oid, (librados::AioCompletionImpl*)completion);
+ tracepoint(librados, rados_aio_remove_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_flush_async(rados_ioctx_t io,
+ rados_completion_t completion)
+{
+ tracepoint(librados, rados_aio_flush_async_enter, io, completion);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ ctx->flush_aio_writes_async((librados::AioCompletionImpl*)completion);
+ tracepoint(librados, rados_aio_flush_async_exit, 0);
+ return 0;
+}
+
+extern "C" int rados_aio_flush(rados_ioctx_t io)
+{
+ tracepoint(librados, rados_aio_flush_enter, io);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ ctx->flush_aio_writes();
+ tracepoint(librados, rados_aio_flush_exit, 0);
+ return 0;
+}
+
+struct AioGetxattrData {
+ AioGetxattrData(char* buf, rados_completion_t c, size_t l) :
+ user_buf(buf), len(l), user_completion((librados::AioCompletionImpl*)c) {}
+ bufferlist bl;
+ char* user_buf;
+ size_t len;
+ struct librados::C_AioCompleteAndSafe user_completion;
+};
+
+static void rados_aio_getxattr_complete(rados_completion_t c, void *arg) {
+ AioGetxattrData *cdata = reinterpret_cast<AioGetxattrData*>(arg);
+ int rc = rados_aio_get_return_value(c);
+ if (rc >= 0) {
+ if (cdata->bl.length() > cdata->len) {
+ rc = -ERANGE;
+ } else {
+ if (!cdata->bl.is_provided_buffer(cdata->user_buf))
+ cdata->bl.copy(0, cdata->bl.length(), cdata->user_buf);
+ rc = cdata->bl.length();
+ }
+ }
+ cdata->user_completion.finish(rc);
+ delete cdata;
+}
+
+extern "C" int rados_aio_getxattr(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *name, char *buf, size_t len)
+{
+ tracepoint(librados, rados_aio_getxattr_enter, io, o, completion, name, len);
+ // create data object to be passed to async callback
+ AioGetxattrData *cdata = new AioGetxattrData(buf, completion, len);
+ if (!cdata) {
+ tracepoint(librados, rados_aio_getxattr_exit, -ENOMEM, NULL, 0);
+ return -ENOMEM;
+ }
+ cdata->bl.push_back(buffer::create_static(len, buf));
+ // create completion callback
+ librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
+ c->set_complete_callback(cdata, rados_aio_getxattr_complete);
+ // call async getxattr of IoCtx
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int ret = ctx->aio_getxattr(oid, c, name, cdata->bl);
+ tracepoint(librados, rados_aio_getxattr_exit, ret, buf, ret);
+ return ret;
+}
+
+namespace {
+struct AioGetxattrsData {
+ AioGetxattrsData(rados_completion_t c, rados_xattrs_iter_t *_iter) :
+ iter(_iter), user_completion((librados::AioCompletionImpl*)c) {
+ it = new librados::RadosXattrsIter();
+ }
+ ~AioGetxattrsData() {
+ if (it) delete it;
+ }
+ librados::RadosXattrsIter *it;
+ rados_xattrs_iter_t *iter;
+ struct librados::C_AioCompleteAndSafe user_completion;
+};
+}
+
+static void rados_aio_getxattrs_complete(rados_completion_t c, void *arg) {
+ AioGetxattrsData *cdata = reinterpret_cast<AioGetxattrsData*>(arg);
+ int rc = rados_aio_get_return_value(c);
+ if (rc) {
+ cdata->user_completion.finish(rc);
+ } else {
+ cdata->it->i = cdata->it->attrset.begin();
+ *cdata->iter = cdata->it;
+ cdata->it = 0;
+ cdata->user_completion.finish(0);
+ }
+ delete cdata;
+}
+
+extern "C" int rados_aio_getxattrs(rados_ioctx_t io, const char *oid,
+ rados_completion_t completion,
+ rados_xattrs_iter_t *iter)
+{
+ tracepoint(librados, rados_aio_getxattrs_enter, io, oid, completion);
+ // create data object to be passed to async callback
+ AioGetxattrsData *cdata = new AioGetxattrsData(completion, iter);
+ if (!cdata) {
+ tracepoint(librados, rados_getxattrs_exit, -ENOMEM, NULL);
+ return -ENOMEM;
+ }
+ // create completion callback
+ librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
+ c->set_complete_callback(cdata, rados_aio_getxattrs_complete);
+ // call async getxattrs of IoCtx
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t obj(oid);
+ int ret = ctx->aio_getxattrs(obj, c, cdata->it->attrset);
+ tracepoint(librados, rados_aio_getxattrs_exit, ret, cdata->it);
+ return ret;
+}
+
+extern "C" int rados_aio_setxattr(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *name, const char *buf, size_t len)
+{
+ tracepoint(librados, rados_aio_setxattr_enter, io, o, completion, name, buf, len);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ bl.append(buf, len);
+ int retval = ctx->aio_setxattr(oid, (librados::AioCompletionImpl*)completion, name, bl);
+ tracepoint(librados, rados_aio_setxattr_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_rmxattr(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *name)
+{
+ tracepoint(librados, rados_aio_rmxattr_enter, io, o, completion, name);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->aio_rmxattr(oid, (librados::AioCompletionImpl*)completion, name);
+ tracepoint(librados, rados_aio_rmxattr_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_stat(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ uint64_t *psize, time_t *pmtime)
+{
+ tracepoint(librados, rados_aio_stat_enter, io, o, completion);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->aio_stat(oid, (librados::AioCompletionImpl*)completion,
+ psize, pmtime);
+ tracepoint(librados, rados_aio_stat_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_cmpext(rados_ioctx_t io, const char *o,
+ rados_completion_t completion, const char *cmp_buf,
+ size_t cmp_len, uint64_t off)
+{
+ tracepoint(librados, rados_aio_cmpext_enter, io, o, completion, cmp_buf,
+ cmp_len, off);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->aio_cmpext(oid, (librados::AioCompletionImpl*)completion,
+ cmp_buf, cmp_len, off);
+ tracepoint(librados, rados_aio_cmpext_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_cancel(rados_ioctx_t io, rados_completion_t completion)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ return ctx->aio_cancel((librados::AioCompletionImpl*)completion);
+}
+
+extern "C" int rados_aio_exec(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *cls, const char *method,
+ const char *inbuf, size_t in_len,
+ char *buf, size_t out_len)
+{
+ tracepoint(librados, rados_aio_exec_enter, io, o, completion);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist inbl;
+ inbl.append(inbuf, in_len);
+ int retval = ctx->aio_exec(oid, (librados::AioCompletionImpl*)completion,
+ cls, method, inbl, buf, out_len);
+ tracepoint(librados, rados_aio_exec_exit, retval);
+ return retval;
+}
+
+struct C_WatchCB : public librados::WatchCtx {
+ rados_watchcb_t wcb;
+ void *arg;
+ C_WatchCB(rados_watchcb_t _wcb, void *_arg) : wcb(_wcb), arg(_arg) {}
+ void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) override {
+ wcb(opcode, ver, arg);
+ }
+};
+
+extern "C" int rados_watch(rados_ioctx_t io, const char *o, uint64_t ver,
+ uint64_t *handle,
+ rados_watchcb_t watchcb, void *arg)
+{
+ tracepoint(librados, rados_watch_enter, io, o, ver, watchcb, arg);
+ uint64_t *cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ C_WatchCB *wc = new C_WatchCB(watchcb, arg);
+ int retval = ctx->watch(oid, cookie, wc, NULL, true);
+ tracepoint(librados, rados_watch_exit, retval, *handle);
+ return retval;
+}
+
+struct C_WatchCB2 : public librados::WatchCtx2 {
+ rados_watchcb2_t wcb;
+ rados_watcherrcb_t errcb;
+ void *arg;
+ C_WatchCB2(rados_watchcb2_t _wcb,
+ rados_watcherrcb_t _errcb,
+ void *_arg) : wcb(_wcb), errcb(_errcb), arg(_arg) {}
+ void handle_notify(uint64_t notify_id,
+ uint64_t cookie,
+ uint64_t notifier_gid,
+ bufferlist& bl) override {
+ wcb(arg, notify_id, cookie, notifier_gid, bl.c_str(), bl.length());
+ }
+ void handle_error(uint64_t cookie, int err) override {
+ if (errcb)
+ errcb(arg, cookie, err);
+ }
+};
+
+extern "C" int rados_watch2(rados_ioctx_t io, const char *o, uint64_t *handle,
+ rados_watchcb2_t watchcb,
+ rados_watcherrcb_t watcherrcb,
+ void *arg) {
+ return rados_watch3(io, o, handle, watchcb, watcherrcb, 0, arg);
+}
+
+extern "C" int rados_watch3(rados_ioctx_t io, const char *o, uint64_t *handle,
+ rados_watchcb2_t watchcb,
+ rados_watcherrcb_t watcherrcb,
+ uint32_t timeout,
+ void *arg)
+{
+ tracepoint(librados, rados_watch3_enter, io, o, handle, watchcb, timeout, arg);
+ int ret;
+ if (!watchcb || !o || !handle) {
+ ret = -EINVAL;
+ } else {
+ uint64_t *cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ C_WatchCB2 *wc = new C_WatchCB2(watchcb, watcherrcb, arg);
+ ret = ctx->watch(oid, cookie, NULL, wc, timeout, true);
+ }
+ tracepoint(librados, rados_watch3_exit, ret, handle ? *handle : 0);
+ return ret;
+}
+
+extern "C" int rados_aio_watch(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ uint64_t *handle,
+ rados_watchcb2_t watchcb,
+ rados_watcherrcb_t watcherrcb, void *arg) {
+ return rados_aio_watch2(io, o, completion, handle, watchcb, watcherrcb, 0, arg);
+}
+
+extern "C" int rados_aio_watch2(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ uint64_t *handle,
+ rados_watchcb2_t watchcb,
+ rados_watcherrcb_t watcherrcb,
+ uint32_t timeout, void *arg)
+{
+ tracepoint(librados, rados_aio_watch2_enter, io, o, completion, handle, watchcb, timeout, arg);
+ int ret;
+ if (!completion || !watchcb || !o || !handle) {
+ ret = -EINVAL;
+ } else {
+ uint64_t *cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ librados::AioCompletionImpl *c =
+ reinterpret_cast<librados::AioCompletionImpl*>(completion);
+ C_WatchCB2 *wc = new C_WatchCB2(watchcb, watcherrcb, arg);
+ ret = ctx->aio_watch(oid, c, cookie, NULL, wc, timeout, true);
+ }
+ tracepoint(librados, rados_aio_watch2_exit, ret, handle ? *handle : 0);
+ return ret;
+}
+
+
+extern "C" int rados_unwatch(rados_ioctx_t io, const char *o, uint64_t handle)
+{
+ tracepoint(librados, rados_unwatch_enter, io, o, handle);
+ uint64_t cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->unwatch(cookie);
+ tracepoint(librados, rados_unwatch_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_unwatch2(rados_ioctx_t io, uint64_t handle)
+{
+ tracepoint(librados, rados_unwatch2_enter, io, handle);
+ uint64_t cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->unwatch(cookie);
+ tracepoint(librados, rados_unwatch2_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_unwatch(rados_ioctx_t io, uint64_t handle,
+ rados_completion_t completion)
+{
+ tracepoint(librados, rados_aio_unwatch_enter, io, handle, completion);
+ uint64_t cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ librados::AioCompletionImpl *c =
+ reinterpret_cast<librados::AioCompletionImpl*>(completion);
+ int retval = ctx->aio_unwatch(cookie, c);
+ tracepoint(librados, rados_aio_unwatch_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_watch_check(rados_ioctx_t io, uint64_t handle)
+{
+ tracepoint(librados, rados_watch_check_enter, io, handle);
+ uint64_t cookie = handle;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->watch_check(cookie);
+ tracepoint(librados, rados_watch_check_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_notify(rados_ioctx_t io, const char *o,
+ uint64_t ver, const char *buf, int buf_len)
+{
+ tracepoint(librados, rados_notify_enter, io, o, ver, buf, buf_len);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ if (buf) {
+ bufferptr p = buffer::create(buf_len);
+ memcpy(p.c_str(), buf, buf_len);
+ bl.push_back(p);
+ }
+ int retval = ctx->notify(oid, bl, 0, NULL, NULL, NULL);
+ tracepoint(librados, rados_notify_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_notify2(rados_ioctx_t io, const char *o,
+ const char *buf, int buf_len,
+ uint64_t timeout_ms,
+ char **reply_buffer,
+ size_t *reply_buffer_len)
+{
+ tracepoint(librados, rados_notify2_enter, io, o, buf, buf_len, timeout_ms);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ if (buf) {
+ bufferptr p = buffer::create(buf_len);
+ memcpy(p.c_str(), buf, buf_len);
+ bl.push_back(p);
+ }
+ int ret = ctx->notify(oid, bl, timeout_ms, NULL, reply_buffer, reply_buffer_len);
+ tracepoint(librados, rados_notify2_exit, ret);
+ return ret;
+}
+
+extern "C" int rados_aio_notify(rados_ioctx_t io, const char *o,
+ rados_completion_t completion,
+ const char *buf, int buf_len,
+ uint64_t timeout_ms, char **reply_buffer,
+ size_t *reply_buffer_len)
+{
+ tracepoint(librados, rados_aio_notify_enter, io, o, completion, buf, buf_len,
+ timeout_ms);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ if (buf) {
+ bl.push_back(buffer::copy(buf, buf_len));
+ }
+ librados::AioCompletionImpl *c =
+ reinterpret_cast<librados::AioCompletionImpl*>(completion);
+ int ret = ctx->aio_notify(oid, c, bl, timeout_ms, NULL, reply_buffer,
+ reply_buffer_len);
+ tracepoint(librados, rados_aio_notify_exit, ret);
+ return ret;
+}
+
+extern "C" int rados_notify_ack(rados_ioctx_t io, const char *o,
+ uint64_t notify_id, uint64_t handle,
+ const char *buf, int buf_len)
+{
+ tracepoint(librados, rados_notify_ack_enter, io, o, notify_id, handle, buf, buf_len);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ bufferlist bl;
+ if (buf) {
+ bufferptr p = buffer::create(buf_len);
+ memcpy(p.c_str(), buf, buf_len);
+ bl.push_back(p);
+ }
+ ctx->notify_ack(oid, notify_id, handle, bl);
+ tracepoint(librados, rados_notify_ack_exit, 0);
+ return 0;
+}
+
+extern "C" int rados_watch_flush(rados_t cluster)
+{
+ tracepoint(librados, rados_watch_flush_enter, cluster);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ int retval = client->watch_flush();
+ tracepoint(librados, rados_watch_flush_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_watch_flush(rados_t cluster, rados_completion_t completion)
+{
+ tracepoint(librados, rados_aio_watch_flush_enter, cluster, completion);
+ librados::RadosClient *client = (librados::RadosClient *)cluster;
+ librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
+ int retval = client->async_watch_flush(c);
+ tracepoint(librados, rados_aio_watch_flush_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_set_alloc_hint(rados_ioctx_t io, const char *o,
+ uint64_t expected_object_size,
+ uint64_t expected_write_size)
+{
+ tracepoint(librados, rados_set_alloc_hint_enter, io, o, expected_object_size, expected_write_size);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->set_alloc_hint(oid, expected_object_size,
+ expected_write_size, 0);
+ tracepoint(librados, rados_set_alloc_hint_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_set_alloc_hint2(rados_ioctx_t io, const char *o,
+ uint64_t expected_object_size,
+ uint64_t expected_write_size,
+ uint32_t flags)
+{
+ tracepoint(librados, rados_set_alloc_hint2_enter, io, o, expected_object_size, expected_write_size, flags);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->set_alloc_hint(oid, expected_object_size,
+ expected_write_size, flags);
+ tracepoint(librados, rados_set_alloc_hint2_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_lock_exclusive(rados_ioctx_t io, const char * o,
+ const char * name, const char * cookie,
+ const char * desc, struct timeval * duration,
+ uint8_t flags)
+{
+ tracepoint(librados, rados_lock_exclusive_enter, io, o, name, cookie, desc, duration, flags);
+ librados::IoCtx ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, ctx);
+
+ int retval = ctx.lock_exclusive(o, name, cookie, desc, duration, flags);
+ tracepoint(librados, rados_lock_exclusive_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_lock_shared(rados_ioctx_t io, const char * o,
+ const char * name, const char * cookie,
+ const char * tag, const char * desc,
+ struct timeval * duration, uint8_t flags)
+{
+ tracepoint(librados, rados_lock_shared_enter, io, o, name, cookie, tag, desc, duration, flags);
+ librados::IoCtx ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, ctx);
+
+ int retval = ctx.lock_shared(o, name, cookie, tag, desc, duration, flags);
+ tracepoint(librados, rados_lock_shared_exit, retval);
+ return retval;
+}
+extern "C" int rados_unlock(rados_ioctx_t io, const char *o, const char *name,
+ const char *cookie)
+{
+ tracepoint(librados, rados_unlock_enter, io, o, name, cookie);
+ librados::IoCtx ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, ctx);
+
+ int retval = ctx.unlock(o, name, cookie);
+ tracepoint(librados, rados_unlock_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_unlock(rados_ioctx_t io, const char *o, const char *name,
+ const char *cookie, rados_completion_t completion)
+{
+ tracepoint(librados, rados_aio_unlock_enter, io, o, name, cookie, completion);
+ librados::IoCtx ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, ctx);
+ librados::AioCompletionImpl *comp = (librados::AioCompletionImpl*)completion;
+ librados::AioCompletion c(comp);
+ int retval = ctx.aio_unlock(o, name, cookie, &c);
+ tracepoint(librados, rados_aio_unlock_exit, retval);
+ return retval;
+}
+
+extern "C" ssize_t rados_list_lockers(rados_ioctx_t io, const char *o,
+ const char *name, int *exclusive,
+ char *tag, size_t *tag_len,
+ char *clients, size_t *clients_len,
+ char *cookies, size_t *cookies_len,
+ char *addrs, size_t *addrs_len)
+{
+ tracepoint(librados, rados_list_lockers_enter, io, o, name, *tag_len, *clients_len, *cookies_len, *addrs_len);
+ librados::IoCtx ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, ctx);
+ std::string name_str = name;
+ std::string oid = o;
+ std::string tag_str;
+ int tmp_exclusive;
+ std::list<librados::locker_t> lockers;
+ int r = ctx.list_lockers(oid, name_str, &tmp_exclusive, &tag_str, &lockers);
+ if (r < 0) {
+ tracepoint(librados, rados_list_lockers_exit, r, *exclusive, "", *tag_len, *clients_len, *cookies_len, *addrs_len);
+ return r;
+ }
+
+ size_t clients_total = 0;
+ size_t cookies_total = 0;
+ size_t addrs_total = 0;
+ list<librados::locker_t>::const_iterator it;
+ for (it = lockers.begin(); it != lockers.end(); ++it) {
+ clients_total += it->client.length() + 1;
+ cookies_total += it->cookie.length() + 1;
+ addrs_total += it->address.length() + 1;
+ }
+
+ bool too_short = ((clients_total > *clients_len) ||
+ (cookies_total > *cookies_len) ||
+ (addrs_total > *addrs_len) ||
+ (tag_str.length() + 1 > *tag_len));
+ *clients_len = clients_total;
+ *cookies_len = cookies_total;
+ *addrs_len = addrs_total;
+ *tag_len = tag_str.length() + 1;
+ if (too_short) {
+ tracepoint(librados, rados_list_lockers_exit, -ERANGE, *exclusive, "", *tag_len, *clients_len, *cookies_len, *addrs_len);
+ return -ERANGE;
+ }
+
+ strcpy(tag, tag_str.c_str());
+ char *clients_p = clients;
+ char *cookies_p = cookies;
+ char *addrs_p = addrs;
+ for (it = lockers.begin(); it != lockers.end(); ++it) {
+ strcpy(clients_p, it->client.c_str());
+ strcpy(cookies_p, it->cookie.c_str());
+ strcpy(addrs_p, it->address.c_str());
+ tracepoint(librados, rados_list_lockers_locker, clients_p, cookies_p, addrs_p);
+ clients_p += it->client.length() + 1;
+ cookies_p += it->cookie.length() + 1;
+ addrs_p += it->address.length() + 1;
+ }
+ if (tmp_exclusive)
+ *exclusive = 1;
+ else
+ *exclusive = 0;
+
+ int retval = lockers.size();
+ tracepoint(librados, rados_list_lockers_exit, retval, *exclusive, tag, *tag_len, *clients_len, *cookies_len, *addrs_len);
+ return retval;
+}
+
+extern "C" int rados_break_lock(rados_ioctx_t io, const char *o,
+ const char *name, const char *client,
+ const char *cookie)
+{
+ tracepoint(librados, rados_break_lock_enter, io, o, name, client, cookie);
+ librados::IoCtx ctx;
+ librados::IoCtx::from_rados_ioctx_t(io, ctx);
+
+ int retval = ctx.break_lock(o, name, client, cookie);
+ tracepoint(librados, rados_break_lock_exit, retval);
+ return retval;
+}
+
+extern "C" rados_write_op_t rados_create_write_op()
+{
+ tracepoint(librados, rados_create_write_op_enter);
+ rados_write_op_t retval = new (std::nothrow)::ObjectOperation;
+ tracepoint(librados, rados_create_write_op_exit, retval);
+ return retval;
+}
+
+extern "C" void rados_release_write_op(rados_write_op_t write_op)
+{
+ tracepoint(librados, rados_release_write_op_enter, write_op);
+ delete (::ObjectOperation*)write_op;
+ tracepoint(librados, rados_release_write_op_exit);
+}
+
+extern "C" void rados_write_op_set_flags(rados_write_op_t write_op, int flags)
+{
+ tracepoint(librados, rados_write_op_set_flags_enter, write_op, flags);
+ ((::ObjectOperation *)write_op)->set_last_op_flags(get_op_flags(flags));
+ tracepoint(librados, rados_write_op_set_flags_exit);
+}
+
+extern "C" void rados_write_op_assert_version(rados_write_op_t write_op, uint64_t ver)
+{
+ tracepoint(librados, rados_write_op_assert_version_enter, write_op, ver);
+ ((::ObjectOperation *)write_op)->assert_version(ver);
+ tracepoint(librados, rados_write_op_assert_version_exit);
+}
+
+extern "C" void rados_write_op_assert_exists(rados_write_op_t write_op)
+{
+ tracepoint(librados, rados_write_op_assert_exists_enter, write_op);
+ ((::ObjectOperation *)write_op)->stat(NULL, (ceph::real_time *)NULL, NULL);
+ tracepoint(librados, rados_write_op_assert_exists_exit);
+}
+
+extern "C" void rados_write_op_cmpext(rados_write_op_t write_op,
+ const char *cmp_buf,
+ size_t cmp_len,
+ uint64_t off,
+ int *prval)
+{
+ tracepoint(librados, rados_write_op_cmpext_enter, write_op, cmp_buf,
+ cmp_len, off, prval);
+ ((::ObjectOperation *)write_op)->cmpext(off, cmp_len, cmp_buf, prval);
+ tracepoint(librados, rados_write_op_cmpext_exit);
+}
+
+extern "C" void rados_write_op_cmpxattr(rados_write_op_t write_op,
+ const char *name,
+ uint8_t comparison_operator,
+ const char *value,
+ size_t value_len)
+{
+ tracepoint(librados, rados_write_op_cmpxattr_enter, write_op, name, comparison_operator, value, value_len);
+ bufferlist bl;
+ bl.append(value, value_len);
+ ((::ObjectOperation *)write_op)->cmpxattr(name,
+ comparison_operator,
+ CEPH_OSD_CMPXATTR_MODE_STRING,
+ bl);
+ tracepoint(librados, rados_write_op_cmpxattr_exit);
+}
+
+static void rados_c_omap_cmp(ObjectOperation *op,
+ const char *key,
+ uint8_t comparison_operator,
+ const char *val,
+ size_t key_len,
+ size_t val_len,
+ int *prval)
+{
+ bufferlist bl;
+ bl.append(val, val_len);
+ std::map<std::string, pair<bufferlist, int> > assertions;
+ string lkey = string(key, key_len);
+
+ assertions[lkey] = std::make_pair(bl, comparison_operator);
+ op->omap_cmp(assertions, prval);
+}
+
+extern "C" void rados_write_op_omap_cmp(rados_write_op_t write_op,
+ const char *key,
+ uint8_t comparison_operator,
+ const char *val,
+ size_t val_len,
+ int *prval)
+{
+ tracepoint(librados, rados_write_op_omap_cmp_enter, write_op, key, comparison_operator, val, val_len, prval);
+ rados_c_omap_cmp((::ObjectOperation *)write_op, key, comparison_operator,
+ val, strlen(key), val_len, prval);
+ tracepoint(librados, rados_write_op_omap_cmp_exit);
+}
+
+extern "C" void rados_write_op_omap_cmp2(rados_write_op_t write_op,
+ const char *key,
+ uint8_t comparison_operator,
+ const char *val,
+ size_t key_len,
+ size_t val_len,
+ int *prval)
+{
+ tracepoint(librados, rados_write_op_omap_cmp_enter, write_op, key, comparison_operator, val, val_len, prval);
+ rados_c_omap_cmp((::ObjectOperation *)write_op, key, comparison_operator,
+ val, key_len, val_len, prval);
+ tracepoint(librados, rados_write_op_omap_cmp_exit);
+}
+
+extern "C" void rados_write_op_setxattr(rados_write_op_t write_op,
+ const char *name,
+ const char *value,
+ size_t value_len)
+{
+ tracepoint(librados, rados_write_op_setxattr_enter, write_op, name, value, value_len);
+ bufferlist bl;
+ bl.append(value, value_len);
+ ((::ObjectOperation *)write_op)->setxattr(name, bl);
+ tracepoint(librados, rados_write_op_setxattr_exit);
+}
+
+extern "C" void rados_write_op_rmxattr(rados_write_op_t write_op,
+ const char *name)
+{
+ tracepoint(librados, rados_write_op_rmxattr_enter, write_op, name);
+ ((::ObjectOperation *)write_op)->rmxattr(name);
+ tracepoint(librados, rados_write_op_rmxattr_exit);
+}
+
+extern "C" void rados_write_op_create(rados_write_op_t write_op,
+ int exclusive,
+ const char* category) // unused
+{
+ tracepoint(librados, rados_write_op_create_enter, write_op, exclusive);
+ ::ObjectOperation *oo = (::ObjectOperation *) write_op;
+ oo->create(!!exclusive);
+ tracepoint(librados, rados_write_op_create_exit);
+}
+
+extern "C" void rados_write_op_write(rados_write_op_t write_op,
+ const char *buffer,
+ size_t len,
+ uint64_t offset)
+{
+ tracepoint(librados, rados_write_op_write_enter, write_op, buffer, len, offset);
+ bufferlist bl;
+ bl.append(buffer,len);
+ ((::ObjectOperation *)write_op)->write(offset, bl);
+ tracepoint(librados, rados_write_op_write_exit);
+}
+
+extern "C" void rados_write_op_write_full(rados_write_op_t write_op,
+ const char *buffer,
+ size_t len)
+{
+ tracepoint(librados, rados_write_op_write_full_enter, write_op, buffer, len);
+ bufferlist bl;
+ bl.append(buffer,len);
+ ((::ObjectOperation *)write_op)->write_full(bl);
+ tracepoint(librados, rados_write_op_write_full_exit);
+}
+
+extern "C" void rados_write_op_writesame(rados_write_op_t write_op,
+ const char *buffer,
+ size_t data_len,
+ size_t write_len,
+ uint64_t offset)
+{
+ tracepoint(librados, rados_write_op_writesame_enter, write_op, buffer, data_len, write_len, offset);
+ bufferlist bl;
+ bl.append(buffer, data_len);
+ ((::ObjectOperation *)write_op)->writesame(offset, write_len, bl);
+ tracepoint(librados, rados_write_op_writesame_exit);
+}
+
+extern "C" void rados_write_op_append(rados_write_op_t write_op,
+ const char *buffer,
+ size_t len)
+{
+ tracepoint(librados, rados_write_op_append_enter, write_op, buffer, len);
+ bufferlist bl;
+ bl.append(buffer,len);
+ ((::ObjectOperation *)write_op)->append(bl);
+ tracepoint(librados, rados_write_op_append_exit);
+}
+
+extern "C" void rados_write_op_remove(rados_write_op_t write_op)
+{
+ tracepoint(librados, rados_write_op_remove_enter, write_op);
+ ((::ObjectOperation *)write_op)->remove();
+ tracepoint(librados, rados_write_op_remove_exit);
+}
+
+extern "C" void rados_write_op_truncate(rados_write_op_t write_op,
+ uint64_t offset)
+{
+ tracepoint(librados, rados_write_op_truncate_enter, write_op, offset);
+ ((::ObjectOperation *)write_op)->truncate(offset);
+ tracepoint(librados, rados_write_op_truncate_exit);
+}
+
+extern "C" void rados_write_op_zero(rados_write_op_t write_op,
+ uint64_t offset,
+ uint64_t len)
+{
+ tracepoint(librados, rados_write_op_zero_enter, write_op, offset, len);
+ ((::ObjectOperation *)write_op)->zero(offset, len);
+ tracepoint(librados, rados_write_op_zero_exit);
+}
+
+extern "C" void rados_write_op_exec(rados_write_op_t write_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ int *prval)
+{
+ tracepoint(librados, rados_write_op_exec_enter, write_op, cls, method, in_buf, in_len, prval);
+ bufferlist inbl;
+ inbl.append(in_buf, in_len);
+ ((::ObjectOperation *)write_op)->call(cls, method, inbl, NULL, NULL, prval);
+ tracepoint(librados, rados_write_op_exec_exit);
+}
+
+extern "C" void rados_write_op_omap_set(rados_write_op_t write_op,
+ char const* const* keys,
+ char const* const* vals,
+ const size_t *lens,
+ size_t num)
+{
+ tracepoint(librados, rados_write_op_omap_set_enter, write_op, num);
+ std::map<std::string, bufferlist> entries;
+ for (size_t i = 0; i < num; ++i) {
+ tracepoint(librados, rados_write_op_omap_set_entry, keys[i], vals[i], lens[i]);
+ bufferlist bl(lens[i]);
+ bl.append(vals[i], lens[i]);
+ entries[keys[i]] = bl;
+ }
+ ((::ObjectOperation *)write_op)->omap_set(entries);
+ tracepoint(librados, rados_write_op_omap_set_exit);
+}
+
+extern "C" void rados_write_op_omap_set2(rados_write_op_t write_op,
+ char const* const* keys,
+ char const* const* vals,
+ const size_t *key_lens,
+ const size_t *val_lens,
+ size_t num)
+{
+ tracepoint(librados, rados_write_op_omap_set_enter, write_op, num);
+ std::map<std::string, bufferlist> entries;
+ for (size_t i = 0; i < num; ++i) {
+ bufferlist bl(val_lens[i]);
+ bl.append(vals[i], val_lens[i]);
+ string key(keys[i], key_lens[i]);
+ entries[key] = bl;
+ }
+ ((::ObjectOperation *)write_op)->omap_set(entries);
+ tracepoint(librados, rados_write_op_omap_set_exit);
+}
+
+extern "C" void rados_write_op_omap_rm_keys(rados_write_op_t write_op,
+ char const* const* keys,
+ size_t keys_len)
+{
+ tracepoint(librados, rados_write_op_omap_rm_keys_enter, write_op, keys_len);
+ for(size_t i = 0; i < keys_len; i++) {
+ tracepoint(librados, rados_write_op_omap_rm_keys_entry, keys[i]);
+ }
+ std::set<std::string> to_remove(keys, keys + keys_len);
+ ((::ObjectOperation *)write_op)->omap_rm_keys(to_remove);
+ tracepoint(librados, rados_write_op_omap_rm_keys_exit);
+}
+
+extern "C" void rados_write_op_omap_rm_keys2(rados_write_op_t write_op,
+ char const* const* keys,
+ const size_t* key_lens,
+ size_t keys_len)
+{
+ tracepoint(librados, rados_write_op_omap_rm_keys_enter, write_op, keys_len);
+ std::set<std::string> to_remove;
+ for(size_t i = 0; i < keys_len; i++) {
+ to_remove.emplace(keys[i], key_lens[i]);
+ }
+ ((::ObjectOperation *)write_op)->omap_rm_keys(to_remove);
+ tracepoint(librados, rados_write_op_omap_rm_keys_exit);
+}
+
+extern "C" void rados_write_op_omap_clear(rados_write_op_t write_op)
+{
+ tracepoint(librados, rados_write_op_omap_clear_enter, write_op);
+ ((::ObjectOperation *)write_op)->omap_clear();
+ tracepoint(librados, rados_write_op_omap_clear_exit);
+}
+
+extern "C" void rados_write_op_set_alloc_hint(rados_write_op_t write_op,
+ uint64_t expected_object_size,
+ uint64_t expected_write_size)
+{
+ tracepoint(librados, rados_write_op_set_alloc_hint_enter, write_op, expected_object_size, expected_write_size);
+ ((::ObjectOperation *)write_op)->set_alloc_hint(expected_object_size,
+ expected_write_size, 0);
+ tracepoint(librados, rados_write_op_set_alloc_hint_exit);
+}
+
+extern "C" void rados_write_op_set_alloc_hint2(rados_write_op_t write_op,
+ uint64_t expected_object_size,
+ uint64_t expected_write_size,
+ uint32_t flags)
+{
+ tracepoint(librados, rados_write_op_set_alloc_hint2_enter, write_op, expected_object_size, expected_write_size, flags);
+ ((::ObjectOperation *)write_op)->set_alloc_hint(expected_object_size,
+ expected_write_size,
+ flags);
+ tracepoint(librados, rados_write_op_set_alloc_hint2_exit);
+}
+
+extern "C" int rados_write_op_operate(rados_write_op_t write_op,
+ rados_ioctx_t io,
+ const char *oid,
+ time_t *mtime,
+ int flags)
+{
+ tracepoint(librados, rados_write_op_operate_enter, write_op, io, oid, mtime, flags);
+ object_t obj(oid);
+ ::ObjectOperation *oo = (::ObjectOperation *) write_op;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ ceph::real_time *prt = NULL;
+ ceph::real_time rt;
+
+ if (mtime) {
+ rt = ceph::real_clock::from_time_t(*mtime);
+ prt = &rt;
+ }
+
+ int retval = ctx->operate(obj, oo, prt, translate_flags(flags));
+ tracepoint(librados, rados_write_op_operate_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_write_op_operate2(rados_write_op_t write_op,
+ rados_ioctx_t io,
+ const char *oid,
+ struct timespec *ts,
+ int flags)
+{
+ tracepoint(librados, rados_write_op_operate2_enter, write_op, io, oid, ts, flags);
+ object_t obj(oid);
+ ::ObjectOperation *oo = (::ObjectOperation *) write_op;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ ceph::real_time *prt = NULL;
+ ceph::real_time rt;
+
+ if (ts) {
+ rt = ceph::real_clock::from_timespec(*ts);
+ prt = &rt;
+ }
+
+ int retval = ctx->operate(obj, oo, prt, translate_flags(flags));
+ tracepoint(librados, rados_write_op_operate_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_write_op_operate(rados_write_op_t write_op,
+ rados_ioctx_t io,
+ rados_completion_t completion,
+ const char *oid,
+ time_t *mtime,
+ int flags)
+{
+ tracepoint(librados, rados_aio_write_op_operate_enter, write_op, io, completion, oid, mtime, flags);
+ object_t obj(oid);
+ ::ObjectOperation *oo = (::ObjectOperation *) write_op;
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
+ int retval = ctx->aio_operate(obj, oo, c, ctx->snapc, translate_flags(flags));
+ tracepoint(librados, rados_aio_write_op_operate_exit, retval);
+ return retval;
+}
+
+extern "C" rados_read_op_t rados_create_read_op()
+{
+ tracepoint(librados, rados_create_read_op_enter);
+ rados_read_op_t retval = new (std::nothrow)::ObjectOperation;
+ tracepoint(librados, rados_create_read_op_exit, retval);
+ return retval;
+}
+
+extern "C" void rados_release_read_op(rados_read_op_t read_op)
+{
+ tracepoint(librados, rados_release_read_op_enter, read_op);
+ delete (::ObjectOperation *)read_op;
+ tracepoint(librados, rados_release_read_op_exit);
+}
+
+extern "C" void rados_read_op_set_flags(rados_read_op_t read_op, int flags)
+{
+ tracepoint(librados, rados_read_op_set_flags_enter, read_op, flags);
+ ((::ObjectOperation *)read_op)->set_last_op_flags(get_op_flags(flags));
+ tracepoint(librados, rados_read_op_set_flags_exit);
+}
+
+extern "C" void rados_read_op_assert_version(rados_read_op_t read_op, uint64_t ver)
+{
+ tracepoint(librados, rados_read_op_assert_version_enter, read_op, ver);
+ ((::ObjectOperation *)read_op)->assert_version(ver);
+ tracepoint(librados, rados_read_op_assert_version_exit);
+}
+
+extern "C" void rados_read_op_assert_exists(rados_read_op_t read_op)
+{
+ tracepoint(librados, rados_read_op_assert_exists_enter, read_op);
+ ((::ObjectOperation *)read_op)->stat(NULL, (ceph::real_time *)NULL, NULL);
+ tracepoint(librados, rados_read_op_assert_exists_exit);
+}
+
+extern "C" void rados_read_op_cmpext(rados_read_op_t read_op,
+ const char *cmp_buf,
+ size_t cmp_len,
+ uint64_t off,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_cmpext_enter, read_op, cmp_buf,
+ cmp_len, off, prval);
+ ((::ObjectOperation *)read_op)->cmpext(off, cmp_len, cmp_buf, prval);
+ tracepoint(librados, rados_read_op_cmpext_exit);
+}
+
+extern "C" void rados_read_op_cmpxattr(rados_read_op_t read_op,
+ const char *name,
+ uint8_t comparison_operator,
+ const char *value,
+ size_t value_len)
+{
+ tracepoint(librados, rados_read_op_cmpxattr_enter, read_op, name, comparison_operator, value, value_len);
+ bufferlist bl;
+ bl.append(value, value_len);
+ ((::ObjectOperation *)read_op)->cmpxattr(name,
+ comparison_operator,
+ CEPH_OSD_CMPXATTR_MODE_STRING,
+ bl);
+ tracepoint(librados, rados_read_op_cmpxattr_exit);
+}
+
+extern "C" void rados_read_op_omap_cmp(rados_read_op_t read_op,
+ const char *key,
+ uint8_t comparison_operator,
+ const char *val,
+ size_t val_len,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_cmp_enter, read_op, key, comparison_operator, val, val_len, prval);
+ rados_c_omap_cmp((::ObjectOperation *)read_op, key, comparison_operator,
+ val, strlen(key), val_len, prval);
+ tracepoint(librados, rados_read_op_omap_cmp_exit);
+}
+
+extern "C" void rados_read_op_omap_cmp2(rados_read_op_t read_op,
+ const char *key,
+ uint8_t comparison_operator,
+ const char *val,
+ size_t key_len,
+ size_t val_len,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_cmp_enter, read_op, key, comparison_operator, val, val_len, prval);
+ rados_c_omap_cmp((::ObjectOperation *)read_op, key, comparison_operator,
+ val, key_len, val_len, prval);
+ tracepoint(librados, rados_read_op_omap_cmp_exit);
+}
+
+extern "C" void rados_read_op_stat(rados_read_op_t read_op,
+ uint64_t *psize,
+ time_t *pmtime,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_stat_enter, read_op, psize, pmtime, prval);
+ ((::ObjectOperation *)read_op)->stat(psize, pmtime, prval);
+ tracepoint(librados, rados_read_op_stat_exit);
+}
+
+class C_bl_to_buf : public Context {
+ char *out_buf;
+ size_t out_len;
+ size_t *bytes_read;
+ int *prval;
+public:
+ bufferlist out_bl;
+ C_bl_to_buf(char *out_buf,
+ size_t out_len,
+ size_t *bytes_read,
+ int *prval) : out_buf(out_buf), out_len(out_len),
+ bytes_read(bytes_read), prval(prval) {}
+ void finish(int r) override {
+ if (out_bl.length() > out_len) {
+ if (prval)
+ *prval = -ERANGE;
+ if (bytes_read)
+ *bytes_read = 0;
+ return;
+ }
+ if (bytes_read)
+ *bytes_read = out_bl.length();
+ if (out_buf && !out_bl.is_provided_buffer(out_buf))
+ out_bl.copy(0, out_bl.length(), out_buf);
+ }
+};
+
+extern "C" void rados_read_op_read(rados_read_op_t read_op,
+ uint64_t offset,
+ size_t len,
+ char *buf,
+ size_t *bytes_read,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_read_enter, read_op, offset, len, buf, bytes_read, prval);
+ C_bl_to_buf *ctx = new C_bl_to_buf(buf, len, bytes_read, prval);
+ ctx->out_bl.push_back(buffer::create_static(len, buf));
+ ((::ObjectOperation *)read_op)->read(offset, len, &ctx->out_bl, prval, ctx);
+ tracepoint(librados, rados_read_op_read_exit);
+}
+
+extern "C" void rados_read_op_checksum(rados_read_op_t read_op,
+ rados_checksum_type_t type,
+ const char *init_value,
+ size_t init_value_len,
+ uint64_t offset, size_t len,
+ size_t chunk_size, char *pchecksum,
+ size_t checksum_len, int *prval)
+{
+ tracepoint(librados, rados_read_op_checksum_enter, read_op, type, init_value,
+ init_value_len, offset, len, chunk_size);
+ bufferlist init_value_bl;
+ init_value_bl.append(init_value, init_value_len);
+
+ C_bl_to_buf *ctx = nullptr;
+ if (pchecksum != nullptr) {
+ ctx = new C_bl_to_buf(pchecksum, checksum_len, nullptr, prval);
+ }
+ ((::ObjectOperation *)read_op)->checksum(get_checksum_op_type(type),
+ init_value_bl, offset, len,
+ chunk_size,
+ (ctx ? &ctx->out_bl : nullptr),
+ prval, ctx);
+ tracepoint(librados, rados_read_op_checksum_exit);
+}
+
+class C_out_buffer : public Context {
+ char **out_buf;
+ size_t *out_len;
+public:
+ bufferlist out_bl;
+ C_out_buffer(char **out_buf, size_t *out_len) : out_buf(out_buf),
+ out_len(out_len) {}
+ void finish(int r) override {
+ // ignore r since we don't know the meaning of return values
+ // from custom class methods
+ do_out_buffer(out_bl, out_buf, out_len);
+ }
+};
+
+extern "C" void rados_read_op_exec(rados_read_op_t read_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ char **out_buf,
+ size_t *out_len,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_exec_enter, read_op, cls, method, in_buf, in_len, out_buf, out_len, prval);
+ bufferlist inbl;
+ inbl.append(in_buf, in_len);
+ C_out_buffer *ctx = new C_out_buffer(out_buf, out_len);
+ ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
+ prval);
+ tracepoint(librados, rados_read_op_exec_exit);
+}
+
+extern "C" void rados_read_op_exec_user_buf(rados_read_op_t read_op,
+ const char *cls,
+ const char *method,
+ const char *in_buf,
+ size_t in_len,
+ char *out_buf,
+ size_t out_len,
+ size_t *used_len,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_exec_user_buf_enter, read_op, cls, method, in_buf, in_len, out_buf, out_len, used_len, prval);
+ C_bl_to_buf *ctx = new C_bl_to_buf(out_buf, out_len, used_len, prval);
+ bufferlist inbl;
+ inbl.append(in_buf, in_len);
+ ((::ObjectOperation *)read_op)->call(cls, method, inbl, &ctx->out_bl, ctx,
+ prval);
+ tracepoint(librados, rados_read_op_exec_user_buf_exit);
+}
+
+struct RadosOmapIter {
+ std::map<std::string, bufferlist> values;
+ std::map<std::string, bufferlist>::iterator i;
+};
+
+class C_OmapIter : public Context {
+ RadosOmapIter *iter;
+public:
+ explicit C_OmapIter(RadosOmapIter *iter) : iter(iter) {}
+ void finish(int r) override {
+ iter->i = iter->values.begin();
+ }
+};
+
+class C_XattrsIter : public Context {
+ librados::RadosXattrsIter *iter;
+public:
+ explicit C_XattrsIter(librados::RadosXattrsIter *iter) : iter(iter) {}
+ void finish(int r) override {
+ iter->i = iter->attrset.begin();
+ }
+};
+
+extern "C" void rados_read_op_getxattrs(rados_read_op_t read_op,
+ rados_xattrs_iter_t *iter,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_getxattrs_enter, read_op, prval);
+ librados::RadosXattrsIter *xattrs_iter = new librados::RadosXattrsIter;
+ ((::ObjectOperation *)read_op)->getxattrs(&xattrs_iter->attrset, prval);
+ ((::ObjectOperation *)read_op)->add_handler(new C_XattrsIter(xattrs_iter));
+ *iter = xattrs_iter;
+ tracepoint(librados, rados_read_op_getxattrs_exit, *iter);
+}
+
+extern "C" void rados_read_op_omap_get_vals(rados_read_op_t read_op,
+ const char *start_after,
+ const char *filter_prefix,
+ uint64_t max_return,
+ rados_omap_iter_t *iter,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_get_vals_enter, read_op, start_after, filter_prefix, max_return, prval);
+ RadosOmapIter *omap_iter = new RadosOmapIter;
+ const char *start = start_after ? start_after : "";
+ const char *filter = filter_prefix ? filter_prefix : "";
+ ((::ObjectOperation *)read_op)->omap_get_vals(
+ start,
+ filter,
+ max_return,
+ &omap_iter->values,
+ nullptr,
+ prval);
+ ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter));
+ *iter = omap_iter;
+ tracepoint(librados, rados_read_op_omap_get_vals_exit, *iter);
+}
+
+extern "C" void rados_read_op_omap_get_vals2(rados_read_op_t read_op,
+ const char *start_after,
+ const char *filter_prefix,
+ uint64_t max_return,
+ rados_omap_iter_t *iter,
+ unsigned char *pmore,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_get_vals_enter, read_op, start_after, filter_prefix, max_return, prval);
+ RadosOmapIter *omap_iter = new RadosOmapIter;
+ const char *start = start_after ? start_after : "";
+ const char *filter = filter_prefix ? filter_prefix : "";
+ ((::ObjectOperation *)read_op)->omap_get_vals(
+ start,
+ filter,
+ max_return,
+ &omap_iter->values,
+ (bool*)pmore,
+ prval);
+ ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter));
+ *iter = omap_iter;
+ tracepoint(librados, rados_read_op_omap_get_vals_exit, *iter);
+}
+
+struct C_OmapKeysIter : public Context {
+ RadosOmapIter *iter;
+ std::set<std::string> keys;
+ explicit C_OmapKeysIter(RadosOmapIter *iter) : iter(iter) {}
+ void finish(int r) override {
+ // map each key to an empty bl
+ for (std::set<std::string>::const_iterator i = keys.begin();
+ i != keys.end(); ++i) {
+ iter->values[*i];
+ }
+ iter->i = iter->values.begin();
+ }
+};
+
+extern "C" void rados_read_op_omap_get_keys(rados_read_op_t read_op,
+ const char *start_after,
+ uint64_t max_return,
+ rados_omap_iter_t *iter,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_get_keys_enter, read_op, start_after, max_return, prval);
+ RadosOmapIter *omap_iter = new RadosOmapIter;
+ C_OmapKeysIter *ctx = new C_OmapKeysIter(omap_iter);
+ ((::ObjectOperation *)read_op)->omap_get_keys(
+ start_after ? start_after : "",
+ max_return, &ctx->keys, nullptr, prval);
+ ((::ObjectOperation *)read_op)->add_handler(ctx);
+ *iter = omap_iter;
+ tracepoint(librados, rados_read_op_omap_get_keys_exit, *iter);
+}
+
+extern "C" void rados_read_op_omap_get_keys2(rados_read_op_t read_op,
+ const char *start_after,
+ uint64_t max_return,
+ rados_omap_iter_t *iter,
+ unsigned char *pmore,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_get_keys_enter, read_op, start_after, max_return, prval);
+ RadosOmapIter *omap_iter = new RadosOmapIter;
+ C_OmapKeysIter *ctx = new C_OmapKeysIter(omap_iter);
+ ((::ObjectOperation *)read_op)->omap_get_keys(
+ start_after ? start_after : "",
+ max_return, &ctx->keys,
+ (bool*)pmore, prval);
+ ((::ObjectOperation *)read_op)->add_handler(ctx);
+ *iter = omap_iter;
+ tracepoint(librados, rados_read_op_omap_get_keys_exit, *iter);
+}
+
+static void internal_rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op,
+ set<string>& to_get,
+ rados_omap_iter_t *iter,
+ int *prval)
+{
+ RadosOmapIter *omap_iter = new RadosOmapIter;
+ ((::ObjectOperation *)read_op)->omap_get_vals_by_keys(to_get,
+ &omap_iter->values,
+ prval);
+ ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter));
+ *iter = omap_iter;
+}
+
+extern "C" void rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op,
+ char const* const* keys,
+ size_t keys_len,
+ rados_omap_iter_t *iter,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_get_vals_by_keys_enter, read_op, keys, keys_len, iter, prval);
+ std::set<std::string> to_get(keys, keys + keys_len);
+ internal_rados_read_op_omap_get_vals_by_keys(read_op, to_get, iter, prval);
+ tracepoint(librados, rados_read_op_omap_get_vals_by_keys_exit, *iter);
+}
+
+extern "C" void rados_read_op_omap_get_vals_by_keys2(rados_read_op_t read_op,
+ char const* const* keys,
+ size_t num_keys,
+ const size_t* key_lens,
+ rados_omap_iter_t *iter,
+ int *prval)
+{
+ tracepoint(librados, rados_read_op_omap_get_vals_by_keys_enter, read_op, keys, num_keys, iter, prval);
+ std::set<std::string> to_get;
+ for (size_t i = 0; i < num_keys; i++) {
+ to_get.emplace(keys[i], key_lens[i]);
+ }
+ internal_rados_read_op_omap_get_vals_by_keys(read_op, to_get, iter, prval);
+ tracepoint(librados, rados_read_op_omap_get_vals_by_keys_exit, *iter);
+}
+
+extern "C" int rados_omap_get_next(rados_omap_iter_t iter,
+ char **key,
+ char **val,
+ size_t *len)
+{
+ return rados_omap_get_next2(iter, key, val, nullptr, len);
+}
+
+extern "C" int rados_omap_get_next2(rados_omap_iter_t iter,
+ char **key,
+ char **val,
+ size_t *key_len,
+ size_t *val_len)
+{
+ tracepoint(librados, rados_omap_get_next_enter, iter);
+ RadosOmapIter *it = static_cast<RadosOmapIter *>(iter);
+ if (it->i == it->values.end()) {
+ if (key)
+ *key = NULL;
+ if (val)
+ *val = NULL;
+ if (key_len)
+ *key_len = 0;
+ if (val_len)
+ *val_len = 0;
+ tracepoint(librados, rados_omap_get_next_exit, 0, key, val, val_len);
+ return 0;
+ }
+ if (key)
+ *key = (char*)it->i->first.c_str();
+ if (val)
+ *val = it->i->second.c_str();
+ if (key_len)
+ *key_len = it->i->first.length();
+ if (val_len)
+ *val_len = it->i->second.length();
+ ++it->i;
+ tracepoint(librados, rados_omap_get_next_exit, 0, key, val, val_len);
+ return 0;
+}
+
+extern "C" unsigned int rados_omap_iter_size(rados_omap_iter_t iter)
+{
+ RadosOmapIter *it = static_cast<RadosOmapIter *>(iter);
+ return it->values.size();
+}
+
+extern "C" void rados_omap_get_end(rados_omap_iter_t iter)
+{
+ tracepoint(librados, rados_omap_get_end_enter, iter);
+ RadosOmapIter *it = static_cast<RadosOmapIter *>(iter);
+ delete it;
+ tracepoint(librados, rados_omap_get_end_exit);
+}
+
+extern "C" int rados_read_op_operate(rados_read_op_t read_op,
+ rados_ioctx_t io,
+ const char *oid,
+ int flags)
+{
+ tracepoint(librados, rados_read_op_operate_enter, read_op, io, oid, flags);
+ object_t obj(oid);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ int retval = ctx->operate_read(obj, (::ObjectOperation *)read_op, NULL,
+ translate_flags(flags));
+ tracepoint(librados, rados_read_op_operate_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_aio_read_op_operate(rados_read_op_t read_op,
+ rados_ioctx_t io,
+ rados_completion_t completion,
+ const char *oid,
+ int flags)
+{
+ tracepoint(librados, rados_aio_read_op_operate_enter, read_op, io, completion, oid, flags);
+ object_t obj(oid);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ librados::AioCompletionImpl *c = (librados::AioCompletionImpl*)completion;
+ int retval = ctx->aio_operate_read(obj, (::ObjectOperation *)read_op,
+ c, translate_flags(flags), NULL);
+ tracepoint(librados, rados_aio_read_op_operate_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_cache_pin(rados_ioctx_t io, const char *o)
+{
+ tracepoint(librados, rados_cache_pin_enter, io, o);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->cache_pin(oid);
+ tracepoint(librados, rados_cache_pin_exit, retval);
+ return retval;
+}
+
+extern "C" int rados_cache_unpin(rados_ioctx_t io, const char *o)
+{
+ tracepoint(librados, rados_cache_unpin_enter, io, o);
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+ object_t oid(o);
+ int retval = ctx->cache_unpin(oid);
+ tracepoint(librados, rados_cache_unpin_exit, retval);
+ return retval;
+}
+
+CEPH_RADOS_API void rados_object_list_slice(
+ rados_ioctx_t io,
+ const rados_object_list_cursor start,
+ const rados_object_list_cursor finish,
+ const size_t n,
+ const size_t m,
+ rados_object_list_cursor *split_start,
+ rados_object_list_cursor *split_finish)
+{
+ librados::IoCtxImpl *ctx = (librados::IoCtxImpl *)io;
+
+ ceph_assert(split_start);
+ ceph_assert(split_finish);
+ hobject_t *split_start_hobj = (hobject_t*)(*split_start);
+ hobject_t *split_finish_hobj = (hobject_t*)(*split_finish);
+ ceph_assert(split_start_hobj);
+ ceph_assert(split_finish_hobj);
+ hobject_t *start_hobj = (hobject_t*)(start);
+ hobject_t *finish_hobj = (hobject_t*)(finish);
+
+ ctx->object_list_slice(
+ *start_hobj,
+ *finish_hobj,
+ n,
+ m,
+ split_start_hobj,
+ split_finish_hobj);
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2012 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include <limits.h>
+
+#include "common/config.h"
+#include "common/errno.h"
+#include "common/ceph_argparse.h"
+#include "common/ceph_json.h"
+#include "common/common_init.h"
+#include "common/TracepointProvider.h"
+#include "common/hobject.h"
+#include "include/rados/librados.h"
+#include "include/rados/librados.hpp"
+#include "include/types.h"
+#include <include/stringify.h>
+
+#include "librados/AioCompletionImpl.h"
+#include "librados/IoCtxImpl.h"
+#include "librados/PoolAsyncCompletionImpl.h"
+#include "librados/RadosClient.h"
+#include "librados/RadosXattrIter.h"
+#include "librados/ListObjectImpl.h"
+#include "librados/librados_util.h"
+#include "cls/lock/cls_lock_client.h"
+
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <list>
+#include <stdexcept>
+
+#ifdef WITH_LTTNG
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#include "tracing/librados.h"
+#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#undef TRACEPOINT_DEFINE
+#else
+#define tracepoint(...)
+#endif
+
+using std::string;
+using std::map;
+using std::set;
+using std::vector;
+using std::list;
+using std::runtime_error;
+
+#define dout_subsys ceph_subsys_rados
+#undef dout_prefix
+#define dout_prefix *_dout << "librados: "
+
+static TracepointProvider::Traits tracepoint_traits("librados_tp.so", "rados_tracing");
+
+/*
+ * Structure of this file
+ *
+ * RadosClient and the related classes are the internal implementation of librados.
+ * Above that layer sits the C API, found in include/rados/librados.h, and
+ * the C++ API, found in include/rados/librados.hpp
+ *
+ * The C++ API sometimes implements things in terms of the C API.
+ * Both the C++ and C API rely on RadosClient.
+ *
+ * Visually:
+ * +--------------------------------------+
+ * | C++ API |
+ * +--------------------+ |
+ * | C API | |
+ * +--------------------+-----------------+
+ * | RadosClient |
+ * +--------------------------------------+
+ */
+
+namespace librados {
+
+struct ObjectOperationImpl {
+ ::ObjectOperation o;
+ real_time rt;
+ real_time *prt;
+
+ ObjectOperationImpl() : prt(NULL) {}
+};
+
+}
+
+size_t librados::ObjectOperation::size()
+{
+ ::ObjectOperation *o = &impl->o;
+ return o->size();
+}
+
+//deprcated
+void librados::ObjectOperation::set_op_flags(ObjectOperationFlags flags)
+{
+ set_op_flags2((int)flags);
+}
+
+void librados::ObjectOperation::set_op_flags2(int flags)
+{
+ impl->o.set_last_op_flags(get_op_flags(flags));
+}
+
+void librados::ObjectOperation::cmpext(uint64_t off,
+ bufferlist &cmp_bl,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cmpext(off, cmp_bl, prval);
+}
+
+void librados::ObjectOperation::cmpxattr(const char *name, uint8_t op, const bufferlist& v)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cmpxattr(name, op, CEPH_OSD_CMPXATTR_MODE_STRING, v);
+}
+
+void librados::ObjectOperation::cmpxattr(const char *name, uint8_t op, uint64_t v)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist bl;
+ encode(v, bl);
+ o->cmpxattr(name, op, CEPH_OSD_CMPXATTR_MODE_U64, bl);
+}
+
+void librados::ObjectOperation::assert_version(uint64_t ver)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->assert_version(ver);
+}
+
+void librados::ObjectOperation::assert_exists()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->stat(NULL, (ceph::real_time*) NULL, NULL);
+}
+
+void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->call(cls, method, inbl);
+}
+
+void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *outbl, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->call(cls, method, inbl, outbl, NULL, prval);
+}
+
+class ObjectOpCompletionCtx : public Context {
+ librados::ObjectOperationCompletion *completion;
+ bufferlist bl;
+public:
+ explicit ObjectOpCompletionCtx(librados::ObjectOperationCompletion *c) : completion(c) {}
+ void finish(int r) override {
+ completion->handle_completion(r, bl);
+ delete completion;
+ }
+
+ bufferlist *outbl() {
+ return &bl;
+ }
+};
+
+void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl, librados::ObjectOperationCompletion *completion)
+{
+ ::ObjectOperation *o = &impl->o;
+
+ ObjectOpCompletionCtx *ctx = new ObjectOpCompletionCtx(completion);
+
+ o->call(cls, method, inbl, ctx->outbl(), ctx, NULL);
+}
+
+void librados::ObjectReadOperation::stat(uint64_t *psize, time_t *pmtime, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->stat(psize, pmtime, prval);
+}
+
+void librados::ObjectReadOperation::stat2(uint64_t *psize, struct timespec *pts, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->stat(psize, pts, prval);
+}
+
+void librados::ObjectReadOperation::read(size_t off, uint64_t len, bufferlist *pbl, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->read(off, len, pbl, prval, NULL);
+}
+
+void librados::ObjectReadOperation::sparse_read(uint64_t off, uint64_t len,
+ std::map<uint64_t,uint64_t> *m,
+ bufferlist *data_bl, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->sparse_read(off, len, m, data_bl, prval);
+}
+
+void librados::ObjectReadOperation::checksum(rados_checksum_type_t type,
+ const bufferlist &init_value_bl,
+ uint64_t off, size_t len,
+ size_t chunk_size, bufferlist *pbl,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->checksum(get_checksum_op_type(type), init_value_bl, off, len, chunk_size,
+ pbl, prval, nullptr);
+}
+
+void librados::ObjectReadOperation::tmap_get(bufferlist *pbl, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->tmap_get(pbl, prval);
+}
+
+void librados::ObjectReadOperation::getxattr(const char *name, bufferlist *pbl, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->getxattr(name, pbl, prval);
+}
+
+void librados::ObjectReadOperation::omap_get_vals(
+ const std::string &start_after,
+ const std::string &filter_prefix,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_vals(start_after, filter_prefix, max_return, out_vals, nullptr,
+ prval);
+}
+
+void librados::ObjectReadOperation::omap_get_vals2(
+ const std::string &start_after,
+ const std::string &filter_prefix,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals,
+ bool *pmore,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_vals(start_after, filter_prefix, max_return, out_vals, pmore,
+ prval);
+}
+
+void librados::ObjectReadOperation::omap_get_vals(
+ const std::string &start_after,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_vals(start_after, "", max_return, out_vals, nullptr, prval);
+}
+
+void librados::ObjectReadOperation::omap_get_vals2(
+ const std::string &start_after,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals,
+ bool *pmore,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_vals(start_after, "", max_return, out_vals, pmore, prval);
+}
+
+void librados::ObjectReadOperation::omap_get_keys(
+ const std::string &start_after,
+ uint64_t max_return,
+ std::set<std::string> *out_keys,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_keys(start_after, max_return, out_keys, nullptr, prval);
+}
+
+void librados::ObjectReadOperation::omap_get_keys2(
+ const std::string &start_after,
+ uint64_t max_return,
+ std::set<std::string> *out_keys,
+ bool *pmore,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_keys(start_after, max_return, out_keys, pmore, prval);
+}
+
+void librados::ObjectReadOperation::omap_get_header(bufferlist *bl, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_header(bl, prval);
+}
+
+void librados::ObjectReadOperation::omap_get_vals_by_keys(
+ const std::set<std::string> &keys,
+ std::map<std::string, bufferlist> *map,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_get_vals_by_keys(keys, map, prval);
+}
+
+void librados::ObjectOperation::omap_cmp(
+ const std::map<std::string, pair<bufferlist, int> > &assertions,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_cmp(assertions, prval);
+}
+
+void librados::ObjectReadOperation::list_watchers(
+ list<obj_watch_t> *out_watchers,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->list_watchers(out_watchers, prval);
+}
+
+void librados::ObjectReadOperation::list_snaps(
+ snap_set_t *out_snaps,
+ int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->list_snaps(out_snaps, prval);
+}
+
+void librados::ObjectReadOperation::is_dirty(bool *is_dirty, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->is_dirty(is_dirty, prval);
+}
+
+int librados::IoCtx::omap_get_vals(const std::string& oid,
+ const std::string& orig_start_after,
+ const std::string& filter_prefix,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals)
+{
+ bool first = true;
+ string start_after = orig_start_after;
+ bool more = true;
+ while (max_return > 0 && more) {
+ std::map<std::string,bufferlist> out;
+ ObjectReadOperation op;
+ op.omap_get_vals2(start_after, filter_prefix, max_return, &out, &more,
+ nullptr);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (more) {
+ if (out.empty()) {
+ return -EINVAL; // wth
+ }
+ start_after = out.rbegin()->first;
+ }
+ if (out.size() <= max_return) {
+ max_return -= out.size();
+ } else {
+ max_return = 0;
+ }
+ if (first) {
+ out_vals->swap(out);
+ first = false;
+ } else {
+ out_vals->insert(out.begin(), out.end());
+ out.clear();
+ }
+ }
+ return 0;
+}
+
+int librados::IoCtx::omap_get_vals2(
+ const std::string& oid,
+ const std::string& start_after,
+ const std::string& filter_prefix,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals,
+ bool *pmore)
+{
+ ObjectReadOperation op;
+ int r;
+ op.omap_get_vals2(start_after, filter_prefix, max_return, out_vals, pmore, &r);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0)
+ return ret;
+ return r;
+}
+
+void librados::ObjectReadOperation::getxattrs(map<string, bufferlist> *pattrs, int *prval)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->getxattrs(pattrs, prval);
+}
+
+void librados::ObjectWriteOperation::mtime(time_t *pt)
+{
+ if (pt) {
+ impl->rt = ceph::real_clock::from_time_t(*pt);
+ impl->prt = &impl->rt;
+ }
+}
+
+void librados::ObjectWriteOperation::mtime2(struct timespec *pts)
+{
+ if (pts) {
+ impl->rt = ceph::real_clock::from_timespec(*pts);
+ impl->prt = &impl->rt;
+ }
+}
+
+void librados::ObjectWriteOperation::create(bool exclusive)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->create(exclusive);
+}
+
+void librados::ObjectWriteOperation::create(bool exclusive,
+ const std::string& category) // unused
+{
+ ::ObjectOperation *o = &impl->o;
+ o->create(exclusive);
+}
+
+void librados::ObjectWriteOperation::write(uint64_t off, const bufferlist& bl)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist c = bl;
+ o->write(off, c);
+}
+
+void librados::ObjectWriteOperation::write_full(const bufferlist& bl)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist c = bl;
+ o->write_full(c);
+}
+
+void librados::ObjectWriteOperation::writesame(uint64_t off, uint64_t write_len,
+ const bufferlist& bl)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist c = bl;
+ o->writesame(off, write_len, c);
+}
+
+void librados::ObjectWriteOperation::append(const bufferlist& bl)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist c = bl;
+ o->append(c);
+}
+
+void librados::ObjectWriteOperation::remove()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->remove();
+}
+
+void librados::ObjectWriteOperation::truncate(uint64_t off)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->truncate(off);
+}
+
+void librados::ObjectWriteOperation::zero(uint64_t off, uint64_t len)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->zero(off, len);
+}
+
+void librados::ObjectWriteOperation::rmxattr(const char *name)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->rmxattr(name);
+}
+
+void librados::ObjectWriteOperation::setxattr(const char *name, const bufferlist& v)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->setxattr(name, v);
+}
+
+void librados::ObjectWriteOperation::omap_set(
+ const map<string, bufferlist> &map)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_set(map);
+}
+
+void librados::ObjectWriteOperation::omap_set_header(const bufferlist &bl)
+{
+ bufferlist c = bl;
+ ::ObjectOperation *o = &impl->o;
+ o->omap_set_header(c);
+}
+
+void librados::ObjectWriteOperation::omap_clear()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_clear();
+}
+
+void librados::ObjectWriteOperation::omap_rm_keys(
+ const std::set<std::string> &to_rm)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->omap_rm_keys(to_rm);
+}
+
+void librados::ObjectWriteOperation::copy_from(const std::string& src,
+ const IoCtx& src_ioctx,
+ uint64_t src_version)
+{
+ copy_from2(src, src_ioctx, src_version, 0);
+}
+
+void librados::ObjectWriteOperation::copy_from2(const std::string& src,
+ const IoCtx& src_ioctx,
+ uint64_t src_version,
+ uint32_t src_fadvise_flags)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->copy_from(object_t(src), src_ioctx.io_ctx_impl->snap_seq,
+ src_ioctx.io_ctx_impl->oloc, src_version, 0, src_fadvise_flags);
+}
+
+void librados::ObjectWriteOperation::undirty()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->undirty();
+}
+
+void librados::ObjectReadOperation::cache_flush()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cache_flush();
+}
+
+void librados::ObjectReadOperation::cache_try_flush()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cache_try_flush();
+}
+
+void librados::ObjectReadOperation::cache_evict()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cache_evict();
+}
+
+void librados::ObjectWriteOperation::set_redirect(const std::string& tgt_obj,
+ const IoCtx& tgt_ioctx,
+ uint64_t tgt_version,
+ int flag)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->set_redirect(object_t(tgt_obj), tgt_ioctx.io_ctx_impl->snap_seq,
+ tgt_ioctx.io_ctx_impl->oloc, tgt_version, flag);
+}
+
+void librados::ObjectWriteOperation::set_chunk(uint64_t src_offset,
+ uint64_t src_length,
+ const IoCtx& tgt_ioctx,
+ string tgt_oid,
+ uint64_t tgt_offset,
+ int flag)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->set_chunk(src_offset, src_length,
+ tgt_ioctx.io_ctx_impl->oloc, object_t(tgt_oid), tgt_offset, flag);
+}
+
+void librados::ObjectWriteOperation::tier_promote()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->tier_promote();
+}
+
+void librados::ObjectWriteOperation::unset_manifest()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->unset_manifest();
+}
+
+void librados::ObjectWriteOperation::tmap_put(const bufferlist &bl)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist c = bl;
+ o->tmap_put(c);
+}
+
+void librados::ObjectWriteOperation::tmap_update(const bufferlist& cmdbl)
+{
+ ::ObjectOperation *o = &impl->o;
+ bufferlist c = cmdbl;
+ o->tmap_update(c);
+}
+
+void librados::ObjectWriteOperation::selfmanaged_snap_rollback(snap_t snapid)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->rollback(snapid);
+}
+
+// You must specify the snapid not the name normally used with pool snapshots
+void librados::ObjectWriteOperation::snap_rollback(snap_t snapid)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->rollback(snapid);
+}
+
+void librados::ObjectWriteOperation::set_alloc_hint(
+ uint64_t expected_object_size,
+ uint64_t expected_write_size)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->set_alloc_hint(expected_object_size, expected_write_size, 0);
+}
+void librados::ObjectWriteOperation::set_alloc_hint2(
+ uint64_t expected_object_size,
+ uint64_t expected_write_size,
+ uint32_t flags)
+{
+ ::ObjectOperation *o = &impl->o;
+ o->set_alloc_hint(expected_object_size, expected_write_size, flags);
+}
+
+void librados::ObjectWriteOperation::cache_pin()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cache_pin();
+}
+
+void librados::ObjectWriteOperation::cache_unpin()
+{
+ ::ObjectOperation *o = &impl->o;
+ o->cache_unpin();
+}
+
+librados::WatchCtx::
+~WatchCtx()
+{
+}
+
+librados::WatchCtx2::
+~WatchCtx2()
+{
+}
+
+///////////////////////////// NObjectIteratorImpl /////////////////////////////
+librados::NObjectIteratorImpl::NObjectIteratorImpl(ObjListCtx *ctx_)
+ : ctx(ctx_)
+{
+}
+
+librados::NObjectIteratorImpl::~NObjectIteratorImpl()
+{
+ ctx.reset();
+}
+
+librados::NObjectIteratorImpl::NObjectIteratorImpl(const NObjectIteratorImpl &rhs)
+{
+ *this = rhs;
+}
+
+librados::NObjectIteratorImpl& librados::NObjectIteratorImpl::operator=(const librados::NObjectIteratorImpl &rhs)
+{
+ if (&rhs == this)
+ return *this;
+ if (rhs.ctx.get() == NULL) {
+ ctx.reset();
+ return *this;
+ }
+ Objecter::NListContext *list_ctx = new Objecter::NListContext(*rhs.ctx->nlc);
+ ctx.reset(new ObjListCtx(rhs.ctx->ctx, list_ctx));
+ cur_obj = rhs.cur_obj;
+ return *this;
+}
+
+bool librados::NObjectIteratorImpl::operator==(const librados::NObjectIteratorImpl& rhs) const {
+
+ if (ctx.get() == NULL) {
+ if (rhs.ctx.get() == NULL)
+ return true;
+ return rhs.ctx->nlc->at_end();
+ }
+ if (rhs.ctx.get() == NULL) {
+ // Redundant but same as ObjectIterator version
+ if (ctx.get() == NULL)
+ return true;
+ return ctx->nlc->at_end();
+ }
+ return ctx.get() == rhs.ctx.get();
+}
+
+bool librados::NObjectIteratorImpl::operator!=(const librados::NObjectIteratorImpl& rhs) const {
+ return !(*this == rhs);
+}
+
+const librados::ListObject& librados::NObjectIteratorImpl::operator*() const {
+ return cur_obj;
+}
+
+const librados::ListObject* librados::NObjectIteratorImpl::operator->() const {
+ return &cur_obj;
+}
+
+librados::NObjectIteratorImpl& librados::NObjectIteratorImpl::operator++()
+{
+ get_next();
+ return *this;
+}
+
+librados::NObjectIteratorImpl librados::NObjectIteratorImpl::operator++(int)
+{
+ librados::NObjectIteratorImpl ret(*this);
+ get_next();
+ return ret;
+}
+
+uint32_t librados::NObjectIteratorImpl::seek(uint32_t pos)
+{
+ uint32_t r = rados_nobjects_list_seek(ctx.get(), pos);
+ get_next();
+ return r;
+}
+
+uint32_t librados::NObjectIteratorImpl::seek(const ObjectCursor& cursor)
+{
+ uint32_t r = rados_nobjects_list_seek_cursor(ctx.get(), (rados_object_list_cursor)cursor.c_cursor);
+ get_next();
+ return r;
+}
+
+librados::ObjectCursor librados::NObjectIteratorImpl::get_cursor()
+{
+ librados::ObjListCtx *lh = (librados::ObjListCtx *)ctx.get();
+ librados::ObjectCursor oc;
+ oc.set(lh->ctx->nlist_get_cursor(lh->nlc));
+ return oc;
+}
+
+void librados::NObjectIteratorImpl::set_filter(const bufferlist &bl)
+{
+ ceph_assert(ctx);
+ ctx->nlc->filter = bl;
+}
+
+void librados::NObjectIteratorImpl::get_next()
+{
+ const char *entry, *key, *nspace;
+ if (ctx->nlc->at_end())
+ return;
+ int ret = rados_nobjects_list_next(ctx.get(), &entry, &key, &nspace);
+ if (ret == -ENOENT) {
+ return;
+ }
+ else if (ret) {
+ ostringstream oss;
+ oss << "rados returned " << cpp_strerror(ret);
+ throw std::runtime_error(oss.str());
+ }
+
+ if (cur_obj.impl == NULL)
+ cur_obj.impl = new ListObjectImpl();
+ cur_obj.impl->nspace = nspace;
+ cur_obj.impl->oid = entry;
+ cur_obj.impl->locator = key ? key : string();
+}
+
+uint32_t librados::NObjectIteratorImpl::get_pg_hash_position() const
+{
+ return ctx->nlc->get_pg_hash_position();
+}
+
+///////////////////////////// NObjectIterator /////////////////////////////
+librados::NObjectIterator::NObjectIterator(ObjListCtx *ctx_)
+{
+ impl = new NObjectIteratorImpl(ctx_);
+}
+
+librados::NObjectIterator::~NObjectIterator()
+{
+ delete impl;
+}
+
+librados::NObjectIterator::NObjectIterator(const NObjectIterator &rhs)
+{
+ if (rhs.impl == NULL) {
+ impl = NULL;
+ return;
+ }
+ impl = new NObjectIteratorImpl();
+ *impl = *(rhs.impl);
+}
+
+librados::NObjectIterator& librados::NObjectIterator::operator=(const librados::NObjectIterator &rhs)
+{
+ if (rhs.impl == NULL) {
+ delete impl;
+ impl = NULL;
+ return *this;
+ }
+ if (impl == NULL)
+ impl = new NObjectIteratorImpl();
+ *impl = *(rhs.impl);
+ return *this;
+}
+
+bool librados::NObjectIterator::operator==(const librados::NObjectIterator& rhs) const
+{
+ if (impl && rhs.impl) {
+ return *impl == *(rhs.impl);
+ } else {
+ return impl == rhs.impl;
+ }
+}
+
+bool librados::NObjectIterator::operator!=(const librados::NObjectIterator& rhs) const
+{
+ return !(*this == rhs);
+}
+
+const librados::ListObject& librados::NObjectIterator::operator*() const {
+ ceph_assert(impl);
+ return *(impl->get_listobjectp());
+}
+
+const librados::ListObject* librados::NObjectIterator::operator->() const {
+ ceph_assert(impl);
+ return impl->get_listobjectp();
+}
+
+librados::NObjectIterator& librados::NObjectIterator::operator++()
+{
+ ceph_assert(impl);
+ impl->get_next();
+ return *this;
+}
+
+librados::NObjectIterator librados::NObjectIterator::operator++(int)
+{
+ librados::NObjectIterator ret(*this);
+ impl->get_next();
+ return ret;
+}
+
+uint32_t librados::NObjectIterator::seek(uint32_t pos)
+{
+ ceph_assert(impl);
+ return impl->seek(pos);
+}
+
+uint32_t librados::NObjectIterator::seek(const ObjectCursor& cursor)
+{
+ ceph_assert(impl);
+ return impl->seek(cursor);
+}
+
+librados::ObjectCursor librados::NObjectIterator::get_cursor()
+{
+ ceph_assert(impl);
+ return impl->get_cursor();
+}
+
+void librados::NObjectIterator::set_filter(const bufferlist &bl)
+{
+ impl->set_filter(bl);
+}
+
+void librados::NObjectIterator::get_next()
+{
+ ceph_assert(impl);
+ impl->get_next();
+}
+
+uint32_t librados::NObjectIterator::get_pg_hash_position() const
+{
+ ceph_assert(impl);
+ return impl->get_pg_hash_position();
+}
+
+const librados::NObjectIterator librados::NObjectIterator::__EndObjectIterator(NULL);
+
+///////////////////////////// PoolAsyncCompletion //////////////////////////////
+int librados::PoolAsyncCompletion::PoolAsyncCompletion::set_callback(void *cb_arg,
+ rados_callback_t cb)
+{
+ PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
+ return c->set_callback(cb_arg, cb);
+}
+
+int librados::PoolAsyncCompletion::PoolAsyncCompletion::wait()
+{
+ PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
+ return c->wait();
+}
+
+bool librados::PoolAsyncCompletion::PoolAsyncCompletion::is_complete()
+{
+ PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
+ return c->is_complete();
+}
+
+int librados::PoolAsyncCompletion::PoolAsyncCompletion::get_return_value()
+{
+ PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
+ return c->get_return_value();
+}
+
+void librados::PoolAsyncCompletion::PoolAsyncCompletion::release()
+{
+ PoolAsyncCompletionImpl *c = (PoolAsyncCompletionImpl *)pc;
+ c->release();
+ delete this;
+}
+
+///////////////////////////// AioCompletion //////////////////////////////
+int librados::AioCompletion::AioCompletion::set_complete_callback(void *cb_arg, rados_callback_t cb)
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->set_complete_callback(cb_arg, cb);
+}
+
+int librados::AioCompletion::AioCompletion::set_safe_callback(void *cb_arg, rados_callback_t cb)
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->set_safe_callback(cb_arg, cb);
+}
+
+int librados::AioCompletion::AioCompletion::wait_for_complete()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->wait_for_complete();
+}
+
+int librados::AioCompletion::AioCompletion::wait_for_safe()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->wait_for_safe();
+}
+
+bool librados::AioCompletion::AioCompletion::is_complete()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->is_complete();
+}
+
+bool librados::AioCompletion::AioCompletion::is_safe()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->is_safe();
+}
+
+int librados::AioCompletion::AioCompletion::wait_for_complete_and_cb()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->wait_for_complete_and_cb();
+}
+
+int librados::AioCompletion::AioCompletion::wait_for_safe_and_cb()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->wait_for_safe_and_cb();
+}
+
+bool librados::AioCompletion::AioCompletion::is_complete_and_cb()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->is_complete_and_cb();
+}
+
+bool librados::AioCompletion::AioCompletion::is_safe_and_cb()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->is_safe_and_cb();
+}
+
+int librados::AioCompletion::AioCompletion::get_return_value()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->get_return_value();
+}
+
+int librados::AioCompletion::AioCompletion::get_version()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->get_version();
+}
+
+uint64_t librados::AioCompletion::AioCompletion::get_version64()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ return c->get_version();
+}
+
+void librados::AioCompletion::AioCompletion::release()
+{
+ AioCompletionImpl *c = (AioCompletionImpl *)pc;
+ c->release();
+ delete this;
+}
+
+///////////////////////////// IoCtx //////////////////////////////
+librados::IoCtx::IoCtx() : io_ctx_impl(NULL)
+{
+}
+
+void librados::IoCtx::from_rados_ioctx_t(rados_ioctx_t p, IoCtx &io)
+{
+ IoCtxImpl *io_ctx_impl = (IoCtxImpl*)p;
+
+ io.io_ctx_impl = io_ctx_impl;
+ if (io_ctx_impl) {
+ io_ctx_impl->get();
+ }
+}
+
+librados::IoCtx::IoCtx(const IoCtx& rhs)
+{
+ io_ctx_impl = rhs.io_ctx_impl;
+ if (io_ctx_impl) {
+ io_ctx_impl->get();
+ }
+}
+
+librados::IoCtx& librados::IoCtx::operator=(const IoCtx& rhs)
+{
+ if (io_ctx_impl)
+ io_ctx_impl->put();
+ io_ctx_impl = rhs.io_ctx_impl;
+ io_ctx_impl->get();
+ return *this;
+}
+
+librados::IoCtx::~IoCtx()
+{
+ close();
+}
+
+void librados::IoCtx::close()
+{
+ if (io_ctx_impl)
+ io_ctx_impl->put();
+ io_ctx_impl = 0;
+}
+
+void librados::IoCtx::dup(const IoCtx& rhs)
+{
+ if (io_ctx_impl)
+ io_ctx_impl->put();
+ io_ctx_impl = new IoCtxImpl();
+ io_ctx_impl->get();
+ io_ctx_impl->dup(*rhs.io_ctx_impl);
+}
+
+int librados::IoCtx::set_auid(uint64_t auid_)
+{
+ return -EOPNOTSUPP;
+}
+
+int librados::IoCtx::set_auid_async(uint64_t auid_, PoolAsyncCompletion *c)
+{
+ return -EOPNOTSUPP;
+}
+
+int librados::IoCtx::get_auid(uint64_t *auid_)
+{
+ return -EOPNOTSUPP;
+}
+
+bool librados::IoCtx::pool_requires_alignment()
+{
+ return io_ctx_impl->client->pool_requires_alignment(get_id());
+}
+
+int librados::IoCtx::pool_requires_alignment2(bool *requires)
+{
+ return io_ctx_impl->client->pool_requires_alignment2(get_id(), requires);
+}
+
+uint64_t librados::IoCtx::pool_required_alignment()
+{
+ return io_ctx_impl->client->pool_required_alignment(get_id());
+}
+
+int librados::IoCtx::pool_required_alignment2(uint64_t *alignment)
+{
+ return io_ctx_impl->client->pool_required_alignment2(get_id(), alignment);
+}
+
+std::string librados::IoCtx::get_pool_name()
+{
+ std::string s;
+ io_ctx_impl->client->pool_get_name(get_id(), &s);
+ return s;
+}
+
+std::string librados::IoCtx::get_pool_name() const
+{
+ return io_ctx_impl->get_cached_pool_name();
+}
+
+uint64_t librados::IoCtx::get_instance_id() const
+{
+ return io_ctx_impl->client->get_instance_id();
+}
+
+int librados::IoCtx::create(const std::string& oid, bool exclusive)
+{
+ object_t obj(oid);
+ return io_ctx_impl->create(obj, exclusive);
+}
+
+int librados::IoCtx::create(const std::string& oid, bool exclusive,
+ const std::string& category) // unused
+{
+ object_t obj(oid);
+ return io_ctx_impl->create(obj, exclusive);
+}
+
+int librados::IoCtx::write(const std::string& oid, bufferlist& bl, size_t len, uint64_t off)
+{
+ object_t obj(oid);
+ return io_ctx_impl->write(obj, bl, len, off);
+}
+
+int librados::IoCtx::append(const std::string& oid, bufferlist& bl, size_t len)
+{
+ object_t obj(oid);
+ return io_ctx_impl->append(obj, bl, len);
+}
+
+int librados::IoCtx::write_full(const std::string& oid, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->write_full(obj, bl);
+}
+
+int librados::IoCtx::writesame(const std::string& oid, bufferlist& bl,
+ size_t write_len, uint64_t off)
+{
+ object_t obj(oid);
+ return io_ctx_impl->writesame(obj, bl, write_len, off);
+}
+
+
+int librados::IoCtx::read(const std::string& oid, bufferlist& bl, size_t len, uint64_t off)
+{
+ object_t obj(oid);
+ return io_ctx_impl->read(obj, bl, len, off);
+}
+
+int librados::IoCtx::checksum(const std::string& oid,
+ rados_checksum_type_t type,
+ const bufferlist &init_value_bl, size_t len,
+ uint64_t off, size_t chunk_size, bufferlist *pbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->checksum(obj, get_checksum_op_type(type), init_value_bl,
+ len, off, chunk_size, pbl);
+}
+
+int librados::IoCtx::remove(const std::string& oid)
+{
+ object_t obj(oid);
+ return io_ctx_impl->remove(obj);
+}
+
+int librados::IoCtx::remove(const std::string& oid, int flags)
+{
+ object_t obj(oid);
+ return io_ctx_impl->remove(obj, flags);
+}
+
+int librados::IoCtx::trunc(const std::string& oid, uint64_t size)
+{
+ object_t obj(oid);
+ return io_ctx_impl->trunc(obj, size);
+}
+
+int librados::IoCtx::mapext(const std::string& oid, uint64_t off, size_t len,
+ std::map<uint64_t,uint64_t>& m)
+{
+ object_t obj(oid);
+ return io_ctx_impl->mapext(obj, off, len, m);
+}
+
+int librados::IoCtx::cmpext(const std::string& oid, uint64_t off, bufferlist& cmp_bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->cmpext(obj, off, cmp_bl);
+}
+
+int librados::IoCtx::sparse_read(const std::string& oid, std::map<uint64_t,uint64_t>& m,
+ bufferlist& bl, size_t len, uint64_t off)
+{
+ object_t obj(oid);
+ return io_ctx_impl->sparse_read(obj, m, bl, len, off);
+}
+
+int librados::IoCtx::getxattr(const std::string& oid, const char *name, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->getxattr(obj, name, bl);
+}
+
+int librados::IoCtx::getxattrs(const std::string& oid, map<std::string, bufferlist>& attrset)
+{
+ object_t obj(oid);
+ return io_ctx_impl->getxattrs(obj, attrset);
+}
+
+int librados::IoCtx::setxattr(const std::string& oid, const char *name, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->setxattr(obj, name, bl);
+}
+
+int librados::IoCtx::rmxattr(const std::string& oid, const char *name)
+{
+ object_t obj(oid);
+ return io_ctx_impl->rmxattr(obj, name);
+}
+
+int librados::IoCtx::stat(const std::string& oid, uint64_t *psize, time_t *pmtime)
+{
+ object_t obj(oid);
+ return io_ctx_impl->stat(obj, psize, pmtime);
+}
+
+int librados::IoCtx::stat2(const std::string& oid, uint64_t *psize, struct timespec *pts)
+{
+ object_t obj(oid);
+ return io_ctx_impl->stat2(obj, psize, pts);
+}
+
+int librados::IoCtx::exec(const std::string& oid, const char *cls, const char *method,
+ bufferlist& inbl, bufferlist& outbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->exec(obj, cls, method, inbl, outbl);
+}
+
+int librados::IoCtx::tmap_update(const std::string& oid, bufferlist& cmdbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->tmap_update(obj, cmdbl);
+}
+
+int librados::IoCtx::tmap_put(const std::string& oid, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->tmap_put(obj, bl);
+}
+
+int librados::IoCtx::tmap_get(const std::string& oid, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->tmap_get(obj, bl);
+}
+
+int librados::IoCtx::tmap_to_omap(const std::string& oid, bool nullok)
+{
+ object_t obj(oid);
+ return io_ctx_impl->tmap_to_omap(obj, nullok);
+}
+
+int librados::IoCtx::omap_get_vals(const std::string& oid,
+ const std::string& start_after,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals)
+{
+ return omap_get_vals(oid, start_after, string(), max_return, out_vals);
+}
+
+int librados::IoCtx::omap_get_vals2(
+ const std::string& oid,
+ const std::string& start_after,
+ uint64_t max_return,
+ std::map<std::string, bufferlist> *out_vals,
+ bool *pmore)
+{
+ ObjectReadOperation op;
+ int r;
+ op.omap_get_vals2(start_after, max_return, out_vals, pmore, &r);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0)
+ return ret;
+ return r;
+}
+
+int librados::IoCtx::omap_get_keys(const std::string& oid,
+ const std::string& orig_start_after,
+ uint64_t max_return,
+ std::set<std::string> *out_keys)
+{
+ bool first = true;
+ string start_after = orig_start_after;
+ bool more = true;
+ while (max_return > 0 && more) {
+ std::set<std::string> out;
+ ObjectReadOperation op;
+ op.omap_get_keys2(start_after, max_return, &out, &more, nullptr);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (more) {
+ if (out.empty()) {
+ return -EINVAL; // wth
+ }
+ start_after = *out.rbegin();
+ }
+ if (out.size() <= max_return) {
+ max_return -= out.size();
+ } else {
+ max_return = 0;
+ }
+ if (first) {
+ out_keys->swap(out);
+ first = false;
+ } else {
+ out_keys->insert(out.begin(), out.end());
+ out.clear();
+ }
+ }
+ return 0;
+}
+
+int librados::IoCtx::omap_get_keys2(
+ const std::string& oid,
+ const std::string& start_after,
+ uint64_t max_return,
+ std::set<std::string> *out_keys,
+ bool *pmore)
+{
+ ObjectReadOperation op;
+ int r;
+ op.omap_get_keys2(start_after, max_return, out_keys, pmore, &r);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0)
+ return ret;
+ return r;
+}
+
+int librados::IoCtx::omap_get_header(const std::string& oid,
+ bufferlist *bl)
+{
+ ObjectReadOperation op;
+ int r;
+ op.omap_get_header(bl, &r);
+ bufferlist b;
+ int ret = operate(oid, &op, &b);
+ if (ret < 0)
+ return ret;
+
+ return r;
+}
+
+int librados::IoCtx::omap_get_vals_by_keys(const std::string& oid,
+ const std::set<std::string>& keys,
+ std::map<std::string, bufferlist> *vals)
+{
+ ObjectReadOperation op;
+ int r;
+ bufferlist bl;
+ op.omap_get_vals_by_keys(keys, vals, &r);
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0)
+ return ret;
+
+ return r;
+}
+
+int librados::IoCtx::omap_set(const std::string& oid,
+ const map<string, bufferlist>& m)
+{
+ ObjectWriteOperation op;
+ op.omap_set(m);
+ return operate(oid, &op);
+}
+
+int librados::IoCtx::omap_set_header(const std::string& oid,
+ const bufferlist& bl)
+{
+ ObjectWriteOperation op;
+ op.omap_set_header(bl);
+ return operate(oid, &op);
+}
+
+int librados::IoCtx::omap_clear(const std::string& oid)
+{
+ ObjectWriteOperation op;
+ op.omap_clear();
+ return operate(oid, &op);
+}
+
+int librados::IoCtx::omap_rm_keys(const std::string& oid,
+ const std::set<std::string>& keys)
+{
+ ObjectWriteOperation op;
+ op.omap_rm_keys(keys);
+ return operate(oid, &op);
+}
+
+int librados::IoCtx::operate(const std::string& oid, librados::ObjectWriteOperation *o)
+{
+ object_t obj(oid);
+ return io_ctx_impl->operate(obj, &o->impl->o, (ceph::real_time *)o->impl->prt);
+}
+
+int librados::IoCtx::operate(const std::string& oid, librados::ObjectReadOperation *o, bufferlist *pbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->operate_read(obj, &o->impl->o, pbl);
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectWriteOperation *o)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
+ io_ctx_impl->snapc, 0);
+}
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ ObjectWriteOperation *o, int flags)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
+ io_ctx_impl->snapc,
+ translate_flags(flags));
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectWriteOperation *o,
+ snap_t snap_seq, std::vector<snap_t>& snaps)
+{
+ object_t obj(oid);
+ vector<snapid_t> snv;
+ snv.resize(snaps.size());
+ for (size_t i = 0; i < snaps.size(); ++i)
+ snv[i] = snaps[i];
+ SnapContext snapc(snap_seq, snv);
+ return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
+ snapc, 0);
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectWriteOperation *o,
+ snap_t snap_seq, std::vector<snap_t>& snaps,
+ const blkin_trace_info *trace_info)
+{
+ object_t obj(oid);
+ vector<snapid_t> snv;
+ snv.resize(snaps.size());
+ for (size_t i = 0; i < snaps.size(); ++i)
+ snv[i] = snaps[i];
+ SnapContext snapc(snap_seq, snv);
+ return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc,
+ snapc, 0, trace_info);
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectWriteOperation *o,
+ snap_t snap_seq, std::vector<snap_t>& snaps, int flags,
+ const blkin_trace_info *trace_info)
+{
+ object_t obj(oid);
+ vector<snapid_t> snv;
+ snv.resize(snaps.size());
+ for (size_t i = 0; i < snaps.size(); ++i)
+ snv[i] = snaps[i];
+ SnapContext snapc(snap_seq, snv);
+ return io_ctx_impl->aio_operate(obj, &o->impl->o, c->pc, snapc,
+ translate_flags(flags), trace_info);
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectReadOperation *o,
+ bufferlist *pbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
+ 0, pbl);
+}
+
+// deprecated
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectReadOperation *o,
+ snap_t snapid_unused_deprecated,
+ int flags, bufferlist *pbl)
+{
+ object_t obj(oid);
+ int op_flags = 0;
+ if (flags & OPERATION_BALANCE_READS)
+ op_flags |= CEPH_OSD_FLAG_BALANCE_READS;
+ if (flags & OPERATION_LOCALIZE_READS)
+ op_flags |= CEPH_OSD_FLAG_LOCALIZE_READS;
+ if (flags & OPERATION_ORDER_READS_WRITES)
+ op_flags |= CEPH_OSD_FLAG_RWORDERED;
+
+ return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
+ op_flags, pbl);
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectReadOperation *o,
+ int flags, bufferlist *pbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
+ translate_flags(flags), pbl);
+}
+
+int librados::IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
+ librados::ObjectReadOperation *o,
+ int flags, bufferlist *pbl, const blkin_trace_info *trace_info)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_operate_read(obj, &o->impl->o, c->pc,
+ translate_flags(flags), pbl, trace_info);
+}
+
+void librados::IoCtx::snap_set_read(snap_t seq)
+{
+ io_ctx_impl->set_snap_read(seq);
+}
+
+int librados::IoCtx::selfmanaged_snap_set_write_ctx(snap_t seq, vector<snap_t>& snaps)
+{
+ vector<snapid_t> snv;
+ snv.resize(snaps.size());
+ for (unsigned i=0; i<snaps.size(); i++)
+ snv[i] = snaps[i];
+ return io_ctx_impl->set_snap_write_context(seq, snv);
+}
+
+int librados::IoCtx::snap_create(const char *snapname)
+{
+ return io_ctx_impl->snap_create(snapname);
+}
+
+int librados::IoCtx::snap_lookup(const char *name, snap_t *snapid)
+{
+ return io_ctx_impl->snap_lookup(name, snapid);
+}
+
+int librados::IoCtx::snap_get_stamp(snap_t snapid, time_t *t)
+{
+ return io_ctx_impl->snap_get_stamp(snapid, t);
+}
+
+int librados::IoCtx::snap_get_name(snap_t snapid, std::string *s)
+{
+ return io_ctx_impl->snap_get_name(snapid, s);
+}
+
+int librados::IoCtx::snap_remove(const char *snapname)
+{
+ return io_ctx_impl->snap_remove(snapname);
+}
+
+int librados::IoCtx::snap_list(std::vector<snap_t> *snaps)
+{
+ return io_ctx_impl->snap_list(snaps);
+}
+
+int librados::IoCtx::snap_rollback(const std::string& oid, const char *snapname)
+{
+ return io_ctx_impl->rollback(oid, snapname);
+}
+
+// Deprecated name kept for backward compatibility
+int librados::IoCtx::rollback(const std::string& oid, const char *snapname)
+{
+ return snap_rollback(oid, snapname);
+}
+
+int librados::IoCtx::selfmanaged_snap_create(uint64_t *snapid)
+{
+ return io_ctx_impl->selfmanaged_snap_create(snapid);
+}
+
+void librados::IoCtx::aio_selfmanaged_snap_create(uint64_t *snapid,
+ AioCompletion *c)
+{
+ io_ctx_impl->aio_selfmanaged_snap_create(snapid, c->pc);
+}
+
+int librados::IoCtx::selfmanaged_snap_remove(uint64_t snapid)
+{
+ return io_ctx_impl->selfmanaged_snap_remove(snapid);
+}
+
+void librados::IoCtx::aio_selfmanaged_snap_remove(uint64_t snapid,
+ AioCompletion *c)
+{
+ io_ctx_impl->aio_selfmanaged_snap_remove(snapid, c->pc);
+}
+
+int librados::IoCtx::selfmanaged_snap_rollback(const std::string& oid, uint64_t snapid)
+{
+ return io_ctx_impl->selfmanaged_snap_rollback_object(oid,
+ io_ctx_impl->snapc,
+ snapid);
+}
+
+int librados::IoCtx::lock_exclusive(const std::string &oid, const std::string &name,
+ const std::string &cookie,
+ const std::string &description,
+ struct timeval * duration, uint8_t flags)
+{
+ utime_t dur = utime_t();
+ if (duration)
+ dur.set_from_timeval(duration);
+
+ return rados::cls::lock::lock(this, oid, name, LOCK_EXCLUSIVE, cookie, "",
+ description, dur, flags);
+}
+
+int librados::IoCtx::lock_shared(const std::string &oid, const std::string &name,
+ const std::string &cookie, const std::string &tag,
+ const std::string &description,
+ struct timeval * duration, uint8_t flags)
+{
+ utime_t dur = utime_t();
+ if (duration)
+ dur.set_from_timeval(duration);
+
+ return rados::cls::lock::lock(this, oid, name, LOCK_SHARED, cookie, tag,
+ description, dur, flags);
+}
+
+int librados::IoCtx::unlock(const std::string &oid, const std::string &name,
+ const std::string &cookie)
+{
+ return rados::cls::lock::unlock(this, oid, name, cookie);
+}
+
+struct AioUnlockCompletion : public librados::ObjectOperationCompletion {
+ librados::AioCompletionImpl *completion;
+ AioUnlockCompletion(librados::AioCompletion *c) : completion(c->pc) {
+ completion->get();
+ };
+ void handle_completion(int r, bufferlist& outbl) override {
+ rados_callback_t cb = completion->callback_complete;
+ void *cb_arg = completion->callback_complete_arg;
+ cb(completion, cb_arg);
+ completion->lock.Lock();
+ completion->callback_complete = NULL;
+ completion->cond.Signal();
+ completion->put_unlock();
+ }
+};
+
+int librados::IoCtx::aio_unlock(const std::string &oid, const std::string &name,
+ const std::string &cookie, AioCompletion *c)
+{
+ return rados::cls::lock::aio_unlock(this, oid, name, cookie, c);
+}
+
+int librados::IoCtx::break_lock(const std::string &oid, const std::string &name,
+ const std::string &client, const std::string &cookie)
+{
+ entity_name_t locker;
+ if (!locker.parse(client))
+ return -EINVAL;
+ return rados::cls::lock::break_lock(this, oid, name, cookie, locker);
+}
+
+int librados::IoCtx::list_lockers(const std::string &oid, const std::string &name,
+ int *exclusive,
+ std::string *tag,
+ std::list<librados::locker_t> *lockers)
+{
+ std::list<librados::locker_t> tmp_lockers;
+ map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t> rados_lockers;
+ std::string tmp_tag;
+ ClsLockType tmp_type;
+ int r = rados::cls::lock::get_lock_info(this, oid, name, &rados_lockers, &tmp_type, &tmp_tag);
+ if (r < 0)
+ return r;
+
+ map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t>::iterator map_it;
+ for (map_it = rados_lockers.begin(); map_it != rados_lockers.end(); ++map_it) {
+ librados::locker_t locker;
+ locker.client = stringify(map_it->first.locker);
+ locker.cookie = map_it->first.cookie;
+ locker.address = stringify(map_it->second.addr);
+ tmp_lockers.push_back(locker);
+ }
+
+ if (lockers)
+ *lockers = tmp_lockers;
+ if (tag)
+ *tag = tmp_tag;
+ if (exclusive) {
+ if (tmp_type == LOCK_EXCLUSIVE)
+ *exclusive = 1;
+ else
+ *exclusive = 0;
+ }
+
+ return tmp_lockers.size();
+}
+
+librados::NObjectIterator librados::IoCtx::nobjects_begin()
+{
+ bufferlist bl;
+ return nobjects_begin(bl);
+}
+
+librados::NObjectIterator librados::IoCtx::nobjects_begin(
+ const bufferlist &filter)
+{
+ rados_list_ctx_t listh;
+ rados_nobjects_list_open(io_ctx_impl, &listh);
+ NObjectIterator iter((ObjListCtx*)listh);
+ if (filter.length() > 0) {
+ iter.set_filter(filter);
+ }
+ iter.get_next();
+ return iter;
+}
+
+librados::NObjectIterator librados::IoCtx::nobjects_begin(uint32_t pos)
+{
+ bufferlist bl;
+ return nobjects_begin(pos, bl);
+}
+
+librados::NObjectIterator librados::IoCtx::nobjects_begin(
+ uint32_t pos, const bufferlist &filter)
+{
+ rados_list_ctx_t listh;
+ rados_nobjects_list_open(io_ctx_impl, &listh);
+ NObjectIterator iter((ObjListCtx*)listh);
+ if (filter.length() > 0) {
+ iter.set_filter(filter);
+ }
+ iter.seek(pos);
+ return iter;
+}
+
+librados::NObjectIterator librados::IoCtx::nobjects_begin(const ObjectCursor& cursor)
+{
+ bufferlist bl;
+ return nobjects_begin(cursor, bl);
+}
+
+librados::NObjectIterator librados::IoCtx::nobjects_begin(
+ const ObjectCursor& cursor, const bufferlist &filter)
+{
+ rados_list_ctx_t listh;
+ rados_nobjects_list_open(io_ctx_impl, &listh);
+ NObjectIterator iter((ObjListCtx*)listh);
+ if (filter.length() > 0) {
+ iter.set_filter(filter);
+ }
+ iter.seek(cursor);
+ return iter;
+}
+
+const librados::NObjectIterator& librados::IoCtx::nobjects_end() const
+{
+ return NObjectIterator::__EndObjectIterator;
+}
+
+int librados::IoCtx::hit_set_list(uint32_t hash, AioCompletion *c,
+ std::list< std::pair<time_t, time_t> > *pls)
+{
+ return io_ctx_impl->hit_set_list(hash, c->pc, pls);
+}
+
+int librados::IoCtx::hit_set_get(uint32_t hash, AioCompletion *c, time_t stamp,
+ bufferlist *pbl)
+{
+ return io_ctx_impl->hit_set_get(hash, c->pc, stamp, pbl);
+}
+
+
+
+uint64_t librados::IoCtx::get_last_version()
+{
+ return io_ctx_impl->last_version();
+}
+
+int librados::IoCtx::aio_read(const std::string& oid, librados::AioCompletion *c,
+ bufferlist *pbl, size_t len, uint64_t off)
+{
+ return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off,
+ io_ctx_impl->snap_seq);
+}
+
+int librados::IoCtx::aio_read(const std::string& oid, librados::AioCompletion *c,
+ bufferlist *pbl, size_t len, uint64_t off,
+ uint64_t snapid)
+{
+ return io_ctx_impl->aio_read(oid, c->pc, pbl, len, off, snapid);
+}
+
+int librados::IoCtx::aio_exec(const std::string& oid,
+ librados::AioCompletion *c, const char *cls,
+ const char *method, bufferlist& inbl,
+ bufferlist *outbl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_exec(obj, c->pc, cls, method, inbl, outbl);
+}
+
+int librados::IoCtx::aio_cmpext(const std::string& oid,
+ librados::AioCompletion *c,
+ uint64_t off,
+ bufferlist& cmp_bl)
+{
+ return io_ctx_impl->aio_cmpext(oid, c->pc, off, cmp_bl);
+}
+
+int librados::IoCtx::aio_sparse_read(const std::string& oid, librados::AioCompletion *c,
+ std::map<uint64_t,uint64_t> *m, bufferlist *data_bl,
+ size_t len, uint64_t off)
+{
+ return io_ctx_impl->aio_sparse_read(oid, c->pc,
+ m, data_bl, len, off,
+ io_ctx_impl->snap_seq);
+}
+
+int librados::IoCtx::aio_sparse_read(const std::string& oid, librados::AioCompletion *c,
+ std::map<uint64_t,uint64_t> *m, bufferlist *data_bl,
+ size_t len, uint64_t off, uint64_t snapid)
+{
+ return io_ctx_impl->aio_sparse_read(oid, c->pc,
+ m, data_bl, len, off, snapid);
+}
+
+int librados::IoCtx::aio_write(const std::string& oid, librados::AioCompletion *c,
+ const bufferlist& bl, size_t len, uint64_t off)
+{
+ return io_ctx_impl->aio_write(oid, c->pc, bl, len, off);
+}
+
+int librados::IoCtx::aio_append(const std::string& oid, librados::AioCompletion *c,
+ const bufferlist& bl, size_t len)
+{
+ return io_ctx_impl->aio_append(oid, c->pc, bl, len);
+}
+
+int librados::IoCtx::aio_write_full(const std::string& oid, librados::AioCompletion *c,
+ const bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_write_full(obj, c->pc, bl);
+}
+
+int librados::IoCtx::aio_writesame(const std::string& oid, librados::AioCompletion *c,
+ const bufferlist& bl, size_t write_len,
+ uint64_t off)
+{
+ return io_ctx_impl->aio_writesame(oid, c->pc, bl, write_len, off);
+}
+
+
+int librados::IoCtx::aio_remove(const std::string& oid, librados::AioCompletion *c)
+{
+ return io_ctx_impl->aio_remove(oid, c->pc);
+}
+
+int librados::IoCtx::aio_remove(const std::string& oid, librados::AioCompletion *c, int flags)
+{
+ return io_ctx_impl->aio_remove(oid, c->pc, flags);
+}
+
+int librados::IoCtx::aio_flush_async(librados::AioCompletion *c)
+{
+ io_ctx_impl->flush_aio_writes_async(c->pc);
+ return 0;
+}
+
+int librados::IoCtx::aio_flush()
+{
+ io_ctx_impl->flush_aio_writes();
+ return 0;
+}
+
+struct AioGetxattrDataPP {
+ AioGetxattrDataPP(librados::AioCompletionImpl *c, bufferlist *_bl) :
+ bl(_bl), completion(c) {}
+ bufferlist *bl;
+ struct librados::C_AioCompleteAndSafe completion;
+};
+
+static void rados_aio_getxattr_completepp(rados_completion_t c, void *arg) {
+ AioGetxattrDataPP *cdata = reinterpret_cast<AioGetxattrDataPP*>(arg);
+ int rc = rados_aio_get_return_value(c);
+ if (rc >= 0) {
+ rc = cdata->bl->length();
+ }
+ cdata->completion.finish(rc);
+ delete cdata;
+}
+
+int librados::IoCtx::aio_getxattr(const std::string& oid, librados::AioCompletion *c,
+ const char *name, bufferlist& bl)
+{
+ // create data object to be passed to async callback
+ AioGetxattrDataPP *cdata = new AioGetxattrDataPP(c->pc, &bl);
+ if (!cdata) {
+ return -ENOMEM;
+ }
+ // create completion callback
+ librados::AioCompletionImpl *comp = new librados::AioCompletionImpl;
+ comp->set_complete_callback(cdata, rados_aio_getxattr_completepp);
+ // call actual getxattr from IoCtxImpl
+ object_t obj(oid);
+ return io_ctx_impl->aio_getxattr(obj, comp, name, bl);
+}
+
+int librados::IoCtx::aio_getxattrs(const std::string& oid, AioCompletion *c,
+ map<std::string, bufferlist>& attrset)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_getxattrs(obj, c->pc, attrset);
+}
+
+int librados::IoCtx::aio_setxattr(const std::string& oid, AioCompletion *c,
+ const char *name, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_setxattr(obj, c->pc, name, bl);
+}
+
+int librados::IoCtx::aio_rmxattr(const std::string& oid, AioCompletion *c,
+ const char *name)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_rmxattr(obj, c->pc, name);
+}
+
+int librados::IoCtx::aio_stat(const std::string& oid, librados::AioCompletion *c,
+ uint64_t *psize, time_t *pmtime)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_stat(obj, c->pc, psize, pmtime);
+}
+
+int librados::IoCtx::aio_cancel(librados::AioCompletion *c)
+{
+ return io_ctx_impl->aio_cancel(c->pc);
+}
+
+int librados::IoCtx::watch(const string& oid, uint64_t ver, uint64_t *cookie,
+ librados::WatchCtx *ctx)
+{
+ object_t obj(oid);
+ return io_ctx_impl->watch(obj, cookie, ctx, NULL);
+}
+
+int librados::IoCtx::watch2(const string& oid, uint64_t *cookie,
+ librados::WatchCtx2 *ctx2)
+{
+ object_t obj(oid);
+ return io_ctx_impl->watch(obj, cookie, NULL, ctx2);
+}
+
+int librados::IoCtx::watch3(const string& oid, uint64_t *cookie,
+ librados::WatchCtx2 *ctx2, uint32_t timeout)
+{
+ object_t obj(oid);
+ return io_ctx_impl->watch(obj, cookie, NULL, ctx2, timeout);
+}
+
+int librados::IoCtx::aio_watch(const string& oid, AioCompletion *c,
+ uint64_t *cookie,
+ librados::WatchCtx2 *ctx2)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_watch(obj, c->pc, cookie, NULL, ctx2);
+}
+
+int librados::IoCtx::aio_watch2(const string& oid, AioCompletion *c,
+ uint64_t *cookie,
+ librados::WatchCtx2 *ctx2,
+ uint32_t timeout)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_watch(obj, c->pc, cookie, NULL, ctx2, timeout);
+}
+
+int librados::IoCtx::unwatch(const string& oid, uint64_t handle)
+{
+ return io_ctx_impl->unwatch(handle);
+}
+
+int librados::IoCtx::unwatch2(uint64_t handle)
+{
+ return io_ctx_impl->unwatch(handle);
+}
+
+int librados::IoCtx::aio_unwatch(uint64_t handle, AioCompletion *c)
+{
+ return io_ctx_impl->aio_unwatch(handle, c->pc);
+}
+
+int librados::IoCtx::watch_check(uint64_t handle)
+{
+ return io_ctx_impl->watch_check(handle);
+}
+
+int librados::IoCtx::notify(const string& oid, uint64_t ver, bufferlist& bl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->notify(obj, bl, 0, NULL, NULL, NULL);
+}
+
+int librados::IoCtx::notify2(const string& oid, bufferlist& bl,
+ uint64_t timeout_ms, bufferlist *preplybl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->notify(obj, bl, timeout_ms, preplybl, NULL, NULL);
+}
+
+int librados::IoCtx::aio_notify(const string& oid, AioCompletion *c,
+ bufferlist& bl, uint64_t timeout_ms,
+ bufferlist *preplybl)
+{
+ object_t obj(oid);
+ return io_ctx_impl->aio_notify(obj, c->pc, bl, timeout_ms, preplybl, NULL,
+ NULL);
+}
+
+void librados::IoCtx::notify_ack(const std::string& o,
+ uint64_t notify_id, uint64_t handle,
+ bufferlist& bl)
+{
+ io_ctx_impl->notify_ack(o, notify_id, handle, bl);
+}
+
+int librados::IoCtx::list_watchers(const std::string& oid,
+ std::list<obj_watch_t> *out_watchers)
+{
+ ObjectReadOperation op;
+ int r;
+ op.list_watchers(out_watchers, &r);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0)
+ return ret;
+
+ return r;
+}
+
+int librados::IoCtx::list_snaps(const std::string& oid,
+ snap_set_t *out_snaps)
+{
+ ObjectReadOperation op;
+ int r;
+ if (io_ctx_impl->snap_seq != CEPH_SNAPDIR)
+ return -EINVAL;
+ op.list_snaps(out_snaps, &r);
+ bufferlist bl;
+ int ret = operate(oid, &op, &bl);
+ if (ret < 0)
+ return ret;
+
+ return r;
+}
+
+void librados::IoCtx::set_notify_timeout(uint32_t timeout)
+{
+ io_ctx_impl->set_notify_timeout(timeout);
+}
+
+int librados::IoCtx::set_alloc_hint(const std::string& o,
+ uint64_t expected_object_size,
+ uint64_t expected_write_size)
+{
+ object_t oid(o);
+ return io_ctx_impl->set_alloc_hint(oid, expected_object_size,
+ expected_write_size, 0);
+}
+
+int librados::IoCtx::set_alloc_hint2(const std::string& o,
+ uint64_t expected_object_size,
+ uint64_t expected_write_size,
+ uint32_t flags)
+{
+ object_t oid(o);
+ return io_ctx_impl->set_alloc_hint(oid, expected_object_size,
+ expected_write_size, flags);
+}
+
+void librados::IoCtx::set_assert_version(uint64_t ver)
+{
+ io_ctx_impl->set_assert_version(ver);
+}
+
+void librados::IoCtx::locator_set_key(const string& key)
+{
+ io_ctx_impl->oloc.key = key;
+}
+
+void librados::IoCtx::set_namespace(const string& nspace)
+{
+ io_ctx_impl->oloc.nspace = nspace;
+}
+
+std::string librados::IoCtx::get_namespace() const
+{
+ return io_ctx_impl->oloc.nspace;
+}
+
+int64_t librados::IoCtx::get_id()
+{
+ return io_ctx_impl->get_id();
+}
+
+uint32_t librados::IoCtx::get_object_hash_position(const std::string& oid)
+{
+ uint32_t hash;
+ int r = io_ctx_impl->get_object_hash_position(oid, &hash);
+ if (r < 0)
+ hash = 0;
+ return hash;
+}
+
+uint32_t librados::IoCtx::get_object_pg_hash_position(const std::string& oid)
+{
+ uint32_t hash;
+ int r = io_ctx_impl->get_object_pg_hash_position(oid, &hash);
+ if (r < 0)
+ hash = 0;
+ return hash;
+}
+
+int librados::IoCtx::get_object_hash_position2(
+ const std::string& oid, uint32_t *hash_position)
+{
+ return io_ctx_impl->get_object_hash_position(oid, hash_position);
+}
+
+int librados::IoCtx::get_object_pg_hash_position2(
+ const std::string& oid, uint32_t *pg_hash_position)
+{
+ return io_ctx_impl->get_object_pg_hash_position(oid, pg_hash_position);
+}
+
+librados::config_t librados::IoCtx::cct()
+{
+ return (config_t)io_ctx_impl->client->cct;
+}
+
+librados::IoCtx::IoCtx(IoCtxImpl *io_ctx_impl_)
+ : io_ctx_impl(io_ctx_impl_)
+{
+}
+
+void librados::IoCtx::set_osdmap_full_try()
+{
+ io_ctx_impl->objecter->set_osdmap_full_try();
+}
+
+void librados::IoCtx::unset_osdmap_full_try()
+{
+ io_ctx_impl->objecter->unset_osdmap_full_try();
+}
+
+///////////////////////////// Rados //////////////////////////////
+void librados::Rados::version(int *major, int *minor, int *extra)
+{
+ rados_version(major, minor, extra);
+}
+
+librados::Rados::Rados() : client(NULL)
+{
+}
+
+librados::Rados::Rados(IoCtx &ioctx)
+{
+ client = ioctx.io_ctx_impl->client;
+ ceph_assert(client != NULL);
+ client->get();
+}
+
+librados::Rados::~Rados()
+{
+ shutdown();
+}
+
+int librados::Rados::init(const char * const id)
+{
+ return rados_create((rados_t *)&client, id);
+}
+
+int librados::Rados::init2(const char * const name,
+ const char * const clustername, uint64_t flags)
+{
+ return rados_create2((rados_t *)&client, clustername, name, flags);
+}
+
+int librados::Rados::init_with_context(config_t cct_)
+{
+ return rados_create_with_context((rados_t *)&client, (rados_config_t)cct_);
+}
+
+int librados::Rados::connect()
+{
+ return client->connect();
+}
+
+librados::config_t librados::Rados::cct()
+{
+ return (config_t)client->cct;
+}
+
+int librados::Rados::watch_flush()
+{
+ if (!client)
+ return -EINVAL;
+ return client->watch_flush();
+}
+
+int librados::Rados::aio_watch_flush(AioCompletion *c)
+{
+ if (!client)
+ return -EINVAL;
+ return client->async_watch_flush(c->pc);
+}
+
+void librados::Rados::shutdown()
+{
+ if (!client)
+ return;
+ if (client->put()) {
+ client->shutdown();
+ delete client;
+ client = NULL;
+ }
+}
+
+uint64_t librados::Rados::get_instance_id()
+{
+ return client->get_instance_id();
+}
+
+int librados::Rados::get_min_compatible_osd(int8_t* require_osd_release)
+{
+ return client->get_min_compatible_osd(require_osd_release);
+}
+
+int librados::Rados::get_min_compatible_client(int8_t* min_compat_client,
+ int8_t* require_min_compat_client)
+{
+ return client->get_min_compatible_client(min_compat_client,
+ require_min_compat_client);
+}
+
+int librados::Rados::conf_read_file(const char * const path) const
+{
+ return rados_conf_read_file((rados_t)client, path);
+}
+
+int librados::Rados::conf_parse_argv(int argc, const char ** argv) const
+{
+ return rados_conf_parse_argv((rados_t)client, argc, argv);
+}
+
+int librados::Rados::conf_parse_argv_remainder(int argc, const char ** argv,
+ const char ** remargv) const
+{
+ return rados_conf_parse_argv_remainder((rados_t)client, argc, argv, remargv);
+}
+
+int librados::Rados::conf_parse_env(const char *name) const
+{
+ return rados_conf_parse_env((rados_t)client, name);
+}
+
+int librados::Rados::conf_set(const char *option, const char *value)
+{
+ return rados_conf_set((rados_t)client, option, value);
+}
+
+int librados::Rados::conf_get(const char *option, std::string &val)
+{
+ char *str = NULL;
+ const auto& conf = client->cct->_conf;
+ int ret = conf.get_val(option, &str, -1);
+ if (ret) {
+ free(str);
+ return ret;
+ }
+ val = str;
+ free(str);
+ return 0;
+}
+
+int librados::Rados::service_daemon_register(
+ const std::string& service, ///< service name (e.g., 'rgw')
+ const std::string& name, ///< daemon name (e.g., 'gwfoo')
+ const std::map<std::string,std::string>& metadata) ///< static metadata about daemon
+{
+ return client->service_daemon_register(service, name, metadata);
+}
+
+int librados::Rados::service_daemon_update_status(
+ std::map<std::string,std::string>&& status)
+{
+ return client->service_daemon_update_status(std::move(status));
+}
+
+int librados::Rados::pool_create(const char *name)
+{
+ string str(name);
+ return client->pool_create(str);
+}
+
+int librados::Rados::pool_create(const char *name, uint64_t auid)
+{
+ if (auid != CEPH_AUTH_UID_DEFAULT) {
+ return -EINVAL;
+ }
+ string str(name);
+ return client->pool_create(str);
+}
+
+int librados::Rados::pool_create(const char *name, uint64_t auid, __u8 crush_rule)
+{
+ if (auid != CEPH_AUTH_UID_DEFAULT) {
+ return -EINVAL;
+ }
+ string str(name);
+ return client->pool_create(str, crush_rule);
+}
+
+int librados::Rados::pool_create_with_rule(const char *name, __u8 crush_rule)
+{
+ string str(name);
+ return client->pool_create(str, crush_rule);
+}
+
+int librados::Rados::pool_create_async(const char *name, PoolAsyncCompletion *c)
+{
+ string str(name);
+ return client->pool_create_async(str, c->pc);
+}
+
+int librados::Rados::pool_create_async(const char *name, uint64_t auid, PoolAsyncCompletion *c)
+{
+ if (auid != CEPH_AUTH_UID_DEFAULT) {
+ return -EINVAL;
+ }
+ string str(name);
+ return client->pool_create_async(str, c->pc);
+}
+
+int librados::Rados::pool_create_async(const char *name, uint64_t auid, __u8 crush_rule,
+ PoolAsyncCompletion *c)
+{
+ if (auid != CEPH_AUTH_UID_DEFAULT) {
+ return -EINVAL;
+ }
+ string str(name);
+ return client->pool_create_async(str, c->pc, crush_rule);
+}
+
+int librados::Rados::pool_create_with_rule_async(
+ const char *name, __u8 crush_rule,
+ PoolAsyncCompletion *c)
+{
+ string str(name);
+ return client->pool_create_async(str, c->pc, crush_rule);
+}
+
+int librados::Rados::pool_get_base_tier(int64_t pool_id, int64_t* base_tier)
+{
+ tracepoint(librados, rados_pool_get_base_tier_enter, (rados_t)client, pool_id);
+ int retval = client->pool_get_base_tier(pool_id, base_tier);
+ tracepoint(librados, rados_pool_get_base_tier_exit, retval, *base_tier);
+ return retval;
+}
+
+int librados::Rados::pool_delete(const char *name)
+{
+ return client->pool_delete(name);
+}
+
+int librados::Rados::pool_delete_async(const char *name, PoolAsyncCompletion *c)
+{
+ return client->pool_delete_async(name, c->pc);
+}
+
+int librados::Rados::pool_list(std::list<std::string>& v)
+{
+ std::list<std::pair<int64_t, std::string> > pools;
+ int r = client->pool_list(pools);
+ if (r < 0) {
+ return r;
+ }
+
+ v.clear();
+ for (std::list<std::pair<int64_t, std::string> >::iterator it = pools.begin();
+ it != pools.end(); ++it) {
+ v.push_back(it->second);
+ }
+ return 0;
+}
+
+int librados::Rados::pool_list2(std::list<std::pair<int64_t, std::string> >& v)
+{
+ return client->pool_list(v);
+}
+
+int64_t librados::Rados::pool_lookup(const char *name)
+{
+ return client->lookup_pool(name);
+}
+
+int librados::Rados::pool_reverse_lookup(int64_t id, std::string *name)
+{
+ return client->pool_get_name(id, name);
+}
+
+int librados::Rados::mon_command(string cmd, const bufferlist& inbl,
+ bufferlist *outbl, string *outs)
+{
+ vector<string> cmdvec;
+ cmdvec.push_back(cmd);
+ return client->mon_command(cmdvec, inbl, outbl, outs);
+}
+
+int librados::Rados::osd_command(int osdid, std::string cmd, const bufferlist& inbl,
+ bufferlist *outbl, std::string *outs)
+{
+ vector<string> cmdvec;
+ cmdvec.push_back(cmd);
+ return client->osd_command(osdid, cmdvec, inbl, outbl, outs);
+}
+
+int librados::Rados::mgr_command(std::string cmd, const bufferlist& inbl,
+ bufferlist *outbl, std::string *outs)
+{
+ vector<string> cmdvec;
+ cmdvec.push_back(cmd);
+ return client->mgr_command(cmdvec, inbl, outbl, outs);
+}
+
+
+
+int librados::Rados::pg_command(const char *pgstr, std::string cmd, const bufferlist& inbl,
+ bufferlist *outbl, std::string *outs)
+{
+ vector<string> cmdvec;
+ cmdvec.push_back(cmd);
+
+ pg_t pgid;
+ if (!pgid.parse(pgstr))
+ return -EINVAL;
+
+ return client->pg_command(pgid, cmdvec, inbl, outbl, outs);
+}
+
+int librados::Rados::ioctx_create(const char *name, IoCtx &io)
+{
+ rados_ioctx_t p;
+ int ret = rados_ioctx_create((rados_t)client, name, &p);
+ if (ret)
+ return ret;
+ io.close();
+ io.io_ctx_impl = (IoCtxImpl*)p;
+ return 0;
+}
+
+int librados::Rados::ioctx_create2(int64_t pool_id, IoCtx &io)
+{
+ rados_ioctx_t p;
+ int ret = rados_ioctx_create2((rados_t)client, pool_id, &p);
+ if (ret)
+ return ret;
+ io.close();
+ io.io_ctx_impl = (IoCtxImpl*)p;
+ return 0;
+}
+
+void librados::Rados::test_blacklist_self(bool set)
+{
+ client->blacklist_self(set);
+}
+
+int librados::Rados::get_pool_stats(std::list<string>& v,
+ stats_map& result)
+{
+ map<string,::pool_stat_t> rawresult;
+ int r = client->get_pool_stats(v, rawresult);
+ for (map<string,::pool_stat_t>::iterator p = rawresult.begin();
+ p != rawresult.end();
+ ++p) {
+ pool_stat_t& pv = result[p->first];
+ object_stat_sum_t *sum = &p->second.stats.sum;
+ pv.num_kb = shift_round_up(sum->num_bytes, 10);
+ pv.num_bytes = sum->num_bytes;
+ pv.num_objects = sum->num_objects;
+ pv.num_object_clones = sum->num_object_clones;
+ pv.num_object_copies = sum->num_object_copies;
+ pv.num_objects_missing_on_primary = sum->num_objects_missing_on_primary;
+ pv.num_objects_unfound = sum->num_objects_unfound;
+ pv.num_objects_degraded = sum->num_objects_degraded;
+ pv.num_rd = sum->num_rd;
+ pv.num_rd_kb = sum->num_rd_kb;
+ pv.num_wr = sum->num_wr;
+ pv.num_wr_kb = sum->num_wr_kb;
+ }
+ return r;
+}
+
+int librados::Rados::get_pool_stats(std::list<string>& v,
+ std::map<string, stats_map>& result)
+{
+ stats_map m;
+ int r = get_pool_stats(v, m);
+ if (r < 0)
+ return r;
+ for (map<string,pool_stat_t>::iterator p = m.begin();
+ p != m.end();
+ ++p) {
+ result[p->first][string()] = p->second;
+ }
+ return r;
+}
+
+int librados::Rados::get_pool_stats(std::list<string>& v,
+ string& category, // unused
+ std::map<string, stats_map>& result)
+{
+ return -EOPNOTSUPP;
+}
+
+bool librados::Rados::get_pool_is_selfmanaged_snaps_mode(const std::string& pool)
+{
+ return client->get_pool_is_selfmanaged_snaps_mode(pool);
+}
+
+int librados::Rados::cluster_stat(cluster_stat_t& result)
+{
+ ceph_statfs stats;
+ int r = client->get_fs_stats(stats);
+ result.kb = stats.kb;
+ result.kb_used = stats.kb_used;
+ result.kb_avail = stats.kb_avail;
+ result.num_objects = stats.num_objects;
+ return r;
+}
+
+int librados::Rados::cluster_fsid(string *fsid)
+{
+ return client->get_fsid(fsid);
+}
+
+namespace librados {
+ struct PlacementGroupImpl {
+ pg_t pgid;
+ };
+
+ PlacementGroup::PlacementGroup()
+ : impl{new PlacementGroupImpl}
+ {}
+
+ PlacementGroup::PlacementGroup(const PlacementGroup& pg)
+ : impl{new PlacementGroupImpl}
+ {
+ impl->pgid = pg.impl->pgid;
+ }
+
+ PlacementGroup::~PlacementGroup()
+ {}
+
+ bool PlacementGroup::parse(const char* s)
+ {
+ return impl->pgid.parse(s);
+ }
+}
+
+std::ostream& librados::operator<<(std::ostream& out,
+ const librados::PlacementGroup& pg)
+{
+ return out << pg.impl->pgid;
+}
+
+int librados::Rados::get_inconsistent_pgs(int64_t pool_id,
+ std::vector<PlacementGroup>* pgs)
+{
+ std::vector<string> pgids;
+ if (auto ret = client->get_inconsistent_pgs(pool_id, &pgids); ret) {
+ return ret;
+ }
+ for (const auto& pgid : pgids) {
+ librados::PlacementGroup pg;
+ if (!pg.parse(pgid.c_str())) {
+ return -EINVAL;
+ }
+ pgs->emplace_back(pg);
+ }
+ return 0;
+}
+
+int librados::Rados::get_inconsistent_objects(const PlacementGroup& pg,
+ const object_id_t &start_after,
+ unsigned max_return,
+ AioCompletion *c,
+ std::vector<inconsistent_obj_t>* objects,
+ uint32_t* interval)
+{
+ IoCtx ioctx;
+ const pg_t pgid = pg.impl->pgid;
+ int r = ioctx_create2(pgid.pool(), ioctx);
+ if (r < 0) {
+ return r;
+ }
+
+ return ioctx.io_ctx_impl->get_inconsistent_objects(pgid,
+ start_after,
+ max_return,
+ c->pc,
+ objects,
+ interval);
+}
+
+int librados::Rados::get_inconsistent_snapsets(const PlacementGroup& pg,
+ const object_id_t &start_after,
+ unsigned max_return,
+ AioCompletion *c,
+ std::vector<inconsistent_snapset_t>* snapsets,
+ uint32_t* interval)
+{
+ IoCtx ioctx;
+ const pg_t pgid = pg.impl->pgid;
+ int r = ioctx_create2(pgid.pool(), ioctx);
+ if (r < 0) {
+ return r;
+ }
+
+ return ioctx.io_ctx_impl->get_inconsistent_snapsets(pgid,
+ start_after,
+ max_return,
+ c->pc,
+ snapsets,
+ interval);
+}
+
+int librados::Rados::wait_for_latest_osdmap()
+{
+ return client->wait_for_latest_osdmap();
+}
+
+int librados::Rados::blacklist_add(const std::string& client_address,
+ uint32_t expire_seconds)
+{
+ return client->blacklist_add(client_address, expire_seconds);
+}
+
+librados::PoolAsyncCompletion *librados::Rados::pool_async_create_completion()
+{
+ PoolAsyncCompletionImpl *c = new PoolAsyncCompletionImpl;
+ return new PoolAsyncCompletion(c);
+}
+
+librados::AioCompletion *librados::Rados::aio_create_completion()
+{
+ AioCompletionImpl *c = new AioCompletionImpl;
+ return new AioCompletion(c);
+}
+
+librados::AioCompletion *librados::Rados::aio_create_completion(void *cb_arg,
+ callback_t cb_complete,
+ callback_t cb_safe)
+{
+ AioCompletionImpl *c;
+ int r = rados_aio_create_completion(cb_arg, cb_complete, cb_safe, (void**)&c);
+ ceph_assert(r == 0);
+ return new AioCompletion(c);
+}
+
+librados::ObjectOperation::ObjectOperation()
+{
+ impl = new ObjectOperationImpl;
+}
+
+librados::ObjectOperation::~ObjectOperation()
+{
+ delete impl;
+}
+
+///////////////////////////// ListObject //////////////////////////////
+librados::ListObject::ListObject() : impl(NULL)
+{
+}
+
+librados::ListObject::ListObject(librados::ListObjectImpl *i): impl(i)
+{
+}
+
+librados::ListObject::ListObject(const ListObject& rhs)
+{
+ if (rhs.impl == NULL) {
+ impl = NULL;
+ return;
+ }
+ impl = new ListObjectImpl();
+ *impl = *(rhs.impl);
+}
+
+librados::ListObject& librados::ListObject::operator=(const ListObject& rhs)
+{
+ if (rhs.impl == NULL) {
+ delete impl;
+ impl = NULL;
+ return *this;
+ }
+ if (impl == NULL)
+ impl = new ListObjectImpl();
+ *impl = *(rhs.impl);
+ return *this;
+}
+
+librados::ListObject::~ListObject()
+{
+ if (impl)
+ delete impl;
+ impl = NULL;
+}
+
+const std::string& librados::ListObject::get_nspace() const
+{
+ return impl->get_nspace();
+}
+
+const std::string& librados::ListObject::get_oid() const
+{
+ return impl->get_oid();
+}
+
+const std::string& librados::ListObject::get_locator() const
+{
+ return impl->get_locator();
+}
+
+std::ostream& librados::operator<<(std::ostream& out, const librados::ListObject& lop)
+{
+ out << *(lop.impl);
+ return out;
+}
+
+librados::ObjectCursor::ObjectCursor()
+{
+ c_cursor = (rados_object_list_cursor)new hobject_t();
+}
+
+librados::ObjectCursor::~ObjectCursor()
+{
+ hobject_t *h = (hobject_t *)c_cursor;
+ delete h;
+}
+
+librados::ObjectCursor::ObjectCursor(rados_object_list_cursor c)
+{
+ if (!c) {
+ c_cursor = nullptr;
+ } else {
+ c_cursor = (rados_object_list_cursor)new hobject_t(*(hobject_t *)c);
+ }
+}
+
+librados::ObjectCursor& librados::ObjectCursor::operator=(const librados::ObjectCursor& rhs)
+{
+ if (rhs.c_cursor != nullptr) {
+ hobject_t *h = (hobject_t*)rhs.c_cursor;
+ c_cursor = (rados_object_list_cursor)(new hobject_t(*h));
+ } else {
+ c_cursor = nullptr;
+ }
+ return *this;
+}
+
+bool librados::ObjectCursor::operator<(const librados::ObjectCursor &rhs) const
+{
+ const hobject_t lhs_hobj = (c_cursor == nullptr) ? hobject_t() : *((hobject_t*)c_cursor);
+ const hobject_t rhs_hobj = (rhs.c_cursor == nullptr) ? hobject_t() : *((hobject_t*)(rhs.c_cursor));
+ return lhs_hobj < rhs_hobj;
+}
+
+bool librados::ObjectCursor::operator==(const librados::ObjectCursor &rhs) const
+{
+ const hobject_t lhs_hobj = (c_cursor == nullptr) ? hobject_t() : *((hobject_t*)c_cursor);
+ const hobject_t rhs_hobj = (rhs.c_cursor == nullptr) ? hobject_t() : *((hobject_t*)(rhs.c_cursor));
+ return cmp(lhs_hobj, rhs_hobj) == 0;
+}
+librados::ObjectCursor::ObjectCursor(const librados::ObjectCursor &rhs)
+{
+ *this = rhs;
+}
+
+librados::ObjectCursor librados::IoCtx::object_list_begin()
+{
+ hobject_t *h = new hobject_t(io_ctx_impl->objecter->enumerate_objects_begin());
+ ObjectCursor oc;
+ oc.set((rados_object_list_cursor)h);
+ return oc;
+}
+
+
+librados::ObjectCursor librados::IoCtx::object_list_end()
+{
+ hobject_t *h = new hobject_t(io_ctx_impl->objecter->enumerate_objects_end());
+ librados::ObjectCursor oc;
+ oc.set((rados_object_list_cursor)h);
+ return oc;
+}
+
+
+void librados::ObjectCursor::set(rados_object_list_cursor c)
+{
+ delete (hobject_t*)c_cursor;
+ c_cursor = c;
+}
+
+string librados::ObjectCursor::to_str() const
+{
+ stringstream ss;
+ ss << *(hobject_t *)c_cursor;
+ return ss.str();
+}
+
+bool librados::ObjectCursor::from_str(const string& s)
+{
+ if (s.empty()) {
+ *(hobject_t *)c_cursor = hobject_t();
+ return true;
+ }
+ return ((hobject_t *)c_cursor)->parse(s);
+}
+
+CEPH_RADOS_API std::ostream& librados::operator<<(std::ostream& os, const librados::ObjectCursor& oc)
+{
+ if (oc.c_cursor) {
+ os << *(hobject_t *)oc.c_cursor;
+ } else {
+ os << hobject_t();
+ }
+ return os;
+}
+
+bool librados::IoCtx::object_list_is_end(const ObjectCursor &oc)
+{
+ hobject_t *h = (hobject_t *)oc.c_cursor;
+ return h->is_max();
+}
+
+int librados::IoCtx::object_list(const ObjectCursor &start,
+ const ObjectCursor &finish,
+ const size_t result_item_count,
+ const bufferlist &filter,
+ std::vector<ObjectItem> *result,
+ ObjectCursor *next)
+{
+ ceph_assert(result != nullptr);
+ ceph_assert(next != nullptr);
+ result->clear();
+
+ C_SaferCond cond;
+ hobject_t next_hash;
+ std::list<librados::ListObjectImpl> obj_result;
+ io_ctx_impl->objecter->enumerate_objects(
+ io_ctx_impl->poolid,
+ io_ctx_impl->oloc.nspace,
+ *((hobject_t*)start.c_cursor),
+ *((hobject_t*)finish.c_cursor),
+ result_item_count,
+ filter,
+ &obj_result,
+ &next_hash,
+ &cond);
+
+ int r = cond.wait();
+ if (r < 0) {
+ next->set((rados_object_list_cursor)(new hobject_t(hobject_t::get_max())));
+ return r;
+ }
+
+ next->set((rados_object_list_cursor)(new hobject_t(next_hash)));
+
+ for (std::list<librados::ListObjectImpl>::iterator i = obj_result.begin();
+ i != obj_result.end(); ++i) {
+ ObjectItem oi;
+ oi.oid = i->oid;
+ oi.nspace = i->nspace;
+ oi.locator = i->locator;
+ result->push_back(oi);
+ }
+
+ return obj_result.size();
+}
+
+void librados::IoCtx::object_list_slice(
+ const ObjectCursor start,
+ const ObjectCursor finish,
+ const size_t n,
+ const size_t m,
+ ObjectCursor *split_start,
+ ObjectCursor *split_finish)
+{
+ ceph_assert(split_start != nullptr);
+ ceph_assert(split_finish != nullptr);
+
+ io_ctx_impl->object_list_slice(
+ *((hobject_t*)(start.c_cursor)),
+ *((hobject_t*)(finish.c_cursor)),
+ n,
+ m,
+ (hobject_t*)(split_start->c_cursor),
+ (hobject_t*)(split_finish->c_cursor));
+}
+
+int librados::IoCtx::application_enable(const std::string& app_name,
+ bool force)
+{
+ return io_ctx_impl->application_enable(app_name, force);
+}
+
+int librados::IoCtx::application_enable_async(const std::string& app_name,
+ bool force,
+ PoolAsyncCompletion *c)
+{
+ io_ctx_impl->application_enable_async(app_name, force, c->pc);
+ return 0;
+}
+
+int librados::IoCtx::application_list(std::set<std::string> *app_names)
+{
+ return io_ctx_impl->application_list(app_names);
+}
+
+int librados::IoCtx::application_metadata_get(const std::string& app_name,
+ const std::string &key,
+ std::string* value)
+{
+ return io_ctx_impl->application_metadata_get(app_name, key, value);
+}
+
+int librados::IoCtx::application_metadata_set(const std::string& app_name,
+ const std::string &key,
+ const std::string& value)
+{
+ return io_ctx_impl->application_metadata_set(app_name, key, value);
+}
+
+int librados::IoCtx::application_metadata_remove(const std::string& app_name,
+ const std::string &key)
+{
+ return io_ctx_impl->application_metadata_remove(app_name, key);
+}
+
+int librados::IoCtx::application_metadata_list(const std::string& app_name,
+ std::map<std::string, std::string> *values)
+{
+ return io_ctx_impl->application_metadata_list(app_name, values);
+}
--- /dev/null
+#include "acconfig.h"
+
+#ifdef WITH_LTTNG
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#include "tracing/librados.h"
+#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
+#undef TRACEPOINT_DEFINE
+#endif
--- /dev/null
+#include "librados_util.h"
+
+uint8_t get_checksum_op_type(rados_checksum_type_t type) {
+ switch (type) {
+ case LIBRADOS_CHECKSUM_TYPE_XXHASH32:
+ return CEPH_OSD_CHECKSUM_OP_TYPE_XXHASH32;
+ case LIBRADOS_CHECKSUM_TYPE_XXHASH64:
+ return CEPH_OSD_CHECKSUM_OP_TYPE_XXHASH64;
+ case LIBRADOS_CHECKSUM_TYPE_CRC32C:
+ return CEPH_OSD_CHECKSUM_OP_TYPE_CRC32C;
+ default:
+ return -1;
+ }
+}
+
+int get_op_flags(int flags)
+{
+ int rados_flags = 0;
+ if (flags & LIBRADOS_OP_FLAG_EXCL)
+ rados_flags |= CEPH_OSD_OP_FLAG_EXCL;
+ if (flags & LIBRADOS_OP_FLAG_FAILOK)
+ rados_flags |= CEPH_OSD_OP_FLAG_FAILOK;
+ if (flags & LIBRADOS_OP_FLAG_FADVISE_RANDOM)
+ rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_RANDOM;
+ if (flags & LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL)
+ rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL;
+ if (flags & LIBRADOS_OP_FLAG_FADVISE_WILLNEED)
+ rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_WILLNEED;
+ if (flags & LIBRADOS_OP_FLAG_FADVISE_DONTNEED)
+ rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_DONTNEED;
+ if (flags & LIBRADOS_OP_FLAG_FADVISE_NOCACHE)
+ rados_flags |= CEPH_OSD_OP_FLAG_FADVISE_NOCACHE;
+ return rados_flags;
+}
+
+int translate_flags(int flags)
+{
+ int op_flags = 0;
+ if (flags & librados::OPERATION_BALANCE_READS)
+ op_flags |= CEPH_OSD_FLAG_BALANCE_READS;
+ if (flags & librados::OPERATION_LOCALIZE_READS)
+ op_flags |= CEPH_OSD_FLAG_LOCALIZE_READS;
+ if (flags & librados::OPERATION_ORDER_READS_WRITES)
+ op_flags |= CEPH_OSD_FLAG_RWORDERED;
+ if (flags & librados::OPERATION_IGNORE_CACHE)
+ op_flags |= CEPH_OSD_FLAG_IGNORE_CACHE;
+ if (flags & librados::OPERATION_SKIPRWLOCKS)
+ op_flags |= CEPH_OSD_FLAG_SKIPRWLOCKS;
+ if (flags & librados::OPERATION_IGNORE_OVERLAY)
+ op_flags |= CEPH_OSD_FLAG_IGNORE_OVERLAY;
+ if (flags & librados::OPERATION_FULL_TRY)
+ op_flags |= CEPH_OSD_FLAG_FULL_TRY;
+ if (flags & librados::OPERATION_FULL_FORCE)
+ op_flags |= CEPH_OSD_FLAG_FULL_FORCE;
+ if (flags & librados::OPERATION_IGNORE_REDIRECT)
+ op_flags |= CEPH_OSD_FLAG_IGNORE_REDIRECT;
+ if (flags & librados::OPERATION_ORDERSNAP)
+ op_flags |= CEPH_OSD_FLAG_ORDERSNAP;
+
+ return op_flags;
+}
--- /dev/null
+#include <cstdint>
+#include "acconfig.h"
+#include "include/rados/librados.h"
+#include "IoCtxImpl.h"
+
+#ifdef WITH_LTTNG
+#include "tracing/librados.h"
+#else
+#define tracepoint(...)
+#endif
+
+uint8_t get_checksum_op_type(rados_checksum_type_t type);
+int get_op_flags(int flags);
+int translate_flags(int flags);
+
+struct librados::ObjListCtx {
+ librados::IoCtxImpl dupctx;
+ librados::IoCtxImpl *ctx;
+ Objecter::NListContext *nlc;
+ bool legacy_list_api;
+
+ ObjListCtx(IoCtxImpl *c, Objecter::NListContext *nl, bool legacy=false)
+ : nlc(nl),
+ legacy_list_api(legacy) {
+ // Get our own private IoCtxImpl so that namespace setting isn't
+ // changed by caller between uses.
+ ctx = &dupctx;
+ dupctx.dup(*c);
+ }
+ ~ObjListCtx() {
+ ctx = NULL;
+ delete nlc;
+ }
+};
RadosStriperImpl.cc
MultiAioCompletionImpl.cc)
add_library(radosstriper ${CEPH_SHARED}
- ${libradosstriper_srcs}
- $<TARGET_OBJECTS:librados_objs>)
+ ${libradosstriper_srcs})
target_link_libraries(radosstriper
- PRIVATE librados cls_lock_client osdc ceph-common pthread ${CRYPTO_LIBS} ${EXTRALIBS})
+ PRIVATE
+ librados-cxx
+ librados_impl cls_lock_client osdc ceph-common
+ pthread ${CRYPTO_LIBS} ${EXTRALIBS})
set_target_properties(radosstriper PROPERTIES
OUPUT_NAME radosstriper
VERSION 1.0.0
rbd_internal
rbd_types
journal
- librados
+ librados-cxx
cls_rbd_client
cls_lock_client
cls_journal_client
rbd_loc.cc
Replayer.cc)
add_library(rbd_replay STATIC ${librbd_replay_srcs})
-target_link_libraries(rbd_replay PRIVATE librbd librados global)
+target_link_libraries(rbd_replay PRIVATE librbd librados-cxx global)
add_executable(rbd-replay
rbd-replay.cc)
target_include_directories(rgw_a SYSTEM PUBLIC "../rapidjson/include")
target_link_libraries(rgw_a PRIVATE
- librados cls_otp_client cls_lock_client cls_rgw_client cls_refcount_client
+ librados-cxx cls_otp_client cls_lock_client cls_rgw_client cls_refcount_client
cls_log_client cls_timeindex_client cls_version_client
cls_user_client ceph-common common_utf8 global
${CURL_LIBRARIES}
add_dependencies(rgw_admin_user civetweb_h)
target_link_libraries(rgw_admin_user PRIVATE
- librados
+ librados-cxx
cls_rgw_client
cls_otp_client
cls_lock_client
add_executable(ceph_test_mutate
test_mutate.cc
)
-target_link_libraries(ceph_test_mutate global librados ${BLKID_LIBRARIES}
+target_link_libraries(ceph_test_mutate global librados-cxx ${BLKID_LIBRARIES}
${CMAKE_DL_LIBS})
# test_trans
${omapbench_srcs}
)
target_link_libraries(ceph_omapbench
- librados
+ librados-cxx
Boost::program_options
global
${BLKID_LIBRARIES}
${CMAKE_SOURCE_DIR}/src/key_value_store/kv_flat_btree_async.cc
)
add_executable(ceph_kvstorebench ${kvstorebench_srcs})
- target_link_libraries(ceph_kvstorebench librados global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
+ target_link_libraries(ceph_kvstorebench librados-cxx global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
install(TARGETS ceph_kvstorebench DESTINATION bin)
endif(WITH_KVS)
add_executable(ceph_multi_stress_watch
multi_stress_watch.cc
)
-target_link_libraries(ceph_multi_stress_watch librados global radostest
+target_link_libraries(ceph_multi_stress_watch librados-cxx global radostest-cxx
${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
#ceph_perf_local
test_stress_watch.cc
)
target_link_libraries(ceph_test_stress_watch
- librados
+ librados-cxx
${UNITTEST_LIBS}
- radostest
+ radostest-cxx
${EXTRALIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
test_cls_hello.cc
)
target_link_libraries(ceph_test_cls_hello
- librados
+ librados-cxx
global
${EXTRALIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
- radostest
+ radostest-cxx
${UNITTEST_LIBS}
)
install(TARGETS
#include "include/rados/librados.hpp"
#include "include/encoding.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
using namespace librados;
$<TARGET_OBJECTS:common_texttable_obj>)
target_link_libraries(ceph_test_cls_journal
cls_journal_client
- librados
+ librados-cxx
global
${UNITTEST_LIBS}
${CMAKE_DL_LIBS}
${CRYPTO_LIBS}
${EXTRALIBS}
- radostest)
+ radostest-cxx)
install(TARGETS
ceph_test_cls_journal
DESTINATION ${CMAKE_INSTALL_BINDIR})
#include "cls/journal/cls_journal_client.h"
#include "include/stringify.h"
#include "common/Cond.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
#include <errno.h>
#include <set>
)
target_link_libraries(ceph_test_cls_lock
cls_lock_client
- librados
+ librados-cxx
global
${UNITTEST_LIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
${CRYPTO_LIBS}
${EXTRALIBS}
- radostest
+ radostest-cxx
)
install(TARGETS
ceph_test_cls_lock
#include "msg/msg_types.h"
#include "include/rados/librados.hpp"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
using namespace librados;
add_executable(ceph_test_cls_log
test_cls_log.cc)
target_link_libraries(ceph_test_cls_log
- librados
+ librados-cxx
cls_log_client
global
- radostest
+ radostest-cxx
${UNITTEST_LIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
#include "global/global_context.h"
#include "gtest/gtest.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include <errno.h>
#include <string>
target_link_libraries(ceph_test_cls_lua
cls_lua_client
liblua
- librados
+ librados-cxx
global
${UNITTEST_LIBS}
${EXTRALIBS}
${CMAKE_DL_LIBS}
- radostest
-)
+ radostest-cxx)
install(TARGETS
ceph_test_cls_lua
DESTINATION ${CMAKE_INSTALL_BINDIR})
#include <errno.h>
#include <lua.hpp>
#include "include/types.h"
-#include "include/rados/librados.h"
+#include "include/rados/librados.hpp"
#include "gtest/gtest.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "cls/lua/cls_lua_client.h"
#include "cls/lua/cls_lua.h"
add_executable(ceph_test_cls_numops
test_cls_numops.cc)
target_link_libraries(ceph_test_cls_numops
- librados
+ librados-cxx
global
cls_numops_client
${EXTRALIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
- radostest
+ radostest-cxx
${UNITTEST_LIBS}
)
install(TARGETS
#include "cls/numops/cls_numops_client.h"
#include "gtest/gtest.h"
#include "include/rados/librados.hpp"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
using namespace librados;
target_link_libraries(ceph_test_cls_rbd
cls_rbd_client
cls_lock_client
- librados
+ librados-cxx
global
${UNITTEST_LIBS}
${CMAKE_DL_LIBS}
${CRYPTO_LIBS}
${EXTRALIBS}
- radostest)
+ radostest-cxx)
install(TARGETS
ceph_test_cls_rbd
DESTINATION ${CMAKE_INSTALL_BINDIR})
#include "librbd/Types.h"
#include "gtest/gtest.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include <errno.h>
#include <string>
test_cls_refcount.cc
)
target_link_libraries(ceph_test_cls_refcount
- librados
+ librados-cxx
cls_refcount_client
global
${UNITTEST_LIBS}
${CMAKE_DL_LIBS}
${CRYPTO_LIBS}
${EXTRALIBS}
- radostest
+ radostest-cxx
)
install(TARGETS
ceph_test_cls_refcount
#include "cls/refcount/cls_refcount_client.h"
#include "gtest/gtest.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include <errno.h>
#include <string>
)
target_link_libraries(ceph_test_cls_rgw
cls_rgw_client
- librados
+ librados-cxx
global
${UNITTEST_LIBS}
${EXTRALIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
- radostest)
+ radostest-cxx)
install(TARGETS
ceph_test_cls_rgw
DESTINATION ${CMAKE_INSTALL_BINDIR})
#include "cls/rgw/cls_rgw_ops.h"
#include "gtest/gtest.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "global/global_context.h"
#include <errno.h>
test_cls_sdk.cc
)
target_link_libraries(ceph_test_cls_sdk
- librados
+ librados-cxx
global
${EXTRALIBS}
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
- radostest
+ radostest-cxx
${UNITTEST_LIBS}
)
install(TARGETS
#include <iostream>
#include <errno.h>
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
using namespace librados;
test_cls_version.cc
)
target_link_libraries(ceph_test_cls_version
- librados
+ librados-cxx
cls_version_client
global
${UNITTEST_LIBS}
${CMAKE_DL_LIBS}
${CRYPTO_LIBS}
${EXTRALIBS}
- radostest
+ radostest-cxx
)
// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include "include/rados/librados.hpp"
#include "include/types.h"
+
#include "cls/version/cls_version_types.h"
#include "cls/version/cls_version_client.h"
#include "gtest/gtest.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include <errno.h>
#include <string>
cls_journal_client
rados_test_stub
librados
- radostest
+ radostest-cxx
global
)
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include "test/librados/test_cxx.h"
#include "test/journal/RadosTestFixture.h"
#include "cls/journal/cls_journal_client.h"
#include "include/stringify.h"
# radostest
-add_library(libradostest_obj OBJECT test.cc)
-target_include_directories(libradostest_obj PRIVATE
+add_library(radostest_shared OBJECT test_shared.cc)
+target_include_directories(radostest_shared PRIVATE
$<TARGET_PROPERTY:GTest::GTest,INTERFACE_INCLUDE_DIRECTORIES>)
-set(libradostest_srcs
- test_common.cc
- TestCase.cc)
+
add_library(radostest STATIC
- ${libradostest_srcs}
- $<TARGET_OBJECTS:libradostest_obj>)
-target_link_libraries(radostest
+ test_common.cc
+ TestCase.cc
+ test.cc
+ $<TARGET_OBJECTS:radostest_shared>)
+target_link_libraries(radostest PUBLIC
GTest::GTest
- librados
ceph-common
json_spirit
${EXTRALIBS})
-
+add_library(radostest-cxx STATIC
+ testcase_cxx.cc
+ test_cxx.cc
+ $<TARGET_OBJECTS:radostest_shared>)
+target_link_libraries(radostest-cxx PUBLIC
+ GTest::GTest
+ ceph-common)
add_executable(ceph_test_rados_api_cmd
cmd.cc)
target_link_libraries(ceph_test_rados_api_cmd
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_cmd_pp
+ cmd_cxx.cc)
+target_link_libraries(ceph_test_rados_api_cmd_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_io
io.cc)
target_link_libraries(ceph_test_rados_api_io
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_io_pp
+ io_cxx.cc)
+target_link_libraries(ceph_test_rados_api_io_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_c_write_operations
c_write_operations.cc)
aio.cc)
target_link_libraries(ceph_test_rados_api_aio
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_aio_pp
+ aio_cxx.cc)
+target_link_libraries(ceph_test_rados_api_aio_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_asio asio.cc)
target_link_libraries(ceph_test_rados_api_asio global
- librados ${UNITTEST_LIBS})
+ librados-cxx ${UNITTEST_LIBS})
if(WITH_BOOST_CONTEXT)
target_link_libraries(ceph_test_rados_api_asio Boost::coroutine Boost::context)
endif()
stat.cc)
target_link_libraries(ceph_test_rados_api_stat
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_stat_pp
+ stat_cxx.cc)
+target_link_libraries(ceph_test_rados_api_stat_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_watch_notify
watch_notify.cc)
target_link_libraries(ceph_test_rados_api_watch_notify
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_watch_notify_pp
+ watch_notify_cxx.cc)
+target_link_libraries(ceph_test_rados_api_watch_notify_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_cls
cls.cc)
target_link_libraries(ceph_test_rados_api_cls
- librados ${UNITTEST_LIBS} radostest)
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_misc
misc.cc
$<TARGET_OBJECTS:unit-main>)
target_link_libraries(ceph_test_rados_api_misc
librados global ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_misc_pp
+ misc_cxx.cc
+ $<TARGET_OBJECTS:unit-main>)
+target_link_libraries(ceph_test_rados_api_misc_pp
+ librados-cxx global ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_lock
lock.cc)
target_link_libraries(ceph_test_rados_api_lock
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_lock_pp
+ lock_cxx.cc)
+target_link_libraries(ceph_test_rados_api_lock_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
add_executable(ceph_test_rados_api_service
service.cc)
target_link_libraries(ceph_test_rados_api_service
librados global ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_service_pp
+ service_cxx.cc)
+target_link_libraries(ceph_test_rados_api_service_pp
+ librados-cxx global ${UNITTEST_LIBS} radostest-cxx)
-add_executable(ceph_test_rados_api_tier
- tier.cc
+add_executable(ceph_test_rados_api_tier_pp
+ tier_cxx.cc
$<TARGET_OBJECTS:unit-main>)
-target_link_libraries(ceph_test_rados_api_tier
- librados global ${UNITTEST_LIBS} Boost::system radostest)
+target_link_libraries(ceph_test_rados_api_tier_pp
+ librados-cxx global ${UNITTEST_LIBS} Boost::system radostest-cxx)
add_executable(ceph_test_rados_api_snapshots
snapshots.cc)
target_link_libraries(ceph_test_rados_api_snapshots
librados ${UNITTEST_LIBS} radostest)
+add_executable(ceph_test_rados_api_snapshots_pp
+ snapshots_cxx.cc)
+target_link_libraries(ceph_test_rados_api_snapshots_pp
+ librados-cxx ${UNITTEST_LIBS} radostest-cxx)
install(TARGETS
ceph_test_rados_api_aio
+ ceph_test_rados_api_aio_pp
ceph_test_rados_api_asio
ceph_test_rados_api_c_read_operations
ceph_test_rados_api_c_write_operations
ceph_test_rados_api_cmd
+ ceph_test_rados_api_cmd_pp
ceph_test_rados_api_io
+ ceph_test_rados_api_io_pp
ceph_test_rados_api_list
ceph_test_rados_api_lock
+ ceph_test_rados_api_lock_pp
ceph_test_rados_api_misc
+ ceph_test_rados_api_misc_pp
ceph_test_rados_api_pool
ceph_test_rados_api_service
+ ceph_test_rados_api_service_pp
ceph_test_rados_api_snapshots
+ ceph_test_rados_api_snapshots_pp
ceph_test_rados_api_stat
- ceph_test_rados_api_tier
+ ceph_test_rados_api_stat_pp
+ ceph_test_rados_api_tier_pp
ceph_test_rados_api_watch_notify
+ ceph_test_rados_api_watch_notify_pp
DESTINATION ${CMAKE_INSTALL_BINDIR})
# unittest_librados
#include "test/librados/TestCase.h"
#include "include/scope_guard.h"
-using namespace librados;
std::string RadosTestNS::pool_name;
rados_t RadosTestNS::s_cluster = NULL;
-namespace {
-
-void init_rand() {
- static bool seeded = false;
- if (!seeded) {
- seeded = true;
- int seed = getpid();
- std::cout << "seed " << seed << std::endl;
- srand(seed);
- }
-}
-
-} // anonymous namespace
void RadosTestNS::SetUpTestCase()
{
}
}
-std::string RadosTestPPNS::pool_name;
-Rados RadosTestPPNS::s_cluster;
-
-void RadosTestPPNS::SetUpTestCase()
-{
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestPPNS::TearDownTestCase()
-{
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestPPNS::SetUp()
-{
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
- bool requires;
- ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
- ASSERT_FALSE(requires);
-}
-
-void RadosTestPPNS::TearDown()
-{
- if (cleanup)
- cleanup_all_objects(ioctx);
- ioctx.close();
-}
-
-void RadosTestPPNS::cleanup_all_objects(librados::IoCtx ioctx)
-{
- // remove all objects to avoid polluting other tests
- ioctx.snap_set_read(librados::SNAP_HEAD);
- ioctx.set_namespace(all_nspaces);
- for (NObjectIterator it = ioctx.nobjects_begin();
- it != ioctx.nobjects_end(); ++it) {
- ioctx.locator_set_key(it->get_locator());
- ioctx.set_namespace(it->get_nspace());
- ASSERT_EQ(0, ioctx.remove(it->get_oid()));
- }
-}
-
-std::string RadosTestParamPPNS::pool_name;
-std::string RadosTestParamPPNS::cache_pool_name;
-Rados RadosTestParamPPNS::s_cluster;
-
-void RadosTestParamPPNS::SetUpTestCase()
-{
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestParamPPNS::TearDownTestCase()
-{
- if (cache_pool_name.length()) {
- // tear down tiers
- bufferlist inbl;
- ASSERT_EQ(0, s_cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, s_cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, s_cluster.mon_command(
- "{\"prefix\": \"osd pool delete\", \"pool\": \"" + cache_pool_name +
- "\", \"pool2\": \"" + cache_pool_name + "\", \"sure\": \"--yes-i-really-really-mean-it\"}",
- inbl, NULL, NULL));
- cache_pool_name = "";
- }
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestParamPPNS::SetUp()
-{
- if (strcmp(GetParam(), "cache") == 0 && cache_pool_name.empty()) {
- cache_pool_name = get_temp_pool_name();
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd pool create\", \"pool\": \"" + cache_pool_name +
- "\", \"pg_num\": 4}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
- cluster.wait_for_latest_osdmap();
- }
-
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
- bool requires;
- ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
- ASSERT_FALSE(requires);
-}
-
-void RadosTestParamPPNS::TearDown()
-{
- if (cleanup)
- cleanup_all_objects(ioctx);
- ioctx.close();
-}
-
-void RadosTestParamPPNS::cleanup_all_objects(librados::IoCtx ioctx)
-{
- // remove all objects to avoid polluting other tests
- ioctx.snap_set_read(librados::SNAP_HEAD);
- ioctx.set_namespace(all_nspaces);
- for (NObjectIterator it = ioctx.nobjects_begin();
- it != ioctx.nobjects_end(); ++it) {
- ioctx.locator_set_key(it->get_locator());
- ioctx.set_namespace(it->get_nspace());
- ASSERT_EQ(0, ioctx.remove(it->get_oid()));
- }
-}
-
std::string RadosTestECNS::pool_name;
rados_t RadosTestECNS::s_cluster = NULL;
rados_ioctx_destroy(ioctx);
}
-std::string RadosTestECPPNS::pool_name;
-Rados RadosTestECPPNS::s_cluster;
-
-void RadosTestECPPNS::SetUpTestCase()
-{
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestECPPNS::TearDownTestCase()
-{
- ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestECPPNS::SetUp()
-{
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
- bool requires;
- ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
- ASSERT_TRUE(requires);
- ASSERT_EQ(0, ioctx.pool_required_alignment2(&alignment));
- ASSERT_NE(0U, alignment);
-}
-
-void RadosTestECPPNS::TearDown()
-{
- if (cleanup)
- cleanup_all_objects(ioctx);
- ioctx.close();
-}
-
std::string RadosTest::pool_name;
rados_t RadosTest::s_cluster = NULL;
}
}
-std::string RadosTestPP::pool_name;
-Rados RadosTestPP::s_cluster;
-
-void RadosTestPP::SetUpTestCase()
-{
- init_rand();
-
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestPP::TearDownTestCase()
-{
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestPP::SetUp()
-{
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
- nspace = get_temp_pool_name();
- ioctx.set_namespace(nspace);
- bool requires;
- ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
- ASSERT_FALSE(requires);
-}
-
-void RadosTestPP::TearDown()
-{
- if (cleanup) {
- cleanup_default_namespace(ioctx);
- cleanup_namespace(ioctx, nspace);
- }
- ioctx.close();
-}
-
-void RadosTestPP::cleanup_default_namespace(librados::IoCtx ioctx)
-{
- // remove all objects from the default namespace to avoid polluting
- // other tests
- cleanup_namespace(ioctx, "");
-}
-
-void RadosTestPP::cleanup_namespace(librados::IoCtx ioctx, std::string ns)
-{
- ioctx.snap_set_read(librados::SNAP_HEAD);
- ioctx.set_namespace(ns);
- int tries = 600;
- while (--tries) {
- int got_enoent = 0;
- for (NObjectIterator it = ioctx.nobjects_begin();
- it != ioctx.nobjects_end(); ++it) {
- ioctx.locator_set_key(it->get_locator());
- ObjectWriteOperation op;
- op.remove();
- librados::AioCompletion *completion = s_cluster.aio_create_completion();
- auto sg = make_scope_guard([&] { completion->release(); });
- ASSERT_EQ(0, ioctx.aio_operate(it->get_oid(), completion, &op,
- librados::OPERATION_IGNORE_CACHE));
- completion->wait_for_safe();
- if (completion->get_return_value() == -ENOENT) {
- ++got_enoent;
- std::cout << " got ENOENT removing " << it->get_oid() << std::endl;
- } else {
- ASSERT_EQ(0, completion->get_return_value());
- }
- }
- if (!got_enoent) {
- break;
- }
- std::cout << " got ENOENT on " << got_enoent
- << " objects, waiting a bit for snap"
- << " trimming before retrying " << tries << " more times..."
- << std::endl;
- sleep(1);
- }
- if (tries == 0) {
- std::cout << "failed to clean up" << std::endl;
- ASSERT_TRUE(false);
- }
-}
-
-std::string RadosTestParamPP::pool_name;
-std::string RadosTestParamPP::cache_pool_name;
-Rados RadosTestParamPP::s_cluster;
-
-void RadosTestParamPP::SetUpTestCase()
-{
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestParamPP::TearDownTestCase()
-{
- if (cache_pool_name.length()) {
- // tear down tiers
- bufferlist inbl;
- ASSERT_EQ(0, s_cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, s_cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, s_cluster.mon_command(
- "{\"prefix\": \"osd pool delete\", \"pool\": \"" + cache_pool_name +
- "\", \"pool2\": \"" + cache_pool_name + "\", \"sure\": \"--yes-i-really-really-mean-it\"}",
- inbl, NULL, NULL));
- cache_pool_name = "";
- }
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestParamPP::SetUp()
-{
- if (strcmp(GetParam(), "cache") == 0 && cache_pool_name.empty()) {
- cache_pool_name = get_temp_pool_name();
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd pool create\", \"pool\": \"" + cache_pool_name +
- "\", \"pg_num\": 4}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
- cluster.wait_for_latest_osdmap();
- }
-
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
- nspace = get_temp_pool_name();
- ioctx.set_namespace(nspace);
- bool requires;
- ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
- ASSERT_FALSE(requires);
-}
-
-void RadosTestParamPP::TearDown()
-{
- if (cleanup) {
- cleanup_default_namespace(ioctx);
- cleanup_namespace(ioctx, nspace);
- }
- ioctx.close();
-}
-
-void RadosTestParamPP::cleanup_default_namespace(librados::IoCtx ioctx)
-{
- // remove all objects from the default namespace to avoid polluting
- // other tests
- cleanup_namespace(ioctx, "");
-}
-
-void RadosTestParamPP::cleanup_namespace(librados::IoCtx ioctx, std::string ns)
-{
- ioctx.snap_set_read(librados::SNAP_HEAD);
- ioctx.set_namespace(ns);
- for (NObjectIterator it = ioctx.nobjects_begin();
- it != ioctx.nobjects_end(); ++it) {
- ioctx.locator_set_key(it->get_locator());
- ASSERT_EQ(0, ioctx.remove(it->get_oid()));
- }
-}
-
std::string RadosTestEC::pool_name;
rados_t RadosTestEC::s_cluster = NULL;
rados_ioctx_destroy(ioctx);
}
-std::string RadosTestECPP::pool_name;
-Rados RadosTestECPP::s_cluster;
-
-void RadosTestECPP::SetUpTestCase()
-{
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestECPP::TearDownTestCase()
-{
- ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
-}
-
-void RadosTestECPP::SetUp()
-{
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
- nspace = get_temp_pool_name();
- ioctx.set_namespace(nspace);
- bool requires;
- ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
- ASSERT_TRUE(requires);
- ASSERT_EQ(0, ioctx.pool_required_alignment2(&alignment));
- ASSERT_NE(0U, alignment);
-}
-
-void RadosTestECPP::TearDown()
-{
- if (cleanup) {
- cleanup_default_namespace(ioctx);
- cleanup_namespace(ioctx, nspace);
- }
- ioctx.close();
-}
-
#define CEPH_TEST_RADOS_TESTCASE_H
#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
#include "gtest/gtest.h"
#include <string>
RadosTestNSCleanup() : RadosTestNS(true) {}
};
-class RadosTestPPNS : public ::testing::Test {
-public:
- RadosTestPPNS(bool c=false) : cluster(s_cluster), cleanup(c) {}
- ~RadosTestPPNS() override {}
-protected:
- static void SetUpTestCase();
- static void TearDownTestCase();
- static void cleanup_all_objects(librados::IoCtx ioctx);
- static librados::Rados s_cluster;
- static std::string pool_name;
-
- void SetUp() override;
- void TearDown() override;
- librados::Rados &cluster;
- librados::IoCtx ioctx;
- bool cleanup;
-};
-
-struct RadosTestPPNSCleanup : public RadosTestPPNS {
- RadosTestPPNSCleanup() : RadosTestPPNS(true) {}
-};
-
-class RadosTestParamPPNS : public ::testing::TestWithParam<const char*> {
-public:
- RadosTestParamPPNS(bool c=false) : cluster(s_cluster), cleanup(c) {}
- ~RadosTestParamPPNS() override {}
- static void SetUpTestCase();
- static void TearDownTestCase();
-protected:
- static void cleanup_all_objects(librados::IoCtx ioctx);
- static librados::Rados s_cluster;
- static std::string pool_name;
- static std::string cache_pool_name;
-
- void SetUp() override;
- void TearDown() override;
- librados::Rados &cluster;
- librados::IoCtx ioctx;
- bool cleanup;
-};
-
class RadosTestECNS : public RadosTestNS {
public:
RadosTestECNS(bool c=false) : cleanup(c) {}
RadosTestECNSCleanup() : RadosTestECNS(true) {}
};
-class RadosTestECPPNS : public RadosTestPPNS {
-public:
- RadosTestECPPNS(bool c=false) : cluster(s_cluster), cleanup(c) {}
- ~RadosTestECPPNS() override {}
-protected:
- static void SetUpTestCase();
- static void TearDownTestCase();
- static librados::Rados s_cluster;
- static std::string pool_name;
-
- void SetUp() override;
- void TearDown() override;
- librados::Rados &cluster;
- librados::IoCtx ioctx;
- uint64_t alignment = 0;
- bool cleanup;
-};
-
-struct RadosTestECPPNSCleanup : public RadosTestECPPNS {
- RadosTestECPPNSCleanup() : RadosTestECPPNS(true) {}
-};
-
/**
* These test cases create a temporary pool that lives as long as the
* test case. Each test within a test case gets a new ioctx set to a
bool cleanup;
};
-class RadosTestPP : public ::testing::Test {
-public:
- RadosTestPP(bool c=false) : cluster(s_cluster), cleanup(c) {}
- ~RadosTestPP() override {}
-protected:
- static void SetUpTestCase();
- static void TearDownTestCase();
- static void cleanup_default_namespace(librados::IoCtx ioctx);
- static void cleanup_namespace(librados::IoCtx ioctx, std::string ns);
- static librados::Rados s_cluster;
- static std::string pool_name;
-
- void SetUp() override;
- void TearDown() override;
- librados::Rados &cluster;
- librados::IoCtx ioctx;
- bool cleanup;
- std::string nspace;
-};
-
-class RadosTestParamPP : public ::testing::TestWithParam<const char*> {
-public:
- RadosTestParamPP(bool c=false) : cluster(s_cluster), cleanup(c) {}
- ~RadosTestParamPP() override {}
- static void SetUpTestCase();
- static void TearDownTestCase();
-protected:
- static void cleanup_default_namespace(librados::IoCtx ioctx);
- static void cleanup_namespace(librados::IoCtx ioctx, std::string ns);
- static librados::Rados s_cluster;
- static std::string pool_name;
- static std::string cache_pool_name;
-
- void SetUp() override;
- void TearDown() override;
- librados::Rados &cluster;
- librados::IoCtx ioctx;
- bool cleanup;
- std::string nspace;
-};
-
class RadosTestEC : public RadosTest {
public:
RadosTestEC(bool c=false) : cleanup(c) {}
uint64_t alignment = 0;
};
-class RadosTestECPP : public RadosTestPP {
-public:
- RadosTestECPP(bool c=false) : cluster(s_cluster), cleanup(c) {}
- ~RadosTestECPP() override {}
-protected:
- static void SetUpTestCase();
- static void TearDownTestCase();
- static librados::Rados s_cluster;
- static std::string pool_name;
-
- void SetUp() override;
- void TearDown() override;
- librados::Rados &cluster;
- librados::IoCtx ioctx;
- bool cleanup;
- std::string nspace;
- uint64_t alignment = 0;
-};
-
/**
* Test case without creating a temporary pool in advance.
* This is necessary for scenarios such that we need to
-#include "common/errno.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <boost/scoped_ptr.hpp>
+
#include "include/err.h"
#include "include/rados/librados.h"
-#include "test/librados/test.h"
#include "include/types.h"
#include "include/stringify.h"
#include "include/scope_guard.h"
+#include "common/errno.h"
+
#include "gtest/gtest.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sstream>
-#include <string>
-#include <boost/scoped_ptr.hpp>
-#include <utility>
+
+#include "test.h"
using std::ostringstream;
-using namespace librados;
-using std::pair;
class AioTestData
{
bool m_init;
};
-class AioTestDataPP
-{
-public:
- AioTestDataPP()
- : m_init(false)
- {
- }
-
- ~AioTestDataPP()
- {
- if (m_init) {
- m_ioctx.close();
- destroy_one_pool_pp(m_pool_name, m_cluster);
- }
- }
-
- std::string init()
- {
- return init({});
- }
-
- std::string init(const std::map<std::string, std::string> &config)
- {
- int ret;
-
- m_pool_name = get_temp_pool_name();
- std::string err = create_one_pool_pp(m_pool_name, m_cluster, config);
- if (!err.empty()) {
- ostringstream oss;
- oss << "create_one_pool(" << m_pool_name << ") failed: error " << err;
- return oss.str();
- }
- ret = m_cluster.ioctx_create(m_pool_name.c_str(), m_ioctx);
- if (ret) {
- destroy_one_pool_pp(m_pool_name, m_cluster);
- ostringstream oss;
- oss << "rados_ioctx_create failed: error " << ret;
- return oss.str();
- }
- m_init = true;
- return "";
- }
-
- Rados m_cluster;
- IoCtx m_ioctx;
- std::string m_pool_name;
- bool m_init;
-};
-
TEST(LibRadosAio, TooBig) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion);
}
-TEST(LibRadosAio, TooBigPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
-
- bufferlist bl;
- AioCompletion *aio_completion = test_data.m_cluster.aio_create_completion(
- nullptr, NULL, NULL);
- ASSERT_EQ(-E2BIG, test_data.m_ioctx.aio_write("foo", aio_completion, bl, UINT_MAX, 0));
- ASSERT_EQ(-E2BIG, test_data.m_ioctx.aio_append("foo", aio_completion, bl, UINT_MAX));
- // ioctx.aio_write_full no way to overflow bl.length()
- delete aio_completion;
-}
-
-TEST(LibRadosAio, PoolQuotaPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- string p = get_temp_pool_name();
- ASSERT_EQ(0, test_data.m_cluster.pool_create(p.c_str()));
- IoCtx ioctx;
- ASSERT_EQ(0, test_data.m_cluster.ioctx_create(p.c_str(), ioctx));
- ioctx.application_enable("rados", true);
-
- bufferlist inbl;
- ASSERT_EQ(0, test_data.m_cluster.mon_command(
- "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" + p +
- "\", \"field\": \"max_bytes\", \"val\": \"4096\"}",
- inbl, NULL, NULL));
-
- bufferlist bl;
- bufferptr z(4096);
- bl.append(z);
- int n;
- for (n = 0; n < 1024; ++n) {
- ObjectWriteOperation op;
- op.write_full(bl);
- librados::AioCompletion *completion =
- test_data.m_cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo" + stringify(n), completion, &op,
- librados::OPERATION_FULL_TRY));
- completion->wait_for_safe();
- int r = completion->get_return_value();
- completion->release();
- if (r == -EDQUOT)
- break;
- ASSERT_EQ(0, r);
- sleep(1);
- }
- ASSERT_LT(n, 1024);
-
- // make sure we have latest map that marked the pool full
- test_data.m_cluster.wait_for_latest_osdmap();
-
- // make sure we block without FULL_TRY
- {
- ObjectWriteOperation op;
- op.write_full(bl);
- librados::AioCompletion *completion =
- test_data.m_cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op, 0));
- sleep(5);
- ASSERT_FALSE(completion->is_safe());
- completion->release();
- }
-
- ioctx.close();
- ASSERT_EQ(0, test_data.m_cluster.pool_delete(p.c_str()));
-}
-
TEST(LibRadosAio, SimpleWrite) {
AioTestData test_data;
rados_completion_t my_completion;
ASSERT_EQ(0, rados_aio_get_return_value(my_completion2));
}
-TEST(LibRadosAio, SimpleWritePP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
- my_completion, bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- delete my_completion;
- }
-
- {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- test_data.m_ioctx.set_namespace("nspace");
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
- my_completion, bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- delete my_completion;
- }
-}
-
TEST(LibRadosAio, WaitForSafe) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion);
}
-TEST(LibRadosAio, WaitForSafePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
- my_completion, bl1, sizeof(buf), 0));
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_safe());
- ASSERT_EQ(0, my_completion->get_return_value());
- delete my_completion;
-}
-
TEST(LibRadosAio, RoundTrip) {
AioTestData test_data;
rados_completion_t my_completion;
ASSERT_EQ(bl.crc32c(-1), checksum[1]);
}
-TEST(LibRadosAio, RoundTripPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
- my_completion2, &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
-TEST(LibRadosAio, RoundTripPP2) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
- my_completion2, &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_safe());
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
-//using ObjectWriteOperation/ObjectReadOperation with iohint
-TEST(LibRadosAio, RoundTripPP3)
-{
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- op.write(0, bl);
- op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", my_completion1.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion1->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion1->get_return_value());
-
- boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
- bl.clear();
- ObjectReadOperation op1;
- op1.read(0, sizeof(buf), &bl, NULL);
- op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- bufferlist init_value_bl;
- encode(static_cast<int32_t>(-1), init_value_bl);
- bufferlist csum_bl;
- op1.checksum(LIBRADOS_CHECKSUM_TYPE_CRC32C, init_value_bl,
- 0, 0, 0, &csum_bl, nullptr);
- ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
-
- ASSERT_EQ(8U, csum_bl.length());
- auto csum_bl_it = csum_bl.cbegin();
- uint32_t csum_count;
- uint32_t csum;
- decode(csum_count, csum_bl_it);
- ASSERT_EQ(1U, csum_count);
- decode(csum, csum_bl_it);
- ASSERT_EQ(bl.crc32c(-1), csum);
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
-TEST(LibRadosAio, RoundTripSparseReadPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- std::map<uint64_t, uint64_t> extents;
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_sparse_read("foo",
- my_completion2, &extents, &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- assert_eq_sparse(bl1, extents, bl2);
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAio, RoundTripAppend) {
AioTestData test_data;
rados_completion_t my_completion, my_completion2, my_completion3;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAio, RoundTripAppendPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion,
- bl1, sizeof(buf)));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- char buf2[128];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion2,
- bl2, sizeof(buf2)));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- bufferlist bl3;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
- my_completion3, &bl3, 2 * sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)(sizeof(buf) * 2), my_completion3->get_return_value());
- ASSERT_EQ(sizeof(buf) * 2, bl3.length());
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2)));
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
TEST(LibRadosAio, RemoveTest) {
char buf[128];
char buf2[sizeof(buf)];
rados_aio_release(my_completion);
}
-TEST(LibRadosAioPP, RemoveTestPP) {
- char buf[128];
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
- boost::scoped_ptr<AioCompletion> my_completion
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion.get()));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- ASSERT_EQ(-ENOENT, test_data.m_ioctx.read("foo", bl2, sizeof(buf), 0));
-}
-
TEST(LibRadosAio, XattrsRoundTrip) {
char buf[128];
char attr1[] = "attr1";
ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
}
-TEST(LibRadosAioPP, XattrsRoundTripPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- // async getxattr
- boost::scoped_ptr<AioCompletion> my_completion
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_getxattr("foo", my_completion.get(), attr1, bl2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(-ENODATA, my_completion->get_return_value());
- // append
- bufferlist bl3;
- bl3.append(attr1_buf, sizeof(attr1_buf));
- // async setxattr
- AioTestDataPP test_data2;
- ASSERT_EQ("", test_data2.init());
- boost::scoped_ptr<AioCompletion> my_completion2
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_setxattr("foo", my_completion2.get(), attr1, bl3));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- // async getxattr
- bufferlist bl4;
- AioTestDataPP test_data3;
- ASSERT_EQ("", test_data3.init());
- boost::scoped_ptr<AioCompletion> my_completion3
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_getxattr("foo", my_completion3.get(), attr1, bl4));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(attr1_buf), my_completion3->get_return_value());
- // check content of attribute
- ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
-}
-
TEST(LibRadosAio, RmXattr) {
char buf[128];
char attr1[] = "attr1";
rados_aio_release(my_completion5);
}
-TEST(LibRadosAioPP, RmXattrPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
- // async setxattr
- bufferlist bl2;
- bl2.append(attr1_buf, sizeof(attr1_buf));
- boost::scoped_ptr<AioCompletion> my_completion
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_setxattr("foo", my_completion.get(), attr1, bl2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- // async rmxattr
- AioTestDataPP test_data2;
- ASSERT_EQ("", test_data2.init());
- boost::scoped_ptr<AioCompletion> my_completion2
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_rmxattr("foo", my_completion2.get(), attr1));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- // async getxattr
- AioTestDataPP test_data3;
- ASSERT_EQ("", test_data3.init());
- boost::scoped_ptr<AioCompletion> my_completion3
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- bufferlist bl3;
- ASSERT_EQ(0, test_data.m_ioctx.aio_getxattr("foo", my_completion3.get(), attr1, bl3));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ(-ENODATA, my_completion3->get_return_value());
- // Test rmxattr on a removed object
- char buf2[128];
- char attr2[] = "attr2";
- char attr2_buf[] = "foo bar baz";
- memset(buf2, 0xbb, sizeof(buf2));
- bufferlist bl21;
- bl21.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
- bufferlist bl22;
- bl22.append(attr2_buf, sizeof(attr2_buf));
- // async setxattr
- AioTestDataPP test_data4;
- ASSERT_EQ("", test_data4.init());
- boost::scoped_ptr<AioCompletion> my_completion4
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_setxattr("foo_rmxattr", my_completion4.get(), attr2, bl22));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion4->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion4->get_return_value());
- // remove object
- ASSERT_EQ(0, test_data.m_ioctx.remove("foo_rmxattr"));
- // async rmxattr on non existing object
- AioTestDataPP test_data5;
- ASSERT_EQ("", test_data5.init());
- boost::scoped_ptr<AioCompletion> my_completion5
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_rmxattr("foo_rmxattr", my_completion5.get(), attr2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion5->wait_for_complete());
- }
- ASSERT_EQ(-ENOENT, my_completion5->get_return_value());
-}
-
TEST(LibRadosAio, XattrIter) {
AioTestData test_data;
ASSERT_EQ("", test_data.init());
ASSERT_EQ(0, rados_setxattr(test_data.m_ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf)));
// call async version of getxattrs and wait for completion
rados_completion_t my_completion;
- ASSERT_EQ(0, rados_aio_create_completion(nullptr,
+ ASSERT_EQ(0, rados_aio_create_completion((void*)&test_data,
nullptr, nullptr, &my_completion));
rados_xattrs_iter_t iter;
ASSERT_EQ(0, rados_aio_getxattrs(test_data.m_ioctx, "foo", my_completion, &iter));
rados_getxattrs_end(iter);
}
-TEST(LibRadosIoPP, XattrListPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- // create an object with 2 attributes
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- char attr2[] = "attr2";
- char attr2_buf[256];
- for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
- attr2_buf[j] = j % 0xff;
- }
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- bl2.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, test_data.m_ioctx.setxattr("foo", attr1, bl2));
- bufferlist bl3;
- bl3.append(attr2_buf, sizeof(attr2_buf));
- ASSERT_EQ(0, test_data.m_ioctx.setxattr("foo", attr2, bl3));
- // call async version of getxattrs
- boost::scoped_ptr<AioCompletion> my_completion
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- std::map<std::string, bufferlist> attrset;
- ASSERT_EQ(0, test_data.m_ioctx.aio_getxattrs("foo", my_completion.get(), attrset));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
- i != attrset.end(); ++i) {
- if (i->first == string(attr1)) {
- ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
- }
- else if (i->first == string(attr2)) {
- ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
- }
- else {
- ASSERT_EQ(0, 1);
- }
- }
-}
-
TEST(LibRadosAio, IsComplete) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAio, IsCompletePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
-
- // Busy-wait until the AIO completes.
- // Normally we wouldn't do this, but we want to test is_complete.
- while (true) {
- int is_complete = my_completion2->is_complete();
- if (is_complete)
- break;
- }
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAio, IsSafe) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAio, IsSafePP) {
- AioTestDataPP test_data;
+TEST(LibRadosAio, ReturnValue) {
+ AioTestData test_data;
+ rados_completion_t my_completion;
ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
-
- // Busy-wait until the AIO completes.
- // Normally we wouldn't do this, but we want to test rados_aio_is_safe.
- while (true) {
- int is_safe = my_completion->is_safe();
- if (is_safe)
- break;
- }
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- bufferlist bl2;
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
-TEST(LibRadosAio, ReturnValue) {
- AioTestData test_data;
- rados_completion_t my_completion;
- ASSERT_EQ("", test_data.init());
- ASSERT_EQ(0, rados_aio_create_completion(nullptr,
- nullptr, nullptr, &my_completion));
+ ASSERT_EQ(0, rados_aio_create_completion(nullptr,
+ nullptr, nullptr, &my_completion));
char buf[128];
memset(buf, 0, sizeof(buf));
ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "nonexistent",
rados_aio_release(my_completion);
}
-TEST(LibRadosAio, ReturnValuePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- bufferlist bl1;
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("nonexistent",
- my_completion, &bl1, 128, 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(-ENOENT, my_completion->get_return_value());
- delete my_completion;
-}
-
TEST(LibRadosAio, Flush) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAio, FlushPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xee, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- ASSERT_EQ(0, test_data.m_ioctx.aio_flush());
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAio, FlushAsync) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(flush_completion);
}
-TEST(LibRadosAio, FlushAsyncPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *flush_completion =
- test_data.m_cluster.aio_create_completion(NULL, NULL, NULL);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xee, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- ASSERT_EQ(0, test_data.m_ioctx.aio_flush_async(flush_completion));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, flush_completion->wait_for_complete());
- ASSERT_EQ(0, flush_completion->wait_for_safe());
- }
- ASSERT_EQ(1, my_completion->is_complete());
- ASSERT_EQ(1, my_completion->is_safe());
- ASSERT_EQ(1, flush_completion->is_complete());
- ASSERT_EQ(1, flush_completion->is_safe());
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
- delete flush_completion;
-}
-
TEST(LibRadosAio, RoundTripWriteFull) {
AioTestData test_data;
rados_completion_t my_completion, my_completion2, my_completion3;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAio, RoundTripWriteFullPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- char buf2[64];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write_full("foo", my_completion2, bl2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- bufferlist bl3;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
- &bl3, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf2), my_completion3->get_return_value());
- ASSERT_EQ(sizeof(buf2), bl3.length());
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
-//using ObjectWriteOperation/ObjectReadOperation with iohint
-TEST(LibRadosAio, RoundTripWriteFullPP2)
-{
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf);
-
- op.write_full(bl);
- op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", my_completion1.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion1->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion1->get_return_value());
-
- boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
- bl.clear();
- ObjectReadOperation op1;
- op1.read(0, sizeof(buf), &bl, NULL);
- op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
-
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
TEST(LibRadosAio, RoundTripWriteSame) {
AioTestData test_data;
rados_completion_t my_completion, my_completion2, my_completion3;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAio, RoundTripWriteSamePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char full[128];
- memset(full, 0xcc, sizeof(full));
- bufferlist bl1;
- bl1.append(full, sizeof(full));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(full), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- /* write the same buf four times */
- char buf[32];
- size_t ws_write_len = sizeof(full);
- memset(buf, 0xdd, sizeof(buf));
- bufferlist bl2;
- bl2.append(buf, sizeof(buf));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_writesame("foo", my_completion2, bl2,
- ws_write_len, 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- bufferlist bl3;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
- &bl3, sizeof(full), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(full), my_completion3->get_return_value());
- ASSERT_EQ(sizeof(full), bl3.length());
- for (char *cmp = bl3.c_str(); cmp < bl3.c_str() + bl3.length();
- cmp += sizeof(buf)) {
- ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
- }
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
-TEST(LibRadosAio, RoundTripWriteSamePP2)
-{
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- boost::scoped_ptr<AioCompletion>
- wr_cmpl(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- op.writesame(0, sizeof(buf) * 4, bl);
- op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", wr_cmpl.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, wr_cmpl->wait_for_complete());
- }
- EXPECT_EQ(0, wr_cmpl->get_return_value());
-
- boost::scoped_ptr<AioCompletion>
- rd_cmpl(cluster.aio_create_completion(0, 0, 0));
- char *cmp;
- char full[sizeof(buf) * 4];
- memset(full, 0, sizeof(full));
- bufferlist fl;
- fl.append(full, sizeof(full));
- ObjectReadOperation op1;
- op1.read(0, sizeof(full), &fl, NULL);
- op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", rd_cmpl.get(), &op1, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, rd_cmpl->wait_for_complete());
- }
- EXPECT_EQ(0, rd_cmpl->get_return_value());
- for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) {
- ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
- }
-
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
TEST(LibRadosAio, SimpleStat) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAio, SimpleStatPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- uint64_t psize;
- time_t pmtime;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
- &psize, &pmtime));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), psize);
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAio, SimpleStatNS) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAio, SimpleStatPPNS) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- uint64_t psize;
- time_t pmtime;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
- &psize, &pmtime));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), psize);
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAio, StatRemove) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion4);
}
-TEST(LibRadosAio, StatRemovePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- uint64_t psize;
- time_t pmtime;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
- &psize, &pmtime));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), psize);
- uint64_t psize2;
- time_t pmtime2;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion3));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion3->get_return_value());
-
- AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion4, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion4,
- &psize2, &pmtime2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion4->wait_for_complete());
- }
- ASSERT_EQ(-ENOENT, my_completion4->get_return_value());
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
- delete my_completion4;
-}
-
TEST(LibRadosAio, ExecuteClass) {
AioTestData test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAio, ExecuteClassPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- bufferlist in, out;
- ASSERT_EQ(0, test_data.m_ioctx.aio_exec("foo", my_completion2,
- "hello", "say_hello", in, &out));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length()));
- delete my_completion;
- delete my_completion2;
-}
-
using std::string;
using std::map;
using std::set;
-TEST(LibRadosAio, OmapPP) {
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- string header_str = "baz";
- bufferptr bp(header_str.c_str(), header_str.size() + 1);
- bufferlist header_to_set;
- header_to_set.push_back(bp);
- map<string, bufferlist> to_set;
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- to_set["foo"] = header_to_set;
- to_set["foo2"] = header_to_set;
- to_set["qfoo3"] = header_to_set;
- op.omap_set(to_set);
-
- op.omap_set_header(header_to_set);
-
- ioctx.aio_operate("test_obj", my_completion.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- }
-
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectReadOperation op;
- map<string, pair<bufferlist, int> > assertions;
- bufferlist val;
- val.append(string("bar"));
- assertions["foo"] = pair<bufferlist, int>(val, CEPH_OSD_CMPXATTR_OP_EQ);
-
- int r;
- op.omap_cmp(assertions, &r);
-
- ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(-ECANCELED, my_completion->get_return_value());
- ASSERT_EQ(-ECANCELED, r);
- }
-
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectReadOperation op;
-
- set<string> set_got;
- map<string, bufferlist> map_got;
-
- set<string> to_get;
- map<string, bufferlist> got3;
-
- map<string, bufferlist> got4;
-
- bufferlist header;
-
- op.omap_get_keys2("", 1, &set_got, nullptr, 0);
- op.omap_get_vals2("foo", 1, &map_got, nullptr, 0);
-
- to_get.insert("foo");
- to_get.insert("qfoo3");
- op.omap_get_vals_by_keys(to_get, &got3, 0);
-
- op.omap_get_header(&header, 0);
-
- op.omap_get_vals2("foo2", "q", 1, &got4, nullptr, 0);
-
- ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
-
- ASSERT_EQ(header.length(), header_to_set.length());
- ASSERT_EQ(set_got.size(), (unsigned)1);
- ASSERT_EQ(*set_got.begin(), "foo");
- ASSERT_EQ(map_got.size(), (unsigned)1);
- ASSERT_EQ(map_got.begin()->first, "foo2");
- ASSERT_EQ(got3.size(), (unsigned)2);
- ASSERT_EQ(got3.begin()->first, "foo");
- ASSERT_EQ(got3.rbegin()->first, "qfoo3");
- ASSERT_EQ(got4.size(), (unsigned)1);
- ASSERT_EQ(got4.begin()->first, "qfoo3");
- }
-
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- set<string> to_remove;
- to_remove.insert("foo2");
- op.omap_rm_keys(to_remove);
- ioctx.aio_operate("test_obj", my_completion.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- }
-
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectReadOperation op;
-
- set<string> set_got;
- op.omap_get_keys2("", -1, &set_got, nullptr, 0);
- ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- ASSERT_EQ(set_got.size(), (unsigned)2);
- }
-
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- op.omap_clear();
- ioctx.aio_operate("test_obj", my_completion.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- }
-
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectReadOperation op;
-
- set<string> set_got;
- op.omap_get_keys2("", -1, &set_got, nullptr, 0);
- ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- ASSERT_EQ(set_got.size(), (unsigned)0);
- }
-
- // omap_clear clears header *and* keys
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- bufferlist bl;
- bl.append("some data");
- map<string,bufferlist> to_set;
- to_set["foo"] = bl;
- to_set["foo2"] = bl;
- to_set["qfoo3"] = bl;
- op.omap_set(to_set);
- op.omap_set_header(bl);
- ioctx.aio_operate("foo3", my_completion.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- }
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- op.omap_clear();
- ioctx.aio_operate("foo3", my_completion.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- }
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectReadOperation op;
- set<string> set_got;
- bufferlist hdr;
- op.omap_get_keys2("", -1, &set_got, nullptr, 0);
- op.omap_get_header(&hdr, NULL);
- ioctx.aio_operate("foo3", my_completion.get(), &op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion->get_return_value());
- ASSERT_EQ(set_got.size(), (unsigned)0);
- ASSERT_EQ(hdr.length(), 0u);
- }
-
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
TEST(LibRadosAio, MultiWrite) {
AioTestData test_data;
rados_completion_t my_completion, my_completion2, my_completion3;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAio, MultiWritePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
-
- char buf2[64];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion2,
- bl2, sizeof(buf2), sizeof(buf)));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
-
- bufferlist bl3;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
- &bl3, (sizeof(buf) + sizeof(buf2) * 3), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)), my_completion3->get_return_value());
- ASSERT_EQ(sizeof(buf) + sizeof(buf2), bl3.length());
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2)));
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
TEST(LibRadosAio, AioUnlock) {
AioTestData test_data;
ASSERT_EQ("", test_data.init());
ASSERT_EQ(0, rados_lock_exclusive(test_data.m_ioctx, "foo", "TestLock", "Cookie", "", NULL, 0));
}
-TEST(LibRadosAio, AioUnlockPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- ASSERT_EQ(0, test_data.m_ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0));
- boost::scoped_ptr<AioCompletion> my_completion
- (test_data.m_cluster.aio_create_completion
- (nullptr, nullptr, nullptr));
- ASSERT_EQ(0, test_data.m_ioctx.aio_unlock("foo", "TestLock", "Cookie", my_completion.get()));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- ASSERT_EQ(0, test_data.m_ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0));
-}
-
// EC test cases
class AioTestDataEC
{
bool m_init;
};
-class AioTestDataECPP
-{
-public:
- AioTestDataECPP()
- : m_init(false)
- {
- }
-
- ~AioTestDataECPP()
- {
- if (m_init) {
- m_ioctx.close();
- destroy_one_ec_pool_pp(m_pool_name, m_cluster);
- }
- }
-
- std::string init()
- {
- int ret;
- m_pool_name = get_temp_pool_name();
- std::string err = create_one_ec_pool_pp(m_pool_name, m_cluster);
- if (!err.empty()) {
- ostringstream oss;
- oss << "create_one_ec_pool(" << m_pool_name << ") failed: error " << err;
- return oss.str();
- }
- ret = m_cluster.ioctx_create(m_pool_name.c_str(), m_ioctx);
- if (ret) {
- destroy_one_ec_pool_pp(m_pool_name, m_cluster);
- ostringstream oss;
- oss << "rados_ioctx_create failed: error " << ret;
- return oss.str();
- }
- m_init = true;
- return "";
- }
-
- Rados m_cluster;
- IoCtx m_ioctx;
- std::string m_pool_name;
- bool m_init;
-};
-
TEST(LibRadosAioEC, SimpleWrite) {
AioTestDataEC test_data;
rados_completion_t my_completion;
ASSERT_EQ(0, rados_aio_get_return_value(my_completion2));
}
-TEST(LibRadosAioEC, SimpleWritePP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
- my_completion, bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- delete my_completion;
- }
-
- {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- test_data.m_ioctx.set_namespace("nspace");
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
- my_completion, bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- delete my_completion;
- }
-}
-
TEST(LibRadosAioEC, WaitForSafe) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion);
}
-TEST(LibRadosAioEC, WaitForSafePP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
- my_completion, bl1, sizeof(buf), 0));
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_safe());
- ASSERT_EQ(0, my_completion->get_return_value());
- delete my_completion;
-}
-
TEST(LibRadosAioEC, RoundTrip) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_completion_t my_completion2;
ASSERT_EQ(0, rados_aio_create_completion(nullptr,
nullptr, nullptr, &my_completion2));
- ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo",
- my_completion2, buf2, sizeof(buf2), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2));
- }
- ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2));
- ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
- rados_aio_release(my_completion);
- rados_aio_release(my_completion2);
-}
-
-TEST(LibRadosAioEC, RoundTripPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
- my_completion2, &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
-TEST(LibRadosAioEC, RoundTripPP2) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
- my_completion2, &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_safe());
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
-//using ObjectWriteOperation/ObjectReadOperation with iohint
-TEST(LibRadosAioEC, RoundTripPP3)
-{
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf);
-
- op.write(0, bl);
- op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", my_completion1.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion1->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion1->get_return_value());
-
- boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
- bl.clear();
- ObjectReadOperation op1;
- op1.read(0, sizeof(buf), &bl, NULL);
- op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
-
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
-TEST(LibRadosAioEC, RoundTripSparseReadPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
-
- map<uint64_t, uint64_t> extents;
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_sparse_read("foo",
- my_completion2, &extents, &bl2, sizeof(buf), 0));
+ ASSERT_EQ(0, rados_aio_read(test_data.m_ioctx, "foo",
+ my_completion2, buf2, sizeof(buf2), 0));
{
TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
+ ASSERT_EQ(0, rados_aio_wait_for_complete(my_completion2));
}
- ASSERT_EQ(0, my_completion2->get_return_value());
- assert_eq_sparse(bl1, extents, bl2);
- delete my_completion;
- delete my_completion2;
+ ASSERT_EQ((int)sizeof(buf), rados_aio_get_return_value(my_completion2));
+ ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
+ rados_aio_release(my_completion);
+ rados_aio_release(my_completion2);
}
TEST(LibRadosAioEC, RoundTripAppend) {
delete[] buf3;
}
-TEST(LibRadosAioEC, RoundTripAppendPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- bool requires;
- ASSERT_EQ(0, test_data.m_ioctx.pool_requires_alignment2(&requires));
- ASSERT_TRUE(requires);
- uint64_t alignment;
- ASSERT_EQ(0, test_data.m_ioctx.pool_required_alignment2(&alignment));
- ASSERT_NE((unsigned)0, alignment);
- int bsize = alignment;
- char *buf = (char *)new char[bsize];
- memset(buf, 0xcc, bsize);
- bufferlist bl1;
- bl1.append(buf, bsize);
- ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion,
- bl1, bsize));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
-
- int hbsize = bsize / 2;
- char *buf2 = (char *)new char[hbsize];
- memset(buf2, 0xdd, hbsize);
- bufferlist bl2;
- bl2.append(buf2, hbsize);
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion2,
- bl2, hbsize));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
-
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion3,
- bl2, hbsize));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- EXPECT_EQ(-EOPNOTSUPP, my_completion3->get_return_value());
-
- bufferlist bl3;
- AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion4, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
- my_completion4, &bl3, bsize * 3, 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion4->wait_for_complete());
- }
- int tbsize = bsize + hbsize;
- ASSERT_EQ(tbsize, my_completion4->get_return_value());
- ASSERT_EQ((unsigned)tbsize, bl3.length());
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
- ASSERT_EQ(0, memcmp(bl3.c_str() + bsize, buf2, hbsize));
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
- delete[] buf;
- delete[] buf2;
-}
-
TEST(LibRadosAioEC, IsComplete) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAioEC, IsCompletePP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
-
- // Busy-wait until the AIO completes.
- // Normally we wouldn't do this, but we want to test is_complete.
- while (true) {
- int is_complete = my_completion2->is_complete();
- if (is_complete)
- break;
- }
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAioEC, IsSafe) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAioEC, IsSafePP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
-
- // Busy-wait until the AIO completes.
- // Normally we wouldn't do this, but we want to test rados_aio_is_safe.
- while (true) {
- int is_safe = my_completion->is_safe();
- if (is_safe)
- break;
- }
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- bufferlist bl2;
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAioEC, ReturnValue) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion);
}
-TEST(LibRadosAioEC, ReturnValuePP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- bufferlist bl1;
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("nonexistent",
- my_completion, &bl1, 128, 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(-ENOENT, my_completion->get_return_value());
- delete my_completion;
-}
-
TEST(LibRadosAioEC, Flush) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAioEC, FlushPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xee, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- ASSERT_EQ(0, test_data.m_ioctx.aio_flush());
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAioEC, FlushAsync) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(flush_completion);
}
-TEST(LibRadosAioEC, FlushAsyncPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *flush_completion =
- test_data.m_cluster.aio_create_completion(NULL, NULL, NULL);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xee, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- ASSERT_EQ(0, test_data.m_ioctx.aio_flush_async(flush_completion));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, flush_completion->wait_for_complete());
- ASSERT_EQ(0, flush_completion->wait_for_safe());
- }
- ASSERT_EQ(1, my_completion->is_complete());
- ASSERT_EQ(1, my_completion->is_safe());
- ASSERT_EQ(1, flush_completion->is_complete());
- ASSERT_EQ(1, flush_completion->is_safe());
- ASSERT_EQ(0, my_completion->get_return_value());
- bufferlist bl2;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
- &bl2, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), bl2.length());
- ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
- delete my_completion;
- delete my_completion2;
- delete flush_completion;
-}
-
TEST(LibRadosAioEC, RoundTripWriteFull) {
AioTestDataEC test_data;
rados_completion_t my_completion, my_completion2, my_completion3;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAioEC, RoundTripWriteFullPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- char buf2[64];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write_full("foo", my_completion2, bl2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- bufferlist bl3;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
- &bl3, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf2), my_completion3->get_return_value());
- ASSERT_EQ(sizeof(buf2), bl3.length());
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
-//using ObjectWriteOperation/ObjectReadOperation with iohint
-TEST(LibRadosAioEC, RoundTripWriteFullPP2)
-{
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf);
-
- op.write_full(bl);
- op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
- ioctx.aio_operate("test_obj", my_completion1.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion1->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion1->get_return_value());
-
- boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
- bl.clear();
- ObjectReadOperation op1;
- op1.read(0, sizeof(buf), &bl, NULL);
- op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- EXPECT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
-
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
TEST(LibRadosAioEC, SimpleStat) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAioEC, SimpleStatPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- uint64_t psize;
- time_t pmtime;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
- &psize, &pmtime));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), psize);
- delete my_completion;
- delete my_completion2;
-}
TEST(LibRadosAioEC, SimpleStatNS) {
AioTestDataEC test_data;
rados_aio_release(my_completion3);
}
-TEST(LibRadosAioEC, SimpleStatPPNS) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- uint64_t psize;
- time_t pmtime;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
- &psize, &pmtime));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), psize);
- delete my_completion;
- delete my_completion2;
-}
-
TEST(LibRadosAioEC, StatRemove) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion4);
}
-TEST(LibRadosAioEC, StatRemovePP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- uint64_t psize;
- time_t pmtime;
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
- &psize, &pmtime));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(sizeof(buf), psize);
- uint64_t psize2;
- time_t pmtime2;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion3));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion3->get_return_value());
-
- AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion4, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion4,
- &psize2, &pmtime2));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion4->wait_for_complete());
- }
- ASSERT_EQ(-ENOENT, my_completion4->get_return_value());
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
- delete my_completion4;
-}
-
TEST(LibRadosAioEC, ExecuteClass) {
AioTestDataEC test_data;
rados_completion_t my_completion;
rados_aio_release(my_completion2);
}
-TEST(LibRadosAioEC, ExecuteClassPP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- bufferlist in, out;
- ASSERT_EQ(0, test_data.m_ioctx.aio_exec("foo", my_completion2,
- "hello", "say_hello", in, &out));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
- ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length()));
- delete my_completion;
- delete my_completion2;
-}
-
-TEST(LibRadosAioEC, OmapPP) {
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_ec_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- string header_str = "baz";
- bufferptr bp(header_str.c_str(), header_str.size() + 1);
- bufferlist header_to_set;
- header_to_set.push_back(bp);
- map<string, bufferlist> to_set;
- {
- boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation op;
- to_set["foo"] = header_to_set;
- to_set["foo2"] = header_to_set;
- to_set["qfoo3"] = header_to_set;
- op.omap_set(to_set);
-
- op.omap_set_header(header_to_set);
-
- ioctx.aio_operate("test_obj", my_completion.get(), &op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- EXPECT_EQ(-EOPNOTSUPP, my_completion->get_return_value());
- }
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
-
TEST(LibRadosAioEC, MultiWrite) {
AioTestDataEC test_data;
rados_completion_t my_completion, my_completion2, my_completion3;
rados_aio_release(my_completion2);
rados_aio_release(my_completion3);
}
-
-TEST(LibRadosAioEC, MultiWritePP) {
- AioTestDataECPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(buf), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
-
- char buf2[64];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion2,
- bl2, sizeof(buf2), sizeof(buf)));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(-EOPNOTSUPP, my_completion2->get_return_value());
-
- bufferlist bl3;
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion3, my_completion_null);
- ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
- &bl3, (sizeof(buf) + sizeof(buf2) * 3), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ((int)sizeof(buf), my_completion3->get_return_value());
- ASSERT_EQ(sizeof(buf), bl3.length());
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
-TEST(LibRadosAio, RacingRemovePP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init({{"objecter_retry_writes_after_first_reply", "true"}}));
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion, nullptr);
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_NE(my_completion2, nullptr);
- ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion2));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl, sizeof(buf), 0));
- {
- TestAlarm alarm;
- my_completion2->wait_for_complete();
- my_completion->wait_for_complete();
- }
- ASSERT_EQ(-ENOENT, my_completion2->get_return_value());
- ASSERT_EQ(0, my_completion->get_return_value());
- ASSERT_EQ(0, test_data.m_ioctx.stat("foo", nullptr, nullptr));
- delete my_completion;
- delete my_completion2;
-}
-
-TEST(LibRadosAio, RoundTripCmpExtPP) {
- AioTestDataPP test_data;
- ASSERT_EQ("", test_data.init());
- AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
- char full[128];
- memset(full, 0xcc, sizeof(full));
- bufferlist bl1;
- bl1.append(full, sizeof(full));
- ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
- bl1, sizeof(full), 0));
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion->get_return_value());
-
- /* compare with match */
- bufferlist cbl;
- cbl.append(full, sizeof(full));
- AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_EQ(0, test_data.m_ioctx.aio_cmpext("foo", my_completion2, 0, cbl));
-
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion2->wait_for_complete());
- }
- ASSERT_EQ(0, my_completion2->get_return_value());
-
- /* compare with mismatch */
- memset(full, 0xdd, sizeof(full));
- cbl.clear();
- cbl.append(full, sizeof(full));
- AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
- nullptr, nullptr, nullptr);
- ASSERT_EQ(0, test_data.m_ioctx.aio_cmpext("foo", my_completion3, 0, cbl));
-
- {
- TestAlarm alarm;
- ASSERT_EQ(0, my_completion3->wait_for_complete());
- }
- ASSERT_EQ(-MAX_ERRNO, my_completion3->get_return_value());
-
- delete my_completion;
- delete my_completion2;
- delete my_completion3;
-}
-
-TEST(LibRadosAio, RoundTripCmpExtPP2)
-{
- int ret;
- char buf[128];
- char miscmp_buf[128];
- bufferlist cbl;
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- IoCtx ioctx;
- cluster.ioctx_create(pool_name.c_str(), ioctx);
-
- boost::scoped_ptr<AioCompletion>
- wr_cmpl(cluster.aio_create_completion(0, 0, 0));
- ObjectWriteOperation wr_op;
- memset(buf, 0xcc, sizeof(buf));
- memset(miscmp_buf, 0xdd, sizeof(miscmp_buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- wr_op.write_full(bl);
- wr_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", wr_cmpl.get(), &wr_op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, wr_cmpl->wait_for_complete());
- }
- EXPECT_EQ(0, wr_cmpl->get_return_value());
-
- /* cmpext as write op. first match then mismatch */
- boost::scoped_ptr<AioCompletion>
- wr_cmpext_cmpl(cluster.aio_create_completion(0, 0, 0));
- cbl.append(buf, sizeof(buf));
- ret = 0;
-
- wr_op.cmpext(0, cbl, &ret);
- wr_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", wr_cmpext_cmpl.get(), &wr_op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, wr_cmpext_cmpl->wait_for_complete());
- }
- EXPECT_EQ(0, wr_cmpext_cmpl->get_return_value());
- EXPECT_EQ(0, ret);
-
- boost::scoped_ptr<AioCompletion>
- wr_cmpext_cmpl2(cluster.aio_create_completion(0, 0, 0));
- cbl.clear();
- cbl.append(miscmp_buf, sizeof(miscmp_buf));
- ret = 0;
-
- wr_op.cmpext(0, cbl, &ret);
- wr_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", wr_cmpext_cmpl2.get(), &wr_op);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, wr_cmpext_cmpl2->wait_for_complete());
- }
- EXPECT_EQ(-MAX_ERRNO, wr_cmpext_cmpl2->get_return_value());
- EXPECT_EQ(-MAX_ERRNO, ret);
-
- /* cmpext as read op */
- boost::scoped_ptr<AioCompletion>
- rd_cmpext_cmpl(cluster.aio_create_completion(0, 0, 0));
- ObjectReadOperation rd_op;
- cbl.clear();
- cbl.append(buf, sizeof(buf));
- ret = 0;
- rd_op.cmpext(0, cbl, &ret);
- rd_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", rd_cmpext_cmpl.get(), &rd_op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, rd_cmpext_cmpl->wait_for_complete());
- }
- EXPECT_EQ(0, rd_cmpext_cmpl->get_return_value());
- EXPECT_EQ(0, ret);
-
- boost::scoped_ptr<AioCompletion>
- rd_cmpext_cmpl2(cluster.aio_create_completion(0, 0, 0));
- cbl.clear();
- cbl.append(miscmp_buf, sizeof(miscmp_buf));
- ret = 0;
-
- rd_op.cmpext(0, cbl, &ret);
- rd_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ioctx.aio_operate("test_obj", rd_cmpext_cmpl2.get(), &rd_op, 0);
- {
- TestAlarm alarm;
- ASSERT_EQ(0, rd_cmpext_cmpl2->wait_for_complete());
- }
- EXPECT_EQ(-MAX_ERRNO, rd_cmpext_cmpl2->get_return_value());
- EXPECT_EQ(-MAX_ERRNO, ret);
-
- ioctx.remove("test_obj");
- destroy_one_pool_pp(pool_name, cluster);
-}
--- /dev/null
+#include <errno.h>
+#include <fcntl.h>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <boost/scoped_ptr.hpp>
+
+#include "gtest/gtest.h"
+
+#include "common/errno.h"
+#include "include/err.h"
+#include "include/rados/librados.hpp"
+#include "include/types.h"
+#include "include/stringify.h"
+#include "include/scope_guard.h"
+
+#include "test_cxx.h"
+
+using namespace librados;
+using std::pair;
+using std::ostringstream;
+
+class AioTestDataPP
+{
+public:
+ AioTestDataPP()
+ : m_init(false)
+ {
+ }
+
+ ~AioTestDataPP()
+ {
+ if (m_init) {
+ m_ioctx.close();
+ destroy_one_pool_pp(m_pool_name, m_cluster);
+ }
+ }
+
+ std::string init()
+ {
+ return init({});
+ }
+
+ std::string init(const std::map<std::string, std::string> &config)
+ {
+ int ret;
+
+ m_pool_name = get_temp_pool_name();
+ std::string err = create_one_pool_pp(m_pool_name, m_cluster, config);
+ if (!err.empty()) {
+ ostringstream oss;
+ oss << "create_one_pool(" << m_pool_name << ") failed: error " << err;
+ return oss.str();
+ }
+ ret = m_cluster.ioctx_create(m_pool_name.c_str(), m_ioctx);
+ if (ret) {
+ destroy_one_pool_pp(m_pool_name, m_cluster);
+ ostringstream oss;
+ oss << "rados_ioctx_create failed: error " << ret;
+ return oss.str();
+ }
+ m_init = true;
+ return "";
+ }
+
+ Rados m_cluster;
+ IoCtx m_ioctx;
+ std::string m_pool_name;
+ bool m_init;
+};
+
+TEST(LibRadosAio, TooBigPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+
+ bufferlist bl;
+ AioCompletion *aio_completion = test_data.m_cluster.aio_create_completion(nullptr, NULL, NULL);
+ ASSERT_EQ(-E2BIG, test_data.m_ioctx.aio_write("foo", aio_completion, bl, UINT_MAX, 0));
+ ASSERT_EQ(-E2BIG, test_data.m_ioctx.aio_append("foo", aio_completion, bl, UINT_MAX));
+ // ioctx.aio_write_full no way to overflow bl.length()
+ delete aio_completion;
+}
+
+TEST(LibRadosAio, PoolQuotaPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ string p = get_temp_pool_name();
+ ASSERT_EQ(0, test_data.m_cluster.pool_create(p.c_str()));
+ IoCtx ioctx;
+ ASSERT_EQ(0, test_data.m_cluster.ioctx_create(p.c_str(), ioctx));
+ ioctx.application_enable("rados", true);
+
+ bufferlist inbl;
+ ASSERT_EQ(0, test_data.m_cluster.mon_command(
+ "{\"prefix\": \"osd pool set-quota\", \"pool\": \"" + p +
+ "\", \"field\": \"max_bytes\", \"val\": \"4096\"}",
+ inbl, NULL, NULL));
+
+ bufferlist bl;
+ bufferptr z(4096);
+ bl.append(z);
+ int n;
+ for (n = 0; n < 1024; ++n) {
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ librados::AioCompletion *completion =
+ test_data.m_cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo" + stringify(n), completion, &op,
+ librados::OPERATION_FULL_TRY));
+ completion->wait_for_safe();
+ int r = completion->get_return_value();
+ completion->release();
+ if (r == -EDQUOT)
+ break;
+ ASSERT_EQ(0, r);
+ sleep(1);
+ }
+ ASSERT_LT(n, 1024);
+
+ // make sure we have latest map that marked the pool full
+ test_data.m_cluster.wait_for_latest_osdmap();
+
+ // make sure we block without FULL_TRY
+ {
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ librados::AioCompletion *completion =
+ test_data.m_cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op, 0));
+ sleep(5);
+ ASSERT_FALSE(completion->is_safe());
+ completion->release();
+ }
+
+ ioctx.close();
+ ASSERT_EQ(0, test_data.m_cluster.pool_delete(p.c_str()));
+}
+
+TEST(LibRadosAio, SimpleWritePP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
+ my_completion, bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ delete my_completion;
+ }
+
+ {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ test_data.m_ioctx.set_namespace("nspace");
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
+ my_completion, bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ delete my_completion;
+ }
+}
+
+TEST(LibRadosAio, WaitForSafePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
+ my_completion, bl1, sizeof(buf), 0));
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_safe());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ delete my_completion;
+}
+
+TEST(LibRadosAio, RoundTripPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
+ my_completion2, &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, RoundTripPP2) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
+ my_completion2, &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_safe());
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+//using ObjectWriteOperation/ObjectReadOperation with iohint
+TEST(LibRadosAio, RoundTripPP3)
+{
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ op.write(0, bl);
+ op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", my_completion1.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion1->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion1->get_return_value());
+
+ boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
+ bl.clear();
+ ObjectReadOperation op1;
+ op1.read(0, sizeof(buf), &bl, NULL);
+ op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ bufferlist init_value_bl;
+ encode(static_cast<int32_t>(-1), init_value_bl);
+ bufferlist csum_bl;
+ op1.checksum(LIBRADOS_CHECKSUM_TYPE_CRC32C, init_value_bl,
+ 0, 0, 0, &csum_bl, nullptr);
+ ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
+
+ ASSERT_EQ(8U, csum_bl.length());
+ auto csum_bl_it = csum_bl.cbegin();
+ uint32_t csum_count;
+ uint32_t csum;
+ decode(csum_count, csum_bl_it);
+ ASSERT_EQ(1U, csum_count);
+ decode(csum, csum_bl_it);
+ ASSERT_EQ(bl.crc32c(-1), csum);
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAio, RoundTripSparseReadPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ std::map<uint64_t, uint64_t> extents;
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_sparse_read("foo",
+ my_completion2, &extents, &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ assert_eq_sparse(bl1, extents, bl2);
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioPP, XattrsRoundTripPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ // async getxattr
+ boost::scoped_ptr<AioCompletion> my_completion
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_getxattr("foo", my_completion.get(), attr1, bl2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(-ENODATA, my_completion->get_return_value());
+ // append
+ bufferlist bl3;
+ bl3.append(attr1_buf, sizeof(attr1_buf));
+ // async setxattr
+ AioTestDataPP test_data2;
+ ASSERT_EQ("", test_data2.init());
+ boost::scoped_ptr<AioCompletion> my_completion2
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_setxattr("foo", my_completion2.get(), attr1, bl3));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ // async getxattr
+ bufferlist bl4;
+ AioTestDataPP test_data3;
+ ASSERT_EQ("", test_data3.init());
+ boost::scoped_ptr<AioCompletion> my_completion3
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_getxattr("foo", my_completion3.get(), attr1, bl4));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(attr1_buf), my_completion3->get_return_value());
+ // check content of attribute
+ ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
+}
+
+TEST(LibRadosAioPP, RmXattrPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
+ // async setxattr
+ bufferlist bl2;
+ bl2.append(attr1_buf, sizeof(attr1_buf));
+ boost::scoped_ptr<AioCompletion> my_completion
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_setxattr("foo", my_completion.get(), attr1, bl2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ // async rmxattr
+ AioTestDataPP test_data2;
+ ASSERT_EQ("", test_data2.init());
+ boost::scoped_ptr<AioCompletion> my_completion2
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_rmxattr("foo", my_completion2.get(), attr1));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ // async getxattr
+ AioTestDataPP test_data3;
+ ASSERT_EQ("", test_data3.init());
+ boost::scoped_ptr<AioCompletion> my_completion3
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ bufferlist bl3;
+ ASSERT_EQ(0, test_data.m_ioctx.aio_getxattr("foo", my_completion3.get(), attr1, bl3));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ(-ENODATA, my_completion3->get_return_value());
+ // Test rmxattr on a removed object
+ char buf2[128];
+ char attr2[] = "attr2";
+ char attr2_buf[] = "foo bar baz";
+ memset(buf2, 0xbb, sizeof(buf2));
+ bufferlist bl21;
+ bl21.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
+ bufferlist bl22;
+ bl22.append(attr2_buf, sizeof(attr2_buf));
+ // async setxattr
+ AioTestDataPP test_data4;
+ ASSERT_EQ("", test_data4.init());
+ boost::scoped_ptr<AioCompletion> my_completion4
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_setxattr("foo_rmxattr", my_completion4.get(), attr2, bl22));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion4->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion4->get_return_value());
+ // remove object
+ ASSERT_EQ(0, test_data.m_ioctx.remove("foo_rmxattr"));
+ // async rmxattr on non existing object
+ AioTestDataPP test_data5;
+ ASSERT_EQ("", test_data5.init());
+ boost::scoped_ptr<AioCompletion> my_completion5
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_rmxattr("foo_rmxattr", my_completion5.get(), attr2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion5->wait_for_complete());
+ }
+ ASSERT_EQ(-ENOENT, my_completion5->get_return_value());
+}
+
+TEST(LibRadosIoPP, XattrListPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ // create an object with 2 attributes
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ char attr2[] = "attr2";
+ char attr2_buf[256];
+ for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
+ attr2_buf[j] = j % 0xff;
+ }
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ bl2.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, test_data.m_ioctx.setxattr("foo", attr1, bl2));
+ bufferlist bl3;
+ bl3.append(attr2_buf, sizeof(attr2_buf));
+ ASSERT_EQ(0, test_data.m_ioctx.setxattr("foo", attr2, bl3));
+ // call async version of getxattrs
+ boost::scoped_ptr<AioCompletion> my_completion
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ std::map<std::string, bufferlist> attrset;
+ ASSERT_EQ(0, test_data.m_ioctx.aio_getxattrs("foo", my_completion.get(), attrset));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
+ i != attrset.end(); ++i) {
+ if (i->first == string(attr1)) {
+ ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
+ }
+ else if (i->first == string(attr2)) {
+ ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
+ }
+ else {
+ ASSERT_EQ(0, 1);
+ }
+ }
+}
+
+TEST(LibRadosAio, IsCompletePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+
+ // Busy-wait until the AIO completes.
+ // Normally we wouldn't do this, but we want to test is_complete.
+ while (true) {
+ int is_complete = my_completion2->is_complete();
+ if (is_complete)
+ break;
+ }
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, IsSafePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+
+ // Busy-wait until the AIO completes.
+ // Normally we wouldn't do this, but we want to test rados_aio_is_safe.
+ while (true) {
+ int is_safe = my_completion->is_safe();
+ if (is_safe)
+ break;
+ }
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ bufferlist bl2;
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, ReturnValuePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ bufferlist bl1;
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("nonexistent",
+ my_completion, &bl1, 128, 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(-ENOENT, my_completion->get_return_value());
+ delete my_completion;
+}
+
+TEST(LibRadosAio, FlushPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xee, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_flush());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, FlushAsyncPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *flush_completion =
+ test_data.m_cluster.aio_create_completion(NULL, NULL, NULL);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xee, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_flush_async(flush_completion));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, flush_completion->wait_for_complete());
+ ASSERT_EQ(0, flush_completion->wait_for_safe());
+ }
+ ASSERT_EQ(1, my_completion->is_complete());
+ ASSERT_EQ(1, my_completion->is_safe());
+ ASSERT_EQ(1, flush_completion->is_complete());
+ ASSERT_EQ(1, flush_completion->is_safe());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+ delete flush_completion;
+}
+
+TEST(LibRadosAio, RoundTripWriteFullPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ char buf2[64];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write_full("foo", my_completion2, bl2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ bufferlist bl3;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
+ &bl3, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf2), my_completion3->get_return_value());
+ ASSERT_EQ(sizeof(buf2), bl3.length());
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+//using ObjectWriteOperation/ObjectReadOperation with iohint
+TEST(LibRadosAio, RoundTripWriteFullPP2)
+{
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf);
+
+ op.write_full(bl);
+ op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", my_completion1.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion1->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion1->get_return_value());
+
+ boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
+ bl.clear();
+ ObjectReadOperation op1;
+ op1.read(0, sizeof(buf), &bl, NULL);
+ op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
+
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAio, RoundTripWriteSamePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char full[128];
+ memset(full, 0xcc, sizeof(full));
+ bufferlist bl1;
+ bl1.append(full, sizeof(full));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(full), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ /* write the same buf four times */
+ char buf[32];
+ size_t ws_write_len = sizeof(full);
+ memset(buf, 0xdd, sizeof(buf));
+ bufferlist bl2;
+ bl2.append(buf, sizeof(buf));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_writesame("foo", my_completion2, bl2,
+ ws_write_len, 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ bufferlist bl3;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
+ &bl3, sizeof(full), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(full), my_completion3->get_return_value());
+ ASSERT_EQ(sizeof(full), bl3.length());
+ for (char *cmp = bl3.c_str(); cmp < bl3.c_str() + bl3.length();
+ cmp += sizeof(buf)) {
+ ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
+ }
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+TEST(LibRadosAio, RoundTripWriteSamePP2)
+{
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ boost::scoped_ptr<AioCompletion>
+ wr_cmpl(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ op.writesame(0, sizeof(buf) * 4, bl);
+ op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", wr_cmpl.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, wr_cmpl->wait_for_complete());
+ }
+ EXPECT_EQ(0, wr_cmpl->get_return_value());
+
+ boost::scoped_ptr<AioCompletion>
+ rd_cmpl(cluster.aio_create_completion(0, 0, 0));
+ char *cmp;
+ char full[sizeof(buf) * 4];
+ memset(full, 0, sizeof(full));
+ bufferlist fl;
+ fl.append(full, sizeof(full));
+ ObjectReadOperation op1;
+ op1.read(0, sizeof(full), &fl, NULL);
+ op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", rd_cmpl.get(), &op1, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, rd_cmpl->wait_for_complete());
+ }
+ EXPECT_EQ(0, rd_cmpl->get_return_value());
+ for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) {
+ ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
+ }
+
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAio, SimpleStatPPNS) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ uint64_t psize;
+ time_t pmtime;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
+ &psize, &pmtime));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), psize);
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, SimpleStatPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ uint64_t psize;
+ time_t pmtime;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
+ &psize, &pmtime));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), psize);
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, StatRemovePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ uint64_t psize;
+ time_t pmtime;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
+ &psize, &pmtime));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), psize);
+ uint64_t psize2;
+ time_t pmtime2;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion3));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion3->get_return_value());
+
+ AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion4, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion4,
+ &psize2, &pmtime2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion4->wait_for_complete());
+ }
+ ASSERT_EQ(-ENOENT, my_completion4->get_return_value());
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+ delete my_completion4;
+}
+
+TEST(LibRadosAio, ExecuteClassPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ bufferlist in, out;
+ ASSERT_EQ(0, test_data.m_ioctx.aio_exec("foo", my_completion2,
+ "hello", "say_hello", in, &out));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length()));
+ delete my_completion;
+ delete my_completion2;
+}
+
+using std::string;
+using std::map;
+using std::set;
+
+TEST(LibRadosAio, OmapPP) {
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ string header_str = "baz";
+ bufferptr bp(header_str.c_str(), header_str.size() + 1);
+ bufferlist header_to_set;
+ header_to_set.push_back(bp);
+ map<string, bufferlist> to_set;
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ to_set["foo"] = header_to_set;
+ to_set["foo2"] = header_to_set;
+ to_set["qfoo3"] = header_to_set;
+ op.omap_set(to_set);
+
+ op.omap_set_header(header_to_set);
+
+ ioctx.aio_operate("test_obj", my_completion.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ }
+
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectReadOperation op;
+ map<string, pair<bufferlist, int> > assertions;
+ bufferlist val;
+ val.append(string("bar"));
+ assertions["foo"] = pair<bufferlist, int>(val, CEPH_OSD_CMPXATTR_OP_EQ);
+
+ int r;
+ op.omap_cmp(assertions, &r);
+
+ ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(-ECANCELED, my_completion->get_return_value());
+ ASSERT_EQ(-ECANCELED, r);
+ }
+
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectReadOperation op;
+
+ set<string> set_got;
+ map<string, bufferlist> map_got;
+
+ set<string> to_get;
+ map<string, bufferlist> got3;
+
+ map<string, bufferlist> got4;
+
+ bufferlist header;
+
+ op.omap_get_keys2("", 1, &set_got, nullptr, 0);
+ op.omap_get_vals2("foo", 1, &map_got, nullptr, 0);
+
+ to_get.insert("foo");
+ to_get.insert("qfoo3");
+ op.omap_get_vals_by_keys(to_get, &got3, 0);
+
+ op.omap_get_header(&header, 0);
+
+ op.omap_get_vals2("foo2", "q", 1, &got4, nullptr, 0);
+
+ ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+
+ ASSERT_EQ(header.length(), header_to_set.length());
+ ASSERT_EQ(set_got.size(), (unsigned)1);
+ ASSERT_EQ(*set_got.begin(), "foo");
+ ASSERT_EQ(map_got.size(), (unsigned)1);
+ ASSERT_EQ(map_got.begin()->first, "foo2");
+ ASSERT_EQ(got3.size(), (unsigned)2);
+ ASSERT_EQ(got3.begin()->first, "foo");
+ ASSERT_EQ(got3.rbegin()->first, "qfoo3");
+ ASSERT_EQ(got4.size(), (unsigned)1);
+ ASSERT_EQ(got4.begin()->first, "qfoo3");
+ }
+
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ set<string> to_remove;
+ to_remove.insert("foo2");
+ op.omap_rm_keys(to_remove);
+ ioctx.aio_operate("test_obj", my_completion.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ }
+
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectReadOperation op;
+
+ set<string> set_got;
+ op.omap_get_keys2("", -1, &set_got, nullptr, 0);
+ ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ ASSERT_EQ(set_got.size(), (unsigned)2);
+ }
+
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ op.omap_clear();
+ ioctx.aio_operate("test_obj", my_completion.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ }
+
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectReadOperation op;
+
+ set<string> set_got;
+ op.omap_get_keys2("", -1, &set_got, nullptr, 0);
+ ioctx.aio_operate("test_obj", my_completion.get(), &op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ ASSERT_EQ(set_got.size(), (unsigned)0);
+ }
+
+ // omap_clear clears header *and* keys
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ bufferlist bl;
+ bl.append("some data");
+ map<string,bufferlist> to_set;
+ to_set["foo"] = bl;
+ to_set["foo2"] = bl;
+ to_set["qfoo3"] = bl;
+ op.omap_set(to_set);
+ op.omap_set_header(bl);
+ ioctx.aio_operate("foo3", my_completion.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ }
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ op.omap_clear();
+ ioctx.aio_operate("foo3", my_completion.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ }
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectReadOperation op;
+ set<string> set_got;
+ bufferlist hdr;
+ op.omap_get_keys2("", -1, &set_got, nullptr, 0);
+ op.omap_get_header(&hdr, NULL);
+ ioctx.aio_operate("foo3", my_completion.get(), &op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion->get_return_value());
+ ASSERT_EQ(set_got.size(), (unsigned)0);
+ ASSERT_EQ(hdr.length(), 0u);
+ }
+
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAio, MultiWritePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+
+ char buf2[64];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion2,
+ bl2, sizeof(buf2), sizeof(buf)));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+
+ bufferlist bl3;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
+ &bl3, (sizeof(buf) + sizeof(buf2) * 3), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)), my_completion3->get_return_value());
+ ASSERT_EQ(sizeof(buf) + sizeof(buf2), bl3.length());
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2)));
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+TEST(LibRadosAio, AioUnlockPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ ASSERT_EQ(0, test_data.m_ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0));
+ boost::scoped_ptr<AioCompletion> my_completion
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_unlock("foo", "TestLock", "Cookie", my_completion.get()));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ ASSERT_EQ(0, test_data.m_ioctx.lock_exclusive("foo", "TestLock", "Cookie", "", NULL, 0));
+}
+
+class AioTestDataECPP
+{
+public:
+ AioTestDataECPP()
+ : m_init(false)
+ {}
+
+ ~AioTestDataECPP()
+ {
+ if (m_init) {
+ m_ioctx.close();
+ destroy_one_ec_pool_pp(m_pool_name, m_cluster);
+ }
+ }
+
+ std::string init()
+ {
+ int ret;
+ m_pool_name = get_temp_pool_name();
+ std::string err = create_one_ec_pool_pp(m_pool_name, m_cluster);
+ if (!err.empty()) {
+ ostringstream oss;
+ oss << "create_one_ec_pool(" << m_pool_name << ") failed: error " << err;
+ return oss.str();
+ }
+ ret = m_cluster.ioctx_create(m_pool_name.c_str(), m_ioctx);
+ if (ret) {
+ destroy_one_ec_pool_pp(m_pool_name, m_cluster);
+ ostringstream oss;
+ oss << "rados_ioctx_create failed: error " << ret;
+ return oss.str();
+ }
+ m_init = true;
+ return "";
+ }
+
+ Rados m_cluster;
+ IoCtx m_ioctx;
+ std::string m_pool_name;
+ bool m_init;
+};
+
+// EC test cases
+TEST(LibRadosAioEC, SimpleWritePP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
+ my_completion, bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ delete my_completion;
+ }
+
+ {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ test_data.m_ioctx.set_namespace("nspace");
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
+ my_completion, bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ delete my_completion;
+ }
+}
+
+TEST(LibRadosAioEC, WaitForSafePP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo",
+ my_completion, bl1, sizeof(buf), 0));
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_safe());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ delete my_completion;
+}
+
+TEST(LibRadosAioEC, RoundTripPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
+ my_completion2, &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, RoundTripPP2) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
+ my_completion2, &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_safe());
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+//using ObjectWriteOperation/ObjectReadOperation with iohint
+TEST(LibRadosAioEC, RoundTripPP3)
+{
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf);
+
+ op.write(0, bl);
+ op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", my_completion1.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion1->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion1->get_return_value());
+
+ boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
+ bl.clear();
+ ObjectReadOperation op1;
+ op1.read(0, sizeof(buf), &bl, NULL);
+ op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
+
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAio, RoundTripAppendPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion,
+ bl1, sizeof(buf)));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ char buf2[128];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion2,
+ bl2, sizeof(buf2)));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ bufferlist bl3;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
+ my_completion3, &bl3, 2 * sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)(sizeof(buf) * 2), my_completion3->get_return_value());
+ ASSERT_EQ(sizeof(buf) * 2, bl3.length());
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf), buf2, sizeof(buf2)));
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+TEST(LibRadosAioPP, RemoveTestPP) {
+ char buf[128];
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ ASSERT_EQ(0, test_data.m_ioctx.append("foo", bl1, sizeof(buf)));
+ boost::scoped_ptr<AioCompletion> my_completion
+ (test_data.m_cluster.aio_create_completion
+ (nullptr, nullptr, nullptr));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion.get()));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ ASSERT_EQ(-ENOENT, test_data.m_ioctx.read("foo", bl2, sizeof(buf), 0));
+}
+
+TEST(LibRadosAioEC, RoundTripSparseReadPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+
+ map<uint64_t, uint64_t> extents;
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_sparse_read("foo",
+ my_completion2, &extents, &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ assert_eq_sparse(bl1, extents, bl2);
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, RoundTripAppendPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ bool requires;
+ ASSERT_EQ(0, test_data.m_ioctx.pool_requires_alignment2(&requires));
+ ASSERT_TRUE(requires);
+ uint64_t alignment;
+ ASSERT_EQ(0, test_data.m_ioctx.pool_required_alignment2(&alignment));
+ ASSERT_NE((unsigned)0, alignment);
+ int bsize = alignment;
+ char *buf = (char *)new char[bsize];
+ memset(buf, 0xcc, bsize);
+ bufferlist bl1;
+ bl1.append(buf, bsize);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion,
+ bl1, bsize));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+
+ int hbsize = bsize / 2;
+ char *buf2 = (char *)new char[hbsize];
+ memset(buf2, 0xdd, hbsize);
+ bufferlist bl2;
+ bl2.append(buf2, hbsize);
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion2,
+ bl2, hbsize));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_append("foo", my_completion3,
+ bl2, hbsize));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ EXPECT_EQ(-EOPNOTSUPP, my_completion3->get_return_value());
+
+ bufferlist bl3;
+ AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion4, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo",
+ my_completion4, &bl3, bsize * 3, 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion4->wait_for_complete());
+ }
+ int tbsize = bsize + hbsize;
+ ASSERT_EQ(tbsize, my_completion4->get_return_value());
+ ASSERT_EQ((unsigned)tbsize, bl3.length());
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
+ ASSERT_EQ(0, memcmp(bl3.c_str() + bsize, buf2, hbsize));
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+ delete[] buf;
+ delete[] buf2;
+}
+
+TEST(LibRadosAioEC, IsCompletePP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+
+ // Busy-wait until the AIO completes.
+ // Normally we wouldn't do this, but we want to test is_complete.
+ while (true) {
+ int is_complete = my_completion2->is_complete();
+ if (is_complete)
+ break;
+ }
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+TEST(LibRadosAioEC, IsSafePP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+
+ // Busy-wait until the AIO completes.
+ // Normally we wouldn't do this, but we want to test rados_aio_is_safe.
+ while (true) {
+ int is_safe = my_completion->is_safe();
+ if (is_safe)
+ break;
+ }
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ bufferlist bl2;
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, ReturnValuePP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ bufferlist bl1;
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("nonexistent",
+ my_completion, &bl1, 128, 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(-ENOENT, my_completion->get_return_value());
+ delete my_completion;
+}
+
+TEST(LibRadosAioEC, FlushPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xee, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_flush());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, FlushAsyncPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *flush_completion =
+ test_data.m_cluster.aio_create_completion(NULL, NULL, NULL);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xee, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_flush_async(flush_completion));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, flush_completion->wait_for_complete());
+ ASSERT_EQ(0, flush_completion->wait_for_safe());
+ }
+ ASSERT_EQ(1, my_completion->is_complete());
+ ASSERT_EQ(1, my_completion->is_safe());
+ ASSERT_EQ(1, flush_completion->is_complete());
+ ASSERT_EQ(1, flush_completion->is_safe());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ bufferlist bl2;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion2,
+ &bl2, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl2.length());
+ ASSERT_EQ(0, memcmp(buf, bl2.c_str(), sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+ delete flush_completion;
+}
+
+TEST(LibRadosAioEC, RoundTripWriteFullPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ char buf2[64];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write_full("foo", my_completion2, bl2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ bufferlist bl3;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
+ &bl3, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf2), my_completion3->get_return_value());
+ ASSERT_EQ(sizeof(buf2), bl3.length());
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+//using ObjectWriteOperation/ObjectReadOperation with iohint
+TEST(LibRadosAioEC, RoundTripWriteFullPP2)
+{
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ boost::scoped_ptr<AioCompletion> my_completion1(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf);
+
+ op.write_full(bl);
+ op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
+ ioctx.aio_operate("test_obj", my_completion1.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion1->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion1->get_return_value());
+
+ boost::scoped_ptr<AioCompletion> my_completion2(cluster.aio_create_completion(0, 0, 0));
+ bl.clear();
+ ObjectReadOperation op1;
+ op1.read(0, sizeof(buf), &bl, NULL);
+ op1.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ioctx.aio_operate("test_obj", my_completion2.get(), &op1, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ EXPECT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(0, memcmp(buf, bl.c_str(), sizeof(buf)));
+
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAioEC, SimpleStatPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ uint64_t psize;
+ time_t pmtime;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
+ &psize, &pmtime));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), psize);
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, SimpleStatPPNS) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ uint64_t psize;
+ time_t pmtime;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
+ &psize, &pmtime));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), psize);
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, StatRemovePP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ uint64_t psize;
+ time_t pmtime;
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion2,
+ &psize, &pmtime));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(sizeof(buf), psize);
+ uint64_t psize2;
+ time_t pmtime2;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion3));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion3->get_return_value());
+
+ AioCompletion *my_completion4 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion4, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_stat("foo", my_completion4,
+ &psize2, &pmtime2));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion4->wait_for_complete());
+ }
+ ASSERT_EQ(-ENOENT, my_completion4->get_return_value());
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+ delete my_completion4;
+}
+
+TEST(LibRadosAioEC, ExecuteClassPP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ bufferlist in, out;
+ ASSERT_EQ(0, test_data.m_ioctx.aio_exec("foo", my_completion2,
+ "hello", "say_hello", in, &out));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+ ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length()));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAioEC, OmapPP) {
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_ec_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ string header_str = "baz";
+ bufferptr bp(header_str.c_str(), header_str.size() + 1);
+ bufferlist header_to_set;
+ header_to_set.push_back(bp);
+ map<string, bufferlist> to_set;
+ {
+ boost::scoped_ptr<AioCompletion> my_completion(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation op;
+ to_set["foo"] = header_to_set;
+ to_set["foo2"] = header_to_set;
+ to_set["qfoo3"] = header_to_set;
+ op.omap_set(to_set);
+
+ op.omap_set_header(header_to_set);
+
+ ioctx.aio_operate("test_obj", my_completion.get(), &op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ EXPECT_EQ(-EOPNOTSUPP, my_completion->get_return_value());
+ }
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
+
+TEST(LibRadosAioEC, MultiWritePP) {
+ AioTestDataECPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+
+ char buf2[64];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion2,
+ bl2, sizeof(buf2), sizeof(buf)));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(-EOPNOTSUPP, my_completion2->get_return_value());
+
+ bufferlist bl3;
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion3, my_completion_null);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_read("foo", my_completion3,
+ &bl3, (sizeof(buf) + sizeof(buf2) * 3), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ((int)sizeof(buf), my_completion3->get_return_value());
+ ASSERT_EQ(sizeof(buf), bl3.length());
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+TEST(LibRadosAio, RacingRemovePP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init({{"objecter_retry_writes_after_first_reply", "true"}}));
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion, nullptr);
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_NE(my_completion2, nullptr);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_remove("foo", my_completion2));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl, sizeof(buf), 0));
+ {
+ TestAlarm alarm;
+ my_completion2->wait_for_complete();
+ my_completion->wait_for_complete();
+ }
+ ASSERT_EQ(-ENOENT, my_completion2->get_return_value());
+ ASSERT_EQ(0, my_completion->get_return_value());
+ ASSERT_EQ(0, test_data.m_ioctx.stat("foo", nullptr, nullptr));
+ delete my_completion;
+ delete my_completion2;
+}
+
+TEST(LibRadosAio, RoundTripCmpExtPP) {
+ AioTestDataPP test_data;
+ ASSERT_EQ("", test_data.init());
+ AioCompletion *my_completion = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+ char full[128];
+ memset(full, 0xcc, sizeof(full));
+ bufferlist bl1;
+ bl1.append(full, sizeof(full));
+ ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion,
+ bl1, sizeof(full), 0));
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion->get_return_value());
+
+ /* compare with match */
+ bufferlist cbl;
+ cbl.append(full, sizeof(full));
+ AioCompletion *my_completion2 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_cmpext("foo", my_completion2, 0, cbl));
+
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion2->wait_for_complete());
+ }
+ ASSERT_EQ(0, my_completion2->get_return_value());
+
+ /* compare with mismatch */
+ memset(full, 0xdd, sizeof(full));
+ cbl.clear();
+ cbl.append(full, sizeof(full));
+ AioCompletion *my_completion3 = test_data.m_cluster.aio_create_completion(
+ nullptr, nullptr, nullptr);
+ ASSERT_EQ(0, test_data.m_ioctx.aio_cmpext("foo", my_completion3, 0, cbl));
+
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, my_completion3->wait_for_complete());
+ }
+ ASSERT_EQ(-MAX_ERRNO, my_completion3->get_return_value());
+
+ delete my_completion;
+ delete my_completion2;
+ delete my_completion3;
+}
+
+TEST(LibRadosAio, RoundTripCmpExtPP2)
+{
+ int ret;
+ char buf[128];
+ char miscmp_buf[128];
+ bufferlist cbl;
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ IoCtx ioctx;
+ cluster.ioctx_create(pool_name.c_str(), ioctx);
+
+ boost::scoped_ptr<AioCompletion>
+ wr_cmpl(cluster.aio_create_completion(0, 0, 0));
+ ObjectWriteOperation wr_op;
+ memset(buf, 0xcc, sizeof(buf));
+ memset(miscmp_buf, 0xdd, sizeof(miscmp_buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ wr_op.write_full(bl);
+ wr_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", wr_cmpl.get(), &wr_op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, wr_cmpl->wait_for_complete());
+ }
+ EXPECT_EQ(0, wr_cmpl->get_return_value());
+
+ /* cmpext as write op. first match then mismatch */
+ boost::scoped_ptr<AioCompletion>
+ wr_cmpext_cmpl(cluster.aio_create_completion(0, 0, 0));
+ cbl.append(buf, sizeof(buf));
+ ret = 0;
+
+ wr_op.cmpext(0, cbl, &ret);
+ wr_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", wr_cmpext_cmpl.get(), &wr_op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, wr_cmpext_cmpl->wait_for_complete());
+ }
+ EXPECT_EQ(0, wr_cmpext_cmpl->get_return_value());
+ EXPECT_EQ(0, ret);
+
+ boost::scoped_ptr<AioCompletion>
+ wr_cmpext_cmpl2(cluster.aio_create_completion(0, 0, 0));
+ cbl.clear();
+ cbl.append(miscmp_buf, sizeof(miscmp_buf));
+ ret = 0;
+
+ wr_op.cmpext(0, cbl, &ret);
+ wr_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", wr_cmpext_cmpl2.get(), &wr_op);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, wr_cmpext_cmpl2->wait_for_complete());
+ }
+ EXPECT_EQ(-MAX_ERRNO, wr_cmpext_cmpl2->get_return_value());
+ EXPECT_EQ(-MAX_ERRNO, ret);
+
+ /* cmpext as read op */
+ boost::scoped_ptr<AioCompletion>
+ rd_cmpext_cmpl(cluster.aio_create_completion(0, 0, 0));
+ ObjectReadOperation rd_op;
+ cbl.clear();
+ cbl.append(buf, sizeof(buf));
+ ret = 0;
+ rd_op.cmpext(0, cbl, &ret);
+ rd_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", rd_cmpext_cmpl.get(), &rd_op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, rd_cmpext_cmpl->wait_for_complete());
+ }
+ EXPECT_EQ(0, rd_cmpext_cmpl->get_return_value());
+ EXPECT_EQ(0, ret);
+
+ boost::scoped_ptr<AioCompletion>
+ rd_cmpext_cmpl2(cluster.aio_create_completion(0, 0, 0));
+ cbl.clear();
+ cbl.append(miscmp_buf, sizeof(miscmp_buf));
+ ret = 0;
+
+ rd_op.cmpext(0, cbl, &ret);
+ rd_op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ioctx.aio_operate("test_obj", rd_cmpext_cmpl2.get(), &rd_op, 0);
+ {
+ TestAlarm alarm;
+ ASSERT_EQ(0, rd_cmpext_cmpl2->wait_for_complete());
+ }
+ EXPECT_EQ(-MAX_ERRNO, rd_cmpext_cmpl2->get_return_value());
+ EXPECT_EQ(-MAX_ERRNO, ret);
+
+ ioctx.remove("test_obj");
+ destroy_one_pool_pp(pool_name, cluster);
+}
// Tests for the C API coverage of atomic write operations
#include <errno.h>
+#include "gtest/gtest.h"
#include "include/err.h"
#include "include/rados/librados.h"
#include "test/librados/test.h"
-#include "gtest/gtest.h"
TEST(LibradosCWriteOps, NewDelete) {
rados_write_op_t op = rados_create_write_op();
-#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
-#include "test/librados/test.h"
-
-#include "gtest/gtest.h"
#include <errno.h>
#include <map>
#include <sstream>
#include <string>
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+#include "test/librados/test_cxx.h"
+
using namespace librados;
using std::map;
using std::ostringstream;
#include <sstream>
#include <string>
-using namespace librados;
using std::map;
using std::ostringstream;
using std::string;
rados_shutdown(cluster);
}
-TEST(LibRadosCmd, MonDescribePP) {
- Rados cluster;
- ASSERT_EQ("", connect_cluster_pp(cluster));
- bufferlist inbl, outbl;
- string outs;
- ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"get_command_descriptions\"}",
- inbl, &outbl, &outs));
- ASSERT_LT(0u, outbl.length());
- ASSERT_LE(0u, outs.length());
- cluster.shutdown();
-}
-
TEST(LibRadosCmd, OSDCmd) {
rados_t cluster;
ASSERT_EQ("", connect_cluster(&cluster));
rados_shutdown(cluster);
}
-TEST(LibRadosCmd, OSDCmdPP) {
- Rados cluster;
- ASSERT_EQ("", connect_cluster_pp(cluster));
- int r;
- bufferlist inbl, outbl;
- string outs;
- string cmd;
-
- // note: tolerate NXIO here in case the cluster is thrashing out underneath us.
- cmd = "asdfasdf";
- r = cluster.osd_command(0, cmd, inbl, &outbl, &outs);
- ASSERT_TRUE(r == -22 || r == -ENXIO);
- cmd = "version";
- r = cluster.osd_command(0, cmd, inbl, &outbl, &outs);
- ASSERT_TRUE(r == -22 || r == -ENXIO);
- cmd = "{\"prefix\":\"version\"}";
- r = cluster.osd_command(0, cmd, inbl, &outbl, &outs);
- ASSERT_TRUE((r == 0 && outbl.length() > 0) || (r == -ENXIO && outbl.length() == 0));
- cluster.shutdown();
-}
-
TEST(LibRadosCmd, PGCmd) {
rados_t cluster;
std::string pool_name = get_temp_pool_name();
ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
}
-TEST(LibRadosCmd, PGCmdPP) {
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
-
- int r;
- bufferlist inbl, outbl;
- string outs;
- string cmd;
-
- int64_t poolid = cluster.pool_lookup(pool_name.c_str());
- ASSERT_LT(0, poolid);
-
- string pgid = stringify(poolid) + ".0";
-
- cmd = "asdfasdf";
- // note: tolerate NXIO here in case the cluster is thrashing out underneath us.
- r = cluster.pg_command(pgid.c_str(), cmd, inbl, &outbl, &outs);
- ASSERT_TRUE(r == -22 || r == -ENXIO);
-
- // make sure the pg exists on the osd before we query it
- IoCtx io;
- cluster.ioctx_create(pool_name.c_str(), io);
- for (int i=0; i<100; i++) {
- string oid = "obj" + stringify(i);
- ASSERT_EQ(-ENOENT, io.stat(oid, NULL, NULL));
- }
- io.close();
-
- cmd = "{\"prefix\":\"pg\", \"cmd\":\"query\", \"pgid\":\"" + pgid + "\"}";
- // note: tolerate ENOENT/ENXIO here if hte osd is thrashing out underneath us
- r = cluster.pg_command(pgid.c_str(), cmd, inbl, &outbl, &outs);
- ASSERT_TRUE(r == 0 || r == -ENOENT || r == -ENXIO);
-
- ASSERT_LT(0u, outbl.length());
-
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
-}
-
struct Log {
list<string> log;
std::condition_variable cond;
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <errno.h>
+#include <condition_variable>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+#include "include/stringify.h"
+#include "test/librados/test_cxx.h"
+
+using namespace librados;
+using std::map;
+using std::ostringstream;
+using std::string;
+
+TEST(LibRadosCmd, MonDescribePP) {
+ Rados cluster;
+ ASSERT_EQ("", connect_cluster_pp(cluster));
+ bufferlist inbl, outbl;
+ string outs;
+ ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"get_command_descriptions\"}",
+ inbl, &outbl, &outs));
+ ASSERT_LT(0u, outbl.length());
+ ASSERT_LE(0u, outs.length());
+ cluster.shutdown();
+}
+
+TEST(LibRadosCmd, OSDCmdPP) {
+ Rados cluster;
+ ASSERT_EQ("", connect_cluster_pp(cluster));
+ int r;
+ bufferlist inbl, outbl;
+ string outs;
+ string cmd;
+
+ // note: tolerate NXIO here in case the cluster is thrashing out underneath us.
+ cmd = "asdfasdf";
+ r = cluster.osd_command(0, cmd, inbl, &outbl, &outs);
+ ASSERT_TRUE(r == -22 || r == -ENXIO);
+ cmd = "version";
+ r = cluster.osd_command(0, cmd, inbl, &outbl, &outs);
+ ASSERT_TRUE(r == -22 || r == -ENXIO);
+ cmd = "{\"prefix\":\"version\"}";
+ r = cluster.osd_command(0, cmd, inbl, &outbl, &outs);
+ ASSERT_TRUE((r == 0 && outbl.length() > 0) || (r == -ENXIO && outbl.length() == 0));
+ cluster.shutdown();
+}
+
+TEST(LibRadosCmd, PGCmdPP) {
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+
+ int r;
+ bufferlist inbl, outbl;
+ string outs;
+ string cmd;
+
+ int64_t poolid = cluster.pool_lookup(pool_name.c_str());
+ ASSERT_LT(0, poolid);
+
+ string pgid = stringify(poolid) + ".0";
+
+ cmd = "asdfasdf";
+ // note: tolerate NXIO here in case the cluster is thrashing out underneath us.
+ r = cluster.pg_command(pgid.c_str(), cmd, inbl, &outbl, &outs);
+ ASSERT_TRUE(r == -22 || r == -ENXIO);
+
+ // make sure the pg exists on the osd before we query it
+ IoCtx io;
+ cluster.ioctx_create(pool_name.c_str(), io);
+ for (int i=0; i<100; i++) {
+ string oid = "obj" + stringify(i);
+ ASSERT_EQ(-ENOENT, io.stat(oid, NULL, NULL));
+ }
+ io.close();
+
+ cmd = "{\"prefix\":\"pg\", \"cmd\":\"query\", \"pgid\":\"" + pgid + "\"}";
+ // note: tolerate ENOENT/ENXIO here if hte osd is thrashing out underneath us
+ r = cluster.pg_command(pgid.c_str(), cmd, inbl, &outbl, &outs);
+ ASSERT_TRUE(r == 0 || r == -ENOENT || r == -ENXIO);
+
+ ASSERT_LT(0u, outbl.length());
+
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}
+
#include <climits>
#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
#include "include/encoding.h"
#include "include/err.h"
#include "include/scope_guard.h"
#include <errno.h>
#include "gtest/gtest.h"
-using namespace librados;
using std::string;
typedef RadosTest LibRadosIo;
typedef RadosTestEC LibRadosIoEC;
-typedef RadosTestPP LibRadosIoPP;
-typedef RadosTestECPP LibRadosIoECPP;
TEST_F(LibRadosIo, SimpleWrite) {
char buf[128];
ASSERT_EQ(-E2BIG, rados_append(ioctx, "A", buf, UINT_MAX));
ASSERT_EQ(-E2BIG, rados_write_full(ioctx, "A", buf, UINT_MAX));
ASSERT_EQ(-E2BIG, rados_writesame(ioctx, "A", buf, sizeof(buf), UINT_MAX, 0));
- IoCtx ioctx;
- bufferlist bl;
- ASSERT_EQ(-E2BIG, ioctx.write("foo", bl, UINT_MAX, 0));
- ASSERT_EQ(-E2BIG, ioctx.append("foo", bl, UINT_MAX));
- // ioctx.write_full no way to overflow bl.length()
- ASSERT_EQ(-E2BIG, ioctx.writesame("foo", bl, UINT_MAX, 0));
}
TEST_F(LibRadosIo, ReadTimeout) {
}
}
-TEST_F(LibRadosIoPP, SimpleWritePP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- ioctx.set_namespace("nspace");
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
-}
-
-TEST_F(LibRadosIoPP, ReadOpPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
-
- {
- bufferlist op_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist op_bl;
- ObjectReadOperation op;
- op.read(0, 0, NULL, NULL); //len=0 mean read the whole object data.
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl, op_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist op_bl;
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, rval);
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl, op_bl;
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, rval);
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl1, read_bl2, op_bl;
- int rval1 = 1000, rval2 = 1002;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl1, &rval1);
- op.read(0, sizeof(buf), &read_bl2, &rval2);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), read_bl1.length());
- ASSERT_EQ(sizeof(buf), read_bl2.length());
- ASSERT_EQ(sizeof(buf) * 2, op_bl.length());
- ASSERT_EQ(0, rval1);
- ASSERT_EQ(0, rval2);
- ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf)));
- }
-
- {
- bufferlist op_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(0, rval);
- }
-
- {
- bufferlist read_bl;
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(0, rval);
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl1, read_bl2;
- int rval1 = 1000, rval2 = 1002;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl1, &rval1);
- op.read(0, sizeof(buf), &read_bl2, &rval2);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(sizeof(buf), read_bl1.length());
- ASSERT_EQ(sizeof(buf), read_bl2.length());
- ASSERT_EQ(0, rval1);
- ASSERT_EQ(0, rval2);
- ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
- }
-}
-
-TEST_F(LibRadosIoPP, SparseReadOpPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
-
- {
- std::map<uint64_t, uint64_t> extents;
- bufferlist read_bl;
- int rval = -1;
- ObjectReadOperation op;
- op.sparse_read(0, sizeof(buf), &extents, &read_bl, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, nullptr));
- ASSERT_EQ(0, rval);
- assert_eq_sparse(bl, extents, read_bl);
- }
-}
TEST_F(LibRadosIo, RoundTrip) {
char buf[128];
ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
}
-TEST_F(LibRadosIoPP, RoundTripPP) {
- char buf[128];
- Rados cluster;
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- bufferlist cl;
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
-}
-
-TEST_F(LibRadosIoPP, RoundTripPP2)
-{
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write;
- write.write(0, bl);
- write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
-}
-
TEST_F(LibRadosIo, Checksum) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(expected_crc, crc[1]);
}
-TEST_F(LibRadosIoPP, Checksum) {
- char buf[128];
- Rados cluster;
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- bufferlist init_value_bl;
- encode(static_cast<uint32_t>(-1), init_value_bl);
- bufferlist csum_bl;
- ASSERT_EQ(0, ioctx.checksum("foo", LIBRADOS_CHECKSUM_TYPE_CRC32C,
- init_value_bl, sizeof(buf), 0, 0, &csum_bl));
- auto csum_bl_it = csum_bl.cbegin();
- uint32_t csum_count;
- decode(csum_count, csum_bl_it);
- ASSERT_EQ(1U, csum_count);
- uint32_t csum;
- decode(csum, csum_bl_it);
- ASSERT_EQ(bl.crc32c(-1), csum);
-}
-
TEST_F(LibRadosIo, OverlappingWriteRoundTrip) {
char buf[128];
char buf2[64];
ASSERT_EQ(0, memcmp(buf3 + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
}
-TEST_F(LibRadosIoPP, OverlappingWriteRoundTripPP) {
- char buf[128];
- char buf2[64];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
- bufferlist bl3;
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
- ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
-}
-
TEST_F(LibRadosIo, WriteFullRoundTrip) {
char buf[128];
char buf2[64];
ASSERT_EQ(0, memcmp(buf2, buf3, sizeof(buf2)));
}
-TEST_F(LibRadosIoPP, WriteFullRoundTripPP) {
- char buf[128];
- char buf2[64];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ASSERT_EQ(0, ioctx.write_full("foo", bl2));
- bufferlist bl3;
- ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
-}
-
-TEST_F(LibRadosIoPP, WriteFullRoundTripPP2)
-{
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write;
- write.write_full(bl);
- write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
-}
-
TEST_F(LibRadosIo, AppendRoundTrip) {
char buf[64];
char buf2[64];
ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2)));
}
-TEST_F(LibRadosIoPP, AppendRoundTripPP) {
- char buf[64];
- char buf2[64];
- memset(buf, 0xde, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- memset(buf2, 0xad, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ASSERT_EQ(0, ioctx.append("foo", bl2, sizeof(buf2)));
- bufferlist bl3;
- ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)),
- ioctx.read("foo", bl3, (sizeof(buf) + sizeof(buf2)), 0));
- const char *bl3_str = bl3.c_str();
- ASSERT_EQ(0, memcmp(bl3_str, buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(bl3_str + sizeof(buf), buf2, sizeof(buf2)));
-}
-
TEST_F(LibRadosIo, TruncTest) {
char buf[128];
char buf2[sizeof(buf)];
ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)/2));
}
-TEST_F(LibRadosIoPP, TruncTestPP) {
- char buf[128];
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf)));
- ASSERT_EQ(0, ioctx.trunc("foo", sizeof(buf) / 2));
- bufferlist bl2;
- ASSERT_EQ((int)(sizeof(buf)/2), ioctx.read("foo", bl2, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)/2));
-}
-
TEST_F(LibRadosIo, RemoveTest) {
char buf[128];
char buf2[sizeof(buf)];
ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
}
-TEST_F(LibRadosIoPP, RemoveTestPP) {
- char buf[128];
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- ASSERT_EQ(0, ioctx.remove("foo"));
- bufferlist bl2;
- ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0));
-}
-
TEST_F(LibRadosIo, XattrsRoundTrip) {
char buf[128];
char attr1[] = "attr1";
ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
}
-TEST_F(LibRadosIoPP, XattrsRoundTripPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2));
- bufferlist bl3;
- bl3.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3));
- bufferlist bl4;
- ASSERT_EQ((int)sizeof(attr1_buf),
- ioctx.getxattr("foo", attr1, bl4));
- ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
-}
-
TEST_F(LibRadosIo, RmXattr) {
char buf[128];
char attr1[] = "attr1";
ASSERT_EQ(-ENOENT, rados_rmxattr(ioctx, "foo_rmxattr", attr2));
}
-TEST_F(LibRadosIoPP, RmXattrPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- bl2.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
- ASSERT_EQ(0, ioctx.rmxattr("foo", attr1));
- bufferlist bl3;
- ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3));
-
- // Test rmxattr on a removed object
- char buf2[128];
- char attr2[] = "attr2";
- char attr2_buf[] = "foo bar baz";
- memset(buf2, 0xbb, sizeof(buf2));
- bufferlist bl21;
- bl21.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
- bufferlist bl22;
- bl22.append(attr2_buf, sizeof(attr2_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo_rmxattr", attr2, bl22));
- ASSERT_EQ(0, ioctx.remove("foo_rmxattr"));
- ASSERT_EQ(-ENOENT, ioctx.rmxattr("foo_rmxattr", attr2));
-}
-
TEST_F(LibRadosIo, XattrIter) {
char buf[128];
char attr1[] = "attr1";
rados_getxattrs_end(iter);
}
-TEST_F(LibRadosIoPP, XattrListPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- char attr2[] = "attr2";
- char attr2_buf[256];
- for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
- attr2_buf[j] = j % 0xff;
- }
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- bl2.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
- bufferlist bl3;
- bl3.append(attr2_buf, sizeof(attr2_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3));
- std::map<std::string, bufferlist> attrset;
- ASSERT_EQ(0, ioctx.getxattrs("foo", attrset));
- for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
- i != attrset.end(); ++i) {
- if (i->first == string(attr1)) {
- ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
- }
- else if (i->first == string(attr2)) {
- ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
- }
- else {
- ASSERT_EQ(0, 1);
- }
- }
-}
-
TEST_F(LibRadosIoEC, SimpleWrite) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
}
-TEST_F(LibRadosIoECPP, SimpleWritePP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- ioctx.set_namespace("nspace");
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
-}
-
-TEST_F(LibRadosIoECPP, ReadOpPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
-
- {
- bufferlist op_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist op_bl;
- ObjectReadOperation op;
- op.read(0, 0, NULL, NULL); //len=0 mean read the whole object data
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl, op_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist op_bl;
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, rval);
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl, op_bl;
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, rval);
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl1, read_bl2, op_bl;
- int rval1 = 1000, rval2 = 1002;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl1, &rval1);
- op.read(0, sizeof(buf), &read_bl2, &rval2);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), read_bl1.length());
- ASSERT_EQ(sizeof(buf), read_bl2.length());
- ASSERT_EQ(sizeof(buf) * 2, op_bl.length());
- ASSERT_EQ(0, rval1);
- ASSERT_EQ(0, rval2);
- ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf)));
- }
-
- {
- bufferlist op_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
- ASSERT_EQ(sizeof(buf), op_bl.length());
- ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), NULL, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(0, rval);
- }
-
- {
- bufferlist read_bl;
- int rval = 1000;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(sizeof(buf), read_bl.length());
- ASSERT_EQ(0, rval);
- ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
- }
-
- {
- bufferlist read_bl1, read_bl2;
- int rval1 = 1000, rval2 = 1002;
- ObjectReadOperation op;
- op.read(0, sizeof(buf), &read_bl1, &rval1);
- op.read(0, sizeof(buf), &read_bl2, &rval2);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(sizeof(buf), read_bl1.length());
- ASSERT_EQ(sizeof(buf), read_bl2.length());
- ASSERT_EQ(0, rval1);
- ASSERT_EQ(0, rval2);
- ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
- ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
- }
-}
-
-TEST_F(LibRadosIoECPP, SparseReadOpPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
-
- {
- std::map<uint64_t, uint64_t> extents;
- bufferlist read_bl;
- int rval = -1;
- ObjectReadOperation op;
- op.sparse_read(0, sizeof(buf), &extents, &read_bl, &rval);
- ASSERT_EQ(0, ioctx.operate("foo", &op, nullptr));
- ASSERT_EQ(0, rval);
- assert_eq_sparse(bl, extents, read_bl);
- }
-}
-
TEST_F(LibRadosIoEC, RoundTrip) {
char buf[128];
char buf2[128];
ASSERT_EQ(-EOPNOTSUPP, rados_write(ioctx, "bar", buf, sizeof(buf), off));
}
-TEST_F(LibRadosIoECPP, RoundTripPP) {
- char buf[128];
- Rados cluster;
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- bufferlist cl;
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf) * 3, 0));
- ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
-}
-
-TEST_F(LibRadosIoECPP, RoundTripPP2)
-{
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write;
- write.write(0, bl);
- write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
-}
-
TEST_F(LibRadosIoEC, OverlappingWriteRoundTrip) {
int bsize = alignment;
int dbsize = bsize * 2;
ASSERT_EQ(0, memcmp(buf3, buf, dbsize));
}
-TEST_F(LibRadosIoECPP, OverlappingWriteRoundTripPP) {
- int bsize = alignment;
- int dbsize = bsize * 2;
- char *buf = (char *)new char[dbsize];
- char *buf2 = (char *)new char[bsize];
- auto cleanup = [&] {
- delete[] buf;
- delete[] buf2;
- };
- scope_guard<decltype(cleanup)> sg(std::move(cleanup));
- memset(buf, 0xcc, dbsize);
- bufferlist bl1;
- bl1.append(buf, dbsize);
- ASSERT_EQ(0, ioctx.write("foo", bl1, dbsize, 0));
- memset(buf2, 0xdd, bsize);
- bufferlist bl2;
- bl2.append(buf2, bsize);
- ASSERT_EQ(-EOPNOTSUPP, ioctx.write("foo", bl2, bsize, 0));
- bufferlist bl3;
- ASSERT_EQ(dbsize, ioctx.read("foo", bl3, dbsize, 0));
- // Read the same as first write
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, dbsize));
-}
-
TEST_F(LibRadosIoEC, WriteFullRoundTrip) {
char buf[128];
char buf2[64];
ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
}
-TEST_F(LibRadosIoECPP, WriteFullRoundTripPP) {
- char buf[128];
- char buf2[64];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ASSERT_EQ(0, ioctx.write_full("foo", bl2));
- bufferlist bl3;
- ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
-}
-
-TEST_F(LibRadosIoECPP, WriteFullRoundTripPP2)
-{
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write;
- write.write_full(bl);
- write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
-}
-
TEST_F(LibRadosIoEC, AppendRoundTrip) {
char *buf = (char *)new char[alignment];
char *buf2 = (char *)new char[alignment];
ASSERT_EQ(-EOPNOTSUPP, rados_append(ioctx, "foo", unalignedbuf, uasize));
}
-TEST_F(LibRadosIoECPP, AppendRoundTripPP) {
- char *buf = (char *)new char[alignment];
- char *buf2 = (char *)new char[alignment];
- auto cleanup = [&] {
- delete[] buf;
- delete[] buf2;
- };
- scope_guard<decltype(cleanup)> sg(std::move(cleanup));
- memset(buf, 0xde, alignment);
- bufferlist bl1;
- bl1.append(buf, alignment);
- ASSERT_EQ(0, ioctx.append("foo", bl1, alignment));
- memset(buf2, 0xad, alignment);
- bufferlist bl2;
- bl2.append(buf2, alignment);
- ASSERT_EQ(0, ioctx.append("foo", bl2, alignment));
- bufferlist bl3;
- ASSERT_EQ((int)(alignment * 2),
- ioctx.read("foo", bl3, (alignment * 4), 0));
- const char *bl3_str = bl3.c_str();
- ASSERT_EQ(0, memcmp(bl3_str, buf, alignment));
- ASSERT_EQ(0, memcmp(bl3_str + alignment, buf2, alignment));
-}
-
TEST_F(LibRadosIoEC, TruncTest) {
char buf[128];
char buf2[sizeof(buf)];
ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
}
-TEST_F(LibRadosIoECPP, TruncTestPP) {
- char buf[128];
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf)));
- ASSERT_EQ(-EOPNOTSUPP, ioctx.trunc("foo", sizeof(buf) / 2));
- bufferlist bl2;
- // Same size
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl2, sizeof(buf), 0));
- // No change
- ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)));
-}
-
TEST_F(LibRadosIoEC, RemoveTest) {
char buf[128];
char buf2[sizeof(buf)];
ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
}
-TEST_F(LibRadosIoECPP, RemoveTestPP) {
- char buf[128];
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- ASSERT_EQ(0, ioctx.remove("foo"));
- bufferlist bl2;
- ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0));
-}
-
TEST_F(LibRadosIoEC, XattrsRoundTrip) {
char buf[128];
char attr1[] = "attr1";
ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
}
-TEST_F(LibRadosIoECPP, XattrsRoundTripPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2));
- bufferlist bl3;
- bl3.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3));
- bufferlist bl4;
- ASSERT_EQ((int)sizeof(attr1_buf),
- ioctx.getxattr("foo", attr1, bl4));
- ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
-}
-
TEST_F(LibRadosIoEC, RmXattr) {
char buf[128];
char attr1[] = "attr1";
ASSERT_EQ(-ENOENT, rados_rmxattr(ioctx, "foo_rmxattr", attr2));
}
-TEST_F(LibRadosIoECPP, RmXattrPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- bl2.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
- ASSERT_EQ(0, ioctx.rmxattr("foo", attr1));
- bufferlist bl3;
- ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3));
-
- // Test rmxattr on a removed object
- char buf2[128];
- char attr2[] = "attr2";
- char attr2_buf[] = "foo bar baz";
- memset(buf2, 0xbb, sizeof(buf2));
- bufferlist bl21;
- bl21.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
- bufferlist bl22;
- bl22.append(attr2_buf, sizeof(attr2_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo_rmxattr", attr2, bl22));
- ASSERT_EQ(0, ioctx.remove("foo_rmxattr"));
- ASSERT_EQ(-ENOENT, ioctx.rmxattr("foo_rmxattr", attr2));
-}
-
TEST_F(LibRadosIoEC, XattrIter) {
char buf[128];
char attr1[] = "attr1";
}
rados_getxattrs_end(iter);
}
-
-TEST_F(LibRadosIoECPP, XattrListPP) {
- char buf[128];
- char attr1[] = "attr1";
- char attr1_buf[] = "foo bar baz";
- char attr2[] = "attr2";
- char attr2_buf[256];
- for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
- attr2_buf[j] = j % 0xff;
- }
- memset(buf, 0xaa, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
- bufferlist bl2;
- bl2.append(attr1_buf, sizeof(attr1_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
- bufferlist bl3;
- bl3.append(attr2_buf, sizeof(attr2_buf));
- ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3));
- std::map<std::string, bufferlist> attrset;
- ASSERT_EQ(0, ioctx.getxattrs("foo", attrset));
- for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
- i != attrset.end(); ++i) {
- if (i->first == string(attr1)) {
- ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
- }
- else if (i->first == string(attr2)) {
- ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
- }
- else {
- ASSERT_EQ(0, 1);
- }
- }
-}
-
-TEST_F(LibRadosIoPP, CmpExtPP) {
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write1;
- write1.write(0, bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write1));
-
- bufferlist new_bl;
- new_bl.append("CEPH");
- ObjectWriteOperation write2;
- write2.cmpext(0, bl, nullptr);
- write2.write(0, new_bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write2));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
-}
-
-TEST_F(LibRadosIoPP, CmpExtDNEPP) {
- bufferlist bl;
- bl.append(std::string(4, '\0'));
-
- bufferlist new_bl;
- new_bl.append("CEPH");
- ObjectWriteOperation write;
- write.cmpext(0, bl, nullptr);
- write.write(0, new_bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
-}
-
-TEST_F(LibRadosIoPP, CmpExtMismatchPP) {
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write1;
- write1.write(0, bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write1));
-
- bufferlist new_bl;
- new_bl.append("CEPH");
- ObjectWriteOperation write2;
- write2.cmpext(0, new_bl, nullptr);
- write2.write(0, new_bl);
- ASSERT_EQ(-MAX_ERRNO, ioctx.operate("foo", &write2));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
-}
-
-TEST_F(LibRadosIoECPP, CmpExtPP) {
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write1;
- write1.write(0, bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write1));
-
- bufferlist new_bl;
- new_bl.append("CEPH");
- ObjectWriteOperation write2;
- write2.cmpext(0, bl, nullptr);
- write2.write_full(new_bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write2));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
-}
-
-TEST_F(LibRadosIoECPP, CmpExtDNEPP) {
- bufferlist bl;
- bl.append(std::string(4, '\0'));
-
- bufferlist new_bl;
- new_bl.append("CEPH");
- ObjectWriteOperation write;
- write.cmpext(0, bl, nullptr);
- write.write_full(new_bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
-}
-
-TEST_F(LibRadosIoECPP, CmpExtMismatchPP) {
- bufferlist bl;
- bl.append("ceph");
- ObjectWriteOperation write1;
- write1.write(0, bl);
- ASSERT_EQ(0, ioctx.operate("foo", &write1));
-
- bufferlist new_bl;
- new_bl.append("CEPH");
- ObjectWriteOperation write2;
- write2.cmpext(0, new_bl, nullptr);
- write2.write_full(new_bl);
- ASSERT_EQ(-MAX_ERRNO, ioctx.operate("foo", &write2));
-
- ObjectReadOperation read;
- read.read(0, bl.length(), NULL, NULL);
- ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
- ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
-}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
+// vim: ts=8 sw=2 smarttab
+
+#include <climits>
+#include <errno.h>
+
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+#include "include/encoding.h"
+#include "include/err.h"
+#include "include/scope_guard.h"
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+
+using namespace librados;
+using std::string;
+
+typedef RadosTestPP LibRadosIoPP;
+typedef RadosTestECPP LibRadosIoECPP;
+
+TEST_F(LibRadosIoPP, TooBigPP) {
+ IoCtx ioctx;
+ bufferlist bl;
+ ASSERT_EQ(-E2BIG, ioctx.write("foo", bl, UINT_MAX, 0));
+ ASSERT_EQ(-E2BIG, ioctx.append("foo", bl, UINT_MAX));
+ // ioctx.write_full no way to overflow bl.length()
+ ASSERT_EQ(-E2BIG, ioctx.writesame("foo", bl, UINT_MAX, 0));
+}
+
+TEST_F(LibRadosIoPP, SimpleWritePP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ ioctx.set_namespace("nspace");
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+}
+
+TEST_F(LibRadosIoPP, ReadOpPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+
+ {
+ bufferlist op_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist op_bl;
+ ObjectReadOperation op;
+ op.read(0, 0, NULL, NULL); //len=0 mean read the whole object data.
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl, op_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist op_bl;
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, rval);
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl, op_bl;
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, rval);
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl1, read_bl2, op_bl;
+ int rval1 = 1000, rval2 = 1002;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl1, &rval1);
+ op.read(0, sizeof(buf), &read_bl2, &rval2);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), read_bl1.length());
+ ASSERT_EQ(sizeof(buf), read_bl2.length());
+ ASSERT_EQ(sizeof(buf) * 2, op_bl.length());
+ ASSERT_EQ(0, rval1);
+ ASSERT_EQ(0, rval2);
+ ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist op_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(0, rval);
+ }
+
+ {
+ bufferlist read_bl;
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(0, rval);
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl1, read_bl2;
+ int rval1 = 1000, rval2 = 1002;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl1, &rval1);
+ op.read(0, sizeof(buf), &read_bl2, &rval2);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(sizeof(buf), read_bl1.length());
+ ASSERT_EQ(sizeof(buf), read_bl2.length());
+ ASSERT_EQ(0, rval1);
+ ASSERT_EQ(0, rval2);
+ ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
+ }
+}
+
+TEST_F(LibRadosIoPP, SparseReadOpPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+
+ {
+ std::map<uint64_t, uint64_t> extents;
+ bufferlist read_bl;
+ int rval = -1;
+ ObjectReadOperation op;
+ op.sparse_read(0, sizeof(buf), &extents, &read_bl, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, nullptr));
+ ASSERT_EQ(0, rval);
+ assert_eq_sparse(bl, extents, read_bl);
+ }
+}
+
+TEST_F(LibRadosIoPP, RoundTripPP) {
+ char buf[128];
+ Rados cluster;
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ bufferlist cl;
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
+}
+
+TEST_F(LibRadosIoPP, RoundTripPP2)
+{
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write;
+ write.write(0, bl);
+ write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
+}
+
+TEST_F(LibRadosIoPP, Checksum) {
+ char buf[128];
+ Rados cluster;
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ bufferlist init_value_bl;
+ encode(static_cast<uint32_t>(-1), init_value_bl);
+ bufferlist csum_bl;
+ ASSERT_EQ(0, ioctx.checksum("foo", LIBRADOS_CHECKSUM_TYPE_CRC32C,
+ init_value_bl, sizeof(buf), 0, 0, &csum_bl));
+ auto csum_bl_it = csum_bl.cbegin();
+ uint32_t csum_count;
+ decode(csum_count, csum_bl_it);
+ ASSERT_EQ(1U, csum_count);
+ uint32_t csum;
+ decode(csum, csum_bl_it);
+ ASSERT_EQ(bl.crc32c(-1), csum);
+}
+
+TEST_F(LibRadosIoPP, OverlappingWriteRoundTripPP) {
+ char buf[128];
+ char buf2[64];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
+ bufferlist bl3;
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+ ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
+}
+
+TEST_F(LibRadosIoPP, WriteFullRoundTripPP) {
+ char buf[128];
+ char buf2[64];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ASSERT_EQ(0, ioctx.write_full("foo", bl2));
+ bufferlist bl3;
+ ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+}
+
+TEST_F(LibRadosIoPP, WriteFullRoundTripPP2)
+{
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write;
+ write.write_full(bl);
+ write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
+}
+
+TEST_F(LibRadosIoPP, AppendRoundTripPP) {
+ char buf[64];
+ char buf2[64];
+ memset(buf, 0xde, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ memset(buf2, 0xad, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ASSERT_EQ(0, ioctx.append("foo", bl2, sizeof(buf2)));
+ bufferlist bl3;
+ ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)),
+ ioctx.read("foo", bl3, (sizeof(buf) + sizeof(buf2)), 0));
+ const char *bl3_str = bl3.c_str();
+ ASSERT_EQ(0, memcmp(bl3_str, buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(bl3_str + sizeof(buf), buf2, sizeof(buf2)));
+}
+
+TEST_F(LibRadosIoPP, TruncTestPP) {
+ char buf[128];
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf)));
+ ASSERT_EQ(0, ioctx.trunc("foo", sizeof(buf) / 2));
+ bufferlist bl2;
+ ASSERT_EQ((int)(sizeof(buf)/2), ioctx.read("foo", bl2, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)/2));
+}
+
+TEST_F(LibRadosIoPP, RemoveTestPP) {
+ char buf[128];
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ ASSERT_EQ(0, ioctx.remove("foo"));
+ bufferlist bl2;
+ ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0));
+}
+
+TEST_F(LibRadosIoPP, XattrsRoundTripPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2));
+ bufferlist bl3;
+ bl3.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3));
+ bufferlist bl4;
+ ASSERT_EQ((int)sizeof(attr1_buf),
+ ioctx.getxattr("foo", attr1, bl4));
+ ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
+}
+
+TEST_F(LibRadosIoPP, RmXattrPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ bl2.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
+ ASSERT_EQ(0, ioctx.rmxattr("foo", attr1));
+ bufferlist bl3;
+ ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3));
+
+ // Test rmxattr on a removed object
+ char buf2[128];
+ char attr2[] = "attr2";
+ char attr2_buf[] = "foo bar baz";
+ memset(buf2, 0xbb, sizeof(buf2));
+ bufferlist bl21;
+ bl21.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
+ bufferlist bl22;
+ bl22.append(attr2_buf, sizeof(attr2_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo_rmxattr", attr2, bl22));
+ ASSERT_EQ(0, ioctx.remove("foo_rmxattr"));
+ ASSERT_EQ(-ENOENT, ioctx.rmxattr("foo_rmxattr", attr2));
+}
+
+TEST_F(LibRadosIoPP, XattrListPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ char attr2[] = "attr2";
+ char attr2_buf[256];
+ for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
+ attr2_buf[j] = j % 0xff;
+ }
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ bl2.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
+ bufferlist bl3;
+ bl3.append(attr2_buf, sizeof(attr2_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3));
+ std::map<std::string, bufferlist> attrset;
+ ASSERT_EQ(0, ioctx.getxattrs("foo", attrset));
+ for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
+ i != attrset.end(); ++i) {
+ if (i->first == string(attr1)) {
+ ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
+ }
+ else if (i->first == string(attr2)) {
+ ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
+ }
+ else {
+ ASSERT_EQ(0, 1);
+ }
+ }
+}
+
+TEST_F(LibRadosIoECPP, SimpleWritePP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ ioctx.set_namespace("nspace");
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+}
+
+TEST_F(LibRadosIoECPP, ReadOpPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+
+ {
+ bufferlist op_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist op_bl;
+ ObjectReadOperation op;
+ op.read(0, 0, NULL, NULL); //len=0 mean read the whole object data
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl, op_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist op_bl;
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, rval);
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl, op_bl;
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, rval);
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl1, read_bl2, op_bl;
+ int rval1 = 1000, rval2 = 1002;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl1, &rval1);
+ op.read(0, sizeof(buf), &read_bl2, &rval2);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), read_bl1.length());
+ ASSERT_EQ(sizeof(buf), read_bl2.length());
+ ASSERT_EQ(sizeof(buf) * 2, op_bl.length());
+ ASSERT_EQ(0, rval1);
+ ASSERT_EQ(0, rval2);
+ ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist op_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
+ ASSERT_EQ(sizeof(buf), op_bl.length());
+ ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), NULL, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(0, rval);
+ }
+
+ {
+ bufferlist read_bl;
+ int rval = 1000;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(sizeof(buf), read_bl.length());
+ ASSERT_EQ(0, rval);
+ ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
+ }
+
+ {
+ bufferlist read_bl1, read_bl2;
+ int rval1 = 1000, rval2 = 1002;
+ ObjectReadOperation op;
+ op.read(0, sizeof(buf), &read_bl1, &rval1);
+ op.read(0, sizeof(buf), &read_bl2, &rval2);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(sizeof(buf), read_bl1.length());
+ ASSERT_EQ(sizeof(buf), read_bl2.length());
+ ASSERT_EQ(0, rval1);
+ ASSERT_EQ(0, rval2);
+ ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
+ }
+}
+
+TEST_F(LibRadosIoECPP, SparseReadOpPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+
+ {
+ std::map<uint64_t, uint64_t> extents;
+ bufferlist read_bl;
+ int rval = -1;
+ ObjectReadOperation op;
+ op.sparse_read(0, sizeof(buf), &extents, &read_bl, &rval);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, nullptr));
+ ASSERT_EQ(0, rval);
+ assert_eq_sparse(bl, extents, read_bl);
+ }
+}
+
+TEST_F(LibRadosIoECPP, RoundTripPP) {
+ char buf[128];
+ Rados cluster;
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ bufferlist cl;
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf) * 3, 0));
+ ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
+}
+
+TEST_F(LibRadosIoECPP, RoundTripPP2)
+{
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write;
+ write.write(0, bl);
+ write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
+}
+
+TEST_F(LibRadosIoECPP, OverlappingWriteRoundTripPP) {
+ int bsize = alignment;
+ int dbsize = bsize * 2;
+ char *buf = (char *)new char[dbsize];
+ char *buf2 = (char *)new char[bsize];
+ auto cleanup = [&] {
+ delete[] buf;
+ delete[] buf2;
+ };
+ scope_guard<decltype(cleanup)> sg(std::move(cleanup));
+ memset(buf, 0xcc, dbsize);
+ bufferlist bl1;
+ bl1.append(buf, dbsize);
+ ASSERT_EQ(0, ioctx.write("foo", bl1, dbsize, 0));
+ memset(buf2, 0xdd, bsize);
+ bufferlist bl2;
+ bl2.append(buf2, bsize);
+ ASSERT_EQ(-EOPNOTSUPP, ioctx.write("foo", bl2, bsize, 0));
+ bufferlist bl3;
+ ASSERT_EQ(dbsize, ioctx.read("foo", bl3, dbsize, 0));
+ // Read the same as first write
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, dbsize));
+}
+
+TEST_F(LibRadosIoECPP, WriteFullRoundTripPP) {
+ char buf[128];
+ char buf2[64];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ASSERT_EQ(0, ioctx.write_full("foo", bl2));
+ bufferlist bl3;
+ ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
+}
+
+TEST_F(LibRadosIoECPP, WriteFullRoundTripPP2)
+{
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write;
+ write.write_full(bl);
+ write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
+}
+
+TEST_F(LibRadosIoECPP, AppendRoundTripPP) {
+ char *buf = (char *)new char[alignment];
+ char *buf2 = (char *)new char[alignment];
+ auto cleanup = [&] {
+ delete[] buf;
+ delete[] buf2;
+ };
+ scope_guard<decltype(cleanup)> sg(std::move(cleanup));
+ memset(buf, 0xde, alignment);
+ bufferlist bl1;
+ bl1.append(buf, alignment);
+ ASSERT_EQ(0, ioctx.append("foo", bl1, alignment));
+ memset(buf2, 0xad, alignment);
+ bufferlist bl2;
+ bl2.append(buf2, alignment);
+ ASSERT_EQ(0, ioctx.append("foo", bl2, alignment));
+ bufferlist bl3;
+ ASSERT_EQ((int)(alignment * 2),
+ ioctx.read("foo", bl3, (alignment * 4), 0));
+ const char *bl3_str = bl3.c_str();
+ ASSERT_EQ(0, memcmp(bl3_str, buf, alignment));
+ ASSERT_EQ(0, memcmp(bl3_str + alignment, buf2, alignment));
+}
+
+TEST_F(LibRadosIoECPP, TruncTestPP) {
+ char buf[128];
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf)));
+ ASSERT_EQ(-EOPNOTSUPP, ioctx.trunc("foo", sizeof(buf) / 2));
+ bufferlist bl2;
+ // Same size
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl2, sizeof(buf), 0));
+ // No change
+ ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)));
+}
+
+TEST_F(LibRadosIoECPP, RemoveTestPP) {
+ char buf[128];
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ ASSERT_EQ(0, ioctx.remove("foo"));
+ bufferlist bl2;
+ ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0));
+}
+
+TEST_F(LibRadosIoECPP, XattrsRoundTripPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2));
+ bufferlist bl3;
+ bl3.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3));
+ bufferlist bl4;
+ ASSERT_EQ((int)sizeof(attr1_buf),
+ ioctx.getxattr("foo", attr1, bl4));
+ ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
+}
+
+TEST_F(LibRadosIoECPP, RmXattrPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ bl2.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
+ ASSERT_EQ(0, ioctx.rmxattr("foo", attr1));
+ bufferlist bl3;
+ ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3));
+
+ // Test rmxattr on a removed object
+ char buf2[128];
+ char attr2[] = "attr2";
+ char attr2_buf[] = "foo bar baz";
+ memset(buf2, 0xbb, sizeof(buf2));
+ bufferlist bl21;
+ bl21.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
+ bufferlist bl22;
+ bl22.append(attr2_buf, sizeof(attr2_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo_rmxattr", attr2, bl22));
+ ASSERT_EQ(0, ioctx.remove("foo_rmxattr"));
+ ASSERT_EQ(-ENOENT, ioctx.rmxattr("foo_rmxattr", attr2));
+}
+
+TEST_F(LibRadosIoECPP, XattrListPP) {
+ char buf[128];
+ char attr1[] = "attr1";
+ char attr1_buf[] = "foo bar baz";
+ char attr2[] = "attr2";
+ char attr2_buf[256];
+ for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
+ attr2_buf[j] = j % 0xff;
+ }
+ memset(buf, 0xaa, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
+ bufferlist bl2;
+ bl2.append(attr1_buf, sizeof(attr1_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
+ bufferlist bl3;
+ bl3.append(attr2_buf, sizeof(attr2_buf));
+ ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3));
+ std::map<std::string, bufferlist> attrset;
+ ASSERT_EQ(0, ioctx.getxattrs("foo", attrset));
+ for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
+ i != attrset.end(); ++i) {
+ if (i->first == string(attr1)) {
+ ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
+ }
+ else if (i->first == string(attr2)) {
+ ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
+ }
+ else {
+ ASSERT_EQ(0, 1);
+ }
+ }
+}
+
+TEST_F(LibRadosIoPP, CmpExtPP) {
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write1;
+ write1.write(0, bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write1));
+
+ bufferlist new_bl;
+ new_bl.append("CEPH");
+ ObjectWriteOperation write2;
+ write2.cmpext(0, bl, nullptr);
+ write2.write(0, new_bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write2));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
+}
+
+TEST_F(LibRadosIoPP, CmpExtDNEPP) {
+ bufferlist bl;
+ bl.append(std::string(4, '\0'));
+
+ bufferlist new_bl;
+ new_bl.append("CEPH");
+ ObjectWriteOperation write;
+ write.cmpext(0, bl, nullptr);
+ write.write(0, new_bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
+}
+
+TEST_F(LibRadosIoPP, CmpExtMismatchPP) {
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write1;
+ write1.write(0, bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write1));
+
+ bufferlist new_bl;
+ new_bl.append("CEPH");
+ ObjectWriteOperation write2;
+ write2.cmpext(0, new_bl, nullptr);
+ write2.write(0, new_bl);
+ ASSERT_EQ(-MAX_ERRNO, ioctx.operate("foo", &write2));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
+}
+
+TEST_F(LibRadosIoECPP, CmpExtPP) {
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write1;
+ write1.write(0, bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write1));
+
+ bufferlist new_bl;
+ new_bl.append("CEPH");
+ ObjectWriteOperation write2;
+ write2.cmpext(0, bl, nullptr);
+ write2.write_full(new_bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write2));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
+}
+
+TEST_F(LibRadosIoECPP, CmpExtDNEPP) {
+ bufferlist bl;
+ bl.append(std::string(4, '\0'));
+
+ bufferlist new_bl;
+ new_bl.append("CEPH");
+ ObjectWriteOperation write;
+ write.cmpext(0, bl, nullptr);
+ write.write_full(new_bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
+}
+
+TEST_F(LibRadosIoECPP, CmpExtMismatchPP) {
+ bufferlist bl;
+ bl.append("ceph");
+ ObjectWriteOperation write1;
+ write1.write(0, bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &write1));
+
+ bufferlist new_bl;
+ new_bl.append("CEPH");
+ ObjectWriteOperation write2;
+ write2.cmpext(0, new_bl, nullptr);
+ write2.write_full(new_bl);
+ ASSERT_EQ(-MAX_ERRNO, ioctx.operate("foo", &write2));
+
+ ObjectReadOperation read;
+ read.read(0, bl.length(), NULL, NULL);
+ ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
+ ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
+}
using namespace librados;
typedef RadosTestNSCleanup LibRadosList;
-typedef RadosTestPPNSCleanup LibRadosListPP;
typedef RadosTestECNSCleanup LibRadosListEC;
-typedef RadosTestECPPNSCleanup LibRadosListECPP;
typedef RadosTestNP LibRadosListNP;
rados_nobjects_list_close(ctx);
}
-TEST_F(LibRadosListPP, ListObjectsPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- NObjectIterator iter(ioctx.nobjects_begin());
- bool foundit = false;
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- }
- ASSERT_TRUE(foundit);
-}
-
-TEST_F(LibRadosListPP, ListObjectsTwicePP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- NObjectIterator iter(ioctx.nobjects_begin());
- bool foundit = false;
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- }
- ASSERT_TRUE(foundit);
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
- foundit = false;
- iter.seek(0);
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- }
- ASSERT_TRUE(foundit);
-}
-
-TEST_F(LibRadosListPP, ListObjectsCopyIterPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- // make sure this is still valid after the original iterators are gone
- NObjectIterator iter3;
- {
- NObjectIterator iter(ioctx.nobjects_begin());
- NObjectIterator iter2(iter);
- iter3 = iter2;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
-
- ASSERT_EQ(iter2->get_oid(), "foo");
- ASSERT_EQ(iter3->get_oid(), "foo");
- ++iter2;
- ASSERT_TRUE(iter2 == ioctx.nobjects_end());
- }
-
- ASSERT_EQ(iter3->get_oid(), "foo");
- iter3 = iter3;
- ASSERT_EQ(iter3->get_oid(), "foo");
- ++iter3;
- ASSERT_TRUE(iter3 == ioctx.nobjects_end());
-}
-
-TEST_F(LibRadosListPP, ListObjectsEndIter) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- NObjectIterator iter(ioctx.nobjects_begin());
- NObjectIterator iter_end(ioctx.nobjects_end());
- NObjectIterator iter_end2 = ioctx.nobjects_end();
- ASSERT_TRUE(iter_end == iter_end2);
- ASSERT_TRUE(iter_end == ioctx.nobjects_end());
- ASSERT_TRUE(iter_end2 == ioctx.nobjects_end());
-
- ASSERT_EQ(iter->get_oid(), "foo");
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
- ASSERT_TRUE(iter == iter_end);
- ASSERT_TRUE(iter == iter_end2);
- NObjectIterator iter2 = iter;
- ASSERT_TRUE(iter2 == ioctx.nobjects_end());
- ASSERT_TRUE(iter2 == iter_end);
- ASSERT_TRUE(iter2 == iter_end2);
-}
static void check_list(
std::set<std::string>& myset,
rados_nobjects_list_close(ctx);
}
-static void check_listpp(std::set<std::string>& myset, IoCtx& ioctx, const std::string &check_nspace)
-{
- NObjectIterator iter(ioctx.nobjects_begin());
- std::set<std::string> orig_set(myset);
- /**
- * During splitting, we might see duplicate items.
- * We assert that every object returned is in myset and that
- * we don't hit ENOENT until we have hit every item in myset
- * at least once.
- */
- while (iter != ioctx.nobjects_end()) {
- std::string test_name;
- if (check_nspace == all_nspaces) {
- test_name = iter->get_nspace() + ":" + iter->get_oid();
- } else {
- ASSERT_TRUE(iter->get_nspace() == check_nspace);
- test_name = iter->get_oid();
- }
- ASSERT_TRUE(orig_set.end() != orig_set.find(test_name));
- myset.erase(test_name);
- ++iter;
- }
- ASSERT_TRUE(myset.empty());
-}
-
-TEST_F(LibRadosListPP, ListObjectsPPNS) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
- ioctx.set_namespace("ns1");
- ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.write("foo2", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo3", bl1, sizeof(buf), 0));
- ioctx.set_namespace("ns1");
- ASSERT_EQ(0, ioctx.write("foo4", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo5", bl1, sizeof(buf), 0));
- ioctx.set_namespace("ns2");
- ASSERT_EQ(0, ioctx.write("foo6", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo7", bl1, sizeof(buf), 0));
- ASSERT_EQ(std::string("ns2"), ioctx.get_namespace());
-
- std::set<std::string> def, ns1, ns2, all;
- def.insert(std::string("foo1"));
- def.insert(std::string("foo2"));
- def.insert(std::string("foo3"));
- ns1.insert(std::string("foo1"));
- ns1.insert(std::string("foo4"));
- ns1.insert(std::string("foo5"));
- ns2.insert(std::string("foo6"));
- ns2.insert(std::string("foo7"));
- all.insert(std::string(":foo1"));
- all.insert(std::string(":foo2"));
- all.insert(std::string(":foo3"));
- all.insert(std::string("ns1:foo1"));
- all.insert(std::string("ns1:foo4"));
- all.insert(std::string("ns1:foo5"));
- all.insert(std::string("ns2:foo6"));
- all.insert(std::string("ns2:foo7"));
-
- ioctx.set_namespace("");
- check_listpp(def, ioctx, "");
-
- ioctx.set_namespace("ns1");
- check_listpp(ns1, ioctx, "ns1");
-
- ioctx.set_namespace("ns2");
- check_listpp(ns2, ioctx, "ns2");
-
- ioctx.set_namespace(all_nspaces);
- check_listpp(all, ioctx, all_nspaces);
-}
-
-TEST_F(LibRadosListPP, ListObjectsManyPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- for (int i=0; i<256; ++i) {
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
- }
-
- librados::NObjectIterator it = ioctx.nobjects_begin();
- std::set<std::string> saw_obj;
- std::set<int> saw_pg;
- for (; it != ioctx.nobjects_end(); ++it) {
- std::cout << it->get_oid()
- << " " << it.get_pg_hash_position() << std::endl;
- saw_obj.insert(it->get_oid());
- saw_pg.insert(it.get_pg_hash_position());
- }
- std::cout << "saw " << saw_pg.size() << " pgs " << std::endl;
-
- // make sure they are 0..n
- for (unsigned i = 0; i < saw_pg.size(); ++i)
- ASSERT_TRUE(saw_pg.count(i));
-}
TEST_F(LibRadosList, ListObjectsStart) {
char buf[128];
rados_nobjects_list_close(ctx);
}
-TEST_F(LibRadosListPP, ListObjectsStartPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- for (int i=0; i<16; ++i) {
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
- }
-
- librados::NObjectIterator it = ioctx.nobjects_begin();
- std::map<int, std::set<std::string> > pg_to_obj;
- for (; it != ioctx.nobjects_end(); ++it) {
- std::cout << it->get_oid() << " " << it.get_pg_hash_position() << std::endl;
- pg_to_obj[it.get_pg_hash_position()].insert(it->get_oid());
- }
-
- std::map<int, std::set<std::string> >::reverse_iterator p =
- pg_to_obj.rbegin();
- it = ioctx.nobjects_begin(p->first);
- while (p != pg_to_obj.rend()) {
- ASSERT_EQ((uint32_t)p->first, it.seek(p->first));
- std::cout << "have " << it->get_oid() << " expect one of " << p->second << std::endl;
- ASSERT_TRUE(p->second.count(it->get_oid()));
- ++p;
- }
-}
-
-TEST_F(LibRadosListPP, ListObjectsCursorNSPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- const int max_objs = 16;
-
- map<string, string> oid_to_ns;
-
- for (int i=0; i<max_objs; ++i) {
- stringstream ss;
- ss << "ns" << i / 4;
- ioctx.set_namespace(ss.str());
- string oid = stringify(i);
- ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0));
-
- oid_to_ns[oid] = ss.str();
- }
-
- ioctx.set_namespace(all_nspaces);
-
- librados::NObjectIterator it = ioctx.nobjects_begin();
- std::map<librados::ObjectCursor, string> cursor_to_obj;
-
- int count = 0;
-
- librados::ObjectCursor seek_cursor;
-
- map<string, list<librados::ObjectCursor> > ns_to_cursors;
-
- for (it = ioctx.nobjects_begin(); it != ioctx.nobjects_end(); ++it) {
- librados::ObjectCursor cursor = it.get_cursor();
- string oid = it->get_oid();
- cout << "> oid=" << oid << " cursor=" << it.get_cursor() << std::endl;
- }
-
- vector<string> objs_order;
-
- for (it = ioctx.nobjects_begin(); it != ioctx.nobjects_end(); ++it, ++count) {
- librados::ObjectCursor cursor = it.get_cursor();
- string oid = it->get_oid();
- std::cout << oid << " " << it.get_pg_hash_position() << std::endl;
- cout << ": oid=" << oid << " cursor=" << it.get_cursor() << std::endl;
- cursor_to_obj[cursor] = oid;
-
- ASSERT_EQ(oid_to_ns[oid], it->get_nspace());
-
- it.seek(cursor);
- cout << ": seek to " << cursor << " it.cursor=" << it.get_cursor() << std::endl;
- ASSERT_EQ(oid, it->get_oid());
- ASSERT_LT(count, max_objs); /* avoid infinite loops due to bad seek */
-
- ns_to_cursors[it->get_nspace()].push_back(cursor);
-
- if (count == max_objs/2) {
- seek_cursor = cursor;
- }
- objs_order.push_back(it->get_oid());
- }
-
- ASSERT_EQ(count, max_objs);
-
- /* check that reading past seek also works */
- cout << "seek_cursor=" << seek_cursor << std::endl;
- it.seek(seek_cursor);
- for (count = max_objs/2; count < max_objs; ++count, ++it) {
- ASSERT_EQ(objs_order[count], it->get_oid());
- }
-
- /* seek to all cursors, check that we get expected obj */
- for (auto& niter : ns_to_cursors) {
- const string& ns = niter.first;
- list<librados::ObjectCursor>& cursors = niter.second;
-
- for (auto& cursor : cursors) {
- cout << ": seek to " << cursor << std::endl;
- it.seek(cursor);
- ASSERT_EQ(cursor, it.get_cursor());
- string& expected_oid = cursor_to_obj[cursor];
- cout << ": it->get_cursor()=" << it.get_cursor() << " expected=" << cursor << std::endl;
- cout << ": it->get_oid()=" << it->get_oid() << " expected=" << expected_oid << std::endl;
- cout << ": it->get_nspace()=" << it->get_oid() << " expected=" << ns << std::endl;
- ASSERT_EQ(expected_oid, it->get_oid());
- ASSERT_EQ(it->get_nspace(), ns);
- }
- }
-}
-
-TEST_F(LibRadosListPP, ListObjectsCursorPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- const int max_objs = 16;
-
- for (int i=0; i<max_objs; ++i) {
- stringstream ss;
- ss << "ns" << i / 4;
- ioctx.set_namespace(ss.str());
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
- }
-
- ioctx.set_namespace(all_nspaces);
-
- librados::NObjectIterator it = ioctx.nobjects_begin();
- std::map<librados::ObjectCursor, string> cursor_to_obj;
-
- int count = 0;
-
- for (; it != ioctx.nobjects_end(); ++it, ++count) {
- librados::ObjectCursor cursor = it.get_cursor();
- string oid = it->get_oid();
- std::cout << oid << " " << it.get_pg_hash_position() << std::endl;
- cout << ": oid=" << oid << " cursor=" << it.get_cursor() << std::endl;
- cursor_to_obj[cursor] = oid;
-
- it.seek(cursor);
- cout << ": seek to " << cursor << std::endl;
- ASSERT_EQ(oid, it->get_oid());
- ASSERT_LT(count, max_objs); /* avoid infinite loops due to bad seek */
- }
-
- ASSERT_EQ(count, max_objs);
-
- auto p = cursor_to_obj.rbegin();
- it = ioctx.nobjects_begin();
- while (p != cursor_to_obj.rend()) {
- cout << ": seek to " << p->first << std::endl;
- it.seek(p->first);
- ASSERT_EQ(p->first, it.get_cursor());
- cout << ": it->get_cursor()=" << it.get_cursor() << " expected=" << p->first << std::endl;
- cout << ": it->get_oid()=" << it->get_oid() << " expected=" << p->second << std::endl;
- ASSERT_EQ(p->second, it->get_oid());
-
- librados::NObjectIterator it2 = ioctx.nobjects_begin(it.get_cursor());
- ASSERT_EQ(it2->get_oid(), it->get_oid());
-
- ++p;
+// this function replicates
+// librados::operator<<(std::ostream& os, const librados::ObjectCursor& oc)
+// because we don't want to use librados-cxx in librados client.
+std::ostream& operator<<(std::ostream&os, const rados_object_list_cursor& oc)
+{
+ if (oc) {
+ os << *(hobject_t *)oc;
+ } else {
+ os << hobject_t{};
}
+ return os;
}
TEST_F(LibRadosList, ListObjectsCursor) {
ASSERT_EQ(0, rados_nobjects_list_open(ioctx, &ctx));
ASSERT_EQ(rados_nobjects_list_get_cursor(ctx, &cursor), 0);
rados_object_list_cursor first_cursor = cursor;
- cout << "x cursor=" << ObjectCursor(cursor) << std::endl;
+ cout << "x cursor=" << cursor << std::endl;
while (rados_nobjects_list_next(ctx, &entry, NULL, NULL) == 0) {
string oid = entry;
ASSERT_EQ(rados_nobjects_list_get_cursor(ctx, &cursor), 0);
- cout << "> oid=" << oid << " cursor=" << ObjectCursor(cursor) << std::endl;
+ cout << "> oid=" << oid << " cursor=" << cursor << std::endl;
}
rados_nobjects_list_seek_cursor(ctx, first_cursor);
ASSERT_EQ(rados_nobjects_list_next(ctx, &entry, NULL, NULL), 0);
- cout << "FIRST> seek to " << ObjectCursor(first_cursor) << " oid=" << string(entry) << std::endl;
+ cout << "FIRST> seek to " << first_cursor << " oid=" << string(entry) << std::endl;
}
rados_list_ctx_t ctx;
ASSERT_EQ(0, rados_nobjects_list_open(ioctx, &ctx));
rados_object_list_cursor cursor;
ASSERT_EQ(rados_nobjects_list_get_cursor(ctx, &cursor), 0);
string oid = entry;
- cout << ": oid=" << oid << " cursor=" << ObjectCursor(cursor) << std::endl;
+ cout << ": oid=" << oid << " cursor=" << cursor << std::endl;
cursor_to_obj[cursor] = oid;
rados_nobjects_list_seek_cursor(ctx, cursor);
- cout << ": seek to " << ObjectCursor(cursor) << std::endl;
+ cout << ": seek to " << cursor << std::endl;
ASSERT_EQ(rados_nobjects_list_next(ctx, &entry, NULL, NULL), 0);
- cout << "> " << ObjectCursor(cursor) << " -> " << entry << std::endl;
+ cout << "> " << cursor << " -> " << entry << std::endl;
ASSERT_EQ(string(entry), oid);
ASSERT_LT(count, max_objs); /* avoid infinite loops due to bad seek */
auto p = cursor_to_obj.rbegin();
ASSERT_EQ(0, rados_nobjects_list_open(ioctx, &ctx));
while (p != cursor_to_obj.rend()) {
- cout << ": seek to " << ObjectCursor(p->first) << std::endl;
+ cout << ": seek to " << p->first << std::endl;
rados_object_list_cursor cursor;
rados_object_list_cursor oid(p->first);
rados_nobjects_list_seek_cursor(ctx, oid);
ASSERT_EQ(rados_nobjects_list_get_cursor(ctx, &cursor), 0);
- cout << ": cursor()=" << ObjectCursor(cursor) << " expected=" << oid << std::endl;
+ cout << ": cursor()=" << cursor << " expected=" << oid << std::endl;
// ASSERT_EQ(ObjectCursor(oid), ObjectCursor(cursor));
ASSERT_EQ(rados_nobjects_list_next(ctx, &entry, NULL, NULL), 0);
- cout << "> " << ObjectCursor(cursor) << " -> " << entry << std::endl;
+ cout << "> " << cursor << " -> " << entry << std::endl;
cout << ": entry=" << entry << " expected=" << p->second << std::endl;
ASSERT_EQ(p->second, string(entry));
rados_nobjects_list_close(ctx);
}
-TEST_F(LibRadosListECPP, ListObjectsPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- NObjectIterator iter(ioctx.nobjects_begin());
- bool foundit = false;
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- }
- ASSERT_TRUE(foundit);
-}
-
-TEST_F(LibRadosListECPP, ListObjectsTwicePP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- NObjectIterator iter(ioctx.nobjects_begin());
- bool foundit = false;
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- }
- ASSERT_TRUE(foundit);
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
- foundit = false;
- iter.seek(0);
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- }
- ASSERT_TRUE(foundit);
-}
-
-TEST_F(LibRadosListECPP, ListObjectsCopyIterPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- // make sure this is still valid after the original iterators are gone
- NObjectIterator iter3;
- {
- NObjectIterator iter(ioctx.nobjects_begin());
- NObjectIterator iter2(iter);
- iter3 = iter2;
- ASSERT_EQ((*iter).get_oid(), "foo");
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
-
- ASSERT_EQ(iter2->get_oid(), "foo");
- ASSERT_EQ(iter3->get_oid(), "foo");
- ++iter2;
- ASSERT_TRUE(iter2 == ioctx.nobjects_end());
- }
-
- ASSERT_EQ(iter3->get_oid(), "foo");
- iter3 = iter3;
- ASSERT_EQ(iter3->get_oid(), "foo");
- ++iter3;
- ASSERT_TRUE(iter3 == ioctx.nobjects_end());
-}
-
-TEST_F(LibRadosListECPP, ListObjectsEndIter) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- NObjectIterator iter(ioctx.nobjects_begin());
- NObjectIterator iter_end(ioctx.nobjects_end());
- NObjectIterator iter_end2 = ioctx.nobjects_end();
- ASSERT_TRUE(iter_end == iter_end2);
- ASSERT_TRUE(iter_end == ioctx.nobjects_end());
- ASSERT_TRUE(iter_end2 == ioctx.nobjects_end());
-
- ASSERT_EQ(iter->get_oid(), "foo");
- ++iter;
- ASSERT_TRUE(iter == ioctx.nobjects_end());
- ASSERT_TRUE(iter == iter_end);
- ASSERT_TRUE(iter == iter_end2);
- NObjectIterator iter2 = iter;
- ASSERT_TRUE(iter2 == ioctx.nobjects_end());
- ASSERT_TRUE(iter2 == iter_end);
- ASSERT_TRUE(iter2 == iter_end2);
-}
-
TEST_F(LibRadosListEC, ListObjectsNS) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
rados_nobjects_list_close(ctx);
}
-TEST_F(LibRadosListECPP, ListObjectsPPNS) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
- ioctx.set_namespace("ns1");
- ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.write("foo2", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo3", bl1, sizeof(buf), 0));
- ioctx.set_namespace("ns1");
- ASSERT_EQ(0, ioctx.write("foo4", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo5", bl1, sizeof(buf), 0));
- ioctx.set_namespace("ns2");
- ASSERT_EQ(0, ioctx.write("foo6", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo7", bl1, sizeof(buf), 0));
-
- std::set<std::string> def, ns1, ns2;
- def.insert(std::string("foo1"));
- def.insert(std::string("foo2"));
- def.insert(std::string("foo3"));
- ns1.insert(std::string("foo1"));
- ns1.insert(std::string("foo4"));
- ns1.insert(std::string("foo5"));
- ns2.insert(std::string("foo6"));
- ns2.insert(std::string("foo7"));
-
- ioctx.set_namespace("");
- check_listpp(def, ioctx, "");
-
- ioctx.set_namespace("ns1");
- check_listpp(ns1, ioctx, "ns1");
-
- ioctx.set_namespace("ns2");
- check_listpp(ns2, ioctx, "ns2");
-}
-
-TEST_F(LibRadosListECPP, ListObjectsManyPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- for (int i=0; i<256; ++i) {
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
- }
-
- librados::NObjectIterator it = ioctx.nobjects_begin();
- std::set<std::string> saw_obj;
- std::set<int> saw_pg;
- for (; it != ioctx.nobjects_end(); ++it) {
- std::cout << it->get_oid()
- << " " << it.get_pg_hash_position() << std::endl;
- saw_obj.insert(it->get_oid());
- saw_pg.insert(it.get_pg_hash_position());
- }
- std::cout << "saw " << saw_pg.size() << " pgs " << std::endl;
-
- // make sure they are 0..n
- for (unsigned i = 0; i < saw_pg.size(); ++i)
- ASSERT_TRUE(saw_pg.count(i));
-}
TEST_F(LibRadosListEC, ListObjectsStart) {
char buf[128];
rados_nobjects_list_close(ctx);
}
-TEST_F(LibRadosListECPP, ListObjectsStartPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- for (int i=0; i<16; ++i) {
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
- }
-
- librados::NObjectIterator it = ioctx.nobjects_begin();
- std::map<int, std::set<std::string> > pg_to_obj;
- for (; it != ioctx.nobjects_end(); ++it) {
- std::cout << it->get_oid() << " " << it.get_pg_hash_position() << std::endl;
- pg_to_obj[it.get_pg_hash_position()].insert(it->get_oid());
- }
-
- std::map<int, std::set<std::string> >::reverse_iterator p =
- pg_to_obj.rbegin();
- it = ioctx.nobjects_begin(p->first);
- while (p != pg_to_obj.rend()) {
- ASSERT_EQ((uint32_t)p->first, it.seek(p->first));
- std::cout << "have " << it->get_oid() << " expect one of " << p->second << std::endl;
- ASSERT_TRUE(p->second.count(it->get_oid()));
- ++p;
- }
-}
-
-TEST_F(LibRadosListPP, ListObjectsFilterPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist obj_content;
- obj_content.append(buf, sizeof(buf));
-
- std::string target_str = "content";
-
- // Write xattr bare, no ::encod'ing
- bufferlist target_val;
- target_val.append(target_str);
- bufferlist nontarget_val;
- nontarget_val.append("rhubarb");
-
- ASSERT_EQ(0, ioctx.write("has_xattr", obj_content, obj_content.length(), 0));
- ASSERT_EQ(0, ioctx.write("has_wrong_xattr", obj_content, obj_content.length(), 0));
- ASSERT_EQ(0, ioctx.write("no_xattr", obj_content, obj_content.length(), 0));
-
- ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val));
- ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val));
-
- bufferlist filter_bl;
- std::string filter_name = "plain";
- encode(filter_name, filter_bl);
- encode("_theattr", filter_bl);
- encode(target_str, filter_bl);
-
- NObjectIterator iter(ioctx.nobjects_begin(filter_bl));
- bool foundit = false;
- int k = 0;
- while (iter != ioctx.nobjects_end()) {
- foundit = true;
- // We should only see the object that matches the filter
- ASSERT_EQ((*iter).get_oid(), "has_xattr");
- // We should only see it once
- ASSERT_EQ(k, 0);
- ++iter;
- ++k;
- }
- ASSERT_TRUE(foundit);
-}
-
TEST_F(LibRadosListNP, ListObjectsError) {
std::string pool_name;
rados_t cluster;
}
ASSERT_EQ(n_objects, saw_obj.size());
}
-
-TEST_F(LibRadosListPP, EnumerateObjectsPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- const uint32_t n_objects = 16;
- for (unsigned i=0; i<n_objects; ++i) {
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, sizeof(buf), 0));
- }
-
- std::set<std::string> saw_obj;
- ObjectCursor c = ioctx.object_list_begin();
- ObjectCursor end = ioctx.object_list_end();
- while(!ioctx.object_list_is_end(c))
- {
- std::vector<ObjectItem> result;
- int r = ioctx.object_list(c, end, 12, {}, &result, &c);
- ASSERT_GE(r, 0);
- ASSERT_EQ(r, (int)result.size());
- for (int i = 0; i < r; ++i) {
- auto oid = result[i].oid;
- if (saw_obj.count(oid)) {
- std::cerr << "duplicate obj " << oid << std::endl;
- }
- ASSERT_FALSE(saw_obj.count(oid));
- saw_obj.insert(oid);
- }
- }
-
- for (unsigned i=0; i<n_objects; ++i) {
- if (!saw_obj.count(stringify(i))) {
- std::cerr << "missing object " << i << std::endl;
- }
- ASSERT_TRUE(saw_obj.count(stringify(i)));
- }
- ASSERT_EQ(n_objects, saw_obj.size());
-}
-
-TEST_F(LibRadosListPP, EnumerateObjectsSplitPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- const uint32_t n_objects = 16;
- for (unsigned i=0; i<n_objects; ++i) {
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, sizeof(buf), 0));
- }
-
- ObjectCursor begin = ioctx.object_list_begin();
- ObjectCursor end = ioctx.object_list_end();
-
- // Step through an odd number of shards
- unsigned m = 5;
- std::set<std::string> saw_obj;
- for (unsigned n = 0; n < m; ++n) {
- ObjectCursor shard_start;
- ObjectCursor shard_end;
-
- ioctx.object_list_slice(
- begin,
- end,
- n,
- m,
- &shard_start,
- &shard_end);
-
- ObjectCursor c(shard_start);
- while(c < shard_end)
- {
- std::vector<ObjectItem> result;
- int r = ioctx.object_list(c, shard_end, 12, {}, &result, &c);
- ASSERT_GE(r, 0);
-
- for (const auto & i : result) {
- const auto &oid = i.oid;
- if (saw_obj.count(oid)) {
- std::cerr << "duplicate obj " << oid << std::endl;
- }
- ASSERT_FALSE(saw_obj.count(oid));
- saw_obj.insert(oid);
- }
- }
- }
-
- for (unsigned i=0; i<n_objects; ++i) {
- if (!saw_obj.count(stringify(i))) {
- std::cerr << "missing object " << i << std::endl;
- }
- ASSERT_TRUE(saw_obj.count(stringify(i)));
- }
- ASSERT_EQ(n_objects, saw_obj.size());
-}
-
-
-TEST_F(LibRadosListPP, EnumerateObjectsFilterPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist obj_content;
- obj_content.append(buf, sizeof(buf));
-
- std::string target_str = "content";
-
- // Write xattr bare, no ::encod'ing
- bufferlist target_val;
- target_val.append(target_str);
- bufferlist nontarget_val;
- nontarget_val.append("rhubarb");
-
- ASSERT_EQ(0, ioctx.write("has_xattr", obj_content, obj_content.length(), 0));
- ASSERT_EQ(0, ioctx.write("has_wrong_xattr", obj_content, obj_content.length(), 0));
- ASSERT_EQ(0, ioctx.write("no_xattr", obj_content, obj_content.length(), 0));
-
- ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val));
- ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val));
-
- bufferlist filter_bl;
- std::string filter_name = "plain";
- encode(filter_name, filter_bl);
- encode("_theattr", filter_bl);
- encode(target_str, filter_bl);
-
- ObjectCursor c = ioctx.object_list_begin();
- ObjectCursor end = ioctx.object_list_end();
- bool foundit = false;
- while(!ioctx.object_list_is_end(c))
- {
- std::vector<ObjectItem> result;
- int r = ioctx.object_list(c, end, 12, filter_bl, &result, &c);
- ASSERT_GE(r, 0);
- ASSERT_EQ(r, (int)result.size());
- for (int i = 0; i < r; ++i) {
- auto oid = result[i].oid;
- // We should only see the object that matches the filter
- ASSERT_EQ(oid, "has_xattr");
- // We should only see it once
- ASSERT_FALSE(foundit);
- foundit = true;
- }
- }
- ASSERT_TRUE(foundit);
-}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include <errno.h>
+#include <string>
+#include <stdexcept>
+
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+#include "include/stringify.h"
+#include "include/types.h"
+#include "common/hobject.h"
+#include "test/librados/test_cxx.h"
+#include "test/librados/test_common.h"
+#include "test/librados/testcase_cxx.h"
+#include "global/global_context.h"
+
+using namespace librados;
+
+typedef RadosTestPPNSCleanup LibRadosListPP;
+typedef RadosTestECPPNSCleanup LibRadosListECPP;
+
+TEST_F(LibRadosListPP, ListObjectsPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ NObjectIterator iter(ioctx.nobjects_begin());
+ bool foundit = false;
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ }
+ ASSERT_TRUE(foundit);
+}
+
+TEST_F(LibRadosListPP, ListObjectsTwicePP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ NObjectIterator iter(ioctx.nobjects_begin());
+ bool foundit = false;
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ }
+ ASSERT_TRUE(foundit);
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+ foundit = false;
+ iter.seek(0);
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ }
+ ASSERT_TRUE(foundit);
+}
+
+TEST_F(LibRadosListPP, ListObjectsCopyIterPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ // make sure this is still valid after the original iterators are gone
+ NObjectIterator iter3;
+ {
+ NObjectIterator iter(ioctx.nobjects_begin());
+ NObjectIterator iter2(iter);
+ iter3 = iter2;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+
+ ASSERT_EQ(iter2->get_oid(), "foo");
+ ASSERT_EQ(iter3->get_oid(), "foo");
+ ++iter2;
+ ASSERT_TRUE(iter2 == ioctx.nobjects_end());
+ }
+
+ ASSERT_EQ(iter3->get_oid(), "foo");
+ iter3 = iter3;
+ ASSERT_EQ(iter3->get_oid(), "foo");
+ ++iter3;
+ ASSERT_TRUE(iter3 == ioctx.nobjects_end());
+}
+
+TEST_F(LibRadosListPP, ListObjectsEndIter) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ NObjectIterator iter(ioctx.nobjects_begin());
+ NObjectIterator iter_end(ioctx.nobjects_end());
+ NObjectIterator iter_end2 = ioctx.nobjects_end();
+ ASSERT_TRUE(iter_end == iter_end2);
+ ASSERT_TRUE(iter_end == ioctx.nobjects_end());
+ ASSERT_TRUE(iter_end2 == ioctx.nobjects_end());
+
+ ASSERT_EQ(iter->get_oid(), "foo");
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+ ASSERT_TRUE(iter == iter_end);
+ ASSERT_TRUE(iter == iter_end2);
+ NObjectIterator iter2 = iter;
+ ASSERT_TRUE(iter2 == ioctx.nobjects_end());
+ ASSERT_TRUE(iter2 == iter_end);
+ ASSERT_TRUE(iter2 == iter_end2);
+}
+
+static void check_listpp(std::set<std::string>& myset, IoCtx& ioctx, const std::string &check_nspace)
+{
+ NObjectIterator iter(ioctx.nobjects_begin());
+ std::set<std::string> orig_set(myset);
+ /**
+ * During splitting, we might see duplicate items.
+ * We assert that every object returned is in myset and that
+ * we don't hit ENOENT until we have hit every item in myset
+ * at least once.
+ */
+ while (iter != ioctx.nobjects_end()) {
+ std::string test_name;
+ if (check_nspace == all_nspaces) {
+ test_name = iter->get_nspace() + ":" + iter->get_oid();
+ } else {
+ ASSERT_TRUE(iter->get_nspace() == check_nspace);
+ test_name = iter->get_oid();
+ }
+ ASSERT_TRUE(orig_set.end() != orig_set.find(test_name));
+ myset.erase(test_name);
+ ++iter;
+ }
+ ASSERT_TRUE(myset.empty());
+}
+
+TEST_F(LibRadosListPP, ListObjectsPPNS) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("ns1");
+ ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.write("foo2", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo3", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("ns1");
+ ASSERT_EQ(0, ioctx.write("foo4", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo5", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("ns2");
+ ASSERT_EQ(0, ioctx.write("foo6", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo7", bl1, sizeof(buf), 0));
+ ASSERT_EQ(std::string("ns2"), ioctx.get_namespace());
+
+ std::set<std::string> def, ns1, ns2, all;
+ def.insert(std::string("foo1"));
+ def.insert(std::string("foo2"));
+ def.insert(std::string("foo3"));
+ ns1.insert(std::string("foo1"));
+ ns1.insert(std::string("foo4"));
+ ns1.insert(std::string("foo5"));
+ ns2.insert(std::string("foo6"));
+ ns2.insert(std::string("foo7"));
+ all.insert(std::string(":foo1"));
+ all.insert(std::string(":foo2"));
+ all.insert(std::string(":foo3"));
+ all.insert(std::string("ns1:foo1"));
+ all.insert(std::string("ns1:foo4"));
+ all.insert(std::string("ns1:foo5"));
+ all.insert(std::string("ns2:foo6"));
+ all.insert(std::string("ns2:foo7"));
+
+ ioctx.set_namespace("");
+ check_listpp(def, ioctx, "");
+
+ ioctx.set_namespace("ns1");
+ check_listpp(ns1, ioctx, "ns1");
+
+ ioctx.set_namespace("ns2");
+ check_listpp(ns2, ioctx, "ns2");
+
+ ioctx.set_namespace(all_nspaces);
+ check_listpp(all, ioctx, all_nspaces);
+}
+
+TEST_F(LibRadosListPP, ListObjectsManyPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ for (int i=0; i<256; ++i) {
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
+ }
+
+ librados::NObjectIterator it = ioctx.nobjects_begin();
+ std::set<std::string> saw_obj;
+ std::set<int> saw_pg;
+ for (; it != ioctx.nobjects_end(); ++it) {
+ std::cout << it->get_oid()
+ << " " << it.get_pg_hash_position() << std::endl;
+ saw_obj.insert(it->get_oid());
+ saw_pg.insert(it.get_pg_hash_position());
+ }
+ std::cout << "saw " << saw_pg.size() << " pgs " << std::endl;
+
+ // make sure they are 0..n
+ for (unsigned i = 0; i < saw_pg.size(); ++i)
+ ASSERT_TRUE(saw_pg.count(i));
+}
+
+TEST_F(LibRadosListPP, ListObjectsStartPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ for (int i=0; i<16; ++i) {
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
+ }
+
+ librados::NObjectIterator it = ioctx.nobjects_begin();
+ std::map<int, std::set<std::string> > pg_to_obj;
+ for (; it != ioctx.nobjects_end(); ++it) {
+ std::cout << it->get_oid() << " " << it.get_pg_hash_position() << std::endl;
+ pg_to_obj[it.get_pg_hash_position()].insert(it->get_oid());
+ }
+
+ std::map<int, std::set<std::string> >::reverse_iterator p =
+ pg_to_obj.rbegin();
+ it = ioctx.nobjects_begin(p->first);
+ while (p != pg_to_obj.rend()) {
+ ASSERT_EQ((uint32_t)p->first, it.seek(p->first));
+ std::cout << "have " << it->get_oid() << " expect one of " << p->second << std::endl;
+ ASSERT_TRUE(p->second.count(it->get_oid()));
+ ++p;
+ }
+}
+
+TEST_F(LibRadosListPP, ListObjectsCursorNSPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ const int max_objs = 16;
+
+ map<string, string> oid_to_ns;
+
+ for (int i=0; i<max_objs; ++i) {
+ stringstream ss;
+ ss << "ns" << i / 4;
+ ioctx.set_namespace(ss.str());
+ string oid = stringify(i);
+ ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0));
+
+ oid_to_ns[oid] = ss.str();
+ }
+
+ ioctx.set_namespace(all_nspaces);
+
+ librados::NObjectIterator it = ioctx.nobjects_begin();
+ std::map<librados::ObjectCursor, string> cursor_to_obj;
+
+ int count = 0;
+
+ librados::ObjectCursor seek_cursor;
+
+ map<string, list<librados::ObjectCursor> > ns_to_cursors;
+
+ for (it = ioctx.nobjects_begin(); it != ioctx.nobjects_end(); ++it) {
+ librados::ObjectCursor cursor = it.get_cursor();
+ string oid = it->get_oid();
+ cout << "> oid=" << oid << " cursor=" << it.get_cursor() << std::endl;
+ }
+
+ vector<string> objs_order;
+
+ for (it = ioctx.nobjects_begin(); it != ioctx.nobjects_end(); ++it, ++count) {
+ librados::ObjectCursor cursor = it.get_cursor();
+ string oid = it->get_oid();
+ std::cout << oid << " " << it.get_pg_hash_position() << std::endl;
+ cout << ": oid=" << oid << " cursor=" << it.get_cursor() << std::endl;
+ cursor_to_obj[cursor] = oid;
+
+ ASSERT_EQ(oid_to_ns[oid], it->get_nspace());
+
+ it.seek(cursor);
+ cout << ": seek to " << cursor << " it.cursor=" << it.get_cursor() << std::endl;
+ ASSERT_EQ(oid, it->get_oid());
+ ASSERT_LT(count, max_objs); /* avoid infinite loops due to bad seek */
+
+ ns_to_cursors[it->get_nspace()].push_back(cursor);
+
+ if (count == max_objs/2) {
+ seek_cursor = cursor;
+ }
+ objs_order.push_back(it->get_oid());
+ }
+
+ ASSERT_EQ(count, max_objs);
+
+ /* check that reading past seek also works */
+ cout << "seek_cursor=" << seek_cursor << std::endl;
+ it.seek(seek_cursor);
+ for (count = max_objs/2; count < max_objs; ++count, ++it) {
+ ASSERT_EQ(objs_order[count], it->get_oid());
+ }
+
+ /* seek to all cursors, check that we get expected obj */
+ for (auto& niter : ns_to_cursors) {
+ const string& ns = niter.first;
+ list<librados::ObjectCursor>& cursors = niter.second;
+
+ for (auto& cursor : cursors) {
+ cout << ": seek to " << cursor << std::endl;
+ it.seek(cursor);
+ ASSERT_EQ(cursor, it.get_cursor());
+ string& expected_oid = cursor_to_obj[cursor];
+ cout << ": it->get_cursor()=" << it.get_cursor() << " expected=" << cursor << std::endl;
+ cout << ": it->get_oid()=" << it->get_oid() << " expected=" << expected_oid << std::endl;
+ cout << ": it->get_nspace()=" << it->get_oid() << " expected=" << ns << std::endl;
+ ASSERT_EQ(expected_oid, it->get_oid());
+ ASSERT_EQ(it->get_nspace(), ns);
+ }
+ }
+}
+
+TEST_F(LibRadosListPP, ListObjectsCursorPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ const int max_objs = 16;
+
+ for (int i=0; i<max_objs; ++i) {
+ stringstream ss;
+ ss << "ns" << i / 4;
+ ioctx.set_namespace(ss.str());
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
+ }
+
+ ioctx.set_namespace(all_nspaces);
+
+ librados::NObjectIterator it = ioctx.nobjects_begin();
+ std::map<librados::ObjectCursor, string> cursor_to_obj;
+
+ int count = 0;
+
+ for (; it != ioctx.nobjects_end(); ++it, ++count) {
+ librados::ObjectCursor cursor = it.get_cursor();
+ string oid = it->get_oid();
+ std::cout << oid << " " << it.get_pg_hash_position() << std::endl;
+ cout << ": oid=" << oid << " cursor=" << it.get_cursor() << std::endl;
+ cursor_to_obj[cursor] = oid;
+
+ it.seek(cursor);
+ cout << ": seek to " << cursor << std::endl;
+ ASSERT_EQ(oid, it->get_oid());
+ ASSERT_LT(count, max_objs); /* avoid infinite loops due to bad seek */
+ }
+
+ ASSERT_EQ(count, max_objs);
+
+ auto p = cursor_to_obj.rbegin();
+ it = ioctx.nobjects_begin();
+ while (p != cursor_to_obj.rend()) {
+ cout << ": seek to " << p->first << std::endl;
+ it.seek(p->first);
+ ASSERT_EQ(p->first, it.get_cursor());
+ cout << ": it->get_cursor()=" << it.get_cursor() << " expected=" << p->first << std::endl;
+ cout << ": it->get_oid()=" << it->get_oid() << " expected=" << p->second << std::endl;
+ ASSERT_EQ(p->second, it->get_oid());
+
+ librados::NObjectIterator it2 = ioctx.nobjects_begin(it.get_cursor());
+ ASSERT_EQ(it2->get_oid(), it->get_oid());
+
+ ++p;
+ }
+}
+
+TEST_F(LibRadosListECPP, ListObjectsPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ NObjectIterator iter(ioctx.nobjects_begin());
+ bool foundit = false;
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ }
+ ASSERT_TRUE(foundit);
+}
+
+TEST_F(LibRadosListECPP, ListObjectsTwicePP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ NObjectIterator iter(ioctx.nobjects_begin());
+ bool foundit = false;
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ }
+ ASSERT_TRUE(foundit);
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+ foundit = false;
+ iter.seek(0);
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ }
+ ASSERT_TRUE(foundit);
+}
+
+TEST_F(LibRadosListECPP, ListObjectsCopyIterPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ // make sure this is still valid after the original iterators are gone
+ NObjectIterator iter3;
+ {
+ NObjectIterator iter(ioctx.nobjects_begin());
+ NObjectIterator iter2(iter);
+ iter3 = iter2;
+ ASSERT_EQ((*iter).get_oid(), "foo");
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+
+ ASSERT_EQ(iter2->get_oid(), "foo");
+ ASSERT_EQ(iter3->get_oid(), "foo");
+ ++iter2;
+ ASSERT_TRUE(iter2 == ioctx.nobjects_end());
+ }
+
+ ASSERT_EQ(iter3->get_oid(), "foo");
+ iter3 = iter3;
+ ASSERT_EQ(iter3->get_oid(), "foo");
+ ++iter3;
+ ASSERT_TRUE(iter3 == ioctx.nobjects_end());
+}
+
+TEST_F(LibRadosListECPP, ListObjectsEndIter) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ NObjectIterator iter(ioctx.nobjects_begin());
+ NObjectIterator iter_end(ioctx.nobjects_end());
+ NObjectIterator iter_end2 = ioctx.nobjects_end();
+ ASSERT_TRUE(iter_end == iter_end2);
+ ASSERT_TRUE(iter_end == ioctx.nobjects_end());
+ ASSERT_TRUE(iter_end2 == ioctx.nobjects_end());
+
+ ASSERT_EQ(iter->get_oid(), "foo");
+ ++iter;
+ ASSERT_TRUE(iter == ioctx.nobjects_end());
+ ASSERT_TRUE(iter == iter_end);
+ ASSERT_TRUE(iter == iter_end2);
+ NObjectIterator iter2 = iter;
+ ASSERT_TRUE(iter2 == ioctx.nobjects_end());
+ ASSERT_TRUE(iter2 == iter_end);
+ ASSERT_TRUE(iter2 == iter_end2);
+}
+
+TEST_F(LibRadosListECPP, ListObjectsPPNS) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ // Create :foo1, :foo2, :foo3, n1:foo1, ns1:foo4, ns1:foo5, ns2:foo6, n2:foo7
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("ns1");
+ ASSERT_EQ(0, ioctx.write("foo1", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.write("foo2", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo3", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("ns1");
+ ASSERT_EQ(0, ioctx.write("foo4", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo5", bl1, sizeof(buf), 0));
+ ioctx.set_namespace("ns2");
+ ASSERT_EQ(0, ioctx.write("foo6", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo7", bl1, sizeof(buf), 0));
+
+ std::set<std::string> def, ns1, ns2;
+ def.insert(std::string("foo1"));
+ def.insert(std::string("foo2"));
+ def.insert(std::string("foo3"));
+ ns1.insert(std::string("foo1"));
+ ns1.insert(std::string("foo4"));
+ ns1.insert(std::string("foo5"));
+ ns2.insert(std::string("foo6"));
+ ns2.insert(std::string("foo7"));
+
+ ioctx.set_namespace("");
+ check_listpp(def, ioctx, "");
+
+ ioctx.set_namespace("ns1");
+ check_listpp(ns1, ioctx, "ns1");
+
+ ioctx.set_namespace("ns2");
+ check_listpp(ns2, ioctx, "ns2");
+}
+
+TEST_F(LibRadosListECPP, ListObjectsManyPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ for (int i=0; i<256; ++i) {
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
+ }
+
+ librados::NObjectIterator it = ioctx.nobjects_begin();
+ std::set<std::string> saw_obj;
+ std::set<int> saw_pg;
+ for (; it != ioctx.nobjects_end(); ++it) {
+ std::cout << it->get_oid()
+ << " " << it.get_pg_hash_position() << std::endl;
+ saw_obj.insert(it->get_oid());
+ saw_pg.insert(it.get_pg_hash_position());
+ }
+ std::cout << "saw " << saw_pg.size() << " pgs " << std::endl;
+
+ // make sure they are 0..n
+ for (unsigned i = 0; i < saw_pg.size(); ++i)
+ ASSERT_TRUE(saw_pg.count(i));
+}
+
+TEST_F(LibRadosListECPP, ListObjectsStartPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ for (int i=0; i<16; ++i) {
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, bl.length(), 0));
+ }
+
+ librados::NObjectIterator it = ioctx.nobjects_begin();
+ std::map<int, std::set<std::string> > pg_to_obj;
+ for (; it != ioctx.nobjects_end(); ++it) {
+ std::cout << it->get_oid() << " " << it.get_pg_hash_position() << std::endl;
+ pg_to_obj[it.get_pg_hash_position()].insert(it->get_oid());
+ }
+
+ std::map<int, std::set<std::string> >::reverse_iterator p =
+ pg_to_obj.rbegin();
+ it = ioctx.nobjects_begin(p->first);
+ while (p != pg_to_obj.rend()) {
+ ASSERT_EQ((uint32_t)p->first, it.seek(p->first));
+ std::cout << "have " << it->get_oid() << " expect one of " << p->second << std::endl;
+ ASSERT_TRUE(p->second.count(it->get_oid()));
+ ++p;
+ }
+}
+
+TEST_F(LibRadosListPP, ListObjectsFilterPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist obj_content;
+ obj_content.append(buf, sizeof(buf));
+
+ std::string target_str = "content";
+
+ // Write xattr bare, no ::encod'ing
+ bufferlist target_val;
+ target_val.append(target_str);
+ bufferlist nontarget_val;
+ nontarget_val.append("rhubarb");
+
+ ASSERT_EQ(0, ioctx.write("has_xattr", obj_content, obj_content.length(), 0));
+ ASSERT_EQ(0, ioctx.write("has_wrong_xattr", obj_content, obj_content.length(), 0));
+ ASSERT_EQ(0, ioctx.write("no_xattr", obj_content, obj_content.length(), 0));
+
+ ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val));
+ ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val));
+
+ bufferlist filter_bl;
+ std::string filter_name = "plain";
+ encode(filter_name, filter_bl);
+ encode("_theattr", filter_bl);
+ encode(target_str, filter_bl);
+
+ NObjectIterator iter(ioctx.nobjects_begin(filter_bl));
+ bool foundit = false;
+ int k = 0;
+ while (iter != ioctx.nobjects_end()) {
+ foundit = true;
+ // We should only see the object that matches the filter
+ ASSERT_EQ((*iter).get_oid(), "has_xattr");
+ // We should only see it once
+ ASSERT_EQ(k, 0);
+ ++iter;
+ ++k;
+ }
+ ASSERT_TRUE(foundit);
+}
+
+TEST_F(LibRadosListPP, EnumerateObjectsPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ const uint32_t n_objects = 16;
+ for (unsigned i=0; i<n_objects; ++i) {
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, sizeof(buf), 0));
+ }
+
+ std::set<std::string> saw_obj;
+ ObjectCursor c = ioctx.object_list_begin();
+ ObjectCursor end = ioctx.object_list_end();
+ while(!ioctx.object_list_is_end(c))
+ {
+ std::vector<ObjectItem> result;
+ int r = ioctx.object_list(c, end, 12, {}, &result, &c);
+ ASSERT_GE(r, 0);
+ ASSERT_EQ(r, (int)result.size());
+ for (int i = 0; i < r; ++i) {
+ auto oid = result[i].oid;
+ if (saw_obj.count(oid)) {
+ std::cerr << "duplicate obj " << oid << std::endl;
+ }
+ ASSERT_FALSE(saw_obj.count(oid));
+ saw_obj.insert(oid);
+ }
+ }
+
+ for (unsigned i=0; i<n_objects; ++i) {
+ if (!saw_obj.count(stringify(i))) {
+ std::cerr << "missing object " << i << std::endl;
+ }
+ ASSERT_TRUE(saw_obj.count(stringify(i)));
+ }
+ ASSERT_EQ(n_objects, saw_obj.size());
+}
+
+TEST_F(LibRadosListPP, EnumerateObjectsSplitPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ const uint32_t n_objects = 16;
+ for (unsigned i=0; i<n_objects; ++i) {
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, sizeof(buf), 0));
+ }
+
+ ObjectCursor begin = ioctx.object_list_begin();
+ ObjectCursor end = ioctx.object_list_end();
+
+ // Step through an odd number of shards
+ unsigned m = 5;
+ std::set<std::string> saw_obj;
+ for (unsigned n = 0; n < m; ++n) {
+ ObjectCursor shard_start;
+ ObjectCursor shard_end;
+
+ ioctx.object_list_slice(
+ begin,
+ end,
+ n,
+ m,
+ &shard_start,
+ &shard_end);
+
+ ObjectCursor c(shard_start);
+ while(c < shard_end)
+ {
+ std::vector<ObjectItem> result;
+ int r = ioctx.object_list(c, shard_end, 12, {}, &result, &c);
+ ASSERT_GE(r, 0);
+
+ for (const auto & i : result) {
+ const auto &oid = i.oid;
+ if (saw_obj.count(oid)) {
+ std::cerr << "duplicate obj " << oid << std::endl;
+ }
+ ASSERT_FALSE(saw_obj.count(oid));
+ saw_obj.insert(oid);
+ }
+ }
+ }
+
+ for (unsigned i=0; i<n_objects; ++i) {
+ if (!saw_obj.count(stringify(i))) {
+ std::cerr << "missing object " << i << std::endl;
+ }
+ ASSERT_TRUE(saw_obj.count(stringify(i)));
+ }
+ ASSERT_EQ(n_objects, saw_obj.size());
+}
+
+
+TEST_F(LibRadosListPP, EnumerateObjectsFilterPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist obj_content;
+ obj_content.append(buf, sizeof(buf));
+
+ std::string target_str = "content";
+
+ // Write xattr bare, no ::encod'ing
+ bufferlist target_val;
+ target_val.append(target_str);
+ bufferlist nontarget_val;
+ nontarget_val.append("rhubarb");
+
+ ASSERT_EQ(0, ioctx.write("has_xattr", obj_content, obj_content.length(), 0));
+ ASSERT_EQ(0, ioctx.write("has_wrong_xattr", obj_content, obj_content.length(), 0));
+ ASSERT_EQ(0, ioctx.write("no_xattr", obj_content, obj_content.length(), 0));
+
+ ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val));
+ ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val));
+
+ bufferlist filter_bl;
+ std::string filter_name = "plain";
+ encode(filter_name, filter_bl);
+ encode("_theattr", filter_bl);
+ encode(target_str, filter_bl);
+
+ ObjectCursor c = ioctx.object_list_begin();
+ ObjectCursor end = ioctx.object_list_end();
+ bool foundit = false;
+ while(!ioctx.object_list_is_end(c))
+ {
+ std::vector<ObjectItem> result;
+ int r = ioctx.object_list(c, end, 12, filter_bl, &result, &c);
+ ASSERT_GE(r, 0);
+ ASSERT_EQ(r, (int)result.size());
+ for (int i = 0; i < r; ++i) {
+ auto oid = result[i].oid;
+ // We should only see the object that matches the filter
+ ASSERT_EQ(oid, "has_xattr");
+ // We should only see it once
+ ASSERT_FALSE(foundit);
+ foundit = true;
+ }
+ }
+ ASSERT_TRUE(foundit);
+}
#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
#include "test/librados/test.h"
#include "test/librados/TestCase.h"
#include "cls/lock/cls_lock_client.h"
#include <sys/time.h>
using namespace std::chrono_literals;
-using namespace librados;
typedef RadosTest LibRadosLock;
-typedef RadosTestPP LibRadosLockPP;
typedef RadosTestEC LibRadosLockEC;
-typedef RadosTestECPP LibRadosLockECPP;
-template<class Rep, class Period, typename Func, typename... Args,
- typename Return = std::result_of_t<Func&&(Args&&...)>>
-Return wait_until(const std::chrono::duration<Rep, Period>& rel_time,
- const std::chrono::duration<Rep, Period>& step,
- const Return& expected,
- Func&& func, Args&&... args)
-{
- std::this_thread::sleep_for(rel_time - step);
- for (auto& s : {step, step}) {
- if (!s.count()) {
- break;
- }
- auto ret = func(std::forward<Args>(args)...);
- if (ret == expected) {
- return ret;
- }
- std::this_thread::sleep_for(s);
- }
- return func(std::forward<Args>(args)...);
-}
-
TEST_F(LibRadosLock, LockExclusive) {
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock1", "Cookie", "", NULL, 0));
ASSERT_EQ(-EEXIST, rados_lock_exclusive(ioctx, "foo", "TestLock1", "Cookie", "", NULL, 0));
}
-TEST_F(LibRadosLockPP, LockExclusivePP) {
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP1", "Cookie", "", NULL, 0));
- ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockPP1", "Cookie", "", NULL, 0));
-}
-
TEST_F(LibRadosLock, LockShared) {
ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLock2", "Cookie", "Tag", "", NULL, 0));
ASSERT_EQ(-EEXIST, rados_lock_shared(ioctx, "foo", "TestLock2", "Cookie", "Tag", "", NULL, 0));
}
-TEST_F(LibRadosLockPP, LockSharedPP) {
- ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockPP2", "Cookie", "Tag", "", NULL, 0));
- ASSERT_EQ(-EEXIST, ioctx.lock_shared("foo", "TestLockPP2", "Cookie", "Tag", "", NULL, 0));
-}
-
TEST_F(LibRadosLock, LockExclusiveDur) {
struct timeval tv;
tv.tv_sec = 1;
ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_exclusive, nullptr));
}
-TEST_F(LibRadosLockPP, LockExclusiveDurPP) {
- struct timeval tv;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- auto lock_exclusive = [this](timeval* tv) {
- return ioctx.lock_exclusive("foo", "TestLockPP3", "Cookie", "", tv, 0);
- };
- constexpr int expected = 0;
- ASSERT_EQ(expected, lock_exclusive(&tv));
- ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_exclusive, nullptr));
-}
-
TEST_F(LibRadosLock, LockSharedDur) {
struct timeval tv;
tv.tv_sec = 1;
ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_shared, nullptr));
}
-TEST_F(LibRadosLockPP, LockSharedDurPP) {
- struct timeval tv;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- auto lock_shared = [this](timeval* tv) {
- return ioctx.lock_shared("foo", "TestLockPP4", "Cookie", "Tag", "", tv, 0);
- };
- constexpr int expected = 0;
- ASSERT_EQ(expected, lock_shared(&tv));
- ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_shared, nullptr));
-}
TEST_F(LibRadosLock, LockMayRenew) {
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock5", "Cookie", "", NULL, 0));
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock5", "Cookie", "", NULL, LOCK_FLAG_MAY_RENEW));
}
-TEST_F(LibRadosLockPP, LockMayRenewPP) {
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP5", "Cookie", "", NULL, 0));
- ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockPP5", "Cookie", "", NULL, 0));
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP5", "Cookie", "", NULL, LOCK_FLAG_MAY_RENEW));
-}
-
TEST_F(LibRadosLock, Unlock) {
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock6", "Cookie", "", NULL, 0));
ASSERT_EQ(0, rados_unlock(ioctx, "foo", "TestLock6", "Cookie"));
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLock6", "Cookie", "", NULL, 0));
}
-TEST_F(LibRadosLockPP, UnlockPP) {
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP6", "Cookie", "", NULL, 0));
- ASSERT_EQ(0, ioctx.unlock("foo", "TestLockPP6", "Cookie"));
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP6", "Cookie", "", NULL, 0));
-}
-
TEST_F(LibRadosLock, ListLockers) {
int exclusive;
char tag[1024];
ASSERT_EQ(strlen("Cookie") + 1, cookies_len);
}
-TEST_F(LibRadosLockPP, ListLockersPP) {
- std::stringstream sstm;
- sstm << "client." << cluster.get_instance_id();
- std::string me = sstm.str();
- ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockPP7", "Cookie", "Tag", "", NULL, 0));
- ASSERT_EQ(0, ioctx.unlock("foo", "TestLockPP7", "Cookie"));
- {
- int exclusive;
- std::string tag;
- std::list<librados::locker_t> lockers;
- ASSERT_EQ(0, ioctx.list_lockers("foo", "TestLockPP7", &exclusive, &tag, &lockers));
- }
- ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockPP7", "Cookie", "Tag", "", NULL, 0));
- {
- int exclusive;
- std::string tag;
- std::list<librados::locker_t> lockers;
- ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockPP7", &exclusive, &tag, &lockers));
- std::list<librados::locker_t>::iterator it = lockers.begin();
- ASSERT_FALSE(lockers.end() == it);
- ASSERT_EQ(me, it->client);
- ASSERT_EQ("Cookie", it->cookie);
- }
-}
-
TEST_F(LibRadosLock, BreakLock) {
int exclusive;
char tag[1024];
ASSERT_EQ(0, rados_break_lock(ioctx, "foo", "TestLock8", clients, "Cookie"));
}
-TEST_F(LibRadosLockPP, BreakLockPP) {
- int exclusive;
- std::string tag;
- std::list<librados::locker_t> lockers;
- std::stringstream sstm;
- sstm << "client." << cluster.get_instance_id();
- std::string me = sstm.str();
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP8", "Cookie", "", NULL, 0));
- ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockPP8", &exclusive, &tag, &lockers));
- std::list<librados::locker_t>::iterator it = lockers.begin();
- ASSERT_FALSE(lockers.end() == it);
- ASSERT_EQ(me, it->client);
- ASSERT_EQ("Cookie", it->cookie);
- ASSERT_EQ(0, ioctx.break_lock("foo", "TestLockPP8", it->client, "Cookie"));
-}
-
// EC testing
TEST_F(LibRadosLockEC, LockExclusive) {
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLockEC1", "Cookie", "", NULL, 0));
ASSERT_EQ(-EEXIST, rados_lock_exclusive(ioctx, "foo", "TestLockEC1", "Cookie", "", NULL, 0));
}
-TEST_F(LibRadosLockECPP, LockExclusivePP) {
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP1", "Cookie", "", NULL, 0));
- ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockECPP1", "Cookie", "", NULL, 0));
-}
-
TEST_F(LibRadosLockEC, LockShared) {
ASSERT_EQ(0, rados_lock_shared(ioctx, "foo", "TestLockEC2", "Cookie", "Tag", "", NULL, 0));
ASSERT_EQ(-EEXIST, rados_lock_shared(ioctx, "foo", "TestLockEC2", "Cookie", "Tag", "", NULL, 0));
}
-TEST_F(LibRadosLockECPP, LockSharedPP) {
- ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockECPP2", "Cookie", "Tag", "", NULL, 0));
- ASSERT_EQ(-EEXIST, ioctx.lock_shared("foo", "TestLockECPP2", "Cookie", "Tag", "", NULL, 0));
-}
-
TEST_F(LibRadosLockEC, LockExclusiveDur) {
struct timeval tv;
tv.tv_sec = 1;
ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_exclusive, nullptr));
}
-TEST_F(LibRadosLockECPP, LockExclusiveDurPP) {
- struct timeval tv;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- auto lock_exclusive = [this](timeval* tv) {
- return ioctx.lock_exclusive("foo", "TestLockECPP3", "Cookie", "", tv, 0);
- };
- constexpr int expected = 0;
- ASSERT_EQ(expected, lock_exclusive(&tv));
- ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_exclusive, nullptr));
-}
-
TEST_F(LibRadosLockEC, LockSharedDur) {
struct timeval tv;
tv.tv_sec = 1;
ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_shared, nullptr));
}
-TEST_F(LibRadosLockECPP, LockSharedDurPP) {
- struct timeval tv;
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- auto lock_shared = [this](timeval* tv) {
- return ioctx.lock_shared("foo", "TestLockECPP4", "Cookie", "Tag", "", tv, 0);
- };
- const int expected = 0;
- ASSERT_EQ(expected, lock_shared(&tv));
- ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_shared, nullptr));
-}
TEST_F(LibRadosLockEC, LockMayRenew) {
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLockEC5", "Cookie", "", NULL, 0));
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLockEC5", "Cookie", "", NULL, LOCK_FLAG_MAY_RENEW));
}
-TEST_F(LibRadosLockECPP, LockMayRenewPP) {
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP5", "Cookie", "", NULL, 0));
- ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockECPP5", "Cookie", "", NULL, 0));
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP5", "Cookie", "", NULL, LOCK_FLAG_MAY_RENEW));
-}
-
TEST_F(LibRadosLockEC, Unlock) {
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLockEC6", "Cookie", "", NULL, 0));
ASSERT_EQ(0, rados_unlock(ioctx, "foo", "TestLockEC6", "Cookie"));
ASSERT_EQ(0, rados_lock_exclusive(ioctx, "foo", "TestLockEC6", "Cookie", "", NULL, 0));
}
-TEST_F(LibRadosLockECPP, UnlockPP) {
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP6", "Cookie", "", NULL, 0));
- ASSERT_EQ(0, ioctx.unlock("foo", "TestLockECPP6", "Cookie"));
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP6", "Cookie", "", NULL, 0));
-}
-
TEST_F(LibRadosLockEC, ListLockers) {
int exclusive;
char tag[1024];
ASSERT_EQ(strlen("Cookie") + 1, cookies_len);
}
-TEST_F(LibRadosLockECPP, ListLockersPP) {
- std::stringstream sstm;
- sstm << "client." << cluster.get_instance_id();
- std::string me = sstm.str();
- ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockECPP7", "Cookie", "Tag", "", NULL, 0));
- ASSERT_EQ(0, ioctx.unlock("foo", "TestLockECPP7", "Cookie"));
- {
- int exclusive;
- std::string tag;
- std::list<librados::locker_t> lockers;
- ASSERT_EQ(0, ioctx.list_lockers("foo", "TestLockECPP7", &exclusive, &tag, &lockers));
- }
- ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockECPP7", "Cookie", "Tag", "", NULL, 0));
- {
- int exclusive;
- std::string tag;
- std::list<librados::locker_t> lockers;
- ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockECPP7", &exclusive, &tag, &lockers));
- std::list<librados::locker_t>::iterator it = lockers.begin();
- ASSERT_FALSE(lockers.end() == it);
- ASSERT_EQ(me, it->client);
- ASSERT_EQ("Cookie", it->cookie);
- }
-}
-
TEST_F(LibRadosLockEC, BreakLock) {
int exclusive;
char tag[1024];
ASSERT_EQ(0, rados_break_lock(ioctx, "foo", "TestLockEC8", clients, "Cookie"));
}
-TEST_F(LibRadosLockECPP, BreakLockPP) {
- int exclusive;
- std::string tag;
- std::list<librados::locker_t> lockers;
- std::stringstream sstm;
- sstm << "client." << cluster.get_instance_id();
- std::string me = sstm.str();
- ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP8", "Cookie", "", NULL, 0));
- ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockECPP8", &exclusive, &tag, &lockers));
- std::list<librados::locker_t>::iterator it = lockers.begin();
- ASSERT_FALSE(lockers.end() == it);
- ASSERT_EQ(me, it->client);
- ASSERT_EQ("Cookie", it->cookie);
- ASSERT_EQ(0, ioctx.break_lock("foo", "TestLockECPP8", it->client, "Cookie"));
-}
--- /dev/null
+#include <algorithm>
+#include <chrono>
+#include <thread>
+#include <errno.h>
+#include <sys/time.h>
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+#include "cls/lock/cls_lock_client.h"
+
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+
+using namespace std::chrono_literals;
+using namespace librados;
+
+typedef RadosTestPP LibRadosLockPP;
+typedef RadosTestECPP LibRadosLockECPP;
+
+TEST_F(LibRadosLockPP, LockExclusivePP) {
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP1", "Cookie", "", NULL, 0));
+ ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockPP1", "Cookie", "", NULL, 0));
+}
+
+TEST_F(LibRadosLockPP, LockSharedPP) {
+ ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockPP2", "Cookie", "Tag", "", NULL, 0));
+ ASSERT_EQ(-EEXIST, ioctx.lock_shared("foo", "TestLockPP2", "Cookie", "Tag", "", NULL, 0));
+}
+
+TEST_F(LibRadosLockPP, LockExclusiveDurPP) {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ auto lock_exclusive = [this](timeval* tv) {
+ return ioctx.lock_exclusive("foo", "TestLockPP3", "Cookie", "", tv, 0);
+ };
+ constexpr int expected = 0;
+ ASSERT_EQ(expected, lock_exclusive(&tv));
+ ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_exclusive, nullptr));
+}
+
+TEST_F(LibRadosLockPP, LockSharedDurPP) {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ auto lock_shared = [this](timeval* tv) {
+ return ioctx.lock_shared("foo", "TestLockPP4", "Cookie", "Tag", "", tv, 0);
+ };
+ constexpr int expected = 0;
+ ASSERT_EQ(expected, lock_shared(&tv));
+ ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_shared, nullptr));
+}
+
+TEST_F(LibRadosLockPP, LockMayRenewPP) {
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP5", "Cookie", "", NULL, 0));
+ ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockPP5", "Cookie", "", NULL, 0));
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP5", "Cookie", "", NULL, LOCK_FLAG_MAY_RENEW));
+}
+
+TEST_F(LibRadosLockPP, UnlockPP) {
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP6", "Cookie", "", NULL, 0));
+ ASSERT_EQ(0, ioctx.unlock("foo", "TestLockPP6", "Cookie"));
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP6", "Cookie", "", NULL, 0));
+}
+
+TEST_F(LibRadosLockPP, ListLockersPP) {
+ std::stringstream sstm;
+ sstm << "client." << cluster.get_instance_id();
+ std::string me = sstm.str();
+ ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockPP7", "Cookie", "Tag", "", NULL, 0));
+ ASSERT_EQ(0, ioctx.unlock("foo", "TestLockPP7", "Cookie"));
+ {
+ int exclusive;
+ std::string tag;
+ std::list<librados::locker_t> lockers;
+ ASSERT_EQ(0, ioctx.list_lockers("foo", "TestLockPP7", &exclusive, &tag, &lockers));
+ }
+ ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockPP7", "Cookie", "Tag", "", NULL, 0));
+ {
+ int exclusive;
+ std::string tag;
+ std::list<librados::locker_t> lockers;
+ ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockPP7", &exclusive, &tag, &lockers));
+ std::list<librados::locker_t>::iterator it = lockers.begin();
+ ASSERT_FALSE(lockers.end() == it);
+ ASSERT_EQ(me, it->client);
+ ASSERT_EQ("Cookie", it->cookie);
+ }
+}
+
+TEST_F(LibRadosLockPP, BreakLockPP) {
+ int exclusive;
+ std::string tag;
+ std::list<librados::locker_t> lockers;
+ std::stringstream sstm;
+ sstm << "client." << cluster.get_instance_id();
+ std::string me = sstm.str();
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockPP8", "Cookie", "", NULL, 0));
+ ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockPP8", &exclusive, &tag, &lockers));
+ std::list<librados::locker_t>::iterator it = lockers.begin();
+ ASSERT_FALSE(lockers.end() == it);
+ ASSERT_EQ(me, it->client);
+ ASSERT_EQ("Cookie", it->cookie);
+ ASSERT_EQ(0, ioctx.break_lock("foo", "TestLockPP8", it->client, "Cookie"));
+}
+
+// EC testing
+TEST_F(LibRadosLockECPP, LockExclusivePP) {
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP1", "Cookie", "", NULL, 0));
+ ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockECPP1", "Cookie", "", NULL, 0));
+}
+
+TEST_F(LibRadosLockECPP, LockSharedPP) {
+ ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockECPP2", "Cookie", "Tag", "", NULL, 0));
+ ASSERT_EQ(-EEXIST, ioctx.lock_shared("foo", "TestLockECPP2", "Cookie", "Tag", "", NULL, 0));
+}
+
+TEST_F(LibRadosLockECPP, LockExclusiveDurPP) {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ auto lock_exclusive = [this](timeval* tv) {
+ return ioctx.lock_exclusive("foo", "TestLockECPP3", "Cookie", "", tv, 0);
+ };
+ constexpr int expected = 0;
+ ASSERT_EQ(expected, lock_exclusive(&tv));
+ ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_exclusive, nullptr));
+}
+
+TEST_F(LibRadosLockECPP, LockSharedDurPP) {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ auto lock_shared = [this](timeval* tv) {
+ return ioctx.lock_shared("foo", "TestLockECPP4", "Cookie", "Tag", "", tv, 0);
+ };
+ const int expected = 0;
+ ASSERT_EQ(expected, lock_shared(&tv));
+ ASSERT_EQ(expected, wait_until(1.0s, 0.1s, expected, lock_shared, nullptr));
+}
+
+TEST_F(LibRadosLockECPP, LockMayRenewPP) {
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP5", "Cookie", "", NULL, 0));
+ ASSERT_EQ(-EEXIST, ioctx.lock_exclusive("foo", "TestLockECPP5", "Cookie", "", NULL, 0));
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP5", "Cookie", "", NULL, LOCK_FLAG_MAY_RENEW));
+}
+
+TEST_F(LibRadosLockECPP, UnlockPP) {
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP6", "Cookie", "", NULL, 0));
+ ASSERT_EQ(0, ioctx.unlock("foo", "TestLockECPP6", "Cookie"));
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP6", "Cookie", "", NULL, 0));
+}
+
+TEST_F(LibRadosLockECPP, ListLockersPP) {
+ std::stringstream sstm;
+ sstm << "client." << cluster.get_instance_id();
+ std::string me = sstm.str();
+ ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockECPP7", "Cookie", "Tag", "", NULL, 0));
+ ASSERT_EQ(0, ioctx.unlock("foo", "TestLockECPP7", "Cookie"));
+ {
+ int exclusive;
+ std::string tag;
+ std::list<librados::locker_t> lockers;
+ ASSERT_EQ(0, ioctx.list_lockers("foo", "TestLockECPP7", &exclusive, &tag, &lockers));
+ }
+ ASSERT_EQ(0, ioctx.lock_shared("foo", "TestLockECPP7", "Cookie", "Tag", "", NULL, 0));
+ {
+ int exclusive;
+ std::string tag;
+ std::list<librados::locker_t> lockers;
+ ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockECPP7", &exclusive, &tag, &lockers));
+ std::list<librados::locker_t>::iterator it = lockers.begin();
+ ASSERT_FALSE(lockers.end() == it);
+ ASSERT_EQ(me, it->client);
+ ASSERT_EQ("Cookie", it->cookie);
+ }
+}
+
+TEST_F(LibRadosLockECPP, BreakLockPP) {
+ int exclusive;
+ std::string tag;
+ std::list<librados::locker_t> lockers;
+ std::stringstream sstm;
+ sstm << "client." << cluster.get_instance_id();
+ std::string me = sstm.str();
+ ASSERT_EQ(0, ioctx.lock_exclusive("foo", "TestLockECPP8", "Cookie", "", NULL, 0));
+ ASSERT_EQ(1, ioctx.list_lockers("foo", "TestLockECPP8", &exclusive, &tag, &lockers));
+ std::list<librados::locker_t>::iterator it = lockers.begin();
+ ASSERT_FALSE(lockers.end() == it);
+ ASSERT_EQ(me, it->client);
+ ASSERT_EQ("Cookie", it->cookie);
+ ASSERT_EQ(0, ioctx.break_lock("foo", "TestLockECPP8", it->client, "Cookie"));
+}
using std::string;
typedef RadosTest LibRadosMisc;
-typedef RadosTestPP LibRadosMiscPP;
-typedef RadosTestECPP LibRadosMiscECPP;
TEST(LibRadosMiscVersion, Version) {
int major, minor, extra;
rados_version(&major, &minor, &extra);
}
-TEST(LibRadosMiscVersion, VersionPP) {
- int major, minor, extra;
- Rados::version(&major, &minor, &extra);
-}
-
static void test_rados_log_cb(void *arg,
const char *line,
const char *who,
(size_t)rados_cluster_fsid(cluster, fsid, sizeof(fsid)));
}
-TEST_F(LibRadosMiscPP, WaitOSDMapPP) {
- ASSERT_EQ(0, cluster.wait_for_latest_osdmap());
-}
-
-TEST_F(LibRadosMiscPP, LongNamePP) {
- bufferlist bl;
- bl.append("content");
- int maxlen = g_conf()->osd_max_object_name_len;
- ASSERT_EQ(0, ioctx.write(string(maxlen/2, 'a').c_str(), bl, bl.length(), 0));
- ASSERT_EQ(0, ioctx.write(string(maxlen-1, 'a').c_str(), bl, bl.length(), 0));
- ASSERT_EQ(0, ioctx.write(string(maxlen, 'a').c_str(), bl, bl.length(), 0));
- ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen+1, 'a').c_str(), bl, bl.length(), 0));
- ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen*2, 'a').c_str(), bl, bl.length(), 0));
-}
-
-TEST_F(LibRadosMiscPP, LongLocatorPP) {
- bufferlist bl;
- bl.append("content");
- int maxlen = g_conf()->osd_max_object_name_len;
- ioctx.locator_set_key(
- string((maxlen/2), 'a'));
- ASSERT_EQ(
- 0,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.locator_set_key(
- string(maxlen - 1, 'a'));
- ASSERT_EQ(
- 0,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.locator_set_key(
- string(maxlen, 'a'));
- ASSERT_EQ(
- 0,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.locator_set_key(
- string(maxlen+1, 'a'));
- ASSERT_EQ(
- -ENAMETOOLONG,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.locator_set_key(
- string((maxlen*2), 'a'));
- ASSERT_EQ(
- -ENAMETOOLONG,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
-}
-
-TEST_F(LibRadosMiscPP, LongNSpacePP) {
- bufferlist bl;
- bl.append("content");
- int maxlen = g_conf()->osd_max_object_namespace_len;
- ioctx.set_namespace(
- string((maxlen/2), 'a'));
- ASSERT_EQ(
- 0,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.set_namespace(
- string(maxlen - 1, 'a'));
- ASSERT_EQ(
- 0,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.set_namespace(
- string(maxlen, 'a'));
- ASSERT_EQ(
- 0,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.set_namespace(
- string(maxlen+1, 'a'));
- ASSERT_EQ(
- -ENAMETOOLONG,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
- ioctx.set_namespace(
- string((maxlen*2), 'a'));
- ASSERT_EQ(
- -ENAMETOOLONG,
- ioctx.write(
- string("a").c_str(),
- bl, bl.length(), 0));
-}
-
-TEST_F(LibRadosMiscPP, LongAttrNamePP) {
- bufferlist bl;
- bl.append("content");
- int maxlen = g_conf()->osd_max_attr_name_len;
- ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen/2, 'a').c_str(), bl));
- ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen-1, 'a').c_str(), bl));
- ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen, 'a').c_str(), bl));
- ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen+1, 'a').c_str(), bl));
- ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen*2, 'a').c_str(), bl));
-}
-
-static std::string read_key_from_tmap(IoCtx& ioctx, const std::string &obj,
- const std::string &key)
-{
- bufferlist bl;
- int r = ioctx.read(obj, bl, 0, 0);
- if (r <= 0) {
- ostringstream oss;
- oss << "ioctx.read(" << obj << ", bl, 0, 0) returned " << r;
- return oss.str();
- }
- auto p = bl.cbegin();
- bufferlist header;
- map<string, bufferlist> m;
- decode(header, p);
- decode(m, p);
- map<string, bufferlist>::iterator i = m.find(key);
- if (i == m.end())
- return "";
- std::string retstring;
- decode(retstring, i->second);
- return retstring;
-}
-
-static std::string add_key_to_tmap(IoCtx &ioctx, const std::string &obj,
- const std::string &key, const std::string &val)
-{
- __u8 c = CEPH_OSD_TMAP_SET;
-
- bufferlist tmbl;
- encode(c, tmbl);
- encode(key, tmbl);
- bufferlist blbl;
- encode(val, blbl);
- encode(blbl, tmbl);
- int ret = ioctx.tmap_update(obj, tmbl);
- if (ret) {
- ostringstream oss;
- oss << "ioctx.tmap_update(obj=" << obj << ", key="
- << key << ", val=" << val << ") failed with error " << ret;
- return oss.str();
- }
- return "";
-}
-
-static int remove_key_from_tmap(IoCtx &ioctx, const std::string &obj,
- const std::string &key)
-{
- __u8 c = CEPH_OSD_TMAP_RM;
-
- bufferlist tmbl;
- encode(c, tmbl);
- encode(key, tmbl);
- int ret = ioctx.tmap_update(obj, tmbl);
- if (ret) {
- ostringstream oss;
- oss << "ioctx.tmap_update(obj=" << obj << ", key="
- << key << ") failed with error " << ret;
- }
- return ret;
-}
-
-TEST_F(LibRadosMiscPP, TmapUpdatePP) {
- // create tmap
- {
- __u8 c = CEPH_OSD_TMAP_CREATE;
- std::string my_tmap("my_tmap");
- bufferlist emptybl;
-
- bufferlist tmbl;
- encode(c, tmbl);
- encode(my_tmap, tmbl);
- encode(emptybl, tmbl);
- ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
- }
-
- ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key1", "val1"));
-
- ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key2", "val2"));
-
- // read key1 from the tmap
- ASSERT_EQ(string("val1"), read_key_from_tmap(ioctx, "foo", "key1"));
-
- // remove key1 from tmap
- ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "key1"));
- ASSERT_EQ(-ENOENT, remove_key_from_tmap(ioctx, "foo", "key1"));
-
- // key should be removed
- ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "key1"));
-}
-
-TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPP) {
- // create tmap
- {
- __u8 c = CEPH_OSD_TMAP_CREATE;
- std::string my_tmap("my_tmap");
- bufferlist emptybl;
-
- bufferlist tmbl;
- encode(c, tmbl);
- encode(my_tmap, tmbl);
- encode(emptybl, tmbl);
- ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
- }
-
- // good update
- {
- __u8 c = CEPH_OSD_TMAP_SET;
- bufferlist tmbl;
- encode(c, tmbl);
- encode("a", tmbl);
- bufferlist blbl;
- encode("old", blbl);
- encode(blbl, tmbl);
-
- encode(c, tmbl);
- encode("b", tmbl);
- encode(blbl, tmbl);
-
- encode(c, tmbl);
- encode("c", tmbl);
- encode(blbl, tmbl);
-
- ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
- }
-
- // bad update
- {
- __u8 c = CEPH_OSD_TMAP_SET;
- bufferlist tmbl;
- encode(c, tmbl);
- encode("b", tmbl);
- bufferlist blbl;
- encode("new", blbl);
- encode(blbl, tmbl);
-
- encode(c, tmbl);
- encode("a", tmbl);
- encode(blbl, tmbl);
-
- encode(c, tmbl);
- encode("c", tmbl);
- encode(blbl, tmbl);
-
- ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
- }
-
- // check
- ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "a"));
- ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "b"));
- ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "c"));
-
- ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "a"));
- ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a"));
-
- ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "b"));
- ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a"));
-}
-
-TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPutPP) {
- // create unsorted tmap
- string h("header");
- bufferlist bl;
- encode(h, bl);
- uint32_t n = 3;
- encode(n, bl);
- encode(string("b"), bl);
- encode(string("bval"), bl);
- encode(string("a"), bl);
- encode(string("aval"), bl);
- encode(string("c"), bl);
- encode(string("cval"), bl);
- bufferlist orig = bl; // tmap_put steals bl content
- ASSERT_EQ(0, ioctx.tmap_put("foo", bl));
-
- // check
- bufferlist newbl;
- ioctx.read("foo", newbl, orig.length(), 0);
- ASSERT_EQ(orig.contents_equal(newbl), false);
-}
-
-TEST_F(LibRadosMiscPP, Tmap2OmapPP) {
- // create tmap
- bufferlist hdr;
- hdr.append("header");
- map<string, bufferlist> omap;
- omap["1"].append("a");
- omap["2"].append("b");
- omap["3"].append("c");
- {
- bufferlist bl;
- encode(hdr, bl);
- encode(omap, bl);
- ASSERT_EQ(0, ioctx.tmap_put("foo", bl));
- }
-
- // convert tmap to omap
- ASSERT_EQ(0, ioctx.tmap_to_omap("foo", false));
-
- // if tmap was truncated ?
- {
- uint64_t size;
- time_t mtime;
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(0U, size);
- }
-
- // if 'nullok' works
- ASSERT_EQ(0, ioctx.tmap_to_omap("foo", true));
- ASSERT_LE(ioctx.tmap_to_omap("foo", false), 0);
-
- {
- // read omap
- bufferlist got;
- map<string, bufferlist> m;
- ObjectReadOperation o;
- o.omap_get_header(&got, NULL);
- o.omap_get_vals2("", 1024, &m, nullptr, nullptr);
- ASSERT_EQ(0, ioctx.operate("foo", &o, NULL));
-
- // compare header
- ASSERT_TRUE(hdr.contents_equal(got));
-
- // compare values
- ASSERT_EQ(omap.size(), m.size());
- bool same = true;
- for (map<string, bufferlist>::iterator p = omap.begin(); p != omap.end(); ++p) {
- map<string, bufferlist>::iterator q = m.find(p->first);
- if (q == m.end() || !p->second.contents_equal(q->second)) {
- same = false;
- break;
- }
- }
- ASSERT_TRUE(same);
- }
-}
-
TEST_F(LibRadosMisc, Exec) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
ASSERT_NE(all_features, (unsigned)0);
}
-TEST_F(LibRadosMiscPP, ExecPP) {
- bufferlist bl;
- ASSERT_EQ(0, ioctx.write("foo", bl, 0, 0));
- bufferlist bl2, out;
- int r = ioctx.exec("foo", "rbd", "get_all_features", bl2, out);
- ASSERT_EQ(0, r);
- auto iter = out.cbegin();
- uint64_t all_features;
- decode(all_features, iter);
- // make sure *some* features are specified; don't care which ones
- ASSERT_NE(all_features, (unsigned)0);
-}
-
-void set_completion_complete(rados_completion_t cb, void *arg)
-{
- bool *my_aio_complete = (bool*)arg;
- *my_aio_complete = true;
-}
-
-TEST_F(LibRadosMiscPP, BadFlagsPP) {
- unsigned badflags = CEPH_OSD_FLAG_PARALLELEXEC;
- {
- bufferlist bl;
- bl.append("data");
- ASSERT_EQ(0, ioctx.write("badfoo", bl, bl.length(), 0));
- }
- {
- ASSERT_EQ(-EINVAL, ioctx.remove("badfoo", badflags));
- }
-}
-
-TEST_F(LibRadosMiscPP, Operate1PP) {
- ObjectWriteOperation o;
- {
- bufferlist bl;
- o.write(0, bl);
- }
- std::string val1("val1");
- {
- bufferlist bl;
- bl.append(val1.c_str(), val1.size() + 1);
- o.setxattr("key1", bl);
- o.omap_clear(); // shouldn't affect attrs!
- }
- ASSERT_EQ(0, ioctx.operate("foo", &o));
-
- ObjectWriteOperation empty;
- ASSERT_EQ(0, ioctx.operate("foo", &empty));
-
- {
- bufferlist bl;
- ASSERT_GT(ioctx.getxattr("foo", "key1", bl), 0);
- ASSERT_EQ(0, strcmp(bl.c_str(), val1.c_str()));
- }
- ObjectWriteOperation o2;
- {
- bufferlist bl;
- bl.append(val1);
- o2.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl);
- o2.rmxattr("key1");
- }
- ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o2));
- ObjectWriteOperation o3;
- {
- bufferlist bl;
- bl.append(val1);
- o3.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl);
- }
- ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o3));
-}
-
-TEST_F(LibRadosMiscPP, Operate2PP) {
- ObjectWriteOperation o;
- {
- bufferlist bl;
- bl.append("abcdefg");
- o.write(0, bl);
- }
- std::string val1("val1");
- {
- bufferlist bl;
- bl.append(val1.c_str(), val1.size() + 1);
- o.setxattr("key1", bl);
- o.truncate(0);
- }
- ASSERT_EQ(0, ioctx.operate("foo", &o));
- uint64_t size;
- time_t mtime;
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(0U, size);
-}
-
-TEST_F(LibRadosMiscPP, BigObjectPP) {
- bufferlist bl;
- bl.append("abcdefg");
- ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0));
-
- {
- ObjectWriteOperation o;
- o.truncate(500000000000ull);
- ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
- }
- {
- ObjectWriteOperation o;
- o.zero(500000000000ull, 1);
- ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
- }
- {
- ObjectWriteOperation o;
- o.zero(1, 500000000000ull);
- ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
- }
- {
- ObjectWriteOperation o;
- o.zero(500000000000ull, 500000000000ull);
- ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
- }
-
-#ifdef __LP64__
- // this test only works on 64-bit platforms
- ASSERT_EQ(-EFBIG, ioctx.write("foo", bl, bl.length(), 500000000000ull));
-#endif
-}
-
-TEST_F(LibRadosMiscPP, AioOperatePP) {
- bool my_aio_complete = false;
- AioCompletion *my_completion = cluster.aio_create_completion(
- (void*)&my_aio_complete, set_completion_complete, NULL);
- AioCompletion *my_completion_null = NULL;
- ASSERT_NE(my_completion, my_completion_null);
-
- ObjectWriteOperation o;
- {
- bufferlist bl;
- o.write(0, bl);
- }
- std::string val1("val1");
- {
- bufferlist bl;
- bl.append(val1.c_str(), val1.size() + 1);
- o.setxattr("key1", bl);
- bufferlist bl2;
- char buf2[1024];
- memset(buf2, 0xdd, sizeof(buf2));
- bl2.append(buf2, sizeof(buf2));
- o.append(bl2);
- }
- ASSERT_EQ(0, ioctx.aio_operate("foo", my_completion, &o));
- ASSERT_EQ(0, my_completion->wait_for_complete_and_cb());
- ASSERT_EQ(my_aio_complete, true);
- my_completion->release();
-
- uint64_t size;
- time_t mtime;
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(1024U, size);
-}
-
-TEST_F(LibRadosMiscPP, AssertExistsPP) {
- char buf[64];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- ObjectWriteOperation op;
- op.assert_exists();
- op.write(0, bl);
- ASSERT_EQ(-ENOENT, ioctx.operate("asdffoo", &op));
- ASSERT_EQ(0, ioctx.create("asdffoo", true));
- ASSERT_EQ(0, ioctx.operate("asdffoo", &op));
- ASSERT_EQ(-EEXIST, ioctx.create("asdffoo", true));
-}
-
-TEST_F(LibRadosMiscPP, AssertVersionPP) {
- char buf[64];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- // Create test object...
- ASSERT_EQ(0, ioctx.create("asdfbar", true));
- // ...then write it again to guarantee that the
- // (unsigned) version must be at least 1 (not 0)
- // since we want to decrement it by 1 later.
- ASSERT_EQ(0, ioctx.write_full("asdfbar", bl));
-
- uint64_t v = ioctx.get_last_version();
- ObjectWriteOperation op1;
- op1.assert_version(v+1);
- op1.write(0, bl);
- ASSERT_EQ(-EOVERFLOW, ioctx.operate("asdfbar", &op1));
- ObjectWriteOperation op2;
- op2.assert_version(v-1);
- op2.write(0, bl);
- ASSERT_EQ(-ERANGE, ioctx.operate("asdfbar", &op2));
- ObjectWriteOperation op3;
- op3.assert_version(v);
- op3.write(0, bl);
- ASSERT_EQ(0, ioctx.operate("asdfbar", &op3));
-}
-
-TEST_F(LibRadosMiscPP, BigAttrPP) {
- char buf[64];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- ASSERT_EQ(0, ioctx.create("foo", true));
-
- bufferlist got;
-
- cout << "osd_max_attr_size = " << g_conf()->osd_max_attr_size << std::endl;
- if (g_conf()->osd_max_attr_size) {
- bl.clear();
- got.clear();
- bl.append(buffer::create(g_conf()->osd_max_attr_size));
- ASSERT_EQ(0, ioctx.setxattr("foo", "one", bl));
- ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", "one", got));
- ASSERT_TRUE(bl.contents_equal(got));
-
- bl.clear();
- bl.append(buffer::create(g_conf()->osd_max_attr_size+1));
- ASSERT_EQ(-EFBIG, ioctx.setxattr("foo", "one", bl));
- } else {
- cout << "osd_max_attr_size == 0; skipping test" << std::endl;
- }
-
- for (int i=0; i<1000; i++) {
- bl.clear();
- got.clear();
- bl.append(buffer::create(std::min<uint64_t>(g_conf()->osd_max_attr_size,
- 1024)));
- char n[10];
- snprintf(n, sizeof(n), "a%d", i);
- ASSERT_EQ(0, ioctx.setxattr("foo", n, bl));
- ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", n, got));
- ASSERT_TRUE(bl.contents_equal(got));
- }
-}
-
-TEST_F(LibRadosMiscPP, CopyPP) {
- bufferlist bl, x;
- bl.append("hi there");
- x.append("bar");
-
- // small object
- bufferlist blc = bl;
- bufferlist xc = x;
- ASSERT_EQ(0, ioctx.write_full("foo", blc));
- ASSERT_EQ(0, ioctx.setxattr("foo", "myattr", xc));
-
- version_t uv = ioctx.get_last_version();
- {
- // pass future version
- ObjectWriteOperation op;
- op.copy_from2("foo", ioctx, uv + 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(-EOVERFLOW, ioctx.operate("foo.copy", &op));
- }
- {
- // pass old version
- ObjectWriteOperation op;
- op.copy_from2("foo", ioctx, uv - 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(-ERANGE, ioctx.operate("foo.copy", &op));
- }
- {
- ObjectWriteOperation op;
- op.copy_from2("foo", ioctx, uv, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(0, ioctx.operate("foo.copy", &op));
-
- bufferlist bl2, x2;
- ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy", bl2, 10000, 0));
- ASSERT_TRUE(bl.contents_equal(bl2));
- ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
- ASSERT_TRUE(x.contents_equal(x2));
- }
-
- // small object without a version
- {
- ObjectWriteOperation op;
- op.copy_from2("foo", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(0, ioctx.operate("foo.copy2", &op));
-
- bufferlist bl2, x2;
- ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy2", bl2, 10000, 0));
- ASSERT_TRUE(bl.contents_equal(bl2));
- ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
- ASSERT_TRUE(x.contents_equal(x2));
- }
-
- // do a big object
- bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3));
- bl.zero();
- bl.append("tail");
- blc = bl;
- xc = x;
- ASSERT_EQ(0, ioctx.write_full("big", blc));
- ASSERT_EQ(0, ioctx.setxattr("big", "myattr", xc));
-
- {
- ObjectWriteOperation op;
- op.copy_from2("big", ioctx, ioctx.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
- ASSERT_EQ(0, ioctx.operate("big.copy", &op));
-
- bufferlist bl2, x2;
- ASSERT_EQ((int)bl.length(), ioctx.read("big.copy", bl2, bl.length(), 0));
- ASSERT_TRUE(bl.contents_equal(bl2));
- ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
- ASSERT_TRUE(x.contents_equal(x2));
- }
-
- {
- ObjectWriteOperation op;
- op.copy_from2("big", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
- ASSERT_EQ(0, ioctx.operate("big.copy2", &op));
-
- bufferlist bl2, x2;
- ASSERT_EQ((int)bl.length(), ioctx.read("big.copy2", bl2, bl.length(), 0));
- ASSERT_TRUE(bl.contents_equal(bl2));
- ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
- ASSERT_TRUE(x.contents_equal(x2));
- }
-}
-
-class LibRadosTwoPoolsECPP : public RadosTestECPP
-{
-public:
- LibRadosTwoPoolsECPP() {};
- ~LibRadosTwoPoolsECPP() override {};
-protected:
- static void SetUpTestCase() {
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
- src_pool_name = get_temp_pool_name();
- ASSERT_EQ(0, s_cluster.pool_create(src_pool_name.c_str()));
-
- librados::IoCtx ioctx;
- ASSERT_EQ(0, s_cluster.ioctx_create(pool_name.c_str(), ioctx));
- ioctx.application_enable("rados", true);
-
- librados::IoCtx src_ioctx;
- ASSERT_EQ(0, s_cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
- src_ioctx.application_enable("rados", true);
- }
- static void TearDownTestCase() {
- ASSERT_EQ(0, s_cluster.pool_delete(src_pool_name.c_str()));
- ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
- }
- static std::string src_pool_name;
-
- void SetUp() override {
- RadosTestECPP::SetUp();
- ASSERT_EQ(0, cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
- src_ioctx.set_namespace(nspace);
- }
- void TearDown() override {
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-
- RadosTestECPP::TearDown();
-
- cleanup_default_namespace(src_ioctx);
- cleanup_namespace(src_ioctx, nspace);
-
- src_ioctx.close();
- }
-
- librados::IoCtx src_ioctx;
-};
-std::string LibRadosTwoPoolsECPP::src_pool_name;
-
-//copy_from between ecpool and no-ecpool.
-TEST_F(LibRadosTwoPoolsECPP, CopyFrom) {
- bufferlist z;
- z.append_zero(4194304*2);
- bufferlist b;
- b.append("copyfrom");
-
- // create big object w/ omapheader
- {
- ASSERT_EQ(0, src_ioctx.write_full("foo", z));
- ASSERT_EQ(0, src_ioctx.omap_set_header("foo", b));
- version_t uv = src_ioctx.get_last_version();
- ObjectWriteOperation op;
- op.copy_from("foo", src_ioctx, uv);
- ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("foo.copy", &op));
- }
-
- // same with small object
- {
- ASSERT_EQ(0, src_ioctx.omap_set_header("bar", b));
- version_t uv = src_ioctx.get_last_version();
- ObjectWriteOperation op;
- op.copy_from("bar", src_ioctx, uv);
- ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("bar.copy", &op));
- }
-}
-
-TEST_F(LibRadosMiscPP, CopyScrubPP) {
- bufferlist inbl, bl, x;
- for (int i=0; i<100; ++i)
- x.append("barrrrrrrrrrrrrrrrrrrrrrrrrr");
- bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3));
- bl.zero();
- bl.append("tail");
- bufferlist cbl;
-
- map<string, bufferlist> to_set;
- for (int i=0; i<1000; ++i)
- to_set[string("foo") + stringify(i)] = x;
-
- // small
- cbl = x;
- ASSERT_EQ(0, ioctx.write_full("small", cbl));
- ASSERT_EQ(0, ioctx.setxattr("small", "myattr", x));
-
- // big
- cbl = bl;
- ASSERT_EQ(0, ioctx.write_full("big", cbl));
-
- // without header
- cbl = bl;
- ASSERT_EQ(0, ioctx.write_full("big2", cbl));
- ASSERT_EQ(0, ioctx.setxattr("big2", "myattr", x));
- ASSERT_EQ(0, ioctx.setxattr("big2", "myattr2", x));
- ASSERT_EQ(0, ioctx.omap_set("big2", to_set));
-
- // with header
- cbl = bl;
- ASSERT_EQ(0, ioctx.write_full("big3", cbl));
- ASSERT_EQ(0, ioctx.omap_set_header("big3", x));
- ASSERT_EQ(0, ioctx.omap_set("big3", to_set));
-
- // deep scrub to ensure digests are in place
- {
- for (int i=0; i<10; ++i) {
- ostringstream ss;
- ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
- << ioctx.get_id() << "." << i
- << "\"}";
- cluster.mon_command(ss.str(), inbl, NULL, NULL);
- }
-
- // give it a few seconds to go. this is sloppy but is usually enough time
- cout << "waiting for initial deep scrubs..." << std::endl;
- sleep(30);
- cout << "done waiting, doing copies" << std::endl;
- }
-
- {
- ObjectWriteOperation op;
- op.copy_from("small", ioctx, 0);
- ASSERT_EQ(0, ioctx.operate("small.copy", &op));
- }
-
- {
- ObjectWriteOperation op;
- op.copy_from("big", ioctx, 0);
- ASSERT_EQ(0, ioctx.operate("big.copy", &op));
- }
-
- {
- ObjectWriteOperation op;
- op.copy_from("big2", ioctx, 0);
- ASSERT_EQ(0, ioctx.operate("big2.copy", &op));
- }
-
- {
- ObjectWriteOperation op;
- op.copy_from("big3", ioctx, 0);
- ASSERT_EQ(0, ioctx.operate("big3.copy", &op));
- }
-
- // deep scrub to ensure digests are correct
- {
- for (int i=0; i<10; ++i) {
- ostringstream ss;
- ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
- << ioctx.get_id() << "." << i
- << "\"}";
- cluster.mon_command(ss.str(), inbl, NULL, NULL);
- }
-
- // give it a few seconds to go. this is sloppy but is usually enough time
- cout << "waiting for final deep scrubs..." << std::endl;
- sleep(30);
- cout << "done waiting" << std::endl;
- }
-}
-
-TEST_F(LibRadosMiscPP, WriteSamePP) {
- bufferlist bl;
- char buf[128];
- bufferlist fl;
- char full[128 * 4];
- char *cmp;
-
- /* zero the full range before using writesame */
- memset(full, 0, sizeof(full));
- fl.append(full, sizeof(full));
- ASSERT_EQ(0, ioctx.write("ws", fl, fl.length(), 0));
-
- memset(buf, 0xcc, sizeof(buf));
- bl.clear();
- bl.append(buf, sizeof(buf));
- /* write the same buf four times */
- ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(full), 0));
-
- /* read back the full buffer and confirm that it matches */
- fl.clear();
- fl.append(full, sizeof(full));
- ASSERT_EQ((int)fl.length(), ioctx.read("ws", fl, fl.length(), 0));
-
- for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) {
- ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
- }
-
- /* write_len not a multiple of data_len should throw error */
- bl.clear();
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(-EINVAL, ioctx.writesame("ws", bl, (sizeof(buf) * 4) - 1, 0));
- ASSERT_EQ(-EINVAL,
- ioctx.writesame("ws", bl, bl.length() / 2, 0));
- /* write_len = data_len, i.e. same as write() */
- ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(buf), 0));
- bl.clear();
- ASSERT_EQ(-EINVAL,
- ioctx.writesame("ws", bl, sizeof(buf), 0));
-}
-
TEST_F(LibRadosMisc, WriteSame) {
char buf[128];
char full[128 * 4];
ASSERT_EQ(0, rados_writesame(ioctx, "ws", buf, sizeof(buf), sizeof(buf), 0));
}
-template <typename T>
-class LibRadosChecksum : public LibRadosMiscPP {
-public:
- typedef typename T::alg_t alg_t;
- typedef typename T::value_t value_t;
- typedef typename alg_t::init_value_t init_value_t;
-
- static const rados_checksum_type_t type = T::type;
-
- bufferlist content_bl;
-
- using LibRadosMiscPP::SetUpTestCase;
- using LibRadosMiscPP::TearDownTestCase;
-
- void SetUp() override {
- LibRadosMiscPP::SetUp();
-
- std::string content(4096, '\0');
- for (size_t i = 0; i < content.length(); ++i) {
- content[i] = static_cast<char>(rand() % (126 - 33) + 33);
- }
- content_bl.append(content);
- ASSERT_EQ(0, ioctx.write("foo", content_bl, content_bl.length(), 0));
- }
-};
-
-template <rados_checksum_type_t _type, typename AlgT, typename ValueT>
-class LibRadosChecksumParams {
-public:
- typedef AlgT alg_t;
- typedef ValueT value_t;
- static const rados_checksum_type_t type = _type;
-};
-
-typedef ::testing::Types<
- LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH32,
- Checksummer::xxhash32, uint32_t>,
- LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH64,
- Checksummer::xxhash64, uint64_t>,
- LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_CRC32C,
- Checksummer::crc32c, uint32_t>
- > LibRadosChecksumTypes;
-
-TYPED_TEST_CASE(LibRadosChecksum, LibRadosChecksumTypes);
-
-TYPED_TEST(LibRadosChecksum, Subset) {
- uint32_t chunk_size = 1024;
- uint32_t csum_count = this->content_bl.length() / chunk_size;
-
- typename TestFixture::init_value_t init_value = -1;
- bufferlist init_value_bl;
- encode(init_value, init_value_bl);
-
- std::vector<bufferlist> checksum_bls(csum_count);
- std::vector<int> checksum_rvals(csum_count);
-
- // individual checksum ops for each chunk
- ObjectReadOperation op;
- for (uint32_t i = 0; i < csum_count; ++i) {
- op.checksum(TestFixture::type, init_value_bl, i * chunk_size, chunk_size,
- 0, &checksum_bls[i], &checksum_rvals[i]);
- }
- ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
-
- for (uint32_t i = 0; i < csum_count; ++i) {
- ASSERT_EQ(0, checksum_rvals[i]);
-
- auto bl_it = checksum_bls[i].cbegin();
- uint32_t count;
- decode(count, bl_it);
- ASSERT_EQ(1U, count);
-
- typename TestFixture::value_t value;
- decode(value, bl_it);
-
- bufferlist content_sub_bl;
- content_sub_bl.substr_of(this->content_bl, i * chunk_size, chunk_size);
-
- typename TestFixture::value_t expected_value;
- bufferptr expected_value_bp = buffer::create_static(
- sizeof(expected_value), reinterpret_cast<char*>(&expected_value));
- Checksummer::template calculate<typename TestFixture::alg_t>(
- init_value, chunk_size, 0, chunk_size, content_sub_bl,
- &expected_value_bp);
- ASSERT_EQ(expected_value, value);
- }
-}
-
-TYPED_TEST(LibRadosChecksum, Chunked) {
- uint32_t chunk_size = 1024;
- uint32_t csum_count = this->content_bl.length() / chunk_size;
-
- typename TestFixture::init_value_t init_value = -1;
- bufferlist init_value_bl;
- encode(init_value, init_value_bl);
-
- bufferlist checksum_bl;
- int checksum_rval;
-
- // single op with chunked checksum results
- ObjectReadOperation op;
- op.checksum(TestFixture::type, init_value_bl, 0, this->content_bl.length(),
- chunk_size, &checksum_bl, &checksum_rval);
- ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
- ASSERT_EQ(0, checksum_rval);
-
- auto bl_it = checksum_bl.cbegin();
- uint32_t count;
- decode(count, bl_it);
- ASSERT_EQ(csum_count, count);
-
- std::vector<typename TestFixture::value_t> expected_values(csum_count);
- bufferptr expected_values_bp = buffer::create_static(
- csum_count * sizeof(typename TestFixture::value_t),
- reinterpret_cast<char*>(&expected_values[0]));
-
- Checksummer::template calculate<typename TestFixture::alg_t>(
- init_value, chunk_size, 0, this->content_bl.length(), this->content_bl,
- &expected_values_bp);
-
- for (uint32_t i = 0; i < csum_count; ++i) {
- typename TestFixture::value_t value;
- decode(value, bl_it);
- ASSERT_EQ(expected_values[i], value);
- }
-}
-
-TEST_F(LibRadosMiscPP, CmpExtPP) {
- bufferlist cmp_bl, bad_cmp_bl, write_bl;
- char stored_str[] = "1234567891";
- char mismatch_str[] = "1234577777";
-
- write_bl.append(stored_str);
- ioctx.write("cmpextpp", write_bl, write_bl.length(), 0);
- cmp_bl.append(stored_str);
- ASSERT_EQ(0, ioctx.cmpext("cmpextpp", 0, cmp_bl));
-
- bad_cmp_bl.append(mismatch_str);
- ASSERT_EQ(-MAX_ERRNO - 5, ioctx.cmpext("cmpextpp", 0, bad_cmp_bl));
-}
-
TEST_F(LibRadosMisc, CmpExt) {
bufferlist cmp_bl, bad_cmp_bl, write_bl;
char stored_str[] = "1234567891";
ASSERT_EQ(0, memcmp("value2\0", vals, val_len));
}
-TEST_F(LibRadosMiscPP, Applications) {
- bufferlist inbl, outbl;
- string outs;
- ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"osd dump\"}",
- inbl, &outbl, &outs));
- ASSERT_LT(0u, outbl.length());
- ASSERT_LE(0u, outs.length());
- if (!std::regex_search(outbl.to_str(),
- std::regex("require_osd_release [l-z]"))) {
- std::cout << "SKIPPING";
- return;
- }
-
- std::set<std::string> expected_apps = {"rados"};
- std::set<std::string> apps;
- ASSERT_EQ(0, ioctx.application_list(&apps));
- ASSERT_EQ(expected_apps, apps);
-
- ASSERT_EQ(0, ioctx.application_enable("app1", true));
- ASSERT_EQ(-EPERM, ioctx.application_enable("app2", false));
- ASSERT_EQ(0, ioctx.application_enable("app2", true));
-
- expected_apps = {"app1", "app2", "rados"};
- ASSERT_EQ(0, ioctx.application_list(&apps));
- ASSERT_EQ(expected_apps, apps);
-
- std::map<std::string, std::string> expected_meta;
- std::map<std::string, std::string> meta;
- ASSERT_EQ(-ENOENT, ioctx.application_metadata_list("dne", &meta));
- ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
- ASSERT_EQ(expected_meta, meta);
-
- ASSERT_EQ(-ENOENT, ioctx.application_metadata_set("dne", "key1", "value1"));
- ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key1", "value1"));
- ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key2", "value2"));
-
- expected_meta = {{"key1", "value1"}, {"key2", "value2"}};
- ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
- ASSERT_EQ(expected_meta, meta);
-
- ASSERT_EQ(0, ioctx.application_metadata_remove("app1", "key1"));
-
- expected_meta = {{"key2", "value2"}};
- ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
- ASSERT_EQ(expected_meta, meta);
-}
-
-TEST_F(LibRadosMiscECPP, CompareExtentRange) {
- bufferlist bl1;
- bl1.append("ceph");
- ObjectWriteOperation write;
- write.write(0, bl1);
- ASSERT_EQ(0, ioctx.operate("foo", &write));
-
- bufferlist bl2;
- bl2.append("ph");
- bl2.append(std::string(2, '\0'));
- ObjectReadOperation read1;
- read1.cmpext(2, bl2, nullptr);
- ASSERT_EQ(0, ioctx.operate("foo", &read1, nullptr));
-
- bufferlist bl3;
- bl3.append(std::string(4, '\0'));
- ObjectReadOperation read2;
- read2.cmpext(2097152, bl3, nullptr);
- ASSERT_EQ(0, ioctx.operate("foo", &read2, nullptr));
-}
-
TEST_F(LibRadosMisc, MinCompatOSD) {
int8_t require_osd_release;
ASSERT_EQ(0, rados_get_min_compatible_osd(cluster, &require_osd_release));
ASSERT_GT(CEPH_RELEASE_MAX, require_osd_release);
}
-TEST_F(LibRadosMiscPP, MinCompatOSD) {
- int8_t require_osd_release;
- ASSERT_EQ(0, cluster.get_min_compatible_osd(&require_osd_release));
- ASSERT_LE(-1, require_osd_release);
- ASSERT_GT(CEPH_RELEASE_MAX, require_osd_release);
-}
-
TEST_F(LibRadosMisc, MinCompatClient) {
int8_t min_compat_client;
int8_t require_min_compat_client;
ASSERT_LE(-1, require_min_compat_client);
ASSERT_GT(CEPH_RELEASE_MAX, require_min_compat_client);
}
-
-TEST_F(LibRadosMiscPP, MinCompatClient) {
- int8_t min_compat_client;
- int8_t require_min_compat_client;
- ASSERT_EQ(0, cluster.get_min_compatible_client(&min_compat_client,
- &require_min_compat_client));
- ASSERT_LE(-1, min_compat_client);
- ASSERT_GT(CEPH_RELEASE_MAX, min_compat_client);
-
- ASSERT_LE(-1, require_min_compat_client);
- ASSERT_GT(CEPH_RELEASE_MAX, require_min_compat_client);
-}
-
-TEST_F(LibRadosMiscPP, Conf) {
- const char* const option = "bluestore_throttle_bytes";
- size_t new_size = 1 << 20;
- std::string original;
- ASSERT_EQ(0, cluster.conf_get(option, original));
- auto restore_setting = make_scope_guard([&] {
- cluster.conf_set(option, original.c_str());
- });
- std::string expected = std::to_string(new_size);
- ASSERT_EQ(0, cluster.conf_set(option, expected.c_str()));
- std::string actual;
- ASSERT_EQ(0, cluster.conf_get(option, actual));
- ASSERT_EQ(expected, actual);
-}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include <errno.h>
+#include <map>
+#include <sstream>
+#include <string>
+#include <regex>
+
+#include "gtest/gtest.h"
+
+#include "include/err.h"
+#include "include/buffer.h"
+#include "include/rbd_types.h"
+#include "include/rados.h"
+#include "include/rados/librados.hpp"
+#include "include/scope_guard.h"
+#include "include/stringify.h"
+#include "common/Checksummer.h"
+#include "mds/mdstypes.h"
+#include "global/global_context.h"
+#include "test/librados/testcase_cxx.h"
+#include "test/librados/test_cxx.h"
+
+using namespace librados;
+using std::map;
+using std::ostringstream;
+using std::string;
+
+typedef RadosTestPP LibRadosMiscPP;
+typedef RadosTestECPP LibRadosMiscECPP;
+
+TEST(LibRadosMiscVersion, VersionPP) {
+ int major, minor, extra;
+ Rados::version(&major, &minor, &extra);
+}
+
+TEST_F(LibRadosMiscPP, WaitOSDMapPP) {
+ ASSERT_EQ(0, cluster.wait_for_latest_osdmap());
+}
+
+TEST_F(LibRadosMiscPP, LongNamePP) {
+ bufferlist bl;
+ bl.append("content");
+ int maxlen = g_conf()->osd_max_object_name_len;
+ ASSERT_EQ(0, ioctx.write(string(maxlen/2, 'a').c_str(), bl, bl.length(), 0));
+ ASSERT_EQ(0, ioctx.write(string(maxlen-1, 'a').c_str(), bl, bl.length(), 0));
+ ASSERT_EQ(0, ioctx.write(string(maxlen, 'a').c_str(), bl, bl.length(), 0));
+ ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen+1, 'a').c_str(), bl, bl.length(), 0));
+ ASSERT_EQ(-ENAMETOOLONG, ioctx.write(string(maxlen*2, 'a').c_str(), bl, bl.length(), 0));
+}
+
+TEST_F(LibRadosMiscPP, LongLocatorPP) {
+ bufferlist bl;
+ bl.append("content");
+ int maxlen = g_conf()->osd_max_object_name_len;
+ ioctx.locator_set_key(
+ string((maxlen/2), 'a'));
+ ASSERT_EQ(
+ 0,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.locator_set_key(
+ string(maxlen - 1, 'a'));
+ ASSERT_EQ(
+ 0,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.locator_set_key(
+ string(maxlen, 'a'));
+ ASSERT_EQ(
+ 0,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.locator_set_key(
+ string(maxlen+1, 'a'));
+ ASSERT_EQ(
+ -ENAMETOOLONG,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.locator_set_key(
+ string((maxlen*2), 'a'));
+ ASSERT_EQ(
+ -ENAMETOOLONG,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+}
+
+TEST_F(LibRadosMiscPP, LongNSpacePP) {
+ bufferlist bl;
+ bl.append("content");
+ int maxlen = g_conf()->osd_max_object_namespace_len;
+ ioctx.set_namespace(
+ string((maxlen/2), 'a'));
+ ASSERT_EQ(
+ 0,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.set_namespace(
+ string(maxlen - 1, 'a'));
+ ASSERT_EQ(
+ 0,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.set_namespace(
+ string(maxlen, 'a'));
+ ASSERT_EQ(
+ 0,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.set_namespace(
+ string(maxlen+1, 'a'));
+ ASSERT_EQ(
+ -ENAMETOOLONG,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+ ioctx.set_namespace(
+ string((maxlen*2), 'a'));
+ ASSERT_EQ(
+ -ENAMETOOLONG,
+ ioctx.write(
+ string("a").c_str(),
+ bl, bl.length(), 0));
+}
+
+TEST_F(LibRadosMiscPP, LongAttrNamePP) {
+ bufferlist bl;
+ bl.append("content");
+ int maxlen = g_conf()->osd_max_attr_name_len;
+ ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen/2, 'a').c_str(), bl));
+ ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen-1, 'a').c_str(), bl));
+ ASSERT_EQ(0, ioctx.setxattr("bigattrobj", string(maxlen, 'a').c_str(), bl));
+ ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen+1, 'a').c_str(), bl));
+ ASSERT_EQ(-ENAMETOOLONG, ioctx.setxattr("bigattrobj", string(maxlen*2, 'a').c_str(), bl));
+}
+
+static std::string read_key_from_tmap(IoCtx& ioctx, const std::string &obj,
+ const std::string &key)
+{
+ bufferlist bl;
+ int r = ioctx.read(obj, bl, 0, 0);
+ if (r <= 0) {
+ ostringstream oss;
+ oss << "ioctx.read(" << obj << ", bl, 0, 0) returned " << r;
+ return oss.str();
+ }
+ auto p = bl.cbegin();
+ bufferlist header;
+ map<string, bufferlist> m;
+ decode(header, p);
+ decode(m, p);
+ map<string, bufferlist>::iterator i = m.find(key);
+ if (i == m.end())
+ return "";
+ std::string retstring;
+ decode(retstring, i->second);
+ return retstring;
+}
+
+static std::string add_key_to_tmap(IoCtx &ioctx, const std::string &obj,
+ const std::string &key, const std::string &val)
+{
+ __u8 c = CEPH_OSD_TMAP_SET;
+
+ bufferlist tmbl;
+ encode(c, tmbl);
+ encode(key, tmbl);
+ bufferlist blbl;
+ encode(val, blbl);
+ encode(blbl, tmbl);
+ int ret = ioctx.tmap_update(obj, tmbl);
+ if (ret) {
+ ostringstream oss;
+ oss << "ioctx.tmap_update(obj=" << obj << ", key="
+ << key << ", val=" << val << ") failed with error " << ret;
+ return oss.str();
+ }
+ return "";
+}
+
+static int remove_key_from_tmap(IoCtx &ioctx, const std::string &obj,
+ const std::string &key)
+{
+ __u8 c = CEPH_OSD_TMAP_RM;
+
+ bufferlist tmbl;
+ encode(c, tmbl);
+ encode(key, tmbl);
+ int ret = ioctx.tmap_update(obj, tmbl);
+ if (ret) {
+ ostringstream oss;
+ oss << "ioctx.tmap_update(obj=" << obj << ", key="
+ << key << ") failed with error " << ret;
+ }
+ return ret;
+}
+
+TEST_F(LibRadosMiscPP, TmapUpdatePP) {
+ // create tmap
+ {
+ __u8 c = CEPH_OSD_TMAP_CREATE;
+ std::string my_tmap("my_tmap");
+ bufferlist emptybl;
+
+ bufferlist tmbl;
+ encode(c, tmbl);
+ encode(my_tmap, tmbl);
+ encode(emptybl, tmbl);
+ ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
+ }
+
+ ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key1", "val1"));
+
+ ASSERT_EQ(string(""), add_key_to_tmap(ioctx, "foo", "key2", "val2"));
+
+ // read key1 from the tmap
+ ASSERT_EQ(string("val1"), read_key_from_tmap(ioctx, "foo", "key1"));
+
+ // remove key1 from tmap
+ ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "key1"));
+ ASSERT_EQ(-ENOENT, remove_key_from_tmap(ioctx, "foo", "key1"));
+
+ // key should be removed
+ ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "key1"));
+}
+
+TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPP) {
+ // create tmap
+ {
+ __u8 c = CEPH_OSD_TMAP_CREATE;
+ std::string my_tmap("my_tmap");
+ bufferlist emptybl;
+
+ bufferlist tmbl;
+ encode(c, tmbl);
+ encode(my_tmap, tmbl);
+ encode(emptybl, tmbl);
+ ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
+ }
+
+ // good update
+ {
+ __u8 c = CEPH_OSD_TMAP_SET;
+ bufferlist tmbl;
+ encode(c, tmbl);
+ encode("a", tmbl);
+ bufferlist blbl;
+ encode("old", blbl);
+ encode(blbl, tmbl);
+
+ encode(c, tmbl);
+ encode("b", tmbl);
+ encode(blbl, tmbl);
+
+ encode(c, tmbl);
+ encode("c", tmbl);
+ encode(blbl, tmbl);
+
+ ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
+ }
+
+ // bad update
+ {
+ __u8 c = CEPH_OSD_TMAP_SET;
+ bufferlist tmbl;
+ encode(c, tmbl);
+ encode("b", tmbl);
+ bufferlist blbl;
+ encode("new", blbl);
+ encode(blbl, tmbl);
+
+ encode(c, tmbl);
+ encode("a", tmbl);
+ encode(blbl, tmbl);
+
+ encode(c, tmbl);
+ encode("c", tmbl);
+ encode(blbl, tmbl);
+
+ ASSERT_EQ(0, ioctx.tmap_update("foo", tmbl));
+ }
+
+ // check
+ ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "a"));
+ ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "b"));
+ ASSERT_EQ(string("new"), read_key_from_tmap(ioctx, "foo", "c"));
+
+ ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "a"));
+ ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a"));
+
+ ASSERT_EQ(0, remove_key_from_tmap(ioctx, "foo", "b"));
+ ASSERT_EQ(string(""), read_key_from_tmap(ioctx, "foo", "a"));
+}
+
+TEST_F(LibRadosMiscPP, TmapUpdateMisorderedPutPP) {
+ // create unsorted tmap
+ string h("header");
+ bufferlist bl;
+ encode(h, bl);
+ uint32_t n = 3;
+ encode(n, bl);
+ encode(string("b"), bl);
+ encode(string("bval"), bl);
+ encode(string("a"), bl);
+ encode(string("aval"), bl);
+ encode(string("c"), bl);
+ encode(string("cval"), bl);
+ bufferlist orig = bl; // tmap_put steals bl content
+ ASSERT_EQ(0, ioctx.tmap_put("foo", bl));
+
+ // check
+ bufferlist newbl;
+ ioctx.read("foo", newbl, orig.length(), 0);
+ ASSERT_EQ(orig.contents_equal(newbl), false);
+}
+
+TEST_F(LibRadosMiscPP, Tmap2OmapPP) {
+ // create tmap
+ bufferlist hdr;
+ hdr.append("header");
+ map<string, bufferlist> omap;
+ omap["1"].append("a");
+ omap["2"].append("b");
+ omap["3"].append("c");
+ {
+ bufferlist bl;
+ encode(hdr, bl);
+ encode(omap, bl);
+ ASSERT_EQ(0, ioctx.tmap_put("foo", bl));
+ }
+
+ // convert tmap to omap
+ ASSERT_EQ(0, ioctx.tmap_to_omap("foo", false));
+
+ // if tmap was truncated ?
+ {
+ uint64_t size;
+ time_t mtime;
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(0U, size);
+ }
+
+ // if 'nullok' works
+ ASSERT_EQ(0, ioctx.tmap_to_omap("foo", true));
+ ASSERT_LE(ioctx.tmap_to_omap("foo", false), 0);
+
+ {
+ // read omap
+ bufferlist got;
+ map<string, bufferlist> m;
+ ObjectReadOperation o;
+ o.omap_get_header(&got, NULL);
+ o.omap_get_vals2("", 1024, &m, nullptr, nullptr);
+ ASSERT_EQ(0, ioctx.operate("foo", &o, NULL));
+
+ // compare header
+ ASSERT_TRUE(hdr.contents_equal(got));
+
+ // compare values
+ ASSERT_EQ(omap.size(), m.size());
+ bool same = true;
+ for (map<string, bufferlist>::iterator p = omap.begin(); p != omap.end(); ++p) {
+ map<string, bufferlist>::iterator q = m.find(p->first);
+ if (q == m.end() || !p->second.contents_equal(q->second)) {
+ same = false;
+ break;
+ }
+ }
+ ASSERT_TRUE(same);
+ }
+}
+
+TEST_F(LibRadosMiscPP, ExecPP) {
+ bufferlist bl;
+ ASSERT_EQ(0, ioctx.write("foo", bl, 0, 0));
+ bufferlist bl2, out;
+ int r = ioctx.exec("foo", "rbd", "get_all_features", bl2, out);
+ ASSERT_EQ(0, r);
+ auto iter = out.cbegin();
+ uint64_t all_features;
+ decode(all_features, iter);
+ // make sure *some* features are specified; don't care which ones
+ ASSERT_NE(all_features, (unsigned)0);
+}
+
+void set_completion_complete(rados_completion_t cb, void *arg)
+{
+ bool *my_aio_complete = (bool*)arg;
+ *my_aio_complete = true;
+}
+
+TEST_F(LibRadosMiscPP, BadFlagsPP) {
+ unsigned badflags = CEPH_OSD_FLAG_PARALLELEXEC;
+ {
+ bufferlist bl;
+ bl.append("data");
+ ASSERT_EQ(0, ioctx.write("badfoo", bl, bl.length(), 0));
+ }
+ {
+ ASSERT_EQ(-EINVAL, ioctx.remove("badfoo", badflags));
+ }
+}
+
+TEST_F(LibRadosMiscPP, Operate1PP) {
+ ObjectWriteOperation o;
+ {
+ bufferlist bl;
+ o.write(0, bl);
+ }
+ std::string val1("val1");
+ {
+ bufferlist bl;
+ bl.append(val1.c_str(), val1.size() + 1);
+ o.setxattr("key1", bl);
+ o.omap_clear(); // shouldn't affect attrs!
+ }
+ ASSERT_EQ(0, ioctx.operate("foo", &o));
+
+ ObjectWriteOperation empty;
+ ASSERT_EQ(0, ioctx.operate("foo", &empty));
+
+ {
+ bufferlist bl;
+ ASSERT_GT(ioctx.getxattr("foo", "key1", bl), 0);
+ ASSERT_EQ(0, strcmp(bl.c_str(), val1.c_str()));
+ }
+ ObjectWriteOperation o2;
+ {
+ bufferlist bl;
+ bl.append(val1);
+ o2.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl);
+ o2.rmxattr("key1");
+ }
+ ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o2));
+ ObjectWriteOperation o3;
+ {
+ bufferlist bl;
+ bl.append(val1);
+ o3.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ, bl);
+ }
+ ASSERT_EQ(-ECANCELED, ioctx.operate("foo", &o3));
+}
+
+TEST_F(LibRadosMiscPP, Operate2PP) {
+ ObjectWriteOperation o;
+ {
+ bufferlist bl;
+ bl.append("abcdefg");
+ o.write(0, bl);
+ }
+ std::string val1("val1");
+ {
+ bufferlist bl;
+ bl.append(val1.c_str(), val1.size() + 1);
+ o.setxattr("key1", bl);
+ o.truncate(0);
+ }
+ ASSERT_EQ(0, ioctx.operate("foo", &o));
+ uint64_t size;
+ time_t mtime;
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(0U, size);
+}
+
+TEST_F(LibRadosMiscPP, BigObjectPP) {
+ bufferlist bl;
+ bl.append("abcdefg");
+ ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0));
+
+ {
+ ObjectWriteOperation o;
+ o.truncate(500000000000ull);
+ ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
+ }
+ {
+ ObjectWriteOperation o;
+ o.zero(500000000000ull, 1);
+ ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
+ }
+ {
+ ObjectWriteOperation o;
+ o.zero(1, 500000000000ull);
+ ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
+ }
+ {
+ ObjectWriteOperation o;
+ o.zero(500000000000ull, 500000000000ull);
+ ASSERT_EQ(-EFBIG, ioctx.operate("foo", &o));
+ }
+
+#ifdef __LP64__
+ // this test only works on 64-bit platforms
+ ASSERT_EQ(-EFBIG, ioctx.write("foo", bl, bl.length(), 500000000000ull));
+#endif
+}
+
+TEST_F(LibRadosMiscPP, AioOperatePP) {
+ bool my_aio_complete = false;
+ AioCompletion *my_completion = cluster.aio_create_completion(
+ (void*)&my_aio_complete, set_completion_complete, NULL);
+ AioCompletion *my_completion_null = NULL;
+ ASSERT_NE(my_completion, my_completion_null);
+
+ ObjectWriteOperation o;
+ {
+ bufferlist bl;
+ o.write(0, bl);
+ }
+ std::string val1("val1");
+ {
+ bufferlist bl;
+ bl.append(val1.c_str(), val1.size() + 1);
+ o.setxattr("key1", bl);
+ bufferlist bl2;
+ char buf2[1024];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bl2.append(buf2, sizeof(buf2));
+ o.append(bl2);
+ }
+ ASSERT_EQ(0, ioctx.aio_operate("foo", my_completion, &o));
+ ASSERT_EQ(0, my_completion->wait_for_complete_and_cb());
+ ASSERT_EQ(my_aio_complete, true);
+ my_completion->release();
+
+ uint64_t size;
+ time_t mtime;
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(1024U, size);
+}
+
+TEST_F(LibRadosMiscPP, AssertExistsPP) {
+ char buf[64];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.write(0, bl);
+ ASSERT_EQ(-ENOENT, ioctx.operate("asdffoo", &op));
+ ASSERT_EQ(0, ioctx.create("asdffoo", true));
+ ASSERT_EQ(0, ioctx.operate("asdffoo", &op));
+ ASSERT_EQ(-EEXIST, ioctx.create("asdffoo", true));
+}
+
+TEST_F(LibRadosMiscPP, AssertVersionPP) {
+ char buf[64];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ // Create test object...
+ ASSERT_EQ(0, ioctx.create("asdfbar", true));
+ // ...then write it again to guarantee that the
+ // (unsigned) version must be at least 1 (not 0)
+ // since we want to decrement it by 1 later.
+ ASSERT_EQ(0, ioctx.write_full("asdfbar", bl));
+
+ uint64_t v = ioctx.get_last_version();
+ ObjectWriteOperation op1;
+ op1.assert_version(v+1);
+ op1.write(0, bl);
+ ASSERT_EQ(-EOVERFLOW, ioctx.operate("asdfbar", &op1));
+ ObjectWriteOperation op2;
+ op2.assert_version(v-1);
+ op2.write(0, bl);
+ ASSERT_EQ(-ERANGE, ioctx.operate("asdfbar", &op2));
+ ObjectWriteOperation op3;
+ op3.assert_version(v);
+ op3.write(0, bl);
+ ASSERT_EQ(0, ioctx.operate("asdfbar", &op3));
+}
+
+TEST_F(LibRadosMiscPP, BigAttrPP) {
+ char buf[64];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ ASSERT_EQ(0, ioctx.create("foo", true));
+
+ bufferlist got;
+
+ cout << "osd_max_attr_size = " << g_conf()->osd_max_attr_size << std::endl;
+ if (g_conf()->osd_max_attr_size) {
+ bl.clear();
+ got.clear();
+ bl.append(buffer::create(g_conf()->osd_max_attr_size));
+ ASSERT_EQ(0, ioctx.setxattr("foo", "one", bl));
+ ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", "one", got));
+ ASSERT_TRUE(bl.contents_equal(got));
+
+ bl.clear();
+ bl.append(buffer::create(g_conf()->osd_max_attr_size+1));
+ ASSERT_EQ(-EFBIG, ioctx.setxattr("foo", "one", bl));
+ } else {
+ cout << "osd_max_attr_size == 0; skipping test" << std::endl;
+ }
+
+ for (int i=0; i<1000; i++) {
+ bl.clear();
+ got.clear();
+ bl.append(buffer::create(std::min<uint64_t>(g_conf()->osd_max_attr_size,
+ 1024)));
+ char n[10];
+ snprintf(n, sizeof(n), "a%d", i);
+ ASSERT_EQ(0, ioctx.setxattr("foo", n, bl));
+ ASSERT_EQ((int)bl.length(), ioctx.getxattr("foo", n, got));
+ ASSERT_TRUE(bl.contents_equal(got));
+ }
+}
+
+TEST_F(LibRadosMiscPP, CopyPP) {
+ bufferlist bl, x;
+ bl.append("hi there");
+ x.append("bar");
+
+ // small object
+ bufferlist blc = bl;
+ bufferlist xc = x;
+ ASSERT_EQ(0, ioctx.write_full("foo", blc));
+ ASSERT_EQ(0, ioctx.setxattr("foo", "myattr", xc));
+
+ version_t uv = ioctx.get_last_version();
+ {
+ // pass future version
+ ObjectWriteOperation op;
+ op.copy_from2("foo", ioctx, uv + 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(-EOVERFLOW, ioctx.operate("foo.copy", &op));
+ }
+ {
+ // pass old version
+ ObjectWriteOperation op;
+ op.copy_from2("foo", ioctx, uv - 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(-ERANGE, ioctx.operate("foo.copy", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.copy_from2("foo", ioctx, uv, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(0, ioctx.operate("foo.copy", &op));
+
+ bufferlist bl2, x2;
+ ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy", bl2, 10000, 0));
+ ASSERT_TRUE(bl.contents_equal(bl2));
+ ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
+ ASSERT_TRUE(x.contents_equal(x2));
+ }
+
+ // small object without a version
+ {
+ ObjectWriteOperation op;
+ op.copy_from2("foo", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(0, ioctx.operate("foo.copy2", &op));
+
+ bufferlist bl2, x2;
+ ASSERT_EQ((int)bl.length(), ioctx.read("foo.copy2", bl2, 10000, 0));
+ ASSERT_TRUE(bl.contents_equal(bl2));
+ ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
+ ASSERT_TRUE(x.contents_equal(x2));
+ }
+
+ // do a big object
+ bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3));
+ bl.zero();
+ bl.append("tail");
+ blc = bl;
+ xc = x;
+ ASSERT_EQ(0, ioctx.write_full("big", blc));
+ ASSERT_EQ(0, ioctx.setxattr("big", "myattr", xc));
+
+ {
+ ObjectWriteOperation op;
+ op.copy_from2("big", ioctx, ioctx.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
+ ASSERT_EQ(0, ioctx.operate("big.copy", &op));
+
+ bufferlist bl2, x2;
+ ASSERT_EQ((int)bl.length(), ioctx.read("big.copy", bl2, bl.length(), 0));
+ ASSERT_TRUE(bl.contents_equal(bl2));
+ ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy", "myattr", x2));
+ ASSERT_TRUE(x.contents_equal(x2));
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.copy_from2("big", ioctx, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL);
+ ASSERT_EQ(0, ioctx.operate("big.copy2", &op));
+
+ bufferlist bl2, x2;
+ ASSERT_EQ((int)bl.length(), ioctx.read("big.copy2", bl2, bl.length(), 0));
+ ASSERT_TRUE(bl.contents_equal(bl2));
+ ASSERT_EQ((int)x.length(), ioctx.getxattr("foo.copy2", "myattr", x2));
+ ASSERT_TRUE(x.contents_equal(x2));
+ }
+}
+
+class LibRadosTwoPoolsECPP : public RadosTestECPP
+{
+public:
+ LibRadosTwoPoolsECPP() {};
+ ~LibRadosTwoPoolsECPP() override {};
+protected:
+ static void SetUpTestCase() {
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
+ src_pool_name = get_temp_pool_name();
+ ASSERT_EQ(0, s_cluster.pool_create(src_pool_name.c_str()));
+
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, s_cluster.ioctx_create(pool_name.c_str(), ioctx));
+ ioctx.application_enable("rados", true);
+
+ librados::IoCtx src_ioctx;
+ ASSERT_EQ(0, s_cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
+ src_ioctx.application_enable("rados", true);
+ }
+ static void TearDownTestCase() {
+ ASSERT_EQ(0, s_cluster.pool_delete(src_pool_name.c_str()));
+ ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
+ }
+ static std::string src_pool_name;
+
+ void SetUp() override {
+ RadosTestECPP::SetUp();
+ ASSERT_EQ(0, cluster.ioctx_create(src_pool_name.c_str(), src_ioctx));
+ src_ioctx.set_namespace(nspace);
+ }
+ void TearDown() override {
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+
+ RadosTestECPP::TearDown();
+
+ cleanup_default_namespace(src_ioctx);
+ cleanup_namespace(src_ioctx, nspace);
+
+ src_ioctx.close();
+ }
+
+ librados::IoCtx src_ioctx;
+};
+std::string LibRadosTwoPoolsECPP::src_pool_name;
+
+//copy_from between ecpool and no-ecpool.
+TEST_F(LibRadosTwoPoolsECPP, CopyFrom) {
+ bufferlist z;
+ z.append_zero(4194304*2);
+ bufferlist b;
+ b.append("copyfrom");
+
+ // create big object w/ omapheader
+ {
+ ASSERT_EQ(0, src_ioctx.write_full("foo", z));
+ ASSERT_EQ(0, src_ioctx.omap_set_header("foo", b));
+ version_t uv = src_ioctx.get_last_version();
+ ObjectWriteOperation op;
+ op.copy_from("foo", src_ioctx, uv);
+ ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("foo.copy", &op));
+ }
+
+ // same with small object
+ {
+ ASSERT_EQ(0, src_ioctx.omap_set_header("bar", b));
+ version_t uv = src_ioctx.get_last_version();
+ ObjectWriteOperation op;
+ op.copy_from("bar", src_ioctx, uv);
+ ASSERT_EQ(-EOPNOTSUPP, ioctx.operate("bar.copy", &op));
+ }
+}
+
+TEST_F(LibRadosMiscPP, CopyScrubPP) {
+ bufferlist inbl, bl, x;
+ for (int i=0; i<100; ++i)
+ x.append("barrrrrrrrrrrrrrrrrrrrrrrrrr");
+ bl.append(buffer::create(g_conf()->osd_copyfrom_max_chunk * 3));
+ bl.zero();
+ bl.append("tail");
+ bufferlist cbl;
+
+ map<string, bufferlist> to_set;
+ for (int i=0; i<1000; ++i)
+ to_set[string("foo") + stringify(i)] = x;
+
+ // small
+ cbl = x;
+ ASSERT_EQ(0, ioctx.write_full("small", cbl));
+ ASSERT_EQ(0, ioctx.setxattr("small", "myattr", x));
+
+ // big
+ cbl = bl;
+ ASSERT_EQ(0, ioctx.write_full("big", cbl));
+
+ // without header
+ cbl = bl;
+ ASSERT_EQ(0, ioctx.write_full("big2", cbl));
+ ASSERT_EQ(0, ioctx.setxattr("big2", "myattr", x));
+ ASSERT_EQ(0, ioctx.setxattr("big2", "myattr2", x));
+ ASSERT_EQ(0, ioctx.omap_set("big2", to_set));
+
+ // with header
+ cbl = bl;
+ ASSERT_EQ(0, ioctx.write_full("big3", cbl));
+ ASSERT_EQ(0, ioctx.omap_set_header("big3", x));
+ ASSERT_EQ(0, ioctx.omap_set("big3", to_set));
+
+ // deep scrub to ensure digests are in place
+ {
+ for (int i=0; i<10; ++i) {
+ ostringstream ss;
+ ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
+ << ioctx.get_id() << "." << i
+ << "\"}";
+ cluster.mon_command(ss.str(), inbl, NULL, NULL);
+ }
+
+ // give it a few seconds to go. this is sloppy but is usually enough time
+ cout << "waiting for initial deep scrubs..." << std::endl;
+ sleep(30);
+ cout << "done waiting, doing copies" << std::endl;
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.copy_from("small", ioctx, 0);
+ ASSERT_EQ(0, ioctx.operate("small.copy", &op));
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.copy_from("big", ioctx, 0);
+ ASSERT_EQ(0, ioctx.operate("big.copy", &op));
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.copy_from("big2", ioctx, 0);
+ ASSERT_EQ(0, ioctx.operate("big2.copy", &op));
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.copy_from("big3", ioctx, 0);
+ ASSERT_EQ(0, ioctx.operate("big3.copy", &op));
+ }
+
+ // deep scrub to ensure digests are correct
+ {
+ for (int i=0; i<10; ++i) {
+ ostringstream ss;
+ ss << "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
+ << ioctx.get_id() << "." << i
+ << "\"}";
+ cluster.mon_command(ss.str(), inbl, NULL, NULL);
+ }
+
+ // give it a few seconds to go. this is sloppy but is usually enough time
+ cout << "waiting for final deep scrubs..." << std::endl;
+ sleep(30);
+ cout << "done waiting" << std::endl;
+ }
+}
+
+TEST_F(LibRadosMiscPP, WriteSamePP) {
+ bufferlist bl;
+ char buf[128];
+ bufferlist fl;
+ char full[128 * 4];
+ char *cmp;
+
+ /* zero the full range before using writesame */
+ memset(full, 0, sizeof(full));
+ fl.append(full, sizeof(full));
+ ASSERT_EQ(0, ioctx.write("ws", fl, fl.length(), 0));
+
+ memset(buf, 0xcc, sizeof(buf));
+ bl.clear();
+ bl.append(buf, sizeof(buf));
+ /* write the same buf four times */
+ ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(full), 0));
+
+ /* read back the full buffer and confirm that it matches */
+ fl.clear();
+ fl.append(full, sizeof(full));
+ ASSERT_EQ((int)fl.length(), ioctx.read("ws", fl, fl.length(), 0));
+
+ for (cmp = fl.c_str(); cmp < fl.c_str() + fl.length(); cmp += sizeof(buf)) {
+ ASSERT_EQ(0, memcmp(cmp, buf, sizeof(buf)));
+ }
+
+ /* write_len not a multiple of data_len should throw error */
+ bl.clear();
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(-EINVAL, ioctx.writesame("ws", bl, (sizeof(buf) * 4) - 1, 0));
+ ASSERT_EQ(-EINVAL,
+ ioctx.writesame("ws", bl, bl.length() / 2, 0));
+ /* write_len = data_len, i.e. same as write() */
+ ASSERT_EQ(0, ioctx.writesame("ws", bl, sizeof(buf), 0));
+ bl.clear();
+ ASSERT_EQ(-EINVAL,
+ ioctx.writesame("ws", bl, sizeof(buf), 0));
+}
+
+template <typename T>
+class LibRadosChecksum : public LibRadosMiscPP {
+public:
+ typedef typename T::alg_t alg_t;
+ typedef typename T::value_t value_t;
+ typedef typename alg_t::init_value_t init_value_t;
+
+ static const rados_checksum_type_t type = T::type;
+
+ bufferlist content_bl;
+
+ using LibRadosMiscPP::SetUpTestCase;
+ using LibRadosMiscPP::TearDownTestCase;
+
+ void SetUp() override {
+ LibRadosMiscPP::SetUp();
+
+ std::string content(4096, '\0');
+ for (size_t i = 0; i < content.length(); ++i) {
+ content[i] = static_cast<char>(rand() % (126 - 33) + 33);
+ }
+ content_bl.append(content);
+ ASSERT_EQ(0, ioctx.write("foo", content_bl, content_bl.length(), 0));
+ }
+};
+
+template <rados_checksum_type_t _type, typename AlgT, typename ValueT>
+class LibRadosChecksumParams {
+public:
+ typedef AlgT alg_t;
+ typedef ValueT value_t;
+ static const rados_checksum_type_t type = _type;
+};
+
+typedef ::testing::Types<
+ LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH32,
+ Checksummer::xxhash32, uint32_t>,
+ LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_XXHASH64,
+ Checksummer::xxhash64, uint64_t>,
+ LibRadosChecksumParams<LIBRADOS_CHECKSUM_TYPE_CRC32C,
+ Checksummer::crc32c, uint32_t>
+ > LibRadosChecksumTypes;
+
+TYPED_TEST_CASE(LibRadosChecksum, LibRadosChecksumTypes);
+
+TYPED_TEST(LibRadosChecksum, Subset) {
+ uint32_t chunk_size = 1024;
+ uint32_t csum_count = this->content_bl.length() / chunk_size;
+
+ typename TestFixture::init_value_t init_value = -1;
+ bufferlist init_value_bl;
+ encode(init_value, init_value_bl);
+
+ std::vector<bufferlist> checksum_bls(csum_count);
+ std::vector<int> checksum_rvals(csum_count);
+
+ // individual checksum ops for each chunk
+ ObjectReadOperation op;
+ for (uint32_t i = 0; i < csum_count; ++i) {
+ op.checksum(TestFixture::type, init_value_bl, i * chunk_size, chunk_size,
+ 0, &checksum_bls[i], &checksum_rvals[i]);
+ }
+ ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
+
+ for (uint32_t i = 0; i < csum_count; ++i) {
+ ASSERT_EQ(0, checksum_rvals[i]);
+
+ auto bl_it = checksum_bls[i].cbegin();
+ uint32_t count;
+ decode(count, bl_it);
+ ASSERT_EQ(1U, count);
+
+ typename TestFixture::value_t value;
+ decode(value, bl_it);
+
+ bufferlist content_sub_bl;
+ content_sub_bl.substr_of(this->content_bl, i * chunk_size, chunk_size);
+
+ typename TestFixture::value_t expected_value;
+ bufferptr expected_value_bp = buffer::create_static(
+ sizeof(expected_value), reinterpret_cast<char*>(&expected_value));
+ Checksummer::template calculate<typename TestFixture::alg_t>(
+ init_value, chunk_size, 0, chunk_size, content_sub_bl,
+ &expected_value_bp);
+ ASSERT_EQ(expected_value, value);
+ }
+}
+
+TYPED_TEST(LibRadosChecksum, Chunked) {
+ uint32_t chunk_size = 1024;
+ uint32_t csum_count = this->content_bl.length() / chunk_size;
+
+ typename TestFixture::init_value_t init_value = -1;
+ bufferlist init_value_bl;
+ encode(init_value, init_value_bl);
+
+ bufferlist checksum_bl;
+ int checksum_rval;
+
+ // single op with chunked checksum results
+ ObjectReadOperation op;
+ op.checksum(TestFixture::type, init_value_bl, 0, this->content_bl.length(),
+ chunk_size, &checksum_bl, &checksum_rval);
+ ASSERT_EQ(0, this->ioctx.operate("foo", &op, NULL));
+ ASSERT_EQ(0, checksum_rval);
+
+ auto bl_it = checksum_bl.cbegin();
+ uint32_t count;
+ decode(count, bl_it);
+ ASSERT_EQ(csum_count, count);
+
+ std::vector<typename TestFixture::value_t> expected_values(csum_count);
+ bufferptr expected_values_bp = buffer::create_static(
+ csum_count * sizeof(typename TestFixture::value_t),
+ reinterpret_cast<char*>(&expected_values[0]));
+
+ Checksummer::template calculate<typename TestFixture::alg_t>(
+ init_value, chunk_size, 0, this->content_bl.length(), this->content_bl,
+ &expected_values_bp);
+
+ for (uint32_t i = 0; i < csum_count; ++i) {
+ typename TestFixture::value_t value;
+ decode(value, bl_it);
+ ASSERT_EQ(expected_values[i], value);
+ }
+}
+
+TEST_F(LibRadosMiscPP, CmpExtPP) {
+ bufferlist cmp_bl, bad_cmp_bl, write_bl;
+ char stored_str[] = "1234567891";
+ char mismatch_str[] = "1234577777";
+
+ write_bl.append(stored_str);
+ ioctx.write("cmpextpp", write_bl, write_bl.length(), 0);
+ cmp_bl.append(stored_str);
+ ASSERT_EQ(0, ioctx.cmpext("cmpextpp", 0, cmp_bl));
+
+ bad_cmp_bl.append(mismatch_str);
+ ASSERT_EQ(-MAX_ERRNO - 5, ioctx.cmpext("cmpextpp", 0, bad_cmp_bl));
+}
+
+TEST_F(LibRadosMiscPP, Applications) {
+ bufferlist inbl, outbl;
+ string outs;
+ ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, &outs));
+ ASSERT_LT(0u, outbl.length());
+ ASSERT_LE(0u, outs.length());
+ if (!std::regex_search(outbl.to_str(),
+ std::regex("require_osd_release [l-z]"))) {
+ std::cout << "SKIPPING";
+ return;
+ }
+
+ std::set<std::string> expected_apps = {"rados"};
+ std::set<std::string> apps;
+ ASSERT_EQ(0, ioctx.application_list(&apps));
+ ASSERT_EQ(expected_apps, apps);
+
+ ASSERT_EQ(0, ioctx.application_enable("app1", true));
+ ASSERT_EQ(-EPERM, ioctx.application_enable("app2", false));
+ ASSERT_EQ(0, ioctx.application_enable("app2", true));
+
+ expected_apps = {"app1", "app2", "rados"};
+ ASSERT_EQ(0, ioctx.application_list(&apps));
+ ASSERT_EQ(expected_apps, apps);
+
+ std::map<std::string, std::string> expected_meta;
+ std::map<std::string, std::string> meta;
+ ASSERT_EQ(-ENOENT, ioctx.application_metadata_list("dne", &meta));
+ ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
+ ASSERT_EQ(expected_meta, meta);
+
+ ASSERT_EQ(-ENOENT, ioctx.application_metadata_set("dne", "key1", "value1"));
+ ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key1", "value1"));
+ ASSERT_EQ(0, ioctx.application_metadata_set("app1", "key2", "value2"));
+
+ expected_meta = {{"key1", "value1"}, {"key2", "value2"}};
+ ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
+ ASSERT_EQ(expected_meta, meta);
+
+ ASSERT_EQ(0, ioctx.application_metadata_remove("app1", "key1"));
+
+ expected_meta = {{"key2", "value2"}};
+ ASSERT_EQ(0, ioctx.application_metadata_list("app1", &meta));
+ ASSERT_EQ(expected_meta, meta);
+}
+
+TEST_F(LibRadosMiscECPP, CompareExtentRange) {
+ bufferlist bl1;
+ bl1.append("ceph");
+ ObjectWriteOperation write;
+ write.write(0, bl1);
+ ASSERT_EQ(0, ioctx.operate("foo", &write));
+
+ bufferlist bl2;
+ bl2.append("ph");
+ bl2.append(std::string(2, '\0'));
+ ObjectReadOperation read1;
+ read1.cmpext(2, bl2, nullptr);
+ ASSERT_EQ(0, ioctx.operate("foo", &read1, nullptr));
+
+ bufferlist bl3;
+ bl3.append(std::string(4, '\0'));
+ ObjectReadOperation read2;
+ read2.cmpext(2097152, bl3, nullptr);
+ ASSERT_EQ(0, ioctx.operate("foo", &read2, nullptr));
+}
+
+TEST_F(LibRadosMiscPP, MinCompatOSD) {
+ int8_t require_osd_release;
+ ASSERT_EQ(0, cluster.get_min_compatible_osd(&require_osd_release));
+ ASSERT_LE(-1, require_osd_release);
+ ASSERT_GT(CEPH_RELEASE_MAX, require_osd_release);
+}
+
+TEST_F(LibRadosMiscPP, MinCompatClient) {
+ int8_t min_compat_client;
+ int8_t require_min_compat_client;
+ ASSERT_EQ(0, cluster.get_min_compatible_client(&min_compat_client,
+ &require_min_compat_client));
+ ASSERT_LE(-1, min_compat_client);
+ ASSERT_GT(CEPH_RELEASE_MAX, min_compat_client);
+
+ ASSERT_LE(-1, require_min_compat_client);
+ ASSERT_GT(CEPH_RELEASE_MAX, require_min_compat_client);
+}
+
+TEST_F(LibRadosMiscPP, Conf) {
+ const char* const option = "bluestore_throttle_bytes";
+ size_t new_size = 1 << 20;
+ std::string original;
+ ASSERT_EQ(0, cluster.conf_get(option, original));
+ auto restore_setting = make_scope_guard([&] {
+ cluster.conf_set(option, original.c_str());
+ });
+ std::string expected = std::to_string(new_size);
+ ASSERT_EQ(0, cluster.conf_set(option, expected.c_str()));
+ std::string actual;
+ ASSERT_EQ(0, cluster.conf_get(option, actual));
+ ASSERT_EQ(expected, actual);
+}
-#include "include/rados/librados.h"
-#include "test/librados/test.h"
-
-#include "gtest/gtest.h"
#include <errno.h>
#include <vector>
+#include "gtest/gtest.h"
+#include "include/rados/librados.h"
+#include "test/librados/test.h"
#define POOL_LIST_BUF_SZ 32768
}
rados_shutdown(cluster);
}
-
-TEST(LibRadosServicePP, RegisterEarly) {
- Rados cluster;
- cluster.init("admin");
- ASSERT_EQ(0, cluster.conf_read_file(NULL));
- cluster.conf_parse_env(NULL);
- string name = string("pid") + stringify(getpid());
- ASSERT_EQ(0, cluster.service_daemon_register(
- "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
- ASSERT_EQ(-EEXIST, cluster.service_daemon_register(
- "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
- ASSERT_EQ(0, cluster.connect());
- sleep(5);
- cluster.shutdown();
-}
-
-TEST(LibRadosServicePP, RegisterLate) {
- Rados cluster;
- cluster.init("admin");
- ASSERT_EQ(0, cluster.conf_read_file(NULL));
- cluster.conf_parse_env(NULL);
- ASSERT_EQ("", connect_cluster_pp(cluster));
- string name = string("pid") + stringify(getpid());
- ASSERT_EQ(0, cluster.service_daemon_register(
- "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
-}
-
-TEST(LibRadosServicePP, Status) {
- Rados cluster;
- cluster.init("admin");
- ASSERT_EQ(0, cluster.conf_read_file(NULL));
- cluster.conf_parse_env(NULL);
- string name = string("pid") + stringify(getpid());
- ASSERT_EQ(-ENOTCONN, cluster.service_daemon_update_status(
- {{"testing", "starting"}}));
- ASSERT_EQ(0, cluster.connect());
- ASSERT_EQ(0, cluster.service_daemon_register(
- "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
- for (int i=0; i<20; ++i) {
- ASSERT_EQ(0, cluster.service_daemon_update_status({
- {"testing", "running"},
- {"count", stringify(i)}
- }));
- sleep(1);
- }
- cluster.shutdown();
-}
-
-TEST(LibRadosServicePP, Close) {
- int tries = 20;
- string name = string("close-test-pid") + stringify(getpid());
- int i;
- for (i = 0; i < tries; ++i) {
- cout << "attempt " << i << " of " << tries << std::endl;
- {
- Rados cluster;
- cluster.init("admin");
- ASSERT_EQ(0, cluster.conf_read_file(NULL));
- cluster.conf_parse_env(NULL);
- ASSERT_EQ(0, cluster.connect());
- ASSERT_EQ(0, cluster.service_daemon_register(
- "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
- sleep(3); // let it register
- cluster.shutdown();
- }
- // mgr updates servicemap every tick
- //sleep(g_conf().get_val<int64_t>("mgr_tick_period"));
- std::this_thread::sleep_for(g_conf().get_val<std::chrono::seconds>(
- "mgr_tick_period"));
- // make sure we are deregistered
- {
- Rados cluster;
- cluster.init("admin");
- ASSERT_EQ(0, cluster.conf_read_file(NULL));
- cluster.conf_parse_env(NULL);
- ASSERT_EQ(0, cluster.connect());
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"service dump\"}",
- inbl, &outbl, NULL));
- string s = outbl.to_str();
- cluster.shutdown();
-
- if (s.find(name) != string::npos) {
- cout << " failed to deregister:\n" << s << std::endl;
- } else {
- break;
- }
- }
- }
- ASSERT_LT(i, tries);
-}
--- /dev/null
+#include <algorithm>
+#include <thread>
+#include <errno.h>
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+#include "include/stringify.h"
+#include "common/config_proxy.h"
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+#include "test/unit.cc"
+
+using namespace librados;
+
+TEST(LibRadosServicePP, RegisterEarly) {
+ Rados cluster;
+ cluster.init("admin");
+ ASSERT_EQ(0, cluster.conf_read_file(NULL));
+ cluster.conf_parse_env(NULL);
+ string name = string("pid") + stringify(getpid());
+ ASSERT_EQ(0, cluster.service_daemon_register(
+ "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
+ ASSERT_EQ(-EEXIST, cluster.service_daemon_register(
+ "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
+ ASSERT_EQ(0, cluster.connect());
+ sleep(5);
+ cluster.shutdown();
+}
+
+TEST(LibRadosServicePP, RegisterLate) {
+ Rados cluster;
+ cluster.init("admin");
+ ASSERT_EQ(0, cluster.conf_read_file(NULL));
+ cluster.conf_parse_env(NULL);
+ ASSERT_EQ("", connect_cluster_pp(cluster));
+ string name = string("pid") + stringify(getpid());
+ ASSERT_EQ(0, cluster.service_daemon_register(
+ "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
+}
+
+TEST(LibRadosServicePP, Status) {
+ Rados cluster;
+ cluster.init("admin");
+ ASSERT_EQ(0, cluster.conf_read_file(NULL));
+ cluster.conf_parse_env(NULL);
+ string name = string("pid") + stringify(getpid());
+ ASSERT_EQ(-ENOTCONN, cluster.service_daemon_update_status(
+ {{"testing", "starting"}}));
+ ASSERT_EQ(0, cluster.connect());
+ ASSERT_EQ(0, cluster.service_daemon_register(
+ "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
+ for (int i=0; i<20; ++i) {
+ ASSERT_EQ(0, cluster.service_daemon_update_status({
+ {"testing", "running"},
+ {"count", stringify(i)}
+ }));
+ sleep(1);
+ }
+ cluster.shutdown();
+}
+
+TEST(LibRadosServicePP, Close) {
+ int tries = 20;
+ string name = string("close-test-pid") + stringify(getpid());
+ int i;
+ for (i = 0; i < tries; ++i) {
+ cout << "attempt " << i << " of " << tries << std::endl;
+ {
+ Rados cluster;
+ cluster.init("admin");
+ ASSERT_EQ(0, cluster.conf_read_file(NULL));
+ cluster.conf_parse_env(NULL);
+ ASSERT_EQ(0, cluster.connect());
+ ASSERT_EQ(0, cluster.service_daemon_register(
+ "laundry", name, {{"foo", "bar"}, {"this", "that"}}));
+ sleep(3); // let it register
+ cluster.shutdown();
+ }
+ // mgr updates servicemap every tick
+ //sleep(g_conf().get_val<int64_t>("mgr_tick_period"));
+ std::this_thread::sleep_for(g_conf().get_val<std::chrono::seconds>(
+ "mgr_tick_period"));
+ // make sure we are deregistered
+ {
+ Rados cluster;
+ cluster.init("admin");
+ ASSERT_EQ(0, cluster.conf_read_file(NULL));
+ cluster.conf_parse_env(NULL);
+ ASSERT_EQ(0, cluster.connect());
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command("{\"prefix\": \"service dump\"}",
+ inbl, &outbl, NULL));
+ string s = outbl.to_str();
+ cluster.shutdown();
+
+ if (s.find(name) != string::npos) {
+ cout << " failed to deregister:\n" << s << std::endl;
+ } else {
+ break;
+ }
+ }
+ }
+ ASSERT_LT(i, tries);
+}
#include "include/rados.h"
-#include "include/rados/librados.hpp"
#include "test/librados/test.h"
#include "test/librados/TestCase.h"
#include "gtest/gtest.h"
#include <string>
-using namespace librados;
using std::string;
typedef RadosTest LibRadosSnapshots;
typedef RadosTest LibRadosSnapshotsSelfManaged;
-typedef RadosTestPP LibRadosSnapshotsPP;
-typedef RadosTestPP LibRadosSnapshotsSelfManagedPP;
typedef RadosTestEC LibRadosSnapshotsEC;
typedef RadosTestEC LibRadosSnapshotsSelfManagedEC;
-typedef RadosTestECPP LibRadosSnapshotsECPP;
-typedef RadosTestECPP LibRadosSnapshotsSelfManagedECPP;
const int bufsize = 128;
EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1"));
}
-TEST_F(LibRadosSnapshotsPP, SnapListPP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
- ASSERT_EQ(0, ioctx.snap_create("snap1"));
- ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
- std::vector<snap_t> snaps;
- EXPECT_EQ(0, ioctx.snap_list(&snaps));
- EXPECT_EQ(1U, snaps.size());
- snap_t rid;
- EXPECT_EQ(0, ioctx.snap_lookup("snap1", &rid));
- EXPECT_EQ(rid, snaps[0]);
- EXPECT_EQ(0, ioctx.snap_remove("snap1"));
- ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
-}
-
TEST_F(LibRadosSnapshots, SnapRemove) {
char buf[bufsize];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(-ENOENT, rados_ioctx_snap_lookup(ioctx, "snap1", &rid));
}
-TEST_F(LibRadosSnapshotsPP, SnapRemovePP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snap1"));
- rados_snap_t rid;
- ASSERT_EQ(0, ioctx.snap_lookup("snap1", &rid));
- ASSERT_EQ(0, ioctx.snap_remove("snap1"));
- ASSERT_EQ(-ENOENT, ioctx.snap_lookup("snap1", &rid));
-}
-
TEST_F(LibRadosSnapshots, Rollback) {
char buf[bufsize];
memset(buf, 0xcc, sizeof(buf));
EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1"));
}
-TEST_F(LibRadosSnapshotsPP, RollbackPP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snap1"));
- char buf2[sizeof(buf)];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- EXPECT_EQ(0, ioctx.write_full("foo", bl2));
- EXPECT_EQ(0, ioctx.snap_rollback("foo", "snap1"));
- bufferlist bl3;
- EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
- EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf)));
- EXPECT_EQ(0, ioctx.snap_remove("snap1"));
-}
-
TEST_F(LibRadosSnapshots, SnapGetName) {
char buf[bufsize];
memset(buf, 0xcc, sizeof(buf));
EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snapfoo"));
}
-TEST_F(LibRadosSnapshotsPP, SnapGetNamePP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snapfoo"));
- rados_snap_t rid;
- EXPECT_EQ(0, ioctx.snap_lookup("snapfoo", &rid));
- EXPECT_EQ(-ENOENT, ioctx.snap_lookup("snapbar", &rid));
- std::string name;
- EXPECT_EQ(0, ioctx.snap_get_name(rid, &name));
- time_t snaptime;
- EXPECT_EQ(0, ioctx.snap_get_stamp(rid, &snaptime));
- EXPECT_EQ(0, strcmp(name.c_str(), "snapfoo"));
- EXPECT_EQ(0, ioctx.snap_remove("snapfoo"));
-}
-
-TEST_F(LibRadosSnapshotsPP, SnapCreateRemovePP) {
- // reproduces http://tracker.ceph.com/issues/10262
- bufferlist bl;
- bl.append("foo");
- ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0));
- ASSERT_EQ(0, ioctx.snap_create("snapfoo"));
- ASSERT_EQ(0, ioctx.remove("foo"));
- ASSERT_EQ(0, ioctx.snap_create("snapbar"));
-
- std::unique_ptr<librados::ObjectWriteOperation> op(new librados::ObjectWriteOperation());
- op->create(false);
- op->remove();
- ASSERT_EQ(0, ioctx.operate("foo", op.get()));
-
- EXPECT_EQ(0, ioctx.snap_remove("snapfoo"));
- EXPECT_EQ(0, ioctx.snap_remove("snapbar"));
-}
-
TEST_F(LibRadosSnapshotsSelfManaged, Snap) {
std::vector<uint64_t> my_snaps;
my_snaps.push_back(-2);
ASSERT_EQ(0, rados_remove(ioctx, "foo"));
}
-TEST_F(LibRadosSnapshotsSelfManagedPP, SnapPP) {
- std::vector<uint64_t> my_snaps;
- my_snaps.push_back(-2);
- ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ASSERT_TRUE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- my_snaps.push_back(-2);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ioctx.aio_selfmanaged_snap_create(&my_snaps.back(), completion);
- ASSERT_EQ(0, completion->wait_for_complete());
- completion->release();
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char buf2[sizeof(buf)];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
-
- ioctx.snap_set_read(my_snaps[1]);
- bufferlist bl3;
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
-
- completion = cluster.aio_create_completion();
- ioctx.aio_selfmanaged_snap_remove(my_snaps.back(), completion);
- ASSERT_EQ(0, completion->wait_for_complete());
- completion->release();
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
- ASSERT_TRUE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
- ASSERT_EQ(0, ioctx.remove("foo"));
-}
-
-TEST_F(LibRadosSnapshotsSelfManagedPP, RollbackPP) {
- std::vector<uint64_t> my_snaps;
- IoCtx readioctx;
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx));
- readioctx.set_namespace(nspace);
- readioctx.snap_set_read(LIBRADOS_SNAP_DIR);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- //Write 3 consecutive buffers
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*2));
-
- snap_set_t ss;
-
- snap_t head = SNAP_HEAD;
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(1u, ss.clones.size());
- ASSERT_EQ(head, ss.clones[0].cloneid);
- ASSERT_EQ(0u, ss.clones[0].snaps.size());
- ASSERT_EQ(0u, ss.clones[0].overlap.size());
- ASSERT_EQ(384u, ss.clones[0].size);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char buf2[sizeof(buf)];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- //Change the middle buffer
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize));
- //Add another after
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*3));
-
- ASSERT_EQ(-EINVAL, ioctx.list_snaps("foo", &ss));
- ObjectReadOperation o;
- o.list_snaps(&ss, NULL);
- ASSERT_EQ(-EINVAL, ioctx.operate("foo", &o, NULL));
-
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(2u, ss.clones.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
- ASSERT_EQ(1u, ss.clones[0].snaps.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
- ASSERT_EQ(2u, ss.clones[0].overlap.size());
- ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[0].second);
- ASSERT_EQ(256u, ss.clones[0].overlap[1].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[1].second);
- ASSERT_EQ(384u, ss.clones[0].size);
- ASSERT_EQ(head, ss.clones[1].cloneid);
- ASSERT_EQ(0u, ss.clones[1].snaps.size());
- ASSERT_EQ(0u, ss.clones[1].overlap.size());
- ASSERT_EQ(512u, ss.clones[1].size);
-
- ioctx.selfmanaged_snap_rollback("foo", my_snaps[1]);
-
- bufferlist bl3;
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), bufsize));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
- ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), bufsize*2));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
- ASSERT_EQ((int)0, ioctx.read("foo", bl3, sizeof(buf), bufsize*3));
-
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- readioctx.close();
-}
-
-TEST_F(LibRadosSnapshotsSelfManagedPP, SnapOverlapPP) {
- std::vector<uint64_t> my_snaps;
- IoCtx readioctx;
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx));
- readioctx.set_namespace(nspace);
- readioctx.snap_set_read(LIBRADOS_SNAP_DIR);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*2));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*4));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*6));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*8));
-
- snap_set_t ss;
- snap_t head = SNAP_HEAD;
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(1u, ss.clones.size());
- ASSERT_EQ(head, ss.clones[0].cloneid);
- ASSERT_EQ(0u, ss.clones[0].snaps.size());
- ASSERT_EQ(0u, ss.clones[0].overlap.size());
- ASSERT_EQ(1152u, ss.clones[0].size);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char buf2[sizeof(buf)];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*1));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*3));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*5));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*7));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*9));
-
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(2u, ss.clones.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
- ASSERT_EQ(1u, ss.clones[0].snaps.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
- ASSERT_EQ(5u, ss.clones[0].overlap.size());
- ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[0].second);
- ASSERT_EQ(256u, ss.clones[0].overlap[1].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[1].second);
- ASSERT_EQ(512u, ss.clones[0].overlap[2].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[2].second);
- ASSERT_EQ(768u, ss.clones[0].overlap[3].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[3].second);
- ASSERT_EQ(1024u, ss.clones[0].overlap[4].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[4].second);
- ASSERT_EQ(1152u, ss.clones[0].size);
- ASSERT_EQ(head, ss.clones[1].cloneid);
- ASSERT_EQ(0u, ss.clones[1].snaps.size());
- ASSERT_EQ(0u, ss.clones[1].overlap.size());
- ASSERT_EQ(1280u, ss.clones[1].size);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
-
- char buf3[sizeof(buf)];
- memset(buf3, 0xee, sizeof(buf3));
- bufferlist bl4;
- bl4.append(buf3, sizeof(buf3));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*1));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*4));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*5));
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*8));
-
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(3u, ss.clones.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
- ASSERT_EQ(1u, ss.clones[0].snaps.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
- ASSERT_EQ(5u, ss.clones[0].overlap.size());
- ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[0].second);
- ASSERT_EQ(256u, ss.clones[0].overlap[1].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[1].second);
- ASSERT_EQ(512u, ss.clones[0].overlap[2].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[2].second);
- ASSERT_EQ(768u, ss.clones[0].overlap[3].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[3].second);
- ASSERT_EQ(1024u, ss.clones[0].overlap[4].first);
- ASSERT_EQ(128u, ss.clones[0].overlap[4].second);
- ASSERT_EQ(1152u, ss.clones[0].size);
-
- ASSERT_EQ(my_snaps[2], ss.clones[1].cloneid);
- ASSERT_EQ(1u, ss.clones[1].snaps.size());
- ASSERT_EQ(my_snaps[2], ss.clones[1].snaps[0]);
- ASSERT_EQ(4u, ss.clones[1].overlap.size());
- ASSERT_EQ(0u, ss.clones[1].overlap[0].first);
- ASSERT_EQ(128u, ss.clones[1].overlap[0].second);
- ASSERT_EQ(256u, ss.clones[1].overlap[1].first);
- ASSERT_EQ(256u, ss.clones[1].overlap[1].second);
- ASSERT_EQ(768u, ss.clones[1].overlap[2].first);
- ASSERT_EQ(256u, ss.clones[1].overlap[2].second);
- ASSERT_EQ(1152u, ss.clones[1].overlap[3].first);
- ASSERT_EQ(128u, ss.clones[1].overlap[3].second);
- ASSERT_EQ(1280u, ss.clones[1].size);
-
- ASSERT_EQ(head, ss.clones[2].cloneid);
- ASSERT_EQ(0u, ss.clones[2].snaps.size());
- ASSERT_EQ(0u, ss.clones[2].overlap.size());
- ASSERT_EQ(1280u, ss.clones[2].size);
-
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- readioctx.close();
-}
-
-TEST_F(LibRadosSnapshotsSelfManagedPP, Bug11677) {
- std::vector<uint64_t> my_snaps;
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
-
- int bsize = 1<<20;
- char *buf = (char *)new char[bsize];
- memset(buf, 0xcc, bsize);
- bufferlist bl1;
- bl1.append(buf, bsize);
- ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
-
- std::unique_ptr<librados::ObjectWriteOperation> op(new librados::ObjectWriteOperation());
- op->assert_exists();
- op->remove();
- ASSERT_EQ(0, ioctx.operate("foo", op.get()));
-
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
- delete[] buf;
-}
-
-TEST_F(LibRadosSnapshotsSelfManagedPP, OrderSnap) {
- std::vector<uint64_t> my_snaps;
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
-
- int flags = librados::OPERATION_ORDERSNAP;
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ObjectWriteOperation op1;
- op1.write(0, bl);
- librados::AioCompletion *comp1 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", comp1, &op1, flags));
- ASSERT_EQ(0, comp1->wait_for_complete());
- ASSERT_EQ(0, comp1->get_return_value());
- comp1->release();
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ObjectWriteOperation op2;
- op2.write(0, bl);
- librados::AioCompletion *comp2 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", comp2, &op2, flags));
- ASSERT_EQ(0, comp2->wait_for_complete());
- ASSERT_EQ(0, comp2->get_return_value());
- comp2->release();
-
- my_snaps.pop_back();
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ObjectWriteOperation op3;
- op3.write(0, bl);
- librados::AioCompletion *comp3 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", comp3, &op3, flags));
- ASSERT_EQ(0, comp3->wait_for_complete());
- ASSERT_EQ(-EOLDSNAPC, comp3->get_return_value());
- comp3->release();
-
- ObjectWriteOperation op4;
- op4.write(0, bl);
- librados::AioCompletion *comp4 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", comp4, &op4, 0));
- ASSERT_EQ(0, comp4->wait_for_complete());
- ASSERT_EQ(0, comp4->get_return_value());
- comp4->release();
-}
-
// EC testing
TEST_F(LibRadosSnapshotsEC, SnapList) {
char buf[bufsize];
EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1"));
}
-TEST_F(LibRadosSnapshotsECPP, SnapListPP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snap1"));
- std::vector<snap_t> snaps;
- EXPECT_EQ(0, ioctx.snap_list(&snaps));
- EXPECT_EQ(1U, snaps.size());
- snap_t rid;
- EXPECT_EQ(0, ioctx.snap_lookup("snap1", &rid));
- EXPECT_EQ(rid, snaps[0]);
- EXPECT_EQ(0, ioctx.snap_remove("snap1"));
-}
-
TEST_F(LibRadosSnapshotsEC, SnapRemove) {
char buf[bufsize];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(-ENOENT, rados_ioctx_snap_lookup(ioctx, "snap1", &rid));
}
-TEST_F(LibRadosSnapshotsECPP, SnapRemovePP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snap1"));
- rados_snap_t rid;
- ASSERT_EQ(0, ioctx.snap_lookup("snap1", &rid));
- ASSERT_EQ(0, ioctx.snap_remove("snap1"));
- ASSERT_EQ(-ENOENT, ioctx.snap_lookup("snap1", &rid));
-}
-
TEST_F(LibRadosSnapshotsEC, Rollback) {
char buf[bufsize];
memset(buf, 0xcc, sizeof(buf));
EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snap1"));
}
-TEST_F(LibRadosSnapshotsECPP, RollbackPP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snap1"));
- char buf2[sizeof(buf)];
- memset(buf2, 0xdd, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- EXPECT_EQ(0, ioctx.write_full("foo", bl2));
- EXPECT_EQ(0, ioctx.snap_rollback("foo", "snap1"));
- bufferlist bl3;
- EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
- EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf)));
- EXPECT_EQ(0, ioctx.snap_remove("snap1"));
-}
-
TEST_F(LibRadosSnapshotsEC, SnapGetName) {
char buf[bufsize];
memset(buf, 0xcc, sizeof(buf));
EXPECT_EQ(0, rados_ioctx_snap_remove(ioctx, "snapfoo"));
}
-TEST_F(LibRadosSnapshotsECPP, SnapGetNamePP) {
- char buf[bufsize];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.snap_create("snapfoo"));
- rados_snap_t rid;
- EXPECT_EQ(0, ioctx.snap_lookup("snapfoo", &rid));
- EXPECT_EQ(-ENOENT, ioctx.snap_lookup("snapbar", &rid));
- std::string name;
- EXPECT_EQ(0, ioctx.snap_get_name(rid, &name));
- time_t snaptime;
- EXPECT_EQ(0, ioctx.snap_get_stamp(rid, &snaptime));
- EXPECT_EQ(0, strcmp(name.c_str(), "snapfoo"));
- EXPECT_EQ(0, ioctx.snap_remove("snapfoo"));
-}
-
TEST_F(LibRadosSnapshotsSelfManagedEC, Snap) {
std::vector<uint64_t> my_snaps;
my_snaps.push_back(-2);
delete[] buf2;
delete[] buf3;
}
-
-TEST_F(LibRadosSnapshotsSelfManagedECPP, SnapPP) {
- std::vector<uint64_t> my_snaps;
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- int bsize = alignment;
- char *buf = (char *)new char[bsize];
- memset(buf, 0xcc, bsize);
- bufferlist bl1;
- bl1.append(buf, bsize);
- ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
-
- my_snaps.push_back(-2);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ioctx.aio_selfmanaged_snap_create(&my_snaps.back(), completion);
- ASSERT_EQ(0, completion->wait_for_complete());
- completion->release();
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char *buf2 = (char *)new char[bsize];
- memset(buf2, 0xdd, bsize);
- bufferlist bl2;
- bl2.append(buf2, bsize);
- // Add another aligned buffer
- ASSERT_EQ(0, ioctx.write("foo", bl2, bsize, bsize));
-
- ioctx.snap_set_read(my_snaps[1]);
- bufferlist bl3;
- ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize*3, 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
-
- completion = cluster.aio_create_completion();
- ioctx.aio_selfmanaged_snap_remove(my_snaps.back(), completion);
- ASSERT_EQ(0, completion->wait_for_complete());
- completion->release();
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
- ASSERT_EQ(0, ioctx.remove("foo"));
- delete[] buf;
- delete[] buf2;
-}
-
-TEST_F(LibRadosSnapshotsSelfManagedECPP, RollbackPP) {
- std::vector<uint64_t> my_snaps;
- IoCtx readioctx;
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx));
- readioctx.set_namespace(nspace);
- readioctx.snap_set_read(LIBRADOS_SNAP_DIR);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- int bsize = alignment;
- char *buf = (char *)new char[bsize];
- memset(buf, 0xcc, bsize);
- bufferlist bl1;
- bl1.append(buf, bsize);
- //Write 3 consecutive buffers
- ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
- ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, bsize));
- ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, bsize*2));
-
- snap_set_t ss;
-
- snap_t head = SNAP_HEAD;
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(1u, ss.clones.size());
- ASSERT_EQ(head, ss.clones[0].cloneid);
- ASSERT_EQ(0u, ss.clones[0].snaps.size());
- ASSERT_EQ(0u, ss.clones[0].overlap.size());
- ASSERT_EQ((unsigned)(bsize*3), ss.clones[0].size);
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- char *buf2 = (char *)new char[bsize];
- memset(buf2, 0xdd, bsize);
- bufferlist bl2;
- bl2.append(buf2, bsize);
- //Change the middle buffer
- //ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize));
- //Add another after
- ASSERT_EQ(0, ioctx.write("foo", bl2, bsize, bsize*3));
-
- ASSERT_EQ(-EINVAL, ioctx.list_snaps("foo", &ss));
- ObjectReadOperation o;
- o.list_snaps(&ss, NULL);
- ASSERT_EQ(-EINVAL, ioctx.operate("foo", &o, NULL));
-
- ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
- ASSERT_EQ(2u, ss.clones.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
- ASSERT_EQ(1u, ss.clones[0].snaps.size());
- ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
- ASSERT_EQ(1u, ss.clones[0].overlap.size());
- ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
- ASSERT_EQ((unsigned)bsize*3, ss.clones[0].overlap[0].second);
- ASSERT_EQ((unsigned)bsize*3, ss.clones[0].size);
- ASSERT_EQ(head, ss.clones[1].cloneid);
- ASSERT_EQ(0u, ss.clones[1].snaps.size());
- ASSERT_EQ(0u, ss.clones[1].overlap.size());
- ASSERT_EQ((unsigned)bsize*4, ss.clones[1].size);
-
- ioctx.selfmanaged_snap_rollback("foo", my_snaps[1]);
-
- bufferlist bl3;
- ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, 0));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
- ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, bsize));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
- ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, bsize*2));
- ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
- ASSERT_EQ(0, ioctx.read("foo", bl3, bsize, bsize*3));
-
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- readioctx.close();
-
- delete[] buf;
- delete[] buf2;
-}
-
-TEST_F(LibRadosSnapshotsSelfManagedECPP, Bug11677) {
- std::vector<uint64_t> my_snaps;
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
-
- int bsize = alignment;
- char *buf = (char *)new char[bsize];
- memset(buf, 0xcc, bsize);
- bufferlist bl1;
- bl1.append(buf, bsize);
- ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
-
- my_snaps.push_back(-2);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
- ::std::reverse(my_snaps.begin(), my_snaps.end());
-
- std::unique_ptr<librados::ObjectWriteOperation> op(new librados::ObjectWriteOperation());
- op->assert_exists();
- op->remove();
- ASSERT_EQ(0, ioctx.operate("foo", op.get()));
-
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
- my_snaps.pop_back();
- ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
- delete[] buf;
-}
-
--- /dev/null
+#include <algorithm>
+#include <errno.h>
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "include/rados.h"
+#include "include/rados/librados.hpp"
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+
+using namespace librados;
+
+typedef RadosTestPP LibRadosSnapshotsPP;
+typedef RadosTestPP LibRadosSnapshotsSelfManagedPP;
+typedef RadosTestECPP LibRadosSnapshotsECPP;
+typedef RadosTestECPP LibRadosSnapshotsSelfManagedECPP;
+
+const int bufsize = 128;
+
+TEST_F(LibRadosSnapshotsPP, SnapListPP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
+ ASSERT_EQ(0, ioctx.snap_create("snap1"));
+ ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
+ std::vector<snap_t> snaps;
+ EXPECT_EQ(0, ioctx.snap_list(&snaps));
+ EXPECT_EQ(1U, snaps.size());
+ snap_t rid;
+ EXPECT_EQ(0, ioctx.snap_lookup("snap1", &rid));
+ EXPECT_EQ(rid, snaps[0]);
+ EXPECT_EQ(0, ioctx.snap_remove("snap1"));
+ ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
+}
+
+TEST_F(LibRadosSnapshotsPP, SnapRemovePP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snap1"));
+ rados_snap_t rid;
+ ASSERT_EQ(0, ioctx.snap_lookup("snap1", &rid));
+ ASSERT_EQ(0, ioctx.snap_remove("snap1"));
+ ASSERT_EQ(-ENOENT, ioctx.snap_lookup("snap1", &rid));
+}
+
+TEST_F(LibRadosSnapshotsPP, RollbackPP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snap1"));
+ char buf2[sizeof(buf)];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ EXPECT_EQ(0, ioctx.write_full("foo", bl2));
+ EXPECT_EQ(0, ioctx.snap_rollback("foo", "snap1"));
+ bufferlist bl3;
+ EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
+ EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf)));
+ EXPECT_EQ(0, ioctx.snap_remove("snap1"));
+}
+
+TEST_F(LibRadosSnapshotsPP, SnapGetNamePP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snapfoo"));
+ rados_snap_t rid;
+ EXPECT_EQ(0, ioctx.snap_lookup("snapfoo", &rid));
+ EXPECT_EQ(-ENOENT, ioctx.snap_lookup("snapbar", &rid));
+ std::string name;
+ EXPECT_EQ(0, ioctx.snap_get_name(rid, &name));
+ time_t snaptime;
+ EXPECT_EQ(0, ioctx.snap_get_stamp(rid, &snaptime));
+ EXPECT_EQ(0, strcmp(name.c_str(), "snapfoo"));
+ EXPECT_EQ(0, ioctx.snap_remove("snapfoo"));
+}
+
+TEST_F(LibRadosSnapshotsPP, SnapCreateRemovePP) {
+ // reproduces http://tracker.ceph.com/issues/10262
+ bufferlist bl;
+ bl.append("foo");
+ ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snapfoo"));
+ ASSERT_EQ(0, ioctx.remove("foo"));
+ ASSERT_EQ(0, ioctx.snap_create("snapbar"));
+
+ std::unique_ptr<librados::ObjectWriteOperation> op(new librados::ObjectWriteOperation());
+ op->create(false);
+ op->remove();
+ ASSERT_EQ(0, ioctx.operate("foo", op.get()));
+
+ EXPECT_EQ(0, ioctx.snap_remove("snapfoo"));
+ EXPECT_EQ(0, ioctx.snap_remove("snapbar"));
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedPP, SnapPP) {
+ std::vector<uint64_t> my_snaps;
+ my_snaps.push_back(-2);
+ ASSERT_FALSE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ASSERT_TRUE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ my_snaps.push_back(-2);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ioctx.aio_selfmanaged_snap_create(&my_snaps.back(), completion);
+ ASSERT_EQ(0, completion->wait_for_complete());
+ completion->release();
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char buf2[sizeof(buf)];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
+
+ ioctx.snap_set_read(my_snaps[1]);
+ bufferlist bl3;
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+
+ completion = cluster.aio_create_completion();
+ ioctx.aio_selfmanaged_snap_remove(my_snaps.back(), completion);
+ ASSERT_EQ(0, completion->wait_for_complete());
+ completion->release();
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
+ ASSERT_TRUE(cluster.get_pool_is_selfmanaged_snaps_mode(pool_name));
+ ASSERT_EQ(0, ioctx.remove("foo"));
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedPP, RollbackPP) {
+ std::vector<uint64_t> my_snaps;
+ IoCtx readioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx));
+ readioctx.set_namespace(nspace);
+ readioctx.snap_set_read(LIBRADOS_SNAP_DIR);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ //Write 3 consecutive buffers
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*2));
+
+ snap_set_t ss;
+
+ snap_t head = SNAP_HEAD;
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(1u, ss.clones.size());
+ ASSERT_EQ(head, ss.clones[0].cloneid);
+ ASSERT_EQ(0u, ss.clones[0].snaps.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap.size());
+ ASSERT_EQ(384u, ss.clones[0].size);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char buf2[sizeof(buf)];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ //Change the middle buffer
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize));
+ //Add another after
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*3));
+
+ ASSERT_EQ(-EINVAL, ioctx.list_snaps("foo", &ss));
+ ObjectReadOperation o;
+ o.list_snaps(&ss, NULL);
+ ASSERT_EQ(-EINVAL, ioctx.operate("foo", &o, NULL));
+
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(2u, ss.clones.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
+ ASSERT_EQ(1u, ss.clones[0].snaps.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
+ ASSERT_EQ(2u, ss.clones[0].overlap.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[0].second);
+ ASSERT_EQ(256u, ss.clones[0].overlap[1].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[1].second);
+ ASSERT_EQ(384u, ss.clones[0].size);
+ ASSERT_EQ(head, ss.clones[1].cloneid);
+ ASSERT_EQ(0u, ss.clones[1].snaps.size());
+ ASSERT_EQ(0u, ss.clones[1].overlap.size());
+ ASSERT_EQ(512u, ss.clones[1].size);
+
+ ioctx.selfmanaged_snap_rollback("foo", my_snaps[1]);
+
+ bufferlist bl3;
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), bufsize));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), bufsize*2));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, sizeof(buf)));
+ ASSERT_EQ((int)0, ioctx.read("foo", bl3, sizeof(buf), bufsize*3));
+
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ readioctx.close();
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedPP, SnapOverlapPP) {
+ std::vector<uint64_t> my_snaps;
+ IoCtx readioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx));
+ readioctx.set_namespace(nspace);
+ readioctx.snap_set_read(LIBRADOS_SNAP_DIR);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*2));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*4));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*6));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), bufsize*8));
+
+ snap_set_t ss;
+ snap_t head = SNAP_HEAD;
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(1u, ss.clones.size());
+ ASSERT_EQ(head, ss.clones[0].cloneid);
+ ASSERT_EQ(0u, ss.clones[0].snaps.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap.size());
+ ASSERT_EQ(1152u, ss.clones[0].size);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char buf2[sizeof(buf)];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*1));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*3));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*5));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*7));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize*9));
+
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(2u, ss.clones.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
+ ASSERT_EQ(1u, ss.clones[0].snaps.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
+ ASSERT_EQ(5u, ss.clones[0].overlap.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[0].second);
+ ASSERT_EQ(256u, ss.clones[0].overlap[1].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[1].second);
+ ASSERT_EQ(512u, ss.clones[0].overlap[2].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[2].second);
+ ASSERT_EQ(768u, ss.clones[0].overlap[3].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[3].second);
+ ASSERT_EQ(1024u, ss.clones[0].overlap[4].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[4].second);
+ ASSERT_EQ(1152u, ss.clones[0].size);
+ ASSERT_EQ(head, ss.clones[1].cloneid);
+ ASSERT_EQ(0u, ss.clones[1].snaps.size());
+ ASSERT_EQ(0u, ss.clones[1].overlap.size());
+ ASSERT_EQ(1280u, ss.clones[1].size);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+
+ char buf3[sizeof(buf)];
+ memset(buf3, 0xee, sizeof(buf3));
+ bufferlist bl4;
+ bl4.append(buf3, sizeof(buf3));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*1));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*4));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*5));
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf3), bufsize*8));
+
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(3u, ss.clones.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
+ ASSERT_EQ(1u, ss.clones[0].snaps.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
+ ASSERT_EQ(5u, ss.clones[0].overlap.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[0].second);
+ ASSERT_EQ(256u, ss.clones[0].overlap[1].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[1].second);
+ ASSERT_EQ(512u, ss.clones[0].overlap[2].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[2].second);
+ ASSERT_EQ(768u, ss.clones[0].overlap[3].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[3].second);
+ ASSERT_EQ(1024u, ss.clones[0].overlap[4].first);
+ ASSERT_EQ(128u, ss.clones[0].overlap[4].second);
+ ASSERT_EQ(1152u, ss.clones[0].size);
+
+ ASSERT_EQ(my_snaps[2], ss.clones[1].cloneid);
+ ASSERT_EQ(1u, ss.clones[1].snaps.size());
+ ASSERT_EQ(my_snaps[2], ss.clones[1].snaps[0]);
+ ASSERT_EQ(4u, ss.clones[1].overlap.size());
+ ASSERT_EQ(0u, ss.clones[1].overlap[0].first);
+ ASSERT_EQ(128u, ss.clones[1].overlap[0].second);
+ ASSERT_EQ(256u, ss.clones[1].overlap[1].first);
+ ASSERT_EQ(256u, ss.clones[1].overlap[1].second);
+ ASSERT_EQ(768u, ss.clones[1].overlap[2].first);
+ ASSERT_EQ(256u, ss.clones[1].overlap[2].second);
+ ASSERT_EQ(1152u, ss.clones[1].overlap[3].first);
+ ASSERT_EQ(128u, ss.clones[1].overlap[3].second);
+ ASSERT_EQ(1280u, ss.clones[1].size);
+
+ ASSERT_EQ(head, ss.clones[2].cloneid);
+ ASSERT_EQ(0u, ss.clones[2].snaps.size());
+ ASSERT_EQ(0u, ss.clones[2].overlap.size());
+ ASSERT_EQ(1280u, ss.clones[2].size);
+
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ readioctx.close();
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedPP, Bug11677) {
+ std::vector<uint64_t> my_snaps;
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+
+ int bsize = 1<<20;
+ char *buf = (char *)new char[bsize];
+ memset(buf, 0xcc, bsize);
+ bufferlist bl1;
+ bl1.append(buf, bsize);
+ ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+
+ std::unique_ptr<librados::ObjectWriteOperation> op(new librados::ObjectWriteOperation());
+ op->assert_exists();
+ op->remove();
+ ASSERT_EQ(0, ioctx.operate("foo", op.get()));
+
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
+ delete[] buf;
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedPP, OrderSnap) {
+ std::vector<uint64_t> my_snaps;
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+
+ int flags = librados::OPERATION_ORDERSNAP;
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ObjectWriteOperation op1;
+ op1.write(0, bl);
+ librados::AioCompletion *comp1 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", comp1, &op1, flags));
+ ASSERT_EQ(0, comp1->wait_for_complete());
+ ASSERT_EQ(0, comp1->get_return_value());
+ comp1->release();
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ObjectWriteOperation op2;
+ op2.write(0, bl);
+ librados::AioCompletion *comp2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", comp2, &op2, flags));
+ ASSERT_EQ(0, comp2->wait_for_complete());
+ ASSERT_EQ(0, comp2->get_return_value());
+ comp2->release();
+
+ my_snaps.pop_back();
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ObjectWriteOperation op3;
+ op3.write(0, bl);
+ librados::AioCompletion *comp3 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", comp3, &op3, flags));
+ ASSERT_EQ(0, comp3->wait_for_complete());
+ ASSERT_EQ(-EOLDSNAPC, comp3->get_return_value());
+ comp3->release();
+
+ ObjectWriteOperation op4;
+ op4.write(0, bl);
+ librados::AioCompletion *comp4 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", comp4, &op4, 0));
+ ASSERT_EQ(0, comp4->wait_for_complete());
+ ASSERT_EQ(0, comp4->get_return_value());
+ comp4->release();
+}
+
+// EC testing
+TEST_F(LibRadosSnapshotsECPP, SnapListPP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snap1"));
+ std::vector<snap_t> snaps;
+ EXPECT_EQ(0, ioctx.snap_list(&snaps));
+ EXPECT_EQ(1U, snaps.size());
+ snap_t rid;
+ EXPECT_EQ(0, ioctx.snap_lookup("snap1", &rid));
+ EXPECT_EQ(rid, snaps[0]);
+ EXPECT_EQ(0, ioctx.snap_remove("snap1"));
+}
+
+TEST_F(LibRadosSnapshotsECPP, SnapRemovePP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snap1"));
+ rados_snap_t rid;
+ ASSERT_EQ(0, ioctx.snap_lookup("snap1", &rid));
+ ASSERT_EQ(0, ioctx.snap_remove("snap1"));
+ ASSERT_EQ(-ENOENT, ioctx.snap_lookup("snap1", &rid));
+}
+
+TEST_F(LibRadosSnapshotsECPP, RollbackPP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snap1"));
+ char buf2[sizeof(buf)];
+ memset(buf2, 0xdd, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ EXPECT_EQ(0, ioctx.write_full("foo", bl2));
+ EXPECT_EQ(0, ioctx.snap_rollback("foo", "snap1"));
+ bufferlist bl3;
+ EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
+ EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf)));
+ EXPECT_EQ(0, ioctx.snap_remove("snap1"));
+}
+
+TEST_F(LibRadosSnapshotsECPP, SnapGetNamePP) {
+ char buf[bufsize];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.snap_create("snapfoo"));
+ rados_snap_t rid;
+ EXPECT_EQ(0, ioctx.snap_lookup("snapfoo", &rid));
+ EXPECT_EQ(-ENOENT, ioctx.snap_lookup("snapbar", &rid));
+ std::string name;
+ EXPECT_EQ(0, ioctx.snap_get_name(rid, &name));
+ time_t snaptime;
+ EXPECT_EQ(0, ioctx.snap_get_stamp(rid, &snaptime));
+ EXPECT_EQ(0, strcmp(name.c_str(), "snapfoo"));
+ EXPECT_EQ(0, ioctx.snap_remove("snapfoo"));
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedECPP, SnapPP) {
+ std::vector<uint64_t> my_snaps;
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ int bsize = alignment;
+ char *buf = (char *)new char[bsize];
+ memset(buf, 0xcc, bsize);
+ bufferlist bl1;
+ bl1.append(buf, bsize);
+ ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
+
+ my_snaps.push_back(-2);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ioctx.aio_selfmanaged_snap_create(&my_snaps.back(), completion);
+ ASSERT_EQ(0, completion->wait_for_complete());
+ completion->release();
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char *buf2 = (char *)new char[bsize];
+ memset(buf2, 0xdd, bsize);
+ bufferlist bl2;
+ bl2.append(buf2, bsize);
+ // Add another aligned buffer
+ ASSERT_EQ(0, ioctx.write("foo", bl2, bsize, bsize));
+
+ ioctx.snap_set_read(my_snaps[1]);
+ bufferlist bl3;
+ ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize*3, 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
+
+ completion = cluster.aio_create_completion();
+ ioctx.aio_selfmanaged_snap_remove(my_snaps.back(), completion);
+ ASSERT_EQ(0, completion->wait_for_complete());
+ completion->release();
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
+ ASSERT_EQ(0, ioctx.remove("foo"));
+ delete[] buf;
+ delete[] buf2;
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedECPP, RollbackPP) {
+ std::vector<uint64_t> my_snaps;
+ IoCtx readioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), readioctx));
+ readioctx.set_namespace(nspace);
+ readioctx.snap_set_read(LIBRADOS_SNAP_DIR);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ int bsize = alignment;
+ char *buf = (char *)new char[bsize];
+ memset(buf, 0xcc, bsize);
+ bufferlist bl1;
+ bl1.append(buf, bsize);
+ //Write 3 consecutive buffers
+ ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, bsize));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, bsize*2));
+
+ snap_set_t ss;
+
+ snap_t head = SNAP_HEAD;
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(1u, ss.clones.size());
+ ASSERT_EQ(head, ss.clones[0].cloneid);
+ ASSERT_EQ(0u, ss.clones[0].snaps.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap.size());
+ ASSERT_EQ((unsigned)(bsize*3), ss.clones[0].size);
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ char *buf2 = (char *)new char[bsize];
+ memset(buf2, 0xdd, bsize);
+ bufferlist bl2;
+ bl2.append(buf2, bsize);
+ //Change the middle buffer
+ //ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), bufsize));
+ //Add another after
+ ASSERT_EQ(0, ioctx.write("foo", bl2, bsize, bsize*3));
+
+ ASSERT_EQ(-EINVAL, ioctx.list_snaps("foo", &ss));
+ ObjectReadOperation o;
+ o.list_snaps(&ss, NULL);
+ ASSERT_EQ(-EINVAL, ioctx.operate("foo", &o, NULL));
+
+ ASSERT_EQ(0, readioctx.list_snaps("foo", &ss));
+ ASSERT_EQ(2u, ss.clones.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].cloneid);
+ ASSERT_EQ(1u, ss.clones[0].snaps.size());
+ ASSERT_EQ(my_snaps[1], ss.clones[0].snaps[0]);
+ ASSERT_EQ(1u, ss.clones[0].overlap.size());
+ ASSERT_EQ(0u, ss.clones[0].overlap[0].first);
+ ASSERT_EQ((unsigned)bsize*3, ss.clones[0].overlap[0].second);
+ ASSERT_EQ((unsigned)bsize*3, ss.clones[0].size);
+ ASSERT_EQ(head, ss.clones[1].cloneid);
+ ASSERT_EQ(0u, ss.clones[1].snaps.size());
+ ASSERT_EQ(0u, ss.clones[1].overlap.size());
+ ASSERT_EQ((unsigned)bsize*4, ss.clones[1].size);
+
+ ioctx.selfmanaged_snap_rollback("foo", my_snaps[1]);
+
+ bufferlist bl3;
+ ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, 0));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
+ ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, bsize));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
+ ASSERT_EQ(bsize, ioctx.read("foo", bl3, bsize, bsize*2));
+ ASSERT_EQ(0, memcmp(bl3.c_str(), buf, bsize));
+ ASSERT_EQ(0, ioctx.read("foo", bl3, bsize, bsize*3));
+
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ readioctx.close();
+
+ delete[] buf;
+ delete[] buf2;
+}
+
+TEST_F(LibRadosSnapshotsSelfManagedECPP, Bug11677) {
+ std::vector<uint64_t> my_snaps;
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+
+ int bsize = alignment;
+ char *buf = (char *)new char[bsize];
+ memset(buf, 0xcc, bsize);
+ bufferlist bl1;
+ bl1.append(buf, bsize);
+ ASSERT_EQ(0, ioctx.write("foo", bl1, bsize, 0));
+
+ my_snaps.push_back(-2);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps.back()));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0], my_snaps));
+ ::std::reverse(my_snaps.begin(), my_snaps.end());
+
+ std::unique_ptr<librados::ObjectWriteOperation> op(new librados::ObjectWriteOperation());
+ op->assert_exists();
+ op->remove();
+ ASSERT_EQ(0, ioctx.operate("foo", op.get()));
+
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps.back()));
+ my_snaps.pop_back();
+ ioctx.snap_set_read(LIBRADOS_SNAP_HEAD);
+ delete[] buf;
+}
#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
#include "test/librados/test.h"
#include "test/librados/TestCase.h"
#include <errno.h>
#include "gtest/gtest.h"
-using namespace librados;
-
typedef RadosTest LibRadosStat;
-typedef RadosTestPP LibRadosStatPP;
typedef RadosTestEC LibRadosStatEC;
-typedef RadosTestECPP LibRadosStatECPP;
TEST_F(LibRadosStat, Stat) {
char buf[128];
ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime));
}
-TEST_F(LibRadosStatPP, StatPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- uint64_t size;
- time_t mtime;
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf), size);
- ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
-}
-
-TEST_F(LibRadosStatPP, Stat2Mtime2PP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- librados::ObjectWriteOperation op;
- struct timespec ts;
- ts.tv_sec = 1457129052;
- ts.tv_nsec = 123456789;
- op.mtime2(&ts);
- op.write(0, bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
-
- /* XXX time comparison asserts could spuriously fail */
-
- uint64_t size;
- time_t mtime;
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf), size);
- ASSERT_EQ(mtime, ts.tv_sec);
-
- struct timespec ts2;
- ASSERT_EQ(0, ioctx.stat2("foo", &size, &ts2));
- ASSERT_EQ(sizeof(buf), size);
- ASSERT_EQ(ts2.tv_sec, ts.tv_sec);
- ASSERT_EQ(ts2.tv_nsec, ts.tv_nsec);
-
- ASSERT_EQ(-ENOENT, ioctx.stat2("nonexistent", &size, &ts2));
-}
-
TEST_F(LibRadosStat, StatNS) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(-ENOENT, rados_stat(ioctx, "foo2", &size, &mtime));
}
-TEST_F(LibRadosStatPP, StatPPNS) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo2", bl, sizeof(buf), 0));
-
- char buf2[64];
- memset(buf2, 0xbb, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ioctx.set_namespace("nspace");
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
-
- uint64_t size;
- time_t mtime;
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf), size);
- ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
-
- ioctx.set_namespace("nspace");
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf2), size);
- ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
- ASSERT_EQ(-ENOENT, ioctx.stat("foo2", &size, &mtime));
-}
-
TEST_F(LibRadosStat, ClusterStat) {
struct rados_cluster_stat_t result;
ASSERT_EQ(0, rados_cluster_stat(cluster, &result));
}
-TEST_F(LibRadosStatPP, ClusterStatPP) {
- cluster_stat_t cstat;
- ASSERT_EQ(0, cluster.cluster_stat(cstat));
-}
-
TEST_F(LibRadosStat, PoolStat) {
char buf[128];
char actual_pool_name[80];
ASSERT_EQ(0, rados_ioctx_pool_stat(ioctx, &stats));
}
-TEST_F(LibRadosStatPP, PoolStatPP) {
- std::string n = ioctx.get_pool_name();
- ASSERT_EQ(n, pool_name);
- char buf[128];
- memset(buf, 0xff, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- std::list<std::string> v;
- std::map<std::string,stats_map> stats;
- ASSERT_EQ(0, cluster.get_pool_stats(v, stats));
-}
-
TEST_F(LibRadosStatEC, Stat) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(-ENOENT, rados_stat(ioctx, "nonexistent", &size, &mtime));
}
-TEST_F(LibRadosStatECPP, StatPP) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- uint64_t size;
- time_t mtime;
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf), size);
- ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
-}
-
TEST_F(LibRadosStatEC, StatNS) {
char buf[128];
memset(buf, 0xcc, sizeof(buf));
ASSERT_EQ(-ENOENT, rados_stat(ioctx, "foo2", &size, &mtime));
}
-TEST_F(LibRadosStatECPP, StatPPNS) {
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl;
- bl.append(buf, sizeof(buf));
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
- ASSERT_EQ(0, ioctx.write("foo2", bl, sizeof(buf), 0));
-
- char buf2[64];
- memset(buf2, 0xbb, sizeof(buf2));
- bufferlist bl2;
- bl2.append(buf2, sizeof(buf2));
- ioctx.set_namespace("nspace");
- ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
-
- uint64_t size;
- time_t mtime;
- ioctx.set_namespace("");
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf), size);
- ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
-
- ioctx.set_namespace("nspace");
- ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
- ASSERT_EQ(sizeof(buf2), size);
- ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
- ASSERT_EQ(-ENOENT, ioctx.stat("foo2", &size, &mtime));
-}
-
TEST_F(LibRadosStatEC, ClusterStat) {
struct rados_cluster_stat_t result;
ASSERT_EQ(0, rados_cluster_stat(cluster, &result));
}
-TEST_F(LibRadosStatECPP, ClusterStatPP) {
- cluster_stat_t cstat;
- ASSERT_EQ(0, cluster.cluster_stat(cstat));
-}
-
TEST_F(LibRadosStatEC, PoolStat) {
char buf[128];
char actual_pool_name[80];
memset(&stats, 0, sizeof(stats));
ASSERT_EQ(0, rados_ioctx_pool_stat(ioctx, &stats));
}
-
-TEST_F(LibRadosStatECPP, PoolStatPP) {
- std::string n = ioctx.get_pool_name();
- ASSERT_EQ(n, pool_name);
- char buf[128];
- memset(buf, 0xff, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- std::list<std::string> v;
- std::map<std::string,stats_map> stats;
- ASSERT_EQ(0, cluster.get_pool_stats(v, stats));
-}
--- /dev/null
+#include "gtest/gtest.h"
+
+#include "include/rados/librados.hpp"
+
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+
+using namespace librados;
+
+typedef RadosTestPP LibRadosStatPP;
+typedef RadosTestECPP LibRadosStatECPP;
+
+TEST_F(LibRadosStatPP, StatPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ uint64_t size;
+ time_t mtime;
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf), size);
+ ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
+}
+
+TEST_F(LibRadosStatPP, Stat2Mtime2PP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ librados::ObjectWriteOperation op;
+ struct timespec ts;
+ ts.tv_sec = 1457129052;
+ ts.tv_nsec = 123456789;
+ op.mtime2(&ts);
+ op.write(0, bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+
+ /* XXX time comparison asserts could spuriously fail */
+
+ uint64_t size;
+ time_t mtime;
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf), size);
+ ASSERT_EQ(mtime, ts.tv_sec);
+
+ struct timespec ts2;
+ ASSERT_EQ(0, ioctx.stat2("foo", &size, &ts2));
+ ASSERT_EQ(sizeof(buf), size);
+ ASSERT_EQ(ts2.tv_sec, ts.tv_sec);
+ ASSERT_EQ(ts2.tv_nsec, ts.tv_nsec);
+
+ ASSERT_EQ(-ENOENT, ioctx.stat2("nonexistent", &size, &ts2));
+}
+
+TEST_F(LibRadosStatPP, ClusterStatPP) {
+ cluster_stat_t cstat;
+ ASSERT_EQ(0, cluster.cluster_stat(cstat));
+}
+
+TEST_F(LibRadosStatPP, PoolStatPP) {
+ std::string n = ioctx.get_pool_name();
+ ASSERT_EQ(n, pool_name);
+ char buf[128];
+ memset(buf, 0xff, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ std::list<std::string> v;
+ std::map<std::string,stats_map> stats;
+ ASSERT_EQ(0, cluster.get_pool_stats(v, stats));
+}
+
+TEST_F(LibRadosStatECPP, StatPP) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ uint64_t size;
+ time_t mtime;
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf), size);
+ ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
+}
+
+TEST_F(LibRadosStatECPP, ClusterStatPP) {
+ cluster_stat_t cstat;
+ ASSERT_EQ(0, cluster.cluster_stat(cstat));
+}
+
+TEST_F(LibRadosStatECPP, PoolStatPP) {
+ std::string n = ioctx.get_pool_name();
+ ASSERT_EQ(n, pool_name);
+ char buf[128];
+ memset(buf, 0xff, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ std::list<std::string> v;
+ std::map<std::string,stats_map> stats;
+ ASSERT_EQ(0, cluster.get_pool_stats(v, stats));
+}
+
+TEST_F(LibRadosStatPP, StatPPNS) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo2", bl, sizeof(buf), 0));
+
+ char buf2[64];
+ memset(buf2, 0xbb, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ioctx.set_namespace("nspace");
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
+
+ uint64_t size;
+ time_t mtime;
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf), size);
+ ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
+
+ ioctx.set_namespace("nspace");
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf2), size);
+ ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
+ ASSERT_EQ(-ENOENT, ioctx.stat("foo2", &size, &mtime));
+}
+
+TEST_F(LibRadosStatECPP, StatPPNS) {
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl;
+ bl.append(buf, sizeof(buf));
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
+ ASSERT_EQ(0, ioctx.write("foo2", bl, sizeof(buf), 0));
+
+ char buf2[64];
+ memset(buf2, 0xbb, sizeof(buf2));
+ bufferlist bl2;
+ bl2.append(buf2, sizeof(buf2));
+ ioctx.set_namespace("nspace");
+ ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
+
+ uint64_t size;
+ time_t mtime;
+ ioctx.set_namespace("");
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf), size);
+ ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
+
+ ioctx.set_namespace("nspace");
+ ASSERT_EQ(0, ioctx.stat("foo", &size, &mtime));
+ ASSERT_EQ(sizeof(buf2), size);
+ ASSERT_EQ(-ENOENT, ioctx.stat("nonexistent", &size, &mtime));
+ ASSERT_EQ(-ENOENT, ioctx.stat("foo2", &size, &mtime));
+}
#include <iostream>
#include "gtest/gtest.h"
-using namespace librados;
-
-std::string get_temp_pool_name(const std::string &prefix)
-{
- char hostname[80];
- char out[160];
- memset(hostname, 0, sizeof(hostname));
- memset(out, 0, sizeof(out));
- gethostname(hostname, sizeof(hostname)-1);
- static int num = 1;
- snprintf(out, sizeof(out), "%s-%d-%d", hostname, getpid(), num);
- num++;
- return prefix + out;
-}
-
-
std::string create_one_pool(
const std::string &pool_name, rados_t *cluster, uint32_t pg_num)
{
return "";
}
-std::string create_one_pool_pp(const std::string &pool_name, Rados &cluster)
-{
- return create_one_pool_pp(pool_name, cluster, {});
-}
-std::string create_one_pool_pp(const std::string &pool_name, Rados &cluster,
- const std::map<std::string, std::string> &config)
-{
- std::string err = connect_cluster_pp(cluster, config);
- if (err.length())
- return err;
- int ret = cluster.pool_create(pool_name.c_str());
- if (ret) {
- cluster.shutdown();
- std::ostringstream oss;
- oss << "cluster.pool_create(" << pool_name << ") failed with error " << ret;
- return oss.str();
- }
-
- IoCtx ioctx;
- ret = cluster.ioctx_create(pool_name.c_str(), ioctx);
- if (ret < 0) {
- cluster.shutdown();
- std::ostringstream oss;
- oss << "cluster.ioctx_create(" << pool_name << ") failed with error "
- << ret;
- return oss.str();
- }
- ioctx.application_enable("rados", true);
- return "";
-}
-
-int destroy_ruleset_pp(Rados &cluster,
- const std::string &ruleset,
- std::ostream &oss)
-{
- bufferlist inbl;
- int ret = cluster.mon_command("{\"prefix\": \"osd crush rule rm\", \"name\":\"" +
- ruleset + "\"}", inbl, NULL, NULL);
- if (ret)
- oss << "mon_command: osd crush rule rm " + ruleset + " failed with error " << ret << std::endl;
- return ret;
-}
-
-int destroy_ec_profile_pp(Rados &cluster, const std::string& pool_name,
- std::ostream &oss)
-{
- bufferlist inbl;
- int ret = cluster.mon_command("{\"prefix\": \"osd erasure-code-profile rm\", \"name\": \"testprofile-" + pool_name + "\"}",
- inbl, NULL, NULL);
- if (ret)
- oss << "mon_command: osd erasure-code-profile rm testprofile-" << pool_name << " failed with error " << ret << std::endl;
- return ret;
-}
-
-int destroy_ec_profile_and_ruleset_pp(Rados &cluster,
- const std::string &ruleset,
- std::ostream &oss)
-{
- int ret;
- ret = destroy_ec_profile_pp(cluster, ruleset, oss);
- if (ret)
- return ret;
- return destroy_ruleset_pp(cluster, ruleset, oss);
-}
-
-std::string create_one_ec_pool_pp(const std::string &pool_name, Rados &cluster)
-{
- std::string err = connect_cluster_pp(cluster);
- if (err.length())
- return err;
-
- std::ostringstream oss;
- int ret = destroy_ec_profile_and_ruleset_pp(cluster, pool_name, oss);
- if (ret) {
- cluster.shutdown();
- return oss.str();
- }
-
- bufferlist inbl;
- ret = cluster.mon_command(
- "{\"prefix\": \"osd erasure-code-profile set\", \"name\": \"testprofile-" + pool_name + "\", \"profile\": [ \"k=2\", \"m=1\", \"crush-failure-domain=osd\"]}",
- inbl, NULL, NULL);
- if (ret) {
- cluster.shutdown();
- oss << "mon_command erasure-code-profile set name:testprofile-" << pool_name << " failed with error " << ret;
- return oss.str();
- }
-
- ret = cluster.mon_command(
- "{\"prefix\": \"osd pool create\", \"pool\": \"" + pool_name + "\", \"pool_type\":\"erasure\", \"pg_num\":8, \"pgp_num\":8, \"erasure_code_profile\":\"testprofile-" + pool_name + "\"}",
- inbl, NULL, NULL);
- if (ret) {
- bufferlist inbl;
- destroy_ec_profile_pp(cluster, pool_name, oss);
- cluster.shutdown();
- oss << "mon_command osd pool create pool:" << pool_name << " pool_type:erasure failed with error " << ret;
- return oss.str();
- }
-
- cluster.wait_for_latest_osdmap();
- return "";
-}
-
std::string connect_cluster(rados_t *cluster)
{
char *id = getenv("CEPH_CLIENT_ID");
return "";
}
-std::string connect_cluster_pp(librados::Rados &cluster)
-{
- return connect_cluster_pp(cluster, {});
-}
-
-std::string connect_cluster_pp(librados::Rados &cluster,
- const std::map<std::string, std::string> &config)
-{
- char *id = getenv("CEPH_CLIENT_ID");
- if (id) std::cerr << "Client id is: " << id << std::endl;
-
- int ret;
- ret = cluster.init(id);
- if (ret) {
- std::ostringstream oss;
- oss << "cluster.init failed with error " << ret;
- return oss.str();
- }
- ret = cluster.conf_read_file(NULL);
- if (ret) {
- cluster.shutdown();
- std::ostringstream oss;
- oss << "cluster.conf_read_file failed with error " << ret;
- return oss.str();
- }
- cluster.conf_parse_env(NULL);
-
- for (auto &setting : config) {
- ret = cluster.conf_set(setting.first.c_str(), setting.second.c_str());
- if (ret) {
- std::ostringstream oss;
- oss << "failed to set config value " << setting.first << " to '"
- << setting.second << "': " << strerror(-ret);
- return oss.str();
- }
- }
-
- ret = cluster.connect();
- if (ret) {
- cluster.shutdown();
- std::ostringstream oss;
- oss << "cluster.connect failed with error " << ret;
- return oss.str();
- }
- return "";
-}
-
int destroy_one_pool(const std::string &pool_name, rados_t *cluster)
{
int ret = rados_pool_delete(*cluster, pool_name.c_str());
rados_shutdown(*cluster);
return ret;
}
-
-int destroy_one_pool_pp(const std::string &pool_name, Rados &cluster)
-{
- int ret = cluster.pool_delete(pool_name.c_str());
- if (ret) {
- cluster.shutdown();
- return ret;
- }
- cluster.shutdown();
- return 0;
-}
-
-int destroy_one_ec_pool_pp(const std::string &pool_name, Rados &cluster)
-{
- int ret = cluster.pool_delete(pool_name.c_str());
- if (ret) {
- cluster.shutdown();
- return ret;
- }
-
- CephContext *cct = static_cast<CephContext*>(cluster.cct());
- if (!cct->_conf->mon_fake_pool_delete) { // hope this is in [global]
- std::ostringstream oss;
- ret = destroy_ec_profile_and_ruleset_pp(cluster, pool_name, oss);
- if (ret) {
- cluster.shutdown();
- return ret;
- }
- }
-
- cluster.wait_for_latest_osdmap();
- cluster.shutdown();
- return ret;
-}
-
-void assert_eq_sparse(bufferlist& expected,
- const std::map<uint64_t, uint64_t>& extents,
- bufferlist& actual) {
- auto i = expected.begin();
- auto p = actual.begin();
- uint64_t pos = 0;
- for (auto extent : extents) {
- const uint64_t start = extent.first;
- const uint64_t end = start + extent.second;
- for (; pos < end; ++i, ++pos) {
- ASSERT_FALSE(i.end());
- if (pos < start) {
- // check the hole
- ASSERT_EQ('\0', *i);
- } else {
- // then the extent
- ASSERT_EQ(*i, *p);
- ++p;
- }
- }
- }
- ASSERT_EQ(expected.length(), pos);
-}
#define CEPH_TEST_RADOS_API_TEST_H
#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
+#include "test/librados/test_shared.h"
#include <map>
#include <string>
#include <unistd.h>
-std::string get_temp_pool_name(const std::string &prefix = "test-rados-api-");
-
std::string create_one_pool(const std::string &pool_name, rados_t *cluster,
uint32_t pg_num=0);
std::string create_one_ec_pool(const std::string &pool_name, rados_t *cluster);
-std::string create_one_pool_pp(const std::string &pool_name,
- librados::Rados &cluster);
-std::string create_one_pool_pp(const std::string &pool_name,
- librados::Rados &cluster,
- const std::map<std::string, std::string> &config);
-std::string create_one_ec_pool_pp(const std::string &pool_name,
- librados::Rados &cluster);
std::string connect_cluster(rados_t *cluster);
-std::string connect_cluster_pp(librados::Rados &cluster);
-std::string connect_cluster_pp(librados::Rados &cluster,
- const std::map<std::string, std::string> &config);
int destroy_one_pool(const std::string &pool_name, rados_t *cluster);
int destroy_one_ec_pool(const std::string &pool_name, rados_t *cluster);
-int destroy_one_pool_pp(const std::string &pool_name, librados::Rados &cluster);
-int destroy_one_ec_pool_pp(const std::string &pool_name, librados::Rados &cluster);
-void assert_eq_sparse(bufferlist& expected,
- const std::map<uint64_t, uint64_t>& extents,
- bufferlist& actual);
-
-class TestAlarm
-{
-public:
- TestAlarm() {
- alarm(1200);
- }
- ~TestAlarm() {
- alarm(0);
- }
-};
#endif
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
+// vim: ts=8 sw=2 smarttab
+
+#include "test_cxx.h"
+
+#include "include/stringify.h"
+#include "common/ceph_context.h"
+#include "common/config.h"
+
+#include <errno.h>
+#include <sstream>
+#include <stdlib.h>
+#include <string>
+#include <time.h>
+#include <unistd.h>
+#include <iostream>
+#include "gtest/gtest.h"
+
+using namespace librados;
+
+std::string create_one_pool_pp(const std::string &pool_name, Rados &cluster)
+{
+ return create_one_pool_pp(pool_name, cluster, {});
+}
+std::string create_one_pool_pp(const std::string &pool_name, Rados &cluster,
+ const std::map<std::string, std::string> &config)
+{
+ std::string err = connect_cluster_pp(cluster, config);
+ if (err.length())
+ return err;
+ int ret = cluster.pool_create(pool_name.c_str());
+ if (ret) {
+ cluster.shutdown();
+ std::ostringstream oss;
+ oss << "cluster.pool_create(" << pool_name << ") failed with error " << ret;
+ return oss.str();
+ }
+
+ IoCtx ioctx;
+ ret = cluster.ioctx_create(pool_name.c_str(), ioctx);
+ if (ret < 0) {
+ cluster.shutdown();
+ std::ostringstream oss;
+ oss << "cluster.ioctx_create(" << pool_name << ") failed with error "
+ << ret;
+ return oss.str();
+ }
+ ioctx.application_enable("rados", true);
+ return "";
+}
+
+int destroy_ruleset_pp(Rados &cluster,
+ const std::string &ruleset,
+ std::ostream &oss)
+{
+ bufferlist inbl;
+ int ret = cluster.mon_command("{\"prefix\": \"osd crush rule rm\", \"name\":\"" +
+ ruleset + "\"}", inbl, NULL, NULL);
+ if (ret)
+ oss << "mon_command: osd crush rule rm " + ruleset + " failed with error " << ret << std::endl;
+ return ret;
+}
+
+int destroy_ec_profile_pp(Rados &cluster, const std::string& pool_name,
+ std::ostream &oss)
+{
+ bufferlist inbl;
+ int ret = cluster.mon_command("{\"prefix\": \"osd erasure-code-profile rm\", \"name\": \"testprofile-" + pool_name + "\"}",
+ inbl, NULL, NULL);
+ if (ret)
+ oss << "mon_command: osd erasure-code-profile rm testprofile-" << pool_name << " failed with error " << ret << std::endl;
+ return ret;
+}
+
+int destroy_ec_profile_and_ruleset_pp(Rados &cluster,
+ const std::string &ruleset,
+ std::ostream &oss)
+{
+ int ret;
+ ret = destroy_ec_profile_pp(cluster, ruleset, oss);
+ if (ret)
+ return ret;
+ return destroy_ruleset_pp(cluster, ruleset, oss);
+}
+
+std::string create_one_ec_pool_pp(const std::string &pool_name, Rados &cluster)
+{
+ std::string err = connect_cluster_pp(cluster);
+ if (err.length())
+ return err;
+
+ std::ostringstream oss;
+ int ret = destroy_ec_profile_and_ruleset_pp(cluster, pool_name, oss);
+ if (ret) {
+ cluster.shutdown();
+ return oss.str();
+ }
+
+ bufferlist inbl;
+ ret = cluster.mon_command(
+ "{\"prefix\": \"osd erasure-code-profile set\", \"name\": \"testprofile-" + pool_name + "\", \"profile\": [ \"k=2\", \"m=1\", \"crush-failure-domain=osd\"]}",
+ inbl, NULL, NULL);
+ if (ret) {
+ cluster.shutdown();
+ oss << "mon_command erasure-code-profile set name:testprofile-" << pool_name << " failed with error " << ret;
+ return oss.str();
+ }
+
+ ret = cluster.mon_command(
+ "{\"prefix\": \"osd pool create\", \"pool\": \"" + pool_name + "\", \"pool_type\":\"erasure\", \"pg_num\":8, \"pgp_num\":8, \"erasure_code_profile\":\"testprofile-" + pool_name + "\"}",
+ inbl, NULL, NULL);
+ if (ret) {
+ bufferlist inbl;
+ destroy_ec_profile_pp(cluster, pool_name, oss);
+ cluster.shutdown();
+ oss << "mon_command osd pool create pool:" << pool_name << " pool_type:erasure failed with error " << ret;
+ return oss.str();
+ }
+
+ cluster.wait_for_latest_osdmap();
+ return "";
+}
+
+std::string connect_cluster_pp(librados::Rados &cluster)
+{
+ return connect_cluster_pp(cluster, {});
+}
+
+std::string connect_cluster_pp(librados::Rados &cluster,
+ const std::map<std::string, std::string> &config)
+{
+ char *id = getenv("CEPH_CLIENT_ID");
+ if (id) std::cerr << "Client id is: " << id << std::endl;
+
+ int ret;
+ ret = cluster.init(id);
+ if (ret) {
+ std::ostringstream oss;
+ oss << "cluster.init failed with error " << ret;
+ return oss.str();
+ }
+ ret = cluster.conf_read_file(NULL);
+ if (ret) {
+ cluster.shutdown();
+ std::ostringstream oss;
+ oss << "cluster.conf_read_file failed with error " << ret;
+ return oss.str();
+ }
+ cluster.conf_parse_env(NULL);
+
+ for (auto &setting : config) {
+ ret = cluster.conf_set(setting.first.c_str(), setting.second.c_str());
+ if (ret) {
+ std::ostringstream oss;
+ oss << "failed to set config value " << setting.first << " to '"
+ << setting.second << "': " << strerror(-ret);
+ return oss.str();
+ }
+ }
+
+ ret = cluster.connect();
+ if (ret) {
+ cluster.shutdown();
+ std::ostringstream oss;
+ oss << "cluster.connect failed with error " << ret;
+ return oss.str();
+ }
+ return "";
+}
+
+int destroy_one_pool_pp(const std::string &pool_name, Rados &cluster)
+{
+ int ret = cluster.pool_delete(pool_name.c_str());
+ if (ret) {
+ cluster.shutdown();
+ return ret;
+ }
+ cluster.shutdown();
+ return 0;
+}
+
+int destroy_one_ec_pool_pp(const std::string &pool_name, Rados &cluster)
+{
+ int ret = cluster.pool_delete(pool_name.c_str());
+ if (ret) {
+ cluster.shutdown();
+ return ret;
+ }
+
+ CephContext *cct = static_cast<CephContext*>(cluster.cct());
+ if (!cct->_conf->mon_fake_pool_delete) { // hope this is in [global]
+ std::ostringstream oss;
+ ret = destroy_ec_profile_and_ruleset_pp(cluster, pool_name, oss);
+ if (ret) {
+ cluster.shutdown();
+ return ret;
+ }
+ }
+
+ cluster.wait_for_latest_osdmap();
+ cluster.shutdown();
+ return ret;
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#pragma once
+
+#include "include/rados/librados.hpp"
+#include "test/librados/test_shared.h"
+
+std::string create_one_pool_pp(const std::string &pool_name,
+ librados::Rados &cluster);
+std::string create_one_pool_pp(const std::string &pool_name,
+ librados::Rados &cluster,
+ const std::map<std::string, std::string> &config);
+std::string create_one_ec_pool_pp(const std::string &pool_name,
+ librados::Rados &cluster);
+std::string connect_cluster_pp(librados::Rados &cluster);
+std::string connect_cluster_pp(librados::Rados &cluster,
+ const std::map<std::string, std::string> &config);
+int destroy_one_pool_pp(const std::string &pool_name, librados::Rados &cluster);
+int destroy_one_ec_pool_pp(const std::string &pool_name, librados::Rados &cluster);
--- /dev/null
+#include "test_shared.h"
+
+#include <cstring>
+#include "gtest/gtest.h"
+#include "include/buffer.h"
+
+using namespace ceph;
+
+std::string get_temp_pool_name(const std::string &prefix)
+{
+ char hostname[80];
+ char out[160];
+ memset(hostname, 0, sizeof(hostname));
+ memset(out, 0, sizeof(out));
+ gethostname(hostname, sizeof(hostname)-1);
+ static int num = 1;
+ snprintf(out, sizeof(out), "%s-%d-%d", hostname, getpid(), num);
+ num++;
+ return prefix + out;
+}
+
+void assert_eq_sparse(bufferlist& expected,
+ const std::map<uint64_t, uint64_t>& extents,
+ bufferlist& actual) {
+ auto i = expected.begin();
+ auto p = actual.begin();
+ uint64_t pos = 0;
+ for (auto extent : extents) {
+ const uint64_t start = extent.first;
+ const uint64_t end = start + extent.second;
+ for (; pos < end; ++i, ++pos) {
+ ASSERT_FALSE(i.end());
+ if (pos < start) {
+ // check the hole
+ ASSERT_EQ('\0', *i);
+ } else {
+ // then the extent
+ ASSERT_EQ(*i, *p);
+ ++p;
+ }
+ }
+ }
+ ASSERT_EQ(expected.length(), pos);
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include <unistd.h>
+#include <chrono>
+#include <map>
+#include <string>
+#include <thread>
+
+#include "include/buffer_fwd.h"
+
+// helpers shared by librados and librados-cxx tests
+std::string get_temp_pool_name(const std::string &prefix = "test-rados-api-");
+void assert_eq_sparse(ceph::bufferlist& expected,
+ const std::map<uint64_t, uint64_t>& extents,
+ ceph::bufferlist& actual);
+class TestAlarm
+{
+public:
+ TestAlarm() {
+ alarm(1200);
+ }
+ ~TestAlarm() {
+ alarm(0);
+ }
+};
+
+template<class Rep, class Period, typename Func, typename... Args,
+ typename Return = std::result_of_t<Func&&(Args&&...)>>
+Return wait_until(const std::chrono::duration<Rep, Period>& rel_time,
+ const std::chrono::duration<Rep, Period>& step,
+ const Return& expected,
+ Func&& func, Args&&... args)
+{
+ std::this_thread::sleep_for(rel_time - step);
+ for (auto& s : {step, step}) {
+ if (!s.count()) {
+ break;
+ }
+ auto ret = func(std::forward<Args>(args)...);
+ if (ret == expected) {
+ return ret;
+ }
+ std::this_thread::sleep_for(s);
+ }
+ return func(std::forward<Args>(args)...);
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "testcase_cxx.h"
+
+#include <errno.h>
+#include "test_cxx.h"
+#include "test_shared.h"
+#include "include/scope_guard.h"
+
+using namespace librados;
+
+namespace {
+
+void init_rand() {
+ static bool seeded = false;
+ if (!seeded) {
+ seeded = true;
+ int seed = getpid();
+ std::cout << "seed " << seed << std::endl;
+ srand(seed);
+ }
+}
+
+} // anonymous namespace
+
+std::string RadosTestPPNS::pool_name;
+Rados RadosTestPPNS::s_cluster;
+
+void RadosTestPPNS::SetUpTestCase()
+{
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestPPNS::TearDownTestCase()
+{
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestPPNS::SetUp()
+{
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+ bool requires;
+ ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
+ ASSERT_FALSE(requires);
+}
+
+void RadosTestPPNS::TearDown()
+{
+ if (cleanup)
+ cleanup_all_objects(ioctx);
+ ioctx.close();
+}
+
+void RadosTestPPNS::cleanup_all_objects(librados::IoCtx ioctx)
+{
+ // remove all objects to avoid polluting other tests
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ ioctx.set_namespace(all_nspaces);
+ for (NObjectIterator it = ioctx.nobjects_begin();
+ it != ioctx.nobjects_end(); ++it) {
+ ioctx.locator_set_key(it->get_locator());
+ ioctx.set_namespace(it->get_nspace());
+ ASSERT_EQ(0, ioctx.remove(it->get_oid()));
+ }
+}
+
+std::string RadosTestParamPPNS::pool_name;
+std::string RadosTestParamPPNS::cache_pool_name;
+Rados RadosTestParamPPNS::s_cluster;
+
+void RadosTestParamPPNS::SetUpTestCase()
+{
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestParamPPNS::TearDownTestCase()
+{
+ if (cache_pool_name.length()) {
+ // tear down tiers
+ bufferlist inbl;
+ ASSERT_EQ(0, s_cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, s_cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, s_cluster.mon_command(
+ "{\"prefix\": \"osd pool delete\", \"pool\": \"" + cache_pool_name +
+ "\", \"pool2\": \"" + cache_pool_name + "\", \"sure\": \"--yes-i-really-really-mean-it\"}",
+ inbl, NULL, NULL));
+ cache_pool_name = "";
+ }
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestParamPPNS::SetUp()
+{
+ if (strcmp(GetParam(), "cache") == 0 && cache_pool_name.empty()) {
+ cache_pool_name = get_temp_pool_name();
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd pool create\", \"pool\": \"" + cache_pool_name +
+ "\", \"pg_num\": 4}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+ cluster.wait_for_latest_osdmap();
+ }
+
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+ bool requires;
+ ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
+ ASSERT_FALSE(requires);
+}
+
+void RadosTestParamPPNS::TearDown()
+{
+ if (cleanup)
+ cleanup_all_objects(ioctx);
+ ioctx.close();
+}
+
+void RadosTestParamPPNS::cleanup_all_objects(librados::IoCtx ioctx)
+{
+ // remove all objects to avoid polluting other tests
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ ioctx.set_namespace(all_nspaces);
+ for (NObjectIterator it = ioctx.nobjects_begin();
+ it != ioctx.nobjects_end(); ++it) {
+ ioctx.locator_set_key(it->get_locator());
+ ioctx.set_namespace(it->get_nspace());
+ ASSERT_EQ(0, ioctx.remove(it->get_oid()));
+ }
+}
+
+std::string RadosTestECPPNS::pool_name;
+Rados RadosTestECPPNS::s_cluster;
+
+void RadosTestECPPNS::SetUpTestCase()
+{
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestECPPNS::TearDownTestCase()
+{
+ ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestECPPNS::SetUp()
+{
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+ bool requires;
+ ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
+ ASSERT_TRUE(requires);
+ ASSERT_EQ(0, ioctx.pool_required_alignment2(&alignment));
+ ASSERT_NE(0U, alignment);
+}
+
+void RadosTestECPPNS::TearDown()
+{
+ if (cleanup)
+ cleanup_all_objects(ioctx);
+ ioctx.close();
+}
+
+std::string RadosTestPP::pool_name;
+Rados RadosTestPP::s_cluster;
+
+void RadosTestPP::SetUpTestCase()
+{
+ init_rand();
+
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestPP::TearDownTestCase()
+{
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestPP::SetUp()
+{
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+ nspace = get_temp_pool_name();
+ ioctx.set_namespace(nspace);
+ bool requires;
+ ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
+ ASSERT_FALSE(requires);
+}
+
+void RadosTestPP::TearDown()
+{
+ if (cleanup) {
+ cleanup_default_namespace(ioctx);
+ cleanup_namespace(ioctx, nspace);
+ }
+ ioctx.close();
+}
+
+void RadosTestPP::cleanup_default_namespace(librados::IoCtx ioctx)
+{
+ // remove all objects from the default namespace to avoid polluting
+ // other tests
+ cleanup_namespace(ioctx, "");
+}
+
+void RadosTestPP::cleanup_namespace(librados::IoCtx ioctx, std::string ns)
+{
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ ioctx.set_namespace(ns);
+ int tries = 600;
+ while (--tries) {
+ int got_enoent = 0;
+ for (NObjectIterator it = ioctx.nobjects_begin();
+ it != ioctx.nobjects_end(); ++it) {
+ ioctx.locator_set_key(it->get_locator());
+ ObjectWriteOperation op;
+ op.remove();
+ librados::AioCompletion *completion = s_cluster.aio_create_completion();
+ auto sg = make_scope_guard([&] { completion->release(); });
+ ASSERT_EQ(0, ioctx.aio_operate(it->get_oid(), completion, &op,
+ librados::OPERATION_IGNORE_CACHE));
+ completion->wait_for_safe();
+ if (completion->get_return_value() == -ENOENT) {
+ ++got_enoent;
+ std::cout << " got ENOENT removing " << it->get_oid() << std::endl;
+ } else {
+ ASSERT_EQ(0, completion->get_return_value());
+ }
+ }
+ if (!got_enoent) {
+ break;
+ }
+ std::cout << " got ENOENT on " << got_enoent
+ << " objects, waiting a bit for snap"
+ << " trimming before retrying " << tries << " more times..."
+ << std::endl;
+ sleep(1);
+ }
+ if (tries == 0) {
+ std::cout << "failed to clean up" << std::endl;
+ ASSERT_TRUE(false);
+ }
+}
+
+std::string RadosTestParamPP::pool_name;
+std::string RadosTestParamPP::cache_pool_name;
+Rados RadosTestParamPP::s_cluster;
+
+void RadosTestParamPP::SetUpTestCase()
+{
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestParamPP::TearDownTestCase()
+{
+ if (cache_pool_name.length()) {
+ // tear down tiers
+ bufferlist inbl;
+ ASSERT_EQ(0, s_cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, s_cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, s_cluster.mon_command(
+ "{\"prefix\": \"osd pool delete\", \"pool\": \"" + cache_pool_name +
+ "\", \"pool2\": \"" + cache_pool_name + "\", \"sure\": \"--yes-i-really-really-mean-it\"}",
+ inbl, NULL, NULL));
+ cache_pool_name = "";
+ }
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestParamPP::SetUp()
+{
+ if (strcmp(GetParam(), "cache") == 0 && cache_pool_name.empty()) {
+ cache_pool_name = get_temp_pool_name();
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd pool create\", \"pool\": \"" + cache_pool_name +
+ "\", \"pg_num\": 4}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+ cluster.wait_for_latest_osdmap();
+ }
+
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+ nspace = get_temp_pool_name();
+ ioctx.set_namespace(nspace);
+ bool requires;
+ ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
+ ASSERT_FALSE(requires);
+}
+
+void RadosTestParamPP::TearDown()
+{
+ if (cleanup) {
+ cleanup_default_namespace(ioctx);
+ cleanup_namespace(ioctx, nspace);
+ }
+ ioctx.close();
+}
+
+void RadosTestParamPP::cleanup_default_namespace(librados::IoCtx ioctx)
+{
+ // remove all objects from the default namespace to avoid polluting
+ // other tests
+ cleanup_namespace(ioctx, "");
+}
+
+void RadosTestParamPP::cleanup_namespace(librados::IoCtx ioctx, std::string ns)
+{
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ ioctx.set_namespace(ns);
+ for (NObjectIterator it = ioctx.nobjects_begin();
+ it != ioctx.nobjects_end(); ++it) {
+ ioctx.locator_set_key(it->get_locator());
+ ASSERT_EQ(0, ioctx.remove(it->get_oid()));
+ }
+}
+
+std::string RadosTestECPP::pool_name;
+Rados RadosTestECPP::s_cluster;
+
+void RadosTestECPP::SetUpTestCase()
+{
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestECPP::TearDownTestCase()
+{
+ ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
+}
+
+void RadosTestECPP::SetUp()
+{
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+ nspace = get_temp_pool_name();
+ ioctx.set_namespace(nspace);
+ bool requires;
+ ASSERT_EQ(0, ioctx.pool_requires_alignment2(&requires));
+ ASSERT_TRUE(requires);
+ ASSERT_EQ(0, ioctx.pool_required_alignment2(&alignment));
+ ASSERT_NE(0U, alignment);
+}
+
+void RadosTestECPP::TearDown()
+{
+ if (cleanup) {
+ cleanup_default_namespace(ioctx);
+ cleanup_namespace(ioctx, nspace);
+ }
+ ioctx.close();
+}
+
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include "gtest/gtest.h"
+#include "include/rados/librados.hpp"
+
+class RadosTestPPNS : public ::testing::Test {
+public:
+ RadosTestPPNS(bool c=false) : cluster(s_cluster), cleanup(c) {}
+ ~RadosTestPPNS() override {}
+protected:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+ static void cleanup_all_objects(librados::IoCtx ioctx);
+ static librados::Rados s_cluster;
+ static std::string pool_name;
+
+ void SetUp() override;
+ void TearDown() override;
+ librados::Rados &cluster;
+ librados::IoCtx ioctx;
+ bool cleanup;
+};
+
+struct RadosTestPPNSCleanup : public RadosTestPPNS {
+ RadosTestPPNSCleanup() : RadosTestPPNS(true) {}
+};
+
+class RadosTestParamPPNS : public ::testing::TestWithParam<const char*> {
+public:
+ RadosTestParamPPNS(bool c=false) : cluster(s_cluster), cleanup(c) {}
+ ~RadosTestParamPPNS() override {}
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+protected:
+ static void cleanup_all_objects(librados::IoCtx ioctx);
+ static librados::Rados s_cluster;
+ static std::string pool_name;
+ static std::string cache_pool_name;
+
+ void SetUp() override;
+ void TearDown() override;
+ librados::Rados &cluster;
+ librados::IoCtx ioctx;
+ bool cleanup;
+};
+
+class RadosTestECPPNS : public RadosTestPPNS {
+public:
+ RadosTestECPPNS(bool c=false) : cluster(s_cluster), cleanup(c) {}
+ ~RadosTestECPPNS() override {}
+protected:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+ static librados::Rados s_cluster;
+ static std::string pool_name;
+
+ void SetUp() override;
+ void TearDown() override;
+ librados::Rados &cluster;
+ librados::IoCtx ioctx;
+ uint64_t alignment = 0;
+ bool cleanup;
+};
+
+struct RadosTestECPPNSCleanup : public RadosTestECPPNS {
+ RadosTestECPPNSCleanup() : RadosTestECPPNS(true) {}
+};
+
+class RadosTestPP : public ::testing::Test {
+public:
+ RadosTestPP(bool c=false) : cluster(s_cluster), cleanup(c) {}
+ ~RadosTestPP() override {}
+protected:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+ static void cleanup_default_namespace(librados::IoCtx ioctx);
+ static void cleanup_namespace(librados::IoCtx ioctx, std::string ns);
+ static librados::Rados s_cluster;
+ static std::string pool_name;
+
+ void SetUp() override;
+ void TearDown() override;
+ librados::Rados &cluster;
+ librados::IoCtx ioctx;
+ bool cleanup;
+ std::string nspace;
+};
+
+class RadosTestParamPP : public ::testing::TestWithParam<const char*> {
+public:
+ RadosTestParamPP(bool c=false) : cluster(s_cluster), cleanup(c) {}
+ ~RadosTestParamPP() override {}
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+protected:
+ static void cleanup_default_namespace(librados::IoCtx ioctx);
+ static void cleanup_namespace(librados::IoCtx ioctx, std::string ns);
+ static librados::Rados s_cluster;
+ static std::string pool_name;
+ static std::string cache_pool_name;
+
+ void SetUp() override;
+ void TearDown() override;
+ librados::Rados &cluster;
+ librados::IoCtx ioctx;
+ bool cleanup;
+ std::string nspace;
+};
+
+class RadosTestECPP : public RadosTestPP {
+public:
+ RadosTestECPP(bool c=false) : cluster(s_cluster), cleanup(c) {}
+ ~RadosTestECPP() override {}
+protected:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+ static librados::Rados s_cluster;
+ static std::string pool_name;
+
+ void SetUp() override;
+ void TearDown() override;
+ librados::Rados &cluster;
+ librados::IoCtx ioctx;
+ bool cleanup;
+ std::string nspace;
+ uint64_t alignment = 0;
+};
+++ /dev/null
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-#include "gtest/gtest.h"
-
-#include "mds/mdstypes.h"
-#include "include/buffer.h"
-#include "include/rbd_types.h"
-#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
-#include "include/stringify.h"
-#include "include/types.h"
-#include "global/global_context.h"
-#include "common/Cond.h"
-#include "test/librados/test.h"
-#include "test/librados/TestCase.h"
-#include "json_spirit/json_spirit.h"
-#include "cls/cas/cls_cas_ops.h"
-
-#include "osd/HitSet.h"
-
-#include <errno.h>
-#include <map>
-#include <sstream>
-#include <string>
-
-using namespace librados;
-using std::map;
-using std::ostringstream;
-using std::string;
-
-typedef RadosTestPP LibRadosTierPP;
-typedef RadosTestECPP LibRadosTierECPP;
-
-void flush_evict_all(librados::Rados& cluster, librados::IoCtx& cache_ioctx)
-{
- bufferlist inbl;
- cache_ioctx.set_namespace(all_nspaces);
- for (NObjectIterator it = cache_ioctx.nobjects_begin();
- it != cache_ioctx.nobjects_end(); ++it) {
- cache_ioctx.locator_set_key(it->get_locator());
- cache_ioctx.set_namespace(it->get_nspace());
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- cache_ioctx.aio_operate(
- it->get_oid(), completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL);
- completion->wait_for_safe();
- completion->get_return_value();
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- cache_ioctx.aio_operate(
- it->get_oid(), completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL);
- completion->wait_for_safe();
- completion->get_return_value();
- completion->release();
- }
- }
-}
-
-class LibRadosTwoPoolsPP : public RadosTestPP
-{
-public:
- LibRadosTwoPoolsPP() {};
- ~LibRadosTwoPoolsPP() override {};
-protected:
- static void SetUpTestCase() {
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
- }
- static void TearDownTestCase() {
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
- }
- static std::string cache_pool_name;
-
- void SetUp() override {
- cache_pool_name = get_temp_pool_name();
- ASSERT_EQ(0, s_cluster.pool_create(cache_pool_name.c_str()));
- RadosTestPP::SetUp();
-
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- cache_ioctx.application_enable("rados", true);
- cache_ioctx.set_namespace(nspace);
- }
- void TearDown() override {
- // flush + evict cache
- flush_evict_all(cluster, cache_ioctx);
-
- bufferlist inbl;
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-
- RadosTestPP::TearDown();
-
- cleanup_default_namespace(cache_ioctx);
- cleanup_namespace(cache_ioctx, nspace);
-
- cache_ioctx.close();
- ASSERT_EQ(0, s_cluster.pool_delete(cache_pool_name.c_str()));
- }
- librados::IoCtx cache_ioctx;
-};
-
-class Completions
-{
-public:
- Completions() = default;
- librados::AioCompletion* getCompletion() {
- librados::AioCompletion* comp = librados::Rados::aio_create_completion();
- m_completions.push_back(comp);
- return comp;
- }
-
- ~Completions() {
- for (auto& comp : m_completions) {
- comp->release();
- }
- }
-
-private:
- vector<librados::AioCompletion *> m_completions;
-};
-
-Completions completions;
-
-std::string LibRadosTwoPoolsPP::cache_pool_name;
-
-TEST_F(LibRadosTierPP, Dirty) {
- {
- ObjectWriteOperation op;
- op.undirty();
- ASSERT_EQ(0, ioctx.operate("foo", &op)); // still get 0 if it dne
- }
- {
- ObjectWriteOperation op;
- op.create(true);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- }
- {
- ObjectWriteOperation op;
- op.undirty();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- ObjectWriteOperation op;
- op.undirty();
- ASSERT_EQ(0, ioctx.operate("foo", &op)); // still 0 if already clean
- }
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
- {
- ObjectWriteOperation op;
- op.truncate(0); // still a write even tho it is a no-op
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, Overlay) {
- // create objects
- {
- bufferlist bl;
- bl.append("base");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("cache");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // by default, the overlay sends us to cache pool
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // unless we say otherwise
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(0, 1, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- ASSERT_EQ('b', bl[0]);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, Promote) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- }
-
- // read, trigger a whiteout
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, PromoteSnap) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote on the head
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- ioctx.snap_set_read(my_snaps[0]);
-
- // read foo snap
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // read bar snap
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // read baz snap
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- ioctx.snap_set_read(librados::SNAP_HEAD);
-
- // read foo
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // read bar
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // read baz
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("baz", bl, 1, 0));
- }
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTwoPoolsPP, PromoteSnapScrub) {
- int num = 100;
-
- // create objects
- for (int i=0; i<num; ++i) {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate(string("foo") + stringify(i), &op));
- }
-
- vector<uint64_t> my_snaps;
- for (int snap=0; snap<4; ++snap) {
- // create a snapshot, clone
- vector<uint64_t> ns(1);
- ns.insert(ns.end(), my_snaps.begin(), my_snaps.end());
- my_snaps.swap(ns);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- cout << "my_snaps " << my_snaps << std::endl;
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- for (int i=0; i<num; ++i) {
- bufferlist bl;
- bl.append(string("ciao! snap") + stringify(snap));
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate(string("foo") + stringify(i), &op));
- }
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote on _some_ heads to make sure we handle cases
- // where snaps are present and where they are not.
- cout << "promoting some heads" << std::endl;
- for (int i=0; i<num; ++i) {
- if (i % 5 == 0 || i > num - 3) {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read(string("foo") + stringify(i), bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- }
-
- for (unsigned snap = 0; snap < my_snaps.size(); ++snap) {
- cout << "promoting from clones for snap " << my_snaps[snap] << std::endl;
- ioctx.snap_set_read(my_snaps[snap]);
-
- // read some snaps, semi-randomly
- for (int i=0; i<50; ++i) {
- bufferlist bl;
- string o = string("foo") + stringify((snap * i * 137) % 80);
- //cout << o << std::endl;
- ASSERT_EQ(1, ioctx.read(o, bl, 1, 0));
- }
- }
-
- // ok, stop and scrub this pool (to make sure scrub can handle
- // missing clones in the cache tier).
- {
- IoCtx cache_ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- for (int i=0; i<10; ++i) {
- do {
- ostringstream ss;
- ss << "{\"prefix\": \"pg scrub\", \"pgid\": \""
- << cache_ioctx.get_id() << "." << i
- << "\"}";
- int r = cluster.mon_command(ss.str(), inbl, NULL, NULL);
- if (r == -ENOENT || // in case mgr osdmap is stale
- r == -EAGAIN) {
- sleep(5);
- continue;
- }
- } while (false);
- }
-
- // give it a few seconds to go. this is sloppy but is usually enough time
- cout << "waiting for scrubs..." << std::endl;
- sleep(30);
- cout << "done waiting" << std::endl;
- }
-
- ioctx.snap_set_read(librados::SNAP_HEAD);
-
- //cleanup
- for (unsigned snap = 0; snap < my_snaps.size(); ++snap) {
- ioctx.selfmanaged_snap_remove(my_snaps[snap]);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, PromoteSnapTrimRace) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // delete the snap
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps[0]));
-
- ioctx.snap_set_read(my_snaps[0]);
-
- // read foo snap
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("foo", bl, 1, 0));
- }
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTwoPoolsPP, Whiteout) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create some whiteouts, verify they behave
- {
- ObjectWriteOperation op;
- op.assert_exists();
- op.remove();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- {
- ObjectWriteOperation op;
- op.assert_exists();
- op.remove();
- ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.assert_exists();
- op.remove();
- ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
- }
-
- // verify the whiteouts are there in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // delete a whiteout and verify it goes away
- ASSERT_EQ(-ENOENT, ioctx.remove("foo"));
- {
- ObjectWriteOperation op;
- op.remove();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
-
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // recreate an object and verify we can read it
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, WhiteoutDeleteCreate) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create an object
- {
- bufferlist bl;
- bl.append("foo");
- ASSERT_EQ(0, ioctx.write_full("foo", bl));
- }
-
- // do delete + create operation
- {
- ObjectWriteOperation op;
- op.remove();
- bufferlist bl;
- bl.append("bar");
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify it still "exists" (w/ new content)
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('b', bl[0]);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, Evict) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- }
-
- // read, trigger a whiteout, and a dirty object
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(0, ioctx.write("bar", bl, bl.length(), 0));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // pin
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // evict the pinned object with -EPERM
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE,
- NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EPERM, completion->get_return_value());
- completion->release();
- }
-
- // unpin
- {
- ObjectWriteOperation op;
- op.cache_unpin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify clean
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE,
- NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, EvictSnap) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote on the head
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // evict bam
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "bam", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "bam", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-ENOENT, completion->get_return_value());
- completion->release();
- }
-
- // read foo snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // evict foo snap
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // snap is gone...
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-ENOENT, completion->get_return_value());
- completion->release();
- }
- // head is still there...
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // promote head + snap of bar
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // evict bar head (fail)
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
-
- // evict bar snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // ...and then head
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-// this test case reproduces http://tracker.ceph.com/issues/8629
-TEST_F(LibRadosTwoPoolsPP, EvictSnap2) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote on the head
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify the snapdir is not present in the cache pool
- {
- ObjectReadOperation op;
- librados::snap_set_t snapset;
- op.list_snaps(&snapset, NULL);
- ioctx.snap_set_read(librados::SNAP_DIR);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-ENOENT, completion->get_return_value());
- completion->release();
- }
-}
-
-//This test case reproduces http://tracker.ceph.com/issues/17445
-TEST_F(LibRadosTwoPoolsPP, ListSnap){
- // Create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // Create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // Configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // Wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // Read, trigger a promote on the head
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // Read foo snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // Evict foo snap
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // Snap is gone...
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-ENOENT, completion->get_return_value());
- completion->release();
- }
-
- // Do list-snaps
- ioctx.snap_set_read(CEPH_SNAPDIR);
- {
- snap_set_t snap_set;
- int snap_ret;
- ObjectReadOperation op;
- op.list_snaps(&snap_set, &snap_ret);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- 0, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, snap_ret);
- ASSERT_LT(0u, snap_set.clones.size());
- for (vector<librados::clone_info_t>::const_iterator r = snap_set.clones.begin();
- r != snap_set.clones.end();
- ++r) {
- if (r->cloneid != librados::SNAP_HEAD) {
- ASSERT_LT(0u, r->snaps.size());
- }
- }
- }
-
- // Cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTwoPoolsPP, TryFlush) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // verify dirty
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // pin
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush the pinned object with -EPERM
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EPERM, completion->get_return_value());
- completion->release();
- }
-
- // unpin
- {
- ObjectWriteOperation op;
- op.cache_unpin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify clean
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // verify in base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it != ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // evict it
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, Flush) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- uint64_t user_version = 0;
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // verify dirty
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- user_version = cache_ioctx.get_last_version();
- }
-
- // pin
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush the pinned object with -EPERM
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EPERM, completion->get_return_value());
- completion->release();
- }
-
- // unpin
- {
- ObjectWriteOperation op;
- op.cache_unpin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify clean
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // verify in base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it != ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // evict it
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // read it again and verify the version is consistent
- {
- bufferlist bl;
- ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ(user_version, cache_ioctx.get_last_version());
- }
-
- // erase it
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush whiteout
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
- // or base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, FlushSnap) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create object
- {
- bufferlist bl;
- bl.append("a");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("b");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // and another
- my_snaps.resize(2);
- my_snaps[1] = my_snaps[0];
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("c");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // flush on head (should fail)
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
- // flush on recent snap (should fail)
- ioctx.snap_set_read(my_snaps[0]);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
- // flush on oldest snap
- ioctx.snap_set_read(my_snaps[1]);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // flush on next oldest snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // flush on head
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify i can read the snaps from the cache pool
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('b', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[1]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('a', bl[0]);
- }
-
- // remove overlay
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // verify i can read the snaps from the base pool
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('b', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[1]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('a', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTierPP, FlushWriteRaces) {
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- std::string cache_pool_name = pool_name + "-cache";
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str()));
- IoCtx cache_ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- cache_ioctx.application_enable("rados", true);
- IoCtx ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- bufferlist bl;
- bl.append("hi there");
- {
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush + write
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- ObjectWriteOperation op2;
- op2.write_full(bl);
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion2, &op2, 0));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-
- int tries = 1000;
- do {
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // try-flush + write
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- ObjectWriteOperation op2;
- op2.write_full(bl);
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion2, &op2, 0));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- int r = completion->get_return_value();
- ASSERT_TRUE(r == -EBUSY || r == 0);
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- if (r == -EBUSY)
- break;
- cout << "didn't get EBUSY, trying again" << std::endl;
- }
- ASSERT_TRUE(--tries);
- } while (true);
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-
- ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str()));
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
-}
-
-TEST_F(LibRadosTwoPoolsPP, FlushTryFlushRaces) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush + flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- ObjectReadOperation op2;
- op2.cache_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush + try-flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- ObjectReadOperation op2;
- op2.cache_try_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-
- // create/dirty object
- int tries = 1000;
- do {
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // try-flush + flush
- // (flush will not piggyback on try-flush)
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- ObjectReadOperation op2;
- op2.cache_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- int r = completion->get_return_value();
- ASSERT_TRUE(r == -EBUSY || r == 0);
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- if (r == -EBUSY)
- break;
- cout << "didn't get EBUSY, trying again" << std::endl;
- }
- ASSERT_TRUE(--tries);
- } while (true);
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // try-flush + try-flush
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- ObjectReadOperation op2;
- op2.cache_try_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-}
-
-
-IoCtx *read_ioctx = 0;
-Mutex test_lock("FlushReadRaces::lock");
-Cond cond;
-int max_reads = 100;
-int num_reads = 0; // in progress
-
-void flush_read_race_cb(completion_t cb, void *arg);
-
-void start_flush_read()
-{
- //cout << " starting read" << std::endl;
- ObjectReadOperation op;
- op.stat(NULL, NULL, NULL);
- librados::AioCompletion *completion = completions.getCompletion();
- completion->set_complete_callback(0, flush_read_race_cb);
- read_ioctx->aio_operate("foo", completion, &op, NULL);
-}
-
-void flush_read_race_cb(completion_t cb, void *arg)
-{
- //cout << " finished read" << std::endl;
- test_lock.Lock();
- if (num_reads > max_reads) {
- num_reads--;
- cond.Signal();
- } else {
- start_flush_read();
- }
- test_lock.Unlock();
-}
-
-TEST_F(LibRadosTwoPoolsPP, TryFlushReadRace) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- bufferptr bp(4000000); // make it big!
- bp.zero();
- bl.append(bp);
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // start a continuous stream of reads
- read_ioctx = &ioctx;
- test_lock.Lock();
- for (int i = 0; i < max_reads; ++i) {
- start_flush_read();
- num_reads++;
- }
- test_lock.Unlock();
-
- // try-flush
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
-
- // stop reads
- test_lock.Lock();
- max_reads = 0;
- while (num_reads > 0)
- cond.Wait(test_lock);
- test_lock.Unlock();
-}
-
-TEST_F(LibRadosTierPP, HitSetNone) {
- {
- list< pair<time_t,time_t> > ls;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, ioctx.hit_set_list(123, c, &ls));
- c->wait_for_complete();
- ASSERT_EQ(0, c->get_return_value());
- ASSERT_TRUE(ls.empty());
- c->release();
- }
- {
- bufferlist bl;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, ioctx.hit_set_get(123, c, 12345, &bl));
- c->wait_for_complete();
- ASSERT_EQ(-ENOENT, c->get_return_value());
- c->release();
- }
-}
-
-string set_pool_str(string pool, string var, string val)
-{
- return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
- + string("\",\"var\": \"") + var + string("\",\"val\": \"")
- + val + string("\"}");
-}
-
-string set_pool_str(string pool, string var, int val)
-{
- return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
- + string("\",\"var\": \"") + var + string("\",\"val\": \"")
- + stringify(val) + string("\"}");
-}
-
-TEST_F(LibRadosTwoPoolsPP, HitSetRead) {
- // make it a tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type",
- "explicit_object"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- cache_ioctx.set_namespace("");
-
- // keep reading until we see our object appear in the HitSet
- utime_t start = ceph_clock_now();
- utime_t hard_stop = start + utime_t(600, 0);
-
- while (true) {
- utime_t now = ceph_clock_now();
- ASSERT_TRUE(now < hard_stop);
-
- string name = "foo";
- uint32_t hash;
- ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
- hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash,
- cluster.pool_lookup(cache_pool_name.c_str()), "");
-
- bufferlist bl;
- ASSERT_EQ(-ENOENT, cache_ioctx.read("foo", bl, 1, 0));
-
- bufferlist hbl;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.hit_set_get(hash, c, now.sec(), &hbl));
- c->wait_for_complete();
- c->release();
-
- if (hbl.length()) {
- auto p = hbl.cbegin();
- HitSet hs;
- decode(hs, p);
- if (hs.contains(oid)) {
- cout << "ok, hit_set contains " << oid << std::endl;
- break;
- }
- cout << "hmm, not in HitSet yet" << std::endl;
- } else {
- cout << "hmm, no HitSet yet" << std::endl;
- }
-
- sleep(1);
- }
-}
-
-static int _get_pg_num(Rados& cluster, string pool_name)
-{
- bufferlist inbl;
- string cmd = string("{\"prefix\": \"osd pool get\",\"pool\":\"")
- + pool_name
- + string("\",\"var\": \"pg_num\",\"format\": \"json\"}");
- bufferlist outbl;
- int r = cluster.mon_command(cmd, inbl, &outbl, NULL);
- ceph_assert(r >= 0);
- string outstr(outbl.c_str(), outbl.length());
- json_spirit::Value v;
- if (!json_spirit::read(outstr, v)) {
- cerr <<" unable to parse json " << outstr << std::endl;
- return -1;
- }
-
- json_spirit::Object& o = v.get_obj();
- for (json_spirit::Object::size_type i=0; i<o.size(); i++) {
- json_spirit::Pair& p = o[i];
- if (p.name_ == "pg_num") {
- cout << "pg_num = " << p.value_.get_int() << std::endl;
- return p.value_.get_int();
- }
- }
- cerr << "didn't find pg_num in " << outstr << std::endl;
- return -1;
-}
-
-
-TEST_F(LibRadosTwoPoolsPP, HitSetWrite) {
- int num_pg = _get_pg_num(cluster, pool_name);
- ceph_assert(num_pg > 0);
-
- // make it a tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 8),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type",
- "explicit_hash"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- cache_ioctx.set_namespace("");
-
- int num = 200;
-
- // do a bunch of writes
- for (int i=0; i<num; ++i) {
- bufferlist bl;
- bl.append("a");
- ASSERT_EQ(0, cache_ioctx.write(stringify(i), bl, 1, 0));
- }
-
- // get HitSets
- std::map<int,HitSet> hitsets;
- for (int i=0; i<num_pg; ++i) {
- list< pair<time_t,time_t> > ls;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.hit_set_list(i, c, &ls));
- c->wait_for_complete();
- c->release();
- std::cout << "pg " << i << " ls " << ls << std::endl;
- ASSERT_FALSE(ls.empty());
-
- // get the latest
- c = librados::Rados::aio_create_completion();
- bufferlist bl;
- ASSERT_EQ(0, cache_ioctx.hit_set_get(i, c, ls.back().first, &bl));
- c->wait_for_complete();
- c->release();
-
- try {
- auto p = bl.cbegin();
- decode(hitsets[i], p);
- }
- catch (buffer::error& e) {
- std::cout << "failed to decode hit set; bl len is " << bl.length() << "\n";
- bl.hexdump(std::cout);
- std::cout << std::endl;
- throw e;
- }
-
- // cope with racing splits by refreshing pg_num
- if (i == num_pg - 1)
- num_pg = _get_pg_num(cluster, cache_pool_name);
- }
-
- for (int i=0; i<num; ++i) {
- string n = stringify(i);
- uint32_t hash;
- ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(n, &hash));
- hobject_t oid(sobject_t(n, CEPH_NOSNAP), "", hash,
- cluster.pool_lookup(cache_pool_name.c_str()), "");
- std::cout << "checking for " << oid << std::endl;
- bool found = false;
- for (int p=0; p<num_pg; ++p) {
- if (hitsets[p].contains(oid)) {
- found = true;
- break;
- }
- }
- ASSERT_TRUE(found);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, HitSetTrim) {
- unsigned count = 3;
- unsigned period = 3;
-
- // make it a tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", count),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", period),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_fpp", ".01"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- cache_ioctx.set_namespace("");
-
- // do a bunch of writes and make sure the hitsets rotate
- utime_t start = ceph_clock_now();
- utime_t hard_stop = start + utime_t(count * period * 50, 0);
-
- time_t first = 0;
- while (true) {
- string name = "foo";
- uint32_t hash;
- ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
- hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash, -1, "");
-
- bufferlist bl;
- bl.append("f");
- ASSERT_EQ(0, cache_ioctx.write("foo", bl, 1, 0));
-
- list<pair<time_t, time_t> > ls;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.hit_set_list(hash, c, &ls));
- c->wait_for_complete();
- c->release();
-
- cout << " got ls " << ls << std::endl;
- if (!ls.empty()) {
- if (!first) {
- first = ls.front().first;
- cout << "first is " << first << std::endl;
- } else {
- if (ls.front().first != first) {
- cout << "first now " << ls.front().first << ", trimmed" << std::endl;
- break;
- }
- }
- }
-
- utime_t now = ceph_clock_now();
- ASSERT_TRUE(now < hard_stop);
-
- sleep(1);
- }
-}
-
-TEST_F(LibRadosTwoPoolsPP, PromoteOn2ndRead) {
- // create object
- for (int i=0; i<20; ++i) {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo" + stringify(i), &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_grade_decay_rate", 20),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_search_last_n", 1),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- int fake = 0; // set this to non-zero to test spurious promotion,
- // e.g. from thrashing
- int attempt = 0;
- string obj;
- while (true) {
- // 1st read, don't trigger a promote
- obj = "foo" + stringify(attempt);
- cout << obj << std::endl;
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
- if (--fake >= 0) {
- sleep(1);
- ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
- sleep(1);
- }
- }
-
- // verify the object is NOT present in the cache tier
- {
- bool found = false;
- NObjectIterator it = cache_ioctx.nobjects_begin();
- while (it != cache_ioctx.nobjects_end()) {
- cout << " see " << it->get_oid() << std::endl;
- if (it->get_oid() == string(obj.c_str())) {
- found = true;
- break;
- }
- ++it;
- }
- if (!found)
- break;
- }
-
- ++attempt;
- ASSERT_LE(attempt, 20);
- cout << "hrm, object is present in cache on attempt " << attempt
- << ", retrying" << std::endl;
- }
-
- // Read until the object is present in the cache tier
- cout << "verifying " << obj << " is eventually promoted" << std::endl;
- while (true) {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
-
- bool there = false;
- NObjectIterator it = cache_ioctx.nobjects_begin();
- while (it != cache_ioctx.nobjects_end()) {
- if (it->get_oid() == string(obj.c_str())) {
- there = true;
- break;
- }
- ++it;
- }
- if (there)
- break;
-
- sleep(1);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, ProxyRead) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"readproxy\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // Verify 10 times the object is NOT present in the cache tier
- uint32_t i = 0;
- while (i++ < 10) {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- sleep(1);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, CachePin) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger promote
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
- ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
- }
-
- // verify the objects are present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- for (uint32_t i = 0; i < 4; i++) {
- ASSERT_TRUE(it->get_oid() == string("foo") ||
- it->get_oid() == string("bar") ||
- it->get_oid() == string("baz") ||
- it->get_oid() == string("bam"));
- ++it;
- }
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // pin objects
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("baz", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // enable agent
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "target_max_objects", 1),
- inbl, NULL, NULL));
-
- sleep(10);
-
- // Verify the pinned object 'foo' is not flushed/evicted
- uint32_t count = 0;
- while (true) {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
-
- count = 0;
- NObjectIterator it = cache_ioctx.nobjects_begin();
- while (it != cache_ioctx.nobjects_end()) {
- ASSERT_TRUE(it->get_oid() == string("foo") ||
- it->get_oid() == string("bar") ||
- it->get_oid() == string("baz") ||
- it->get_oid() == string("bam"));
- ++count;
- ++it;
- }
- if (count == 2) {
- ASSERT_TRUE(it->get_oid() == string("foo") ||
- it->get_oid() == string("baz"));
- break;
- }
-
- sleep(1);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, SetRedirectRead) {
- // skip test if not yet luminous
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("luminous") == std::string::npos) {
- cout << "cluster is not yet luminous, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
-
- // configure tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- {
- ObjectWriteOperation op;
- op.set_redirect("bar", cache_ioctx, 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('t', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, SetChunkRead) {
- // skip test if not yet mimic
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("mimic") == std::string::npos) {
- cout << "cluster is not yet mimic, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- ObjectWriteOperation op;
- op.create(true);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
-
- // configure tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set_chunk
- {
- ObjectWriteOperation op;
- int len = strlen("hi there");
- for (int i = 0; i < len; i+=2) {
- op.set_chunk(i, 2, cache_ioctx, "bar", i);
- }
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // make all chunks dirty --> full flush --> all chunks are evicted
- {
- bufferlist bl;
- bl.append("There hi");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('T', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, ManifestPromoteRead) {
- // skip test if not yet mimic
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("mimic") == std::string::npos) {
- cout << "cluster is not yet mimic, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("base chunk");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
- }
- {
- bufferlist bl;
- bl.append("there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("CHUNK");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
- }
-
- // configure tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set-redirect
- {
- ObjectWriteOperation op;
- op.set_redirect("bar", cache_ioctx, 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // set-chunk
- {
- ObjectWriteOperation op;
- op.set_chunk(0, 2, cache_ioctx, "bar-chunk", 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // promote
- {
- ObjectWriteOperation op;
- op.tier_promote();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // read and verify the object (redirect)
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('t', bl[0]);
- }
- // promote
- {
- ObjectWriteOperation op;
- op.tier_promote();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo-chunk", bl, 1, 0));
- ASSERT_EQ('C', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, ManifestRefRead) {
- // skip test if not yet mimic
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("mimic") == std::string::npos) {
- cout << "cluster is not yet mimic, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("base chunk");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
- }
- {
- bufferlist bl;
- bl.append("there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("CHUNK");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
- }
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set-redirect
- {
- ObjectWriteOperation op;
- op.set_redirect("bar", cache_ioctx, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // set-chunk
- {
- ObjectWriteOperation op;
- op.set_chunk(0, 2, cache_ioctx, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // redirect's refcount
- {
- bufferlist in, out;
- cache_ioctx.exec("bar", "cas", "chunk_read", in, out);
- cls_chunk_refcount_read_ret read_ret;
- try {
- auto iter = out.cbegin();
- decode(read_ret, iter);
- } catch (buffer::error& err) {
- ASSERT_TRUE(0);
- }
- ASSERT_EQ(1U, read_ret.refs.size());
- }
- // chunk's refcount
- {
- bufferlist in, out;
- cache_ioctx.exec("bar-chunk", "cas", "chunk_read", in, out);
- cls_chunk_refcount_read_ret read_ret;
- try {
- auto iter = out.cbegin();
- decode(read_ret, iter);
- } catch (buffer::error& err) {
- ASSERT_TRUE(0);
- }
- ASSERT_EQ(1u, read_ret.refs.size());
- }
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, ManifestUnset) {
- // skip test if not yet nautilus
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("nautilus") == std::string::npos) {
- cout << "cluster is not yet nautilus, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("base chunk");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
- }
- {
- bufferlist bl;
- bl.append("there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("CHUNK");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
- }
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set-redirect
- {
- ObjectWriteOperation op;
- op.set_redirect("bar", cache_ioctx, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // set-chunk
- {
- ObjectWriteOperation op;
- op.set_chunk(0, 2, cache_ioctx, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // redirect's refcount
- {
- bufferlist in, out;
- cache_ioctx.exec("bar", "cas", "chunk_read", in, out);
- cls_chunk_refcount_read_ret read_ret;
- try {
- auto iter = out.cbegin();
- decode(read_ret, iter);
- } catch (buffer::error& err) {
- ASSERT_TRUE(0);
- }
- ASSERT_EQ(1u, read_ret.refs.size());
- }
- // chunk's refcount
- {
- bufferlist in, out;
- cache_ioctx.exec("bar-chunk", "cas", "chunk_read", in, out);
- cls_chunk_refcount_read_ret read_ret;
- try {
- auto iter = out.cbegin();
- decode(read_ret, iter);
- } catch (buffer::error& err) {
- ASSERT_TRUE(0);
- }
- ASSERT_EQ(1u, read_ret.refs.size());
- }
-
- // unset-manifest for set-redirect
- {
- ObjectWriteOperation op;
- op.unset_manifest();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // unset-manifest for set-chunk
- {
- ObjectWriteOperation op;
- op.unset_manifest();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // redirect's refcount
- {
- bufferlist in, out;
- cache_ioctx.exec("bar", "cas", "chunk_read", in, out);
- if (out.length() != 0U) {
- ObjectWriteOperation op;
- op.unset_manifest();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(-EOPNOTSUPP, completion->get_return_value());
- completion->release();
- }
- }
- // chunk's refcount
- {
- bufferlist in, out;
- cache_ioctx.exec("bar-chunk", "cas", "chunk_read", in, out);
- if (out.length() != 0U) {
- ObjectWriteOperation op;
- op.unset_manifest();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(-EOPNOTSUPP, completion->get_return_value());
- completion->release();
- }
- }
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-#include "common/ceph_crypto.h"
-using ceph::crypto::SHA1;
-#include "rgw/rgw_common.h"
-TEST_F(LibRadosTwoPoolsPP, ManifestDedupRefRead) {
- // skip test if not yet nautilus
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("nautilus") == std::string::npos) {
- cout << "cluster is not yet nautilus, skipping test" << std::endl;
- return;
- }
- }
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(pool_name, "fingerprint_algorithm", "sha1"),
- inbl, NULL, NULL));
- cluster.wait_for_latest_osdmap();
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
- }
- {
- bufferlist bl;
- bl.append("there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("CHUNK");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
- }
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set-chunk (dedup)
- {
- ObjectWriteOperation op;
- int len = strlen("hi there");
- op.set_chunk(0, len, cache_ioctx, "bar-chunk", 0,
- CEPH_OSD_OP_FLAG_WITH_REFERENCE);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-dedup", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // set-chunk (dedup)
- {
- ObjectWriteOperation op;
- int len = strlen("hi there");
- op.set_chunk(0, len, cache_ioctx, "bar", 0,
- CEPH_OSD_OP_FLAG_WITH_REFERENCE);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // make all chunks dirty --> flush
- {
- // make a dirty chunks
- bufferlist bl;
- bl.append("There hi");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
- }
- {
- // do flush
- bufferlist bl;
- bl.append("There hi");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
- }
- {
- // make a dirty chunks
- bufferlist bl;
- bl.append("There hi");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- // do flush
- bufferlist bl;
- bl.append("There hi");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- // chunk's refcount
- {
- bufferlist in, out;
- SHA1 sha1_gen;
- int size = strlen("There hi");
- unsigned char fingerprint[CEPH_CRYPTO_SHA1_DIGESTSIZE + 1];
- char p_str[CEPH_CRYPTO_SHA1_DIGESTSIZE*2+1] = {0};
- sha1_gen.Update((const unsigned char *)"There hi", size);
- sha1_gen.Final(fingerprint);
- buf_to_hex(fingerprint, CEPH_CRYPTO_SHA1_DIGESTSIZE, p_str);
- cache_ioctx.exec(p_str, "cas", "chunk_read", in, out);
- cls_chunk_refcount_read_ret read_ret;
- try {
- auto iter = out.cbegin();
- decode(read_ret, iter);
- } catch (buffer::error& err) {
- ASSERT_TRUE(0);
- }
- ASSERT_EQ(2u, read_ret.refs.size());
- }
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-class LibRadosTwoPoolsECPP : public RadosTestECPP
-{
-public:
- LibRadosTwoPoolsECPP() {};
- ~LibRadosTwoPoolsECPP() override {};
-protected:
- static void SetUpTestCase() {
- pool_name = get_temp_pool_name();
- ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
- }
- static void TearDownTestCase() {
- ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
- }
- static std::string cache_pool_name;
-
- void SetUp() override {
- cache_pool_name = get_temp_pool_name();
- ASSERT_EQ(0, s_cluster.pool_create(cache_pool_name.c_str()));
- RadosTestECPP::SetUp();
-
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- cache_ioctx.application_enable("rados", true);
- cache_ioctx.set_namespace(nspace);
- }
- void TearDown() override {
- // flush + evict cache
- flush_evict_all(cluster, cache_ioctx);
-
- bufferlist inbl;
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-
- RadosTestECPP::TearDown();
-
- cleanup_default_namespace(cache_ioctx);
- cleanup_namespace(cache_ioctx, nspace);
-
- cache_ioctx.close();
- ASSERT_EQ(0, s_cluster.pool_delete(cache_pool_name.c_str()));
- }
-
- librados::IoCtx cache_ioctx;
-};
-
-std::string LibRadosTwoPoolsECPP::cache_pool_name;
-
-TEST_F(LibRadosTierECPP, Dirty) {
- {
- ObjectWriteOperation op;
- op.undirty();
- ASSERT_EQ(0, ioctx.operate("foo", &op)); // still get 0 if it dne
- }
- {
- ObjectWriteOperation op;
- op.create(true);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- }
- {
- ObjectWriteOperation op;
- op.undirty();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- ObjectWriteOperation op;
- op.undirty();
- ASSERT_EQ(0, ioctx.operate("foo", &op)); // still 0 if already clean
- }
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
- //{
- // ObjectWriteOperation op;
- // op.truncate(0); // still a write even tho it is a no-op
- // ASSERT_EQ(0, ioctx.operate("foo", &op));
- //}
- //{
- // bool dirty = false;
- // int r = -1;
- // ObjectReadOperation op;
- // op.is_dirty(&dirty, &r);
- // ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
- // ASSERT_TRUE(dirty);
- // ASSERT_EQ(0, r);
- //}
-}
-
-TEST_F(LibRadosTwoPoolsECPP, Overlay) {
- // create objects
- {
- bufferlist bl;
- bl.append("base");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("cache");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // by default, the overlay sends us to cache pool
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // unless we say otherwise
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(0, 1, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- ASSERT_EQ('b', bl[0]);
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, Promote) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- }
-
- // read, trigger a whiteout
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, PromoteSnap) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote on the head
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- ioctx.snap_set_read(my_snaps[0]);
-
- // stop and scrub this pg (to make sure scrub can handle missing
- // clones in the cache tier)
- // This test requires cache tier and base tier to have the same pg_num/pgp_num
- {
- for (int tries = 0; tries < 5; ++tries) {
- IoCtx cache_ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- uint32_t hash;
- ASSERT_EQ(0, ioctx.get_object_pg_hash_position2("foo", &hash));
- ostringstream ss;
- ss << "{\"prefix\": \"pg scrub\", \"pgid\": \""
- << cache_ioctx.get_id() << "."
- << hash
- << "\"}";
- int r = cluster.mon_command(ss.str(), inbl, NULL, NULL);
- if (r == -EAGAIN ||
- r == -ENOENT) { // in case mgr osdmap is a bit stale
- sleep(5);
- continue;
- }
- ASSERT_EQ(0, r);
- break;
- }
- // give it a few seconds to go. this is sloppy but is usually enough time
- cout << "waiting for scrub..." << std::endl;
- sleep(15);
- cout << "done waiting" << std::endl;
- }
-
- // read foo snap
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // read bar snap
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // read baz snap
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- ioctx.snap_set_read(librados::SNAP_HEAD);
-
- // read foo
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // read bar
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // read baz
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("baz", bl, 1, 0));
- }
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTwoPoolsECPP, PromoteSnapTrimRace) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // delete the snap
- ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps[0]));
-
- ioctx.snap_set_read(my_snaps[0]);
-
- // read foo snap
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("foo", bl, 1, 0));
- }
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTwoPoolsECPP, Whiteout) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create some whiteouts, verify they behave
- {
- ObjectWriteOperation op;
- op.assert_exists();
- op.remove();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- {
- ObjectWriteOperation op;
- op.assert_exists();
- op.remove();
- ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.assert_exists();
- op.remove();
- ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
- }
-
- // verify the whiteouts are there in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // delete a whiteout and verify it goes away
- ASSERT_EQ(-ENOENT, ioctx.remove("foo"));
- {
- ObjectWriteOperation op;
- op.remove();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
-
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // recreate an object and verify we can read it
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, Evict) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- }
-
- // read, trigger a whiteout, and a dirty object
- {
- bufferlist bl;
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(0, ioctx.write("bar", bl, bl.length(), 0));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // pin
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // evict the pinned object with -EPERM
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE,
- NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EPERM, completion->get_return_value());
- completion->release();
- }
-
- // unpin
- {
- ObjectWriteOperation op;
- op.cache_unpin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify clean
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE,
- NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, EvictSnap) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("ciao!");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger a promote on the head
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
-
- // evict bam
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "bam", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "bam", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-ENOENT, completion->get_return_value());
- completion->release();
- }
-
- // read foo snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // evict foo snap
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // snap is gone...
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-ENOENT, completion->get_return_value());
- completion->release();
- }
- // head is still there...
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // promote head + snap of bar
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // evict bar head (fail)
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
-
- // evict bar snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // ...and then head
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ObjectReadOperation op;
- op.read(1, 0, &bl, NULL);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "bar", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTwoPoolsECPP, TryFlush) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // verify dirty
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // pin
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush the pinned object with -EPERM
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EPERM, completion->get_return_value());
- completion->release();
- }
-
- // unpin
- {
- ObjectWriteOperation op;
- op.cache_unpin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify clean
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // verify in base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it != ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // evict it
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, FailedFlush) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // set omap
- {
- ObjectWriteOperation op;
- std::map<std::string, bufferlist> omap;
- omap["somekey"] = bufferlist();
- op.omap_set(omap);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_NE(0, completion->get_return_value());
- completion->release();
- }
-
- // get omap
- {
- ObjectReadOperation op;
- bufferlist bl;
- int prval = 0;
- std::set<std::string> keys;
- keys.insert("somekey");
- std::map<std::string, bufferlist> map;
-
- op.omap_get_vals_by_keys(keys, &map, &prval);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op, &bl));
- sleep(5);
- bool completed = completion->is_complete();
- if( !completed ) {
- cache_ioctx.aio_cancel(completion);
- std::cerr << "Most probably test case will hang here, please reset manually" << std::endl;
- ASSERT_TRUE(completed); //in fact we are locked forever at test case shutdown unless fix for http://tracker.ceph.com/issues/14511 is applied. Seems there is no workaround for that
- }
- completion->release();
- }
- // verify still not in base tier
- {
- ASSERT_TRUE(ioctx.nobjects_begin() == ioctx.nobjects_end());
- }
- // erase it
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- // flush whiteout
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
- // or base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, Flush) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- uint64_t user_version = 0;
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // verify dirty
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_TRUE(dirty);
- ASSERT_EQ(0, r);
- user_version = cache_ioctx.get_last_version();
- }
-
- // pin
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush the pinned object with -EPERM
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EPERM, completion->get_return_value());
- completion->release();
- }
-
- // unpin
- {
- ObjectWriteOperation op;
- op.cache_unpin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify clean
- {
- bool dirty = false;
- int r = -1;
- ObjectReadOperation op;
- op.is_dirty(&dirty, &r);
- ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
- ASSERT_FALSE(dirty);
- ASSERT_EQ(0, r);
- }
-
- // verify in base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it != ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // evict it
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // read it again and verify the version is consistent
- {
- bufferlist bl;
- ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ(user_version, cache_ioctx.get_last_version());
- }
-
- // erase it
- {
- ObjectWriteOperation op;
- op.remove();
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush whiteout
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify no longer in cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
- // or base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, FlushSnap) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create object
- {
- bufferlist bl;
- bl.append("a");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // create a snapshot, clone
- vector<uint64_t> my_snaps(1);
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("b");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // and another
- my_snaps.resize(2);
- my_snaps[1] = my_snaps[0];
- ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
- ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
- my_snaps));
- {
- bufferlist bl;
- bl.append("c");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // verify the object is present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // verify the object is NOT present in the base tier
- {
- NObjectIterator it = ioctx.nobjects_begin();
- ASSERT_TRUE(it == ioctx.nobjects_end());
- }
-
- // flush on head (should fail)
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
- // flush on recent snap (should fail)
- ioctx.snap_set_read(my_snaps[0]);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(-EBUSY, completion->get_return_value());
- completion->release();
- }
- // flush on oldest snap
- ioctx.snap_set_read(my_snaps[1]);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // flush on next oldest snap
- ioctx.snap_set_read(my_snaps[0]);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // flush on head
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // verify i can read the snaps from the cache pool
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('b', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[1]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('a', bl[0]);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // verify i can read the snaps from the base pool
- ioctx.snap_set_read(librados::SNAP_HEAD);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('c', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[0]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('b', bl[0]);
- }
- ioctx.snap_set_read(my_snaps[1]);
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('a', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- cluster.wait_for_latest_osdmap();
-
- // cleanup
- ioctx.selfmanaged_snap_remove(my_snaps[0]);
-}
-
-TEST_F(LibRadosTierECPP, FlushWriteRaces) {
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- std::string cache_pool_name = pool_name + "-cache";
- ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
- ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str()));
- IoCtx cache_ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- cache_ioctx.application_enable("rados", true);
- IoCtx ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- bufferlist bl;
- bl.append("hi there");
- {
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush + write
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- ObjectWriteOperation op2;
- op2.write_full(bl);
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate(
- "foo", completion2, &op2, 0));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-
- int tries = 1000;
- do {
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // try-flush + write
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- ObjectWriteOperation op2;
- op2.write_full(bl);
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion2, &op2, 0));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- int r = completion->get_return_value();
- ASSERT_TRUE(r == -EBUSY || r == 0);
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- if (r == -EBUSY)
- break;
- cout << "didn't get EBUSY, trying again" << std::endl;
- }
- ASSERT_TRUE(--tries);
- } while (true);
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-
- ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str()));
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
-}
-
-TEST_F(LibRadosTwoPoolsECPP, FlushTryFlushRaces) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush + flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- ObjectReadOperation op2;
- op2.cache_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush + try-flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- ObjectReadOperation op2;
- op2.cache_try_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-
- // create/dirty object
- int tries = 1000;
- do {
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // try-flush + flush
- // (flush will not piggyback on try-flush)
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- ObjectReadOperation op2;
- op2.cache_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- int r = completion->get_return_value();
- ASSERT_TRUE(r == -EBUSY || r == 0);
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- if (r == -EBUSY)
- break;
- cout << "didn't get EBUSY, trying again" << std::endl;
- }
- ASSERT_TRUE(--tries);
- } while (true);
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // try-flush + try-flush
- {
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- ObjectReadOperation op2;
- op2.cache_try_flush();
- librados::AioCompletion *completion2 = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion2, &op2,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- completion->wait_for_safe();
- completion2->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- ASSERT_EQ(0, completion2->get_return_value());
- completion->release();
- completion2->release();
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, TryFlushReadRace) {
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- {
- bufferlist bl;
- bl.append("hi there");
- bufferptr bp(4000000); // make it big!
- bp.zero();
- bl.append(bp);
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // start a continuous stream of reads
- read_ioctx = &ioctx;
- test_lock.Lock();
- for (int i = 0; i < max_reads; ++i) {
- start_flush_read();
- num_reads++;
- }
- test_lock.Unlock();
-
- // try-flush
- ObjectReadOperation op;
- op.cache_try_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY |
- librados::OPERATION_SKIPRWLOCKS, NULL));
-
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
-
- // stop reads
- test_lock.Lock();
- max_reads = 0;
- while (num_reads > 0)
- cond.Wait(test_lock);
- test_lock.Unlock();
-}
-
-TEST_F(LibRadosTierECPP, CallForcesPromote) {
- Rados cluster;
- std::string pool_name = get_temp_pool_name();
- std::string cache_pool_name = pool_name + "-cache";
- ASSERT_EQ("", create_one_ec_pool_pp(pool_name, cluster));
- ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str()));
- IoCtx cache_ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
- cache_ioctx.application_enable("rados", true);
- IoCtx ioctx;
- ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // set things up such that the op would normally be proxied
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_type",
- "explicit_object"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "min_read_recency_for_promote",
- "4"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // create/dirty object
- bufferlist bl;
- bl.append("hi there");
- {
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // flush
- {
- ObjectReadOperation op;
- op.cache_flush();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate(
- "foo", completion, &op,
- librados::OPERATION_IGNORE_OVERLAY, NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // evict
- {
- ObjectReadOperation op;
- op.cache_evict();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
- librados::OPERATION_IGNORE_CACHE,
- NULL));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // call
- {
- ObjectReadOperation op;
- bufferlist bl;
- op.exec("rbd", "get_id", bl);
- bufferlist out;
- // should get EIO (not an rbd object), not -EOPNOTSUPP (we didn't promote)
- ASSERT_EQ(-5, ioctx.operate("foo", &op, &out));
- }
-
- // make sure foo is back in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- ASSERT_TRUE(it->get_oid() == string("foo"));
- ++it;
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-
- ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str()));
- ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
-}
-
-TEST_F(LibRadosTierECPP, HitSetNone) {
- {
- list< pair<time_t,time_t> > ls;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, ioctx.hit_set_list(123, c, &ls));
- c->wait_for_complete();
- ASSERT_EQ(0, c->get_return_value());
- ASSERT_TRUE(ls.empty());
- c->release();
- }
- {
- bufferlist bl;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, ioctx.hit_set_get(123, c, 12345, &bl));
- c->wait_for_complete();
- ASSERT_EQ(-ENOENT, c->get_return_value());
- c->release();
- }
-}
-
-TEST_F(LibRadosTwoPoolsECPP, HitSetRead) {
- // make it a tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type",
- "explicit_object"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- cache_ioctx.set_namespace("");
-
- // keep reading until we see our object appear in the HitSet
- utime_t start = ceph_clock_now();
- utime_t hard_stop = start + utime_t(600, 0);
-
- while (true) {
- utime_t now = ceph_clock_now();
- ASSERT_TRUE(now < hard_stop);
-
- string name = "foo";
- uint32_t hash;
- ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
- hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash,
- cluster.pool_lookup(cache_pool_name.c_str()), "");
-
- bufferlist bl;
- ASSERT_EQ(-ENOENT, cache_ioctx.read("foo", bl, 1, 0));
-
- bufferlist hbl;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.hit_set_get(hash, c, now.sec(), &hbl));
- c->wait_for_complete();
- c->release();
-
- if (hbl.length()) {
- auto p = hbl.cbegin();
- HitSet hs;
- decode(hs, p);
- if (hs.contains(oid)) {
- cout << "ok, hit_set contains " << oid << std::endl;
- break;
- }
- cout << "hmm, not in HitSet yet" << std::endl;
- } else {
- cout << "hmm, no HitSet yet" << std::endl;
- }
-
- sleep(1);
- }
-}
-
-// disable this test until hitset-get reliably works on EC pools
-#if 0
-TEST_F(LibRadosTierECPP, HitSetWrite) {
- int num_pg = _get_pg_num(cluster, pool_name);
- ceph_assert(num_pg > 0);
-
- // enable hitset tracking for this pool
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_count", 8),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_type",
- "explicit_hash"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- ioctx.set_namespace("");
-
- // do a bunch of writes
- for (int i=0; i<1000; ++i) {
- bufferlist bl;
- bl.append("a");
- ASSERT_EQ(0, ioctx.write(stringify(i), bl, 1, 0));
- }
-
- // get HitSets
- std::map<int,HitSet> hitsets;
- for (int i=0; i<num_pg; ++i) {
- list< pair<time_t,time_t> > ls;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, ioctx.hit_set_list(i, c, &ls));
- c->wait_for_complete();
- c->release();
- std::cout << "pg " << i << " ls " << ls << std::endl;
- ASSERT_FALSE(ls.empty());
-
- // get the latest
- c = librados::Rados::aio_create_completion();
- bufferlist bl;
- ASSERT_EQ(0, ioctx.hit_set_get(i, c, ls.back().first, &bl));
- c->wait_for_complete();
- c->release();
-
- //std::cout << "bl len is " << bl.length() << "\n";
- //bl.hexdump(std::cout);
- //std::cout << std::endl;
-
- auto p = bl.cbegin();
- decode(hitsets[i], p);
-
- // cope with racing splits by refreshing pg_num
- if (i == num_pg - 1)
- num_pg = _get_pg_num(cluster, pool_name);
- }
-
- for (int i=0; i<1000; ++i) {
- string n = stringify(i);
- uint32_t hash = ioctx.get_object_hash_position(n);
- hobject_t oid(sobject_t(n, CEPH_NOSNAP), "", hash,
- cluster.pool_lookup(pool_name.c_str()), "");
- std::cout << "checking for " << oid << std::endl;
- bool found = false;
- for (int p=0; p<num_pg; ++p) {
- if (hitsets[p].contains(oid)) {
- found = true;
- break;
- }
- }
- ASSERT_TRUE(found);
- }
-}
-#endif
-
-TEST_F(LibRadosTwoPoolsECPP, HitSetTrim) {
- unsigned count = 3;
- unsigned period = 3;
-
- // make it a tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", count),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", period),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_fpp", ".01"),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- cache_ioctx.set_namespace("");
-
- // do a bunch of writes and make sure the hitsets rotate
- utime_t start = ceph_clock_now();
- utime_t hard_stop = start + utime_t(count * period * 50, 0);
-
- time_t first = 0;
- int bsize = alignment;
- char *buf = (char *)new char[bsize];
- memset(buf, 'f', bsize);
-
- while (true) {
- string name = "foo";
- uint32_t hash;
- ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
- hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash, -1, "");
-
- bufferlist bl;
- bl.append(buf, bsize);
- ASSERT_EQ(0, cache_ioctx.append("foo", bl, bsize));
-
- list<pair<time_t, time_t> > ls;
- AioCompletion *c = librados::Rados::aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.hit_set_list(hash, c, &ls));
- c->wait_for_complete();
- c->release();
-
- cout << " got ls " << ls << std::endl;
- if (!ls.empty()) {
- if (!first) {
- first = ls.front().first;
- cout << "first is " << first << std::endl;
- } else {
- if (ls.front().first != first) {
- cout << "first now " << ls.front().first << ", trimmed" << std::endl;
- break;
- }
- }
- }
-
- utime_t now = ceph_clock_now();
- ASSERT_TRUE(now < hard_stop);
-
- sleep(1);
- }
- delete[] buf;
-}
-
-TEST_F(LibRadosTwoPoolsECPP, PromoteOn2ndRead) {
- // create object
- for (int i=0; i<20; ++i) {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo" + stringify(i), &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // enable hitset tracking for this pool
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_grade_decay_rate", 20),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_search_last_n", 1),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- int fake = 0; // set this to non-zero to test spurious promotion,
- // e.g. from thrashing
- int attempt = 0;
- string obj;
- while (true) {
- // 1st read, don't trigger a promote
- obj = "foo" + stringify(attempt);
- cout << obj << std::endl;
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
- if (--fake >= 0) {
- sleep(1);
- ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
- sleep(1);
- }
- }
-
- // verify the object is NOT present in the cache tier
- {
- bool found = false;
- NObjectIterator it = cache_ioctx.nobjects_begin();
- while (it != cache_ioctx.nobjects_end()) {
- cout << " see " << it->get_oid() << std::endl;
- if (it->get_oid() == string(obj.c_str())) {
- found = true;
- break;
- }
- ++it;
- }
- if (!found)
- break;
- }
-
- ++attempt;
- ASSERT_LE(attempt, 20);
- cout << "hrm, object is present in cache on attempt " << attempt
- << ", retrying" << std::endl;
- }
-
- // Read until the object is present in the cache tier
- cout << "verifying " << obj << " is eventually promoted" << std::endl;
- while (true) {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
-
- bool there = false;
- NObjectIterator it = cache_ioctx.nobjects_begin();
- while (it != cache_ioctx.nobjects_end()) {
- if (it->get_oid() == string(obj.c_str())) {
- there = true;
- break;
- }
- ++it;
- }
- if (there)
- break;
-
- sleep(1);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsECPP, ProxyRead) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"readproxy\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('h', bl[0]);
- }
-
- // Verify 10 times the object is NOT present in the cache tier
- uint32_t i = 0;
- while (i++ < 10) {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- sleep(1);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsECPP, CachePin) {
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("baz", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("bam", &op));
- }
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // read, trigger promote
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
- ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
- ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
- }
-
- // verify the objects are present in the cache tier
- {
- NObjectIterator it = cache_ioctx.nobjects_begin();
- ASSERT_TRUE(it != cache_ioctx.nobjects_end());
- for (uint32_t i = 0; i < 4; i++) {
- ASSERT_TRUE(it->get_oid() == string("foo") ||
- it->get_oid() == string("bar") ||
- it->get_oid() == string("baz") ||
- it->get_oid() == string("bam"));
- ++it;
- }
- ASSERT_TRUE(it == cache_ioctx.nobjects_end());
- }
-
- // pin objects
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- {
- ObjectWriteOperation op;
- op.cache_pin();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, cache_ioctx.aio_operate("baz", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // enable agent
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_count", 2),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "target_max_objects", 1),
- inbl, NULL, NULL));
-
- sleep(10);
-
- // Verify the pinned object 'foo' is not flushed/evicted
- uint32_t count = 0;
- while (true) {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
-
- count = 0;
- NObjectIterator it = cache_ioctx.nobjects_begin();
- while (it != cache_ioctx.nobjects_end()) {
- ASSERT_TRUE(it->get_oid() == string("foo") ||
- it->get_oid() == string("bar") ||
- it->get_oid() == string("baz") ||
- it->get_oid() == string("bam"));
- ++count;
- ++it;
- }
- if (count == 2) {
- ASSERT_TRUE(it->get_oid() == string("foo") ||
- it->get_oid() == string("baz"));
- break;
- }
-
- sleep(1);
- }
-
- // tear down tiers
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
- "\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-TEST_F(LibRadosTwoPoolsECPP, SetRedirectRead) {
- // skip test if not yet luminous
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("luminous") == std::string::npos) {
- cout << "cluster is not yet luminous, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
-
- // configure tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- {
- ObjectWriteOperation op;
- op.set_redirect("bar", cache_ioctx, 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('t', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsECPP, SetChunkRead) {
- // skip test if not yet mimic
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("mimic") == std::string::npos) {
- cout << "cluster is not yet mimic, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- ObjectWriteOperation op;
- op.create(true);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
-
- // configure tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set_chunk
- {
- ObjectWriteOperation op;
- op.set_chunk(0, 8, cache_ioctx, "bar", 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
-
- // make all chunks dirty --> full flush --> all chunks are evicted
- {
- bufferlist bl;
- bl.append("There hi");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
-
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('T', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsECPP, ManifestPromoteRead) {
- // skip test if not yet mimic
- {
- bufferlist inbl, outbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd dump\"}",
- inbl, &outbl, NULL));
- string s(outbl.c_str(), outbl.length());
- if (s.find("mimic") == std::string::npos) {
- cout << "cluster is not yet mimic, skipping test" << std::endl;
- return;
- }
- }
-
- // create object
- {
- bufferlist bl;
- bl.append("hi there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, ioctx.operate("foo", &op));
- }
- {
- ObjectWriteOperation op;
- op.create(true);
- ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
- }
- {
- bufferlist bl;
- bl.append("HI there");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
- }
- {
- bufferlist bl;
- bl.append("BASE CHUNK");
- ObjectWriteOperation op;
- op.write_full(bl);
- ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
- }
-
- // configure tier
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // set-redirect
- {
- ObjectWriteOperation op;
- op.set_redirect("bar", cache_ioctx, 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // set-chunk
- {
- ObjectWriteOperation op;
- op.set_chunk(0, 10, cache_ioctx, "bar-chunk", 0);
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // promote
- {
- ObjectWriteOperation op;
- op.tier_promote();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // read and verify the object (redirect)
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
- ASSERT_EQ('H', bl[0]);
- }
- // promote
- {
- ObjectWriteOperation op;
- op.tier_promote();
- librados::AioCompletion *completion = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
- completion->wait_for_safe();
- ASSERT_EQ(0, completion->get_return_value());
- completion->release();
- }
- // read and verify the object
- {
- bufferlist bl;
- ASSERT_EQ(1, ioctx.read("foo-chunk", bl, 1, 0));
- ASSERT_EQ('B', bl[0]);
- }
-
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- // wait for maps to settle before next test
- cluster.wait_for_latest_osdmap();
-}
-
-TEST_F(LibRadosTwoPoolsPP, PropagateBaseTierError) {
- // write object to base tier
- bufferlist omap_bl;
- encode(static_cast<uint32_t>(0U), omap_bl);
-
- ObjectWriteOperation op1;
- op1.omap_set({{"somekey", omap_bl}});
- ASSERT_EQ(0, ioctx.operate("propagate-base-tier-error", &op1));
-
- // configure cache
- bufferlist inbl;
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
- "\", \"tierpool\": \"" + cache_pool_name +
- "\", \"force_nonempty\": \"--force-nonempty\" }",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
- "\", \"mode\": \"writeback\"}",
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
- "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
- inbl, NULL, NULL));
-
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_count", 1),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "hit_set_period", 600),
- inbl, NULL, NULL));
- ASSERT_EQ(0, cluster.mon_command(
- set_pool_str(cache_pool_name, "target_max_objects", 250),
- inbl, NULL, NULL));
-
- // wait for maps to settle
- cluster.wait_for_latest_osdmap();
-
- // guarded op should fail so expect error to propagate to cache tier
- bufferlist test_omap_bl;
- encode(static_cast<uint32_t>(1U), test_omap_bl);
-
- ObjectWriteOperation op2;
- op2.omap_cmp({{"somekey", {test_omap_bl, CEPH_OSD_CMPXATTR_OP_EQ}}}, nullptr);
- op2.omap_set({{"somekey", test_omap_bl}});
-
- ASSERT_EQ(-ECANCELED, ioctx.operate("propagate-base-tier-error", &op2));
-}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include "gtest/gtest.h"
+
+#include "mds/mdstypes.h"
+#include "include/buffer.h"
+#include "include/rbd_types.h"
+#include "include/rados/librados.hpp"
+#include "include/stringify.h"
+#include "include/types.h"
+#include "global/global_context.h"
+#include "common/Cond.h"
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+#include "json_spirit/json_spirit.h"
+#include "cls/cas/cls_cas_ops.h"
+
+#include "osd/HitSet.h"
+
+#include <errno.h>
+#include <map>
+#include <sstream>
+#include <string>
+
+using namespace librados;
+using std::map;
+using std::ostringstream;
+using std::string;
+
+typedef RadosTestPP LibRadosTierPP;
+typedef RadosTestECPP LibRadosTierECPP;
+
+void flush_evict_all(librados::Rados& cluster, librados::IoCtx& cache_ioctx)
+{
+ bufferlist inbl;
+ cache_ioctx.set_namespace(all_nspaces);
+ for (NObjectIterator it = cache_ioctx.nobjects_begin();
+ it != cache_ioctx.nobjects_end(); ++it) {
+ cache_ioctx.locator_set_key(it->get_locator());
+ cache_ioctx.set_namespace(it->get_nspace());
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ cache_ioctx.aio_operate(
+ it->get_oid(), completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL);
+ completion->wait_for_safe();
+ completion->get_return_value();
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ cache_ioctx.aio_operate(
+ it->get_oid(), completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL);
+ completion->wait_for_safe();
+ completion->get_return_value();
+ completion->release();
+ }
+ }
+}
+
+class LibRadosTwoPoolsPP : public RadosTestPP
+{
+public:
+ LibRadosTwoPoolsPP() {};
+ ~LibRadosTwoPoolsPP() override {};
+protected:
+ static void SetUpTestCase() {
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_pool_pp(pool_name, s_cluster));
+ }
+ static void TearDownTestCase() {
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, s_cluster));
+ }
+ static std::string cache_pool_name;
+
+ void SetUp() override {
+ cache_pool_name = get_temp_pool_name();
+ ASSERT_EQ(0, s_cluster.pool_create(cache_pool_name.c_str()));
+ RadosTestPP::SetUp();
+
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ cache_ioctx.application_enable("rados", true);
+ cache_ioctx.set_namespace(nspace);
+ }
+ void TearDown() override {
+ // flush + evict cache
+ flush_evict_all(cluster, cache_ioctx);
+
+ bufferlist inbl;
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+
+ RadosTestPP::TearDown();
+
+ cleanup_default_namespace(cache_ioctx);
+ cleanup_namespace(cache_ioctx, nspace);
+
+ cache_ioctx.close();
+ ASSERT_EQ(0, s_cluster.pool_delete(cache_pool_name.c_str()));
+ }
+ librados::IoCtx cache_ioctx;
+};
+
+class Completions
+{
+public:
+ Completions() = default;
+ librados::AioCompletion* getCompletion() {
+ librados::AioCompletion* comp = librados::Rados::aio_create_completion();
+ m_completions.push_back(comp);
+ return comp;
+ }
+
+ ~Completions() {
+ for (auto& comp : m_completions) {
+ comp->release();
+ }
+ }
+
+private:
+ vector<librados::AioCompletion *> m_completions;
+};
+
+Completions completions;
+
+std::string LibRadosTwoPoolsPP::cache_pool_name;
+
+TEST_F(LibRadosTierPP, Dirty) {
+ {
+ ObjectWriteOperation op;
+ op.undirty();
+ ASSERT_EQ(0, ioctx.operate("foo", &op)); // still get 0 if it dne
+ }
+ {
+ ObjectWriteOperation op;
+ op.create(true);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ }
+ {
+ ObjectWriteOperation op;
+ op.undirty();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.undirty();
+ ASSERT_EQ(0, ioctx.operate("foo", &op)); // still 0 if already clean
+ }
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+ {
+ ObjectWriteOperation op;
+ op.truncate(0); // still a write even tho it is a no-op
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, Overlay) {
+ // create objects
+ {
+ bufferlist bl;
+ bl.append("base");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("cache");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // by default, the overlay sends us to cache pool
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // unless we say otherwise
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(0, 1, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ ASSERT_EQ('b', bl[0]);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, Promote) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ }
+
+ // read, trigger a whiteout
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, PromoteSnap) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote on the head
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ ioctx.snap_set_read(my_snaps[0]);
+
+ // read foo snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // read bar snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // read baz snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+
+ // read foo
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // read bar
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // read baz
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("baz", bl, 1, 0));
+ }
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTwoPoolsPP, PromoteSnapScrub) {
+ int num = 100;
+
+ // create objects
+ for (int i=0; i<num; ++i) {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate(string("foo") + stringify(i), &op));
+ }
+
+ vector<uint64_t> my_snaps;
+ for (int snap=0; snap<4; ++snap) {
+ // create a snapshot, clone
+ vector<uint64_t> ns(1);
+ ns.insert(ns.end(), my_snaps.begin(), my_snaps.end());
+ my_snaps.swap(ns);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ cout << "my_snaps " << my_snaps << std::endl;
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ for (int i=0; i<num; ++i) {
+ bufferlist bl;
+ bl.append(string("ciao! snap") + stringify(snap));
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate(string("foo") + stringify(i), &op));
+ }
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote on _some_ heads to make sure we handle cases
+ // where snaps are present and where they are not.
+ cout << "promoting some heads" << std::endl;
+ for (int i=0; i<num; ++i) {
+ if (i % 5 == 0 || i > num - 3) {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read(string("foo") + stringify(i), bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ }
+
+ for (unsigned snap = 0; snap < my_snaps.size(); ++snap) {
+ cout << "promoting from clones for snap " << my_snaps[snap] << std::endl;
+ ioctx.snap_set_read(my_snaps[snap]);
+
+ // read some snaps, semi-randomly
+ for (int i=0; i<50; ++i) {
+ bufferlist bl;
+ string o = string("foo") + stringify((snap * i * 137) % 80);
+ //cout << o << std::endl;
+ ASSERT_EQ(1, ioctx.read(o, bl, 1, 0));
+ }
+ }
+
+ // ok, stop and scrub this pool (to make sure scrub can handle
+ // missing clones in the cache tier).
+ {
+ IoCtx cache_ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ for (int i=0; i<10; ++i) {
+ do {
+ ostringstream ss;
+ ss << "{\"prefix\": \"pg scrub\", \"pgid\": \""
+ << cache_ioctx.get_id() << "." << i
+ << "\"}";
+ int r = cluster.mon_command(ss.str(), inbl, NULL, NULL);
+ if (r == -ENOENT || // in case mgr osdmap is stale
+ r == -EAGAIN) {
+ sleep(5);
+ continue;
+ }
+ } while (false);
+ }
+
+ // give it a few seconds to go. this is sloppy but is usually enough time
+ cout << "waiting for scrubs..." << std::endl;
+ sleep(30);
+ cout << "done waiting" << std::endl;
+ }
+
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+
+ //cleanup
+ for (unsigned snap = 0; snap < my_snaps.size(); ++snap) {
+ ioctx.selfmanaged_snap_remove(my_snaps[snap]);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, PromoteSnapTrimRace) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // delete the snap
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps[0]));
+
+ ioctx.snap_set_read(my_snaps[0]);
+
+ // read foo snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("foo", bl, 1, 0));
+ }
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTwoPoolsPP, Whiteout) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create some whiteouts, verify they behave
+ {
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.remove();
+ ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.remove();
+ ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
+ }
+
+ // verify the whiteouts are there in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // delete a whiteout and verify it goes away
+ ASSERT_EQ(-ENOENT, ioctx.remove("foo"));
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // recreate an object and verify we can read it
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, WhiteoutDeleteCreate) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create an object
+ {
+ bufferlist bl;
+ bl.append("foo");
+ ASSERT_EQ(0, ioctx.write_full("foo", bl));
+ }
+
+ // do delete + create operation
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ bufferlist bl;
+ bl.append("bar");
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify it still "exists" (w/ new content)
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('b', bl[0]);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, Evict) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ }
+
+ // read, trigger a whiteout, and a dirty object
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(0, ioctx.write("bar", bl, bl.length(), 0));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // pin
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict the pinned object with -EPERM
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE,
+ NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EPERM, completion->get_return_value());
+ completion->release();
+ }
+
+ // unpin
+ {
+ ObjectWriteOperation op;
+ op.cache_unpin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify clean
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE,
+ NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, EvictSnap) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote on the head
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // evict bam
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "bam", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "bam", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-ENOENT, completion->get_return_value());
+ completion->release();
+ }
+
+ // read foo snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // evict foo snap
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // snap is gone...
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-ENOENT, completion->get_return_value());
+ completion->release();
+ }
+ // head is still there...
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // promote head + snap of bar
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // evict bar head (fail)
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict bar snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // ...and then head
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+// this test case reproduces http://tracker.ceph.com/issues/8629
+TEST_F(LibRadosTwoPoolsPP, EvictSnap2) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote on the head
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify the snapdir is not present in the cache pool
+ {
+ ObjectReadOperation op;
+ librados::snap_set_t snapset;
+ op.list_snaps(&snapset, NULL);
+ ioctx.snap_set_read(librados::SNAP_DIR);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-ENOENT, completion->get_return_value());
+ completion->release();
+ }
+}
+
+//This test case reproduces http://tracker.ceph.com/issues/17445
+TEST_F(LibRadosTwoPoolsPP, ListSnap){
+ // Create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // Create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // Configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // Wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // Read, trigger a promote on the head
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // Read foo snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // Evict foo snap
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // Snap is gone...
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-ENOENT, completion->get_return_value());
+ completion->release();
+ }
+
+ // Do list-snaps
+ ioctx.snap_set_read(CEPH_SNAPDIR);
+ {
+ snap_set_t snap_set;
+ int snap_ret;
+ ObjectReadOperation op;
+ op.list_snaps(&snap_set, &snap_ret);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ 0, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, snap_ret);
+ ASSERT_LT(0u, snap_set.clones.size());
+ for (vector<librados::clone_info_t>::const_iterator r = snap_set.clones.begin();
+ r != snap_set.clones.end();
+ ++r) {
+ if (r->cloneid != librados::SNAP_HEAD) {
+ ASSERT_LT(0u, r->snaps.size());
+ }
+ }
+ }
+
+ // Cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTwoPoolsPP, TryFlush) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // verify dirty
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // pin
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush the pinned object with -EPERM
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EPERM, completion->get_return_value());
+ completion->release();
+ }
+
+ // unpin
+ {
+ ObjectWriteOperation op;
+ op.cache_unpin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify clean
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // verify in base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it != ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // evict it
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, Flush) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ uint64_t user_version = 0;
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // verify dirty
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ user_version = cache_ioctx.get_last_version();
+ }
+
+ // pin
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush the pinned object with -EPERM
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EPERM, completion->get_return_value());
+ completion->release();
+ }
+
+ // unpin
+ {
+ ObjectWriteOperation op;
+ op.cache_unpin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify clean
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // verify in base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it != ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // evict it
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // read it again and verify the version is consistent
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ(user_version, cache_ioctx.get_last_version());
+ }
+
+ // erase it
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush whiteout
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+ // or base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, FlushSnap) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("a");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("b");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // and another
+ my_snaps.resize(2);
+ my_snaps[1] = my_snaps[0];
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("c");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // flush on head (should fail)
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+ // flush on recent snap (should fail)
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+ // flush on oldest snap
+ ioctx.snap_set_read(my_snaps[1]);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // flush on next oldest snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // flush on head
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify i can read the snaps from the cache pool
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('b', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[1]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('a', bl[0]);
+ }
+
+ // remove overlay
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // verify i can read the snaps from the base pool
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('b', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[1]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('a', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTierPP, FlushWriteRaces) {
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ std::string cache_pool_name = pool_name + "-cache";
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str()));
+ IoCtx cache_ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ cache_ioctx.application_enable("rados", true);
+ IoCtx ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ bufferlist bl;
+ bl.append("hi there");
+ {
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush + write
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ ObjectWriteOperation op2;
+ op2.write_full(bl);
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion2, &op2, 0));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+
+ int tries = 1000;
+ do {
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // try-flush + write
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ ObjectWriteOperation op2;
+ op2.write_full(bl);
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion2, &op2, 0));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ int r = completion->get_return_value();
+ ASSERT_TRUE(r == -EBUSY || r == 0);
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ if (r == -EBUSY)
+ break;
+ cout << "didn't get EBUSY, trying again" << std::endl;
+ }
+ ASSERT_TRUE(--tries);
+ } while (true);
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+
+ ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str()));
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}
+
+TEST_F(LibRadosTwoPoolsPP, FlushTryFlushRaces) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush + flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush + try-flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_try_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+
+ // create/dirty object
+ int tries = 1000;
+ do {
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // try-flush + flush
+ // (flush will not piggyback on try-flush)
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ int r = completion->get_return_value();
+ ASSERT_TRUE(r == -EBUSY || r == 0);
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ if (r == -EBUSY)
+ break;
+ cout << "didn't get EBUSY, trying again" << std::endl;
+ }
+ ASSERT_TRUE(--tries);
+ } while (true);
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // try-flush + try-flush
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_try_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+}
+
+
+IoCtx *read_ioctx = 0;
+Mutex test_lock("FlushReadRaces::lock");
+Cond cond;
+int max_reads = 100;
+int num_reads = 0; // in progress
+
+void flush_read_race_cb(completion_t cb, void *arg);
+
+void start_flush_read()
+{
+ //cout << " starting read" << std::endl;
+ ObjectReadOperation op;
+ op.stat(NULL, NULL, NULL);
+ librados::AioCompletion *completion = completions.getCompletion();
+ completion->set_complete_callback(0, flush_read_race_cb);
+ read_ioctx->aio_operate("foo", completion, &op, NULL);
+}
+
+void flush_read_race_cb(completion_t cb, void *arg)
+{
+ //cout << " finished read" << std::endl;
+ test_lock.Lock();
+ if (num_reads > max_reads) {
+ num_reads--;
+ cond.Signal();
+ } else {
+ start_flush_read();
+ }
+ test_lock.Unlock();
+}
+
+TEST_F(LibRadosTwoPoolsPP, TryFlushReadRace) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ bufferptr bp(4000000); // make it big!
+ bp.zero();
+ bl.append(bp);
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // start a continuous stream of reads
+ read_ioctx = &ioctx;
+ test_lock.Lock();
+ for (int i = 0; i < max_reads; ++i) {
+ start_flush_read();
+ num_reads++;
+ }
+ test_lock.Unlock();
+
+ // try-flush
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+
+ // stop reads
+ test_lock.Lock();
+ max_reads = 0;
+ while (num_reads > 0)
+ cond.Wait(test_lock);
+ test_lock.Unlock();
+}
+
+TEST_F(LibRadosTierPP, HitSetNone) {
+ {
+ list< pair<time_t,time_t> > ls;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, ioctx.hit_set_list(123, c, &ls));
+ c->wait_for_complete();
+ ASSERT_EQ(0, c->get_return_value());
+ ASSERT_TRUE(ls.empty());
+ c->release();
+ }
+ {
+ bufferlist bl;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, ioctx.hit_set_get(123, c, 12345, &bl));
+ c->wait_for_complete();
+ ASSERT_EQ(-ENOENT, c->get_return_value());
+ c->release();
+ }
+}
+
+string set_pool_str(string pool, string var, string val)
+{
+ return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
+ + string("\",\"var\": \"") + var + string("\",\"val\": \"")
+ + val + string("\"}");
+}
+
+string set_pool_str(string pool, string var, int val)
+{
+ return string("{\"prefix\": \"osd pool set\",\"pool\":\"") + pool
+ + string("\",\"var\": \"") + var + string("\",\"val\": \"")
+ + stringify(val) + string("\"}");
+}
+
+TEST_F(LibRadosTwoPoolsPP, HitSetRead) {
+ // make it a tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type",
+ "explicit_object"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ cache_ioctx.set_namespace("");
+
+ // keep reading until we see our object appear in the HitSet
+ utime_t start = ceph_clock_now();
+ utime_t hard_stop = start + utime_t(600, 0);
+
+ while (true) {
+ utime_t now = ceph_clock_now();
+ ASSERT_TRUE(now < hard_stop);
+
+ string name = "foo";
+ uint32_t hash;
+ ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
+ hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash,
+ cluster.pool_lookup(cache_pool_name.c_str()), "");
+
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, cache_ioctx.read("foo", bl, 1, 0));
+
+ bufferlist hbl;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.hit_set_get(hash, c, now.sec(), &hbl));
+ c->wait_for_complete();
+ c->release();
+
+ if (hbl.length()) {
+ auto p = hbl.cbegin();
+ HitSet hs;
+ decode(hs, p);
+ if (hs.contains(oid)) {
+ cout << "ok, hit_set contains " << oid << std::endl;
+ break;
+ }
+ cout << "hmm, not in HitSet yet" << std::endl;
+ } else {
+ cout << "hmm, no HitSet yet" << std::endl;
+ }
+
+ sleep(1);
+ }
+}
+
+static int _get_pg_num(Rados& cluster, string pool_name)
+{
+ bufferlist inbl;
+ string cmd = string("{\"prefix\": \"osd pool get\",\"pool\":\"")
+ + pool_name
+ + string("\",\"var\": \"pg_num\",\"format\": \"json\"}");
+ bufferlist outbl;
+ int r = cluster.mon_command(cmd, inbl, &outbl, NULL);
+ ceph_assert(r >= 0);
+ string outstr(outbl.c_str(), outbl.length());
+ json_spirit::Value v;
+ if (!json_spirit::read(outstr, v)) {
+ cerr <<" unable to parse json " << outstr << std::endl;
+ return -1;
+ }
+
+ json_spirit::Object& o = v.get_obj();
+ for (json_spirit::Object::size_type i=0; i<o.size(); i++) {
+ json_spirit::Pair& p = o[i];
+ if (p.name_ == "pg_num") {
+ cout << "pg_num = " << p.value_.get_int() << std::endl;
+ return p.value_.get_int();
+ }
+ }
+ cerr << "didn't find pg_num in " << outstr << std::endl;
+ return -1;
+}
+
+
+TEST_F(LibRadosTwoPoolsPP, HitSetWrite) {
+ int num_pg = _get_pg_num(cluster, pool_name);
+ ceph_assert(num_pg > 0);
+
+ // make it a tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 8),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type",
+ "explicit_hash"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ cache_ioctx.set_namespace("");
+
+ int num = 200;
+
+ // do a bunch of writes
+ for (int i=0; i<num; ++i) {
+ bufferlist bl;
+ bl.append("a");
+ ASSERT_EQ(0, cache_ioctx.write(stringify(i), bl, 1, 0));
+ }
+
+ // get HitSets
+ std::map<int,HitSet> hitsets;
+ for (int i=0; i<num_pg; ++i) {
+ list< pair<time_t,time_t> > ls;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.hit_set_list(i, c, &ls));
+ c->wait_for_complete();
+ c->release();
+ std::cout << "pg " << i << " ls " << ls << std::endl;
+ ASSERT_FALSE(ls.empty());
+
+ // get the latest
+ c = librados::Rados::aio_create_completion();
+ bufferlist bl;
+ ASSERT_EQ(0, cache_ioctx.hit_set_get(i, c, ls.back().first, &bl));
+ c->wait_for_complete();
+ c->release();
+
+ try {
+ auto p = bl.cbegin();
+ decode(hitsets[i], p);
+ }
+ catch (buffer::error& e) {
+ std::cout << "failed to decode hit set; bl len is " << bl.length() << "\n";
+ bl.hexdump(std::cout);
+ std::cout << std::endl;
+ throw e;
+ }
+
+ // cope with racing splits by refreshing pg_num
+ if (i == num_pg - 1)
+ num_pg = _get_pg_num(cluster, cache_pool_name);
+ }
+
+ for (int i=0; i<num; ++i) {
+ string n = stringify(i);
+ uint32_t hash;
+ ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(n, &hash));
+ hobject_t oid(sobject_t(n, CEPH_NOSNAP), "", hash,
+ cluster.pool_lookup(cache_pool_name.c_str()), "");
+ std::cout << "checking for " << oid << std::endl;
+ bool found = false;
+ for (int p=0; p<num_pg; ++p) {
+ if (hitsets[p].contains(oid)) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(found);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, HitSetTrim) {
+ unsigned count = 3;
+ unsigned period = 3;
+
+ // make it a tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", count),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", period),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_fpp", ".01"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ cache_ioctx.set_namespace("");
+
+ // do a bunch of writes and make sure the hitsets rotate
+ utime_t start = ceph_clock_now();
+ utime_t hard_stop = start + utime_t(count * period * 50, 0);
+
+ time_t first = 0;
+ while (true) {
+ string name = "foo";
+ uint32_t hash;
+ ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
+ hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash, -1, "");
+
+ bufferlist bl;
+ bl.append("f");
+ ASSERT_EQ(0, cache_ioctx.write("foo", bl, 1, 0));
+
+ list<pair<time_t, time_t> > ls;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.hit_set_list(hash, c, &ls));
+ c->wait_for_complete();
+ c->release();
+
+ cout << " got ls " << ls << std::endl;
+ if (!ls.empty()) {
+ if (!first) {
+ first = ls.front().first;
+ cout << "first is " << first << std::endl;
+ } else {
+ if (ls.front().first != first) {
+ cout << "first now " << ls.front().first << ", trimmed" << std::endl;
+ break;
+ }
+ }
+ }
+
+ utime_t now = ceph_clock_now();
+ ASSERT_TRUE(now < hard_stop);
+
+ sleep(1);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsPP, PromoteOn2ndRead) {
+ // create object
+ for (int i=0; i<20; ++i) {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo" + stringify(i), &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_grade_decay_rate", 20),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_search_last_n", 1),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ int fake = 0; // set this to non-zero to test spurious promotion,
+ // e.g. from thrashing
+ int attempt = 0;
+ string obj;
+ while (true) {
+ // 1st read, don't trigger a promote
+ obj = "foo" + stringify(attempt);
+ cout << obj << std::endl;
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
+ if (--fake >= 0) {
+ sleep(1);
+ ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
+ sleep(1);
+ }
+ }
+
+ // verify the object is NOT present in the cache tier
+ {
+ bool found = false;
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ while (it != cache_ioctx.nobjects_end()) {
+ cout << " see " << it->get_oid() << std::endl;
+ if (it->get_oid() == string(obj.c_str())) {
+ found = true;
+ break;
+ }
+ ++it;
+ }
+ if (!found)
+ break;
+ }
+
+ ++attempt;
+ ASSERT_LE(attempt, 20);
+ cout << "hrm, object is present in cache on attempt " << attempt
+ << ", retrying" << std::endl;
+ }
+
+ // Read until the object is present in the cache tier
+ cout << "verifying " << obj << " is eventually promoted" << std::endl;
+ while (true) {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
+
+ bool there = false;
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ while (it != cache_ioctx.nobjects_end()) {
+ if (it->get_oid() == string(obj.c_str())) {
+ there = true;
+ break;
+ }
+ ++it;
+ }
+ if (there)
+ break;
+
+ sleep(1);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, ProxyRead) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"readproxy\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // Verify 10 times the object is NOT present in the cache tier
+ uint32_t i = 0;
+ while (i++ < 10) {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ sleep(1);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, CachePin) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger promote
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
+ ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
+ }
+
+ // verify the objects are present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ for (uint32_t i = 0; i < 4; i++) {
+ ASSERT_TRUE(it->get_oid() == string("foo") ||
+ it->get_oid() == string("bar") ||
+ it->get_oid() == string("baz") ||
+ it->get_oid() == string("bam"));
+ ++it;
+ }
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // pin objects
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("baz", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // enable agent
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "target_max_objects", 1),
+ inbl, NULL, NULL));
+
+ sleep(10);
+
+ // Verify the pinned object 'foo' is not flushed/evicted
+ uint32_t count = 0;
+ while (true) {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
+
+ count = 0;
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ while (it != cache_ioctx.nobjects_end()) {
+ ASSERT_TRUE(it->get_oid() == string("foo") ||
+ it->get_oid() == string("bar") ||
+ it->get_oid() == string("baz") ||
+ it->get_oid() == string("bam"));
+ ++count;
+ ++it;
+ }
+ if (count == 2) {
+ ASSERT_TRUE(it->get_oid() == string("foo") ||
+ it->get_oid() == string("baz"));
+ break;
+ }
+
+ sleep(1);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, SetRedirectRead) {
+ // skip test if not yet luminous
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("luminous") == std::string::npos) {
+ cout << "cluster is not yet luminous, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+
+ // configure tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ {
+ ObjectWriteOperation op;
+ op.set_redirect("bar", cache_ioctx, 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('t', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, SetChunkRead) {
+ // skip test if not yet mimic
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("mimic") == std::string::npos) {
+ cout << "cluster is not yet mimic, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ ObjectWriteOperation op;
+ op.create(true);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+
+ // configure tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set_chunk
+ {
+ ObjectWriteOperation op;
+ int len = strlen("hi there");
+ for (int i = 0; i < len; i+=2) {
+ op.set_chunk(i, 2, cache_ioctx, "bar", i);
+ }
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // make all chunks dirty --> full flush --> all chunks are evicted
+ {
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('T', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, ManifestPromoteRead) {
+ // skip test if not yet mimic
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("mimic") == std::string::npos) {
+ cout << "cluster is not yet mimic, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("base chunk");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("CHUNK");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
+ }
+
+ // configure tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set-redirect
+ {
+ ObjectWriteOperation op;
+ op.set_redirect("bar", cache_ioctx, 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // set-chunk
+ {
+ ObjectWriteOperation op;
+ op.set_chunk(0, 2, cache_ioctx, "bar-chunk", 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // promote
+ {
+ ObjectWriteOperation op;
+ op.tier_promote();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // read and verify the object (redirect)
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('t', bl[0]);
+ }
+ // promote
+ {
+ ObjectWriteOperation op;
+ op.tier_promote();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo-chunk", bl, 1, 0));
+ ASSERT_EQ('C', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, ManifestRefRead) {
+ // skip test if not yet mimic
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("mimic") == std::string::npos) {
+ cout << "cluster is not yet mimic, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("base chunk");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("CHUNK");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
+ }
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set-redirect
+ {
+ ObjectWriteOperation op;
+ op.set_redirect("bar", cache_ioctx, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // set-chunk
+ {
+ ObjectWriteOperation op;
+ op.set_chunk(0, 2, cache_ioctx, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // redirect's refcount
+ {
+ bufferlist in, out;
+ cache_ioctx.exec("bar", "cas", "chunk_read", in, out);
+ cls_chunk_refcount_read_ret read_ret;
+ try {
+ auto iter = out.cbegin();
+ decode(read_ret, iter);
+ } catch (buffer::error& err) {
+ ASSERT_TRUE(0);
+ }
+ ASSERT_EQ(1U, read_ret.refs.size());
+ }
+ // chunk's refcount
+ {
+ bufferlist in, out;
+ cache_ioctx.exec("bar-chunk", "cas", "chunk_read", in, out);
+ cls_chunk_refcount_read_ret read_ret;
+ try {
+ auto iter = out.cbegin();
+ decode(read_ret, iter);
+ } catch (buffer::error& err) {
+ ASSERT_TRUE(0);
+ }
+ ASSERT_EQ(1u, read_ret.refs.size());
+ }
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, ManifestUnset) {
+ // skip test if not yet nautilus
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("nautilus") == std::string::npos) {
+ cout << "cluster is not yet nautilus, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("base chunk");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("CHUNK");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
+ }
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set-redirect
+ {
+ ObjectWriteOperation op;
+ op.set_redirect("bar", cache_ioctx, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // set-chunk
+ {
+ ObjectWriteOperation op;
+ op.set_chunk(0, 2, cache_ioctx, "bar-chunk", 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // redirect's refcount
+ {
+ bufferlist in, out;
+ cache_ioctx.exec("bar", "cas", "chunk_read", in, out);
+ cls_chunk_refcount_read_ret read_ret;
+ try {
+ auto iter = out.cbegin();
+ decode(read_ret, iter);
+ } catch (buffer::error& err) {
+ ASSERT_TRUE(0);
+ }
+ ASSERT_EQ(1u, read_ret.refs.size());
+ }
+ // chunk's refcount
+ {
+ bufferlist in, out;
+ cache_ioctx.exec("bar-chunk", "cas", "chunk_read", in, out);
+ cls_chunk_refcount_read_ret read_ret;
+ try {
+ auto iter = out.cbegin();
+ decode(read_ret, iter);
+ } catch (buffer::error& err) {
+ ASSERT_TRUE(0);
+ }
+ ASSERT_EQ(1u, read_ret.refs.size());
+ }
+
+ // unset-manifest for set-redirect
+ {
+ ObjectWriteOperation op;
+ op.unset_manifest();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // unset-manifest for set-chunk
+ {
+ ObjectWriteOperation op;
+ op.unset_manifest();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // redirect's refcount
+ {
+ bufferlist in, out;
+ cache_ioctx.exec("bar", "cas", "chunk_read", in, out);
+ if (out.length() != 0U) {
+ ObjectWriteOperation op;
+ op.unset_manifest();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EOPNOTSUPP, completion->get_return_value());
+ completion->release();
+ }
+ }
+ // chunk's refcount
+ {
+ bufferlist in, out;
+ cache_ioctx.exec("bar-chunk", "cas", "chunk_read", in, out);
+ if (out.length() != 0U) {
+ ObjectWriteOperation op;
+ op.unset_manifest();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EOPNOTSUPP, completion->get_return_value());
+ completion->release();
+ }
+ }
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+#include "common/ceph_crypto.h"
+using ceph::crypto::SHA1;
+#include "rgw/rgw_common.h"
+TEST_F(LibRadosTwoPoolsPP, ManifestDedupRefRead) {
+ // skip test if not yet nautilus
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("nautilus") == std::string::npos) {
+ cout << "cluster is not yet nautilus, skipping test" << std::endl;
+ return;
+ }
+ }
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(pool_name, "fingerprint_algorithm", "sha1"),
+ inbl, NULL, NULL));
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("CHUNK");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
+ }
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set-chunk (dedup)
+ {
+ ObjectWriteOperation op;
+ int len = strlen("hi there");
+ op.set_chunk(0, len, cache_ioctx, "bar-chunk", 0,
+ CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-dedup", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // set-chunk (dedup)
+ {
+ ObjectWriteOperation op;
+ int len = strlen("hi there");
+ op.set_chunk(0, len, cache_ioctx, "bar", 0,
+ CEPH_OSD_OP_FLAG_WITH_REFERENCE);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // make all chunks dirty --> flush
+ {
+ // make a dirty chunks
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
+ }
+ {
+ // do flush
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo-dedup", &op));
+ }
+ {
+ // make a dirty chunks
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ // do flush
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ // chunk's refcount
+ {
+ bufferlist in, out;
+ SHA1 sha1_gen;
+ int size = strlen("There hi");
+ unsigned char fingerprint[CEPH_CRYPTO_SHA1_DIGESTSIZE + 1];
+ char p_str[CEPH_CRYPTO_SHA1_DIGESTSIZE*2+1] = {0};
+ sha1_gen.Update((const unsigned char *)"There hi", size);
+ sha1_gen.Final(fingerprint);
+ buf_to_hex(fingerprint, CEPH_CRYPTO_SHA1_DIGESTSIZE, p_str);
+ cache_ioctx.exec(p_str, "cas", "chunk_read", in, out);
+ cls_chunk_refcount_read_ret read_ret;
+ try {
+ auto iter = out.cbegin();
+ decode(read_ret, iter);
+ } catch (buffer::error& err) {
+ ASSERT_TRUE(0);
+ }
+ ASSERT_EQ(2u, read_ret.refs.size());
+ }
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+class LibRadosTwoPoolsECPP : public RadosTestECPP
+{
+public:
+ LibRadosTwoPoolsECPP() {};
+ ~LibRadosTwoPoolsECPP() override {};
+protected:
+ static void SetUpTestCase() {
+ pool_name = get_temp_pool_name();
+ ASSERT_EQ("", create_one_ec_pool_pp(pool_name, s_cluster));
+ }
+ static void TearDownTestCase() {
+ ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name, s_cluster));
+ }
+ static std::string cache_pool_name;
+
+ void SetUp() override {
+ cache_pool_name = get_temp_pool_name();
+ ASSERT_EQ(0, s_cluster.pool_create(cache_pool_name.c_str()));
+ RadosTestECPP::SetUp();
+
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ cache_ioctx.application_enable("rados", true);
+ cache_ioctx.set_namespace(nspace);
+ }
+ void TearDown() override {
+ // flush + evict cache
+ flush_evict_all(cluster, cache_ioctx);
+
+ bufferlist inbl;
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+
+ RadosTestECPP::TearDown();
+
+ cleanup_default_namespace(cache_ioctx);
+ cleanup_namespace(cache_ioctx, nspace);
+
+ cache_ioctx.close();
+ ASSERT_EQ(0, s_cluster.pool_delete(cache_pool_name.c_str()));
+ }
+
+ librados::IoCtx cache_ioctx;
+};
+
+std::string LibRadosTwoPoolsECPP::cache_pool_name;
+
+TEST_F(LibRadosTierECPP, Dirty) {
+ {
+ ObjectWriteOperation op;
+ op.undirty();
+ ASSERT_EQ(0, ioctx.operate("foo", &op)); // still get 0 if it dne
+ }
+ {
+ ObjectWriteOperation op;
+ op.create(true);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ }
+ {
+ ObjectWriteOperation op;
+ op.undirty();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.undirty();
+ ASSERT_EQ(0, ioctx.operate("foo", &op)); // still 0 if already clean
+ }
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+ //{
+ // ObjectWriteOperation op;
+ // op.truncate(0); // still a write even tho it is a no-op
+ // ASSERT_EQ(0, ioctx.operate("foo", &op));
+ //}
+ //{
+ // bool dirty = false;
+ // int r = -1;
+ // ObjectReadOperation op;
+ // op.is_dirty(&dirty, &r);
+ // ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
+ // ASSERT_TRUE(dirty);
+ // ASSERT_EQ(0, r);
+ //}
+}
+
+TEST_F(LibRadosTwoPoolsECPP, Overlay) {
+ // create objects
+ {
+ bufferlist bl;
+ bl.append("base");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("cache");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // by default, the overlay sends us to cache pool
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // unless we say otherwise
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(0, 1, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ ASSERT_EQ('b', bl[0]);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, Promote) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ }
+
+ // read, trigger a whiteout
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, PromoteSnap) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote on the head
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ ioctx.snap_set_read(my_snaps[0]);
+
+ // stop and scrub this pg (to make sure scrub can handle missing
+ // clones in the cache tier)
+ // This test requires cache tier and base tier to have the same pg_num/pgp_num
+ {
+ for (int tries = 0; tries < 5; ++tries) {
+ IoCtx cache_ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ uint32_t hash;
+ ASSERT_EQ(0, ioctx.get_object_pg_hash_position2("foo", &hash));
+ ostringstream ss;
+ ss << "{\"prefix\": \"pg scrub\", \"pgid\": \""
+ << cache_ioctx.get_id() << "."
+ << hash
+ << "\"}";
+ int r = cluster.mon_command(ss.str(), inbl, NULL, NULL);
+ if (r == -EAGAIN ||
+ r == -ENOENT) { // in case mgr osdmap is a bit stale
+ sleep(5);
+ continue;
+ }
+ ASSERT_EQ(0, r);
+ break;
+ }
+ // give it a few seconds to go. this is sloppy but is usually enough time
+ cout << "waiting for scrub..." << std::endl;
+ sleep(15);
+ cout << "done waiting" << std::endl;
+ }
+
+ // read foo snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // read bar snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // read baz snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+
+ // read foo
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // read bar
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // read baz
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("baz", bl, 1, 0));
+ }
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTwoPoolsECPP, PromoteSnapTrimRace) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // delete the snap
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(my_snaps[0]));
+
+ ioctx.snap_set_read(my_snaps[0]);
+
+ // read foo snap
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("foo", bl, 1, 0));
+ }
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTwoPoolsECPP, Whiteout) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create some whiteouts, verify they behave
+ {
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ {
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.remove();
+ ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.assert_exists();
+ op.remove();
+ ASSERT_EQ(-ENOENT, ioctx.operate("bar", &op));
+ }
+
+ // verify the whiteouts are there in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // delete a whiteout and verify it goes away
+ ASSERT_EQ(-ENOENT, ioctx.remove("foo"));
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // recreate an object and verify we can read it
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, Evict) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ }
+
+ // read, trigger a whiteout, and a dirty object
+ {
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(-ENOENT, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(0, ioctx.write("bar", bl, bl.length(), 0));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it->get_oid() == string("foo") || it->get_oid() == string("bar"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // pin
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict the pinned object with -EPERM
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE,
+ NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EPERM, completion->get_return_value());
+ completion->release();
+ }
+
+ // unpin
+ {
+ ObjectWriteOperation op;
+ op.cache_unpin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify clean
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE,
+ NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, EvictSnap) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("ciao!");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger a promote on the head
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+
+ // evict bam
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "bam", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "bam", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-ENOENT, completion->get_return_value());
+ completion->release();
+ }
+
+ // read foo snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // evict foo snap
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // snap is gone...
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-ENOENT, completion->get_return_value());
+ completion->release();
+ }
+ // head is still there...
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // promote head + snap of bar
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // evict bar head (fail)
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict bar snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // ...and then head
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ObjectReadOperation op;
+ op.read(1, 0, &bl, NULL);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "bar", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTwoPoolsECPP, TryFlush) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // verify dirty
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // pin
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush the pinned object with -EPERM
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EPERM, completion->get_return_value());
+ completion->release();
+ }
+
+ // unpin
+ {
+ ObjectWriteOperation op;
+ op.cache_unpin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify clean
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // verify in base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it != ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // evict it
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, FailedFlush) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // set omap
+ {
+ ObjectWriteOperation op;
+ std::map<std::string, bufferlist> omap;
+ omap["somekey"] = bufferlist();
+ op.omap_set(omap);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_NE(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // get omap
+ {
+ ObjectReadOperation op;
+ bufferlist bl;
+ int prval = 0;
+ std::set<std::string> keys;
+ keys.insert("somekey");
+ std::map<std::string, bufferlist> map;
+
+ op.omap_get_vals_by_keys(keys, &map, &prval);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op, &bl));
+ sleep(5);
+ bool completed = completion->is_complete();
+ if( !completed ) {
+ cache_ioctx.aio_cancel(completion);
+ std::cerr << "Most probably test case will hang here, please reset manually" << std::endl;
+ ASSERT_TRUE(completed); //in fact we are locked forever at test case shutdown unless fix for http://tracker.ceph.com/issues/14511 is applied. Seems there is no workaround for that
+ }
+ completion->release();
+ }
+ // verify still not in base tier
+ {
+ ASSERT_TRUE(ioctx.nobjects_begin() == ioctx.nobjects_end());
+ }
+ // erase it
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ // flush whiteout
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+ // or base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, Flush) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ uint64_t user_version = 0;
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // verify dirty
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_TRUE(dirty);
+ ASSERT_EQ(0, r);
+ user_version = cache_ioctx.get_last_version();
+ }
+
+ // pin
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush the pinned object with -EPERM
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EPERM, completion->get_return_value());
+ completion->release();
+ }
+
+ // unpin
+ {
+ ObjectWriteOperation op;
+ op.cache_unpin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify clean
+ {
+ bool dirty = false;
+ int r = -1;
+ ObjectReadOperation op;
+ op.is_dirty(&dirty, &r);
+ ASSERT_EQ(0, cache_ioctx.operate("foo", &op, NULL));
+ ASSERT_FALSE(dirty);
+ ASSERT_EQ(0, r);
+ }
+
+ // verify in base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it != ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // evict it
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // read it again and verify the version is consistent
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, cache_ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ(user_version, cache_ioctx.get_last_version());
+ }
+
+ // erase it
+ {
+ ObjectWriteOperation op;
+ op.remove();
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush whiteout
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op, librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify no longer in cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+ // or base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, FlushSnap) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("a");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // create a snapshot, clone
+ vector<uint64_t> my_snaps(1);
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("b");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // and another
+ my_snaps.resize(2);
+ my_snaps[1] = my_snaps[0];
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&my_snaps[0]));
+ ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(my_snaps[0],
+ my_snaps));
+ {
+ bufferlist bl;
+ bl.append("c");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // verify the object is present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // verify the object is NOT present in the base tier
+ {
+ NObjectIterator it = ioctx.nobjects_begin();
+ ASSERT_TRUE(it == ioctx.nobjects_end());
+ }
+
+ // flush on head (should fail)
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+ // flush on recent snap (should fail)
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(-EBUSY, completion->get_return_value());
+ completion->release();
+ }
+ // flush on oldest snap
+ ioctx.snap_set_read(my_snaps[1]);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // flush on next oldest snap
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // flush on head
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // verify i can read the snaps from the cache pool
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('b', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[1]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('a', bl[0]);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // verify i can read the snaps from the base pool
+ ioctx.snap_set_read(librados::SNAP_HEAD);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('c', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[0]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('b', bl[0]);
+ }
+ ioctx.snap_set_read(my_snaps[1]);
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('a', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ cluster.wait_for_latest_osdmap();
+
+ // cleanup
+ ioctx.selfmanaged_snap_remove(my_snaps[0]);
+}
+
+TEST_F(LibRadosTierECPP, FlushWriteRaces) {
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ std::string cache_pool_name = pool_name + "-cache";
+ ASSERT_EQ("", create_one_pool_pp(pool_name, cluster));
+ ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str()));
+ IoCtx cache_ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ cache_ioctx.application_enable("rados", true);
+ IoCtx ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ bufferlist bl;
+ bl.append("hi there");
+ {
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush + write
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ ObjectWriteOperation op2;
+ op2.write_full(bl);
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate(
+ "foo", completion2, &op2, 0));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+
+ int tries = 1000;
+ do {
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // try-flush + write
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ ObjectWriteOperation op2;
+ op2.write_full(bl);
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion2, &op2, 0));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ int r = completion->get_return_value();
+ ASSERT_TRUE(r == -EBUSY || r == 0);
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ if (r == -EBUSY)
+ break;
+ cout << "didn't get EBUSY, trying again" << std::endl;
+ }
+ ASSERT_TRUE(--tries);
+ } while (true);
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+
+ ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str()));
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}
+
+TEST_F(LibRadosTwoPoolsECPP, FlushTryFlushRaces) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush + flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush + try-flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_try_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+
+ // create/dirty object
+ int tries = 1000;
+ do {
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // try-flush + flush
+ // (flush will not piggyback on try-flush)
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ int r = completion->get_return_value();
+ ASSERT_TRUE(r == -EBUSY || r == 0);
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ if (r == -EBUSY)
+ break;
+ cout << "didn't get EBUSY, trying again" << std::endl;
+ }
+ ASSERT_TRUE(--tries);
+ } while (true);
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // try-flush + try-flush
+ {
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ ObjectReadOperation op2;
+ op2.cache_try_flush();
+ librados::AioCompletion *completion2 = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion2, &op2,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ completion->wait_for_safe();
+ completion2->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ ASSERT_EQ(0, completion2->get_return_value());
+ completion->release();
+ completion2->release();
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, TryFlushReadRace) {
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ bufferptr bp(4000000); // make it big!
+ bp.zero();
+ bl.append(bp);
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // start a continuous stream of reads
+ read_ioctx = &ioctx;
+ test_lock.Lock();
+ for (int i = 0; i < max_reads; ++i) {
+ start_flush_read();
+ num_reads++;
+ }
+ test_lock.Unlock();
+
+ // try-flush
+ ObjectReadOperation op;
+ op.cache_try_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY |
+ librados::OPERATION_SKIPRWLOCKS, NULL));
+
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+
+ // stop reads
+ test_lock.Lock();
+ max_reads = 0;
+ while (num_reads > 0)
+ cond.Wait(test_lock);
+ test_lock.Unlock();
+}
+
+TEST_F(LibRadosTierECPP, CallForcesPromote) {
+ Rados cluster;
+ std::string pool_name = get_temp_pool_name();
+ std::string cache_pool_name = pool_name + "-cache";
+ ASSERT_EQ("", create_one_ec_pool_pp(pool_name, cluster));
+ ASSERT_EQ(0, cluster.pool_create(cache_pool_name.c_str()));
+ IoCtx cache_ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(cache_pool_name.c_str(), cache_ioctx));
+ cache_ioctx.application_enable("rados", true);
+ IoCtx ioctx;
+ ASSERT_EQ(0, cluster.ioctx_create(pool_name.c_str(), ioctx));
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // set things up such that the op would normally be proxied
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_type",
+ "explicit_object"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "min_read_recency_for_promote",
+ "4"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // create/dirty object
+ bufferlist bl;
+ bl.append("hi there");
+ {
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // flush
+ {
+ ObjectReadOperation op;
+ op.cache_flush();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate(
+ "foo", completion, &op,
+ librados::OPERATION_IGNORE_OVERLAY, NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // evict
+ {
+ ObjectReadOperation op;
+ op.cache_evict();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op,
+ librados::OPERATION_IGNORE_CACHE,
+ NULL));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // call
+ {
+ ObjectReadOperation op;
+ bufferlist bl;
+ op.exec("rbd", "get_id", bl);
+ bufferlist out;
+ // should get EIO (not an rbd object), not -EOPNOTSUPP (we didn't promote)
+ ASSERT_EQ(-5, ioctx.operate("foo", &op, &out));
+ }
+
+ // make sure foo is back in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ ASSERT_TRUE(it->get_oid() == string("foo"));
+ ++it;
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+
+ ASSERT_EQ(0, cluster.pool_delete(cache_pool_name.c_str()));
+ ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster));
+}
+
+TEST_F(LibRadosTierECPP, HitSetNone) {
+ {
+ list< pair<time_t,time_t> > ls;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, ioctx.hit_set_list(123, c, &ls));
+ c->wait_for_complete();
+ ASSERT_EQ(0, c->get_return_value());
+ ASSERT_TRUE(ls.empty());
+ c->release();
+ }
+ {
+ bufferlist bl;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, ioctx.hit_set_get(123, c, 12345, &bl));
+ c->wait_for_complete();
+ ASSERT_EQ(-ENOENT, c->get_return_value());
+ c->release();
+ }
+}
+
+TEST_F(LibRadosTwoPoolsECPP, HitSetRead) {
+ // make it a tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type",
+ "explicit_object"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ cache_ioctx.set_namespace("");
+
+ // keep reading until we see our object appear in the HitSet
+ utime_t start = ceph_clock_now();
+ utime_t hard_stop = start + utime_t(600, 0);
+
+ while (true) {
+ utime_t now = ceph_clock_now();
+ ASSERT_TRUE(now < hard_stop);
+
+ string name = "foo";
+ uint32_t hash;
+ ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
+ hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash,
+ cluster.pool_lookup(cache_pool_name.c_str()), "");
+
+ bufferlist bl;
+ ASSERT_EQ(-ENOENT, cache_ioctx.read("foo", bl, 1, 0));
+
+ bufferlist hbl;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.hit_set_get(hash, c, now.sec(), &hbl));
+ c->wait_for_complete();
+ c->release();
+
+ if (hbl.length()) {
+ auto p = hbl.cbegin();
+ HitSet hs;
+ decode(hs, p);
+ if (hs.contains(oid)) {
+ cout << "ok, hit_set contains " << oid << std::endl;
+ break;
+ }
+ cout << "hmm, not in HitSet yet" << std::endl;
+ } else {
+ cout << "hmm, no HitSet yet" << std::endl;
+ }
+
+ sleep(1);
+ }
+}
+
+// disable this test until hitset-get reliably works on EC pools
+#if 0
+TEST_F(LibRadosTierECPP, HitSetWrite) {
+ int num_pg = _get_pg_num(cluster, pool_name);
+ ceph_assert(num_pg > 0);
+
+ // enable hitset tracking for this pool
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_count", 8),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(pool_name, "hit_set_type",
+ "explicit_hash"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ ioctx.set_namespace("");
+
+ // do a bunch of writes
+ for (int i=0; i<1000; ++i) {
+ bufferlist bl;
+ bl.append("a");
+ ASSERT_EQ(0, ioctx.write(stringify(i), bl, 1, 0));
+ }
+
+ // get HitSets
+ std::map<int,HitSet> hitsets;
+ for (int i=0; i<num_pg; ++i) {
+ list< pair<time_t,time_t> > ls;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, ioctx.hit_set_list(i, c, &ls));
+ c->wait_for_complete();
+ c->release();
+ std::cout << "pg " << i << " ls " << ls << std::endl;
+ ASSERT_FALSE(ls.empty());
+
+ // get the latest
+ c = librados::Rados::aio_create_completion();
+ bufferlist bl;
+ ASSERT_EQ(0, ioctx.hit_set_get(i, c, ls.back().first, &bl));
+ c->wait_for_complete();
+ c->release();
+
+ //std::cout << "bl len is " << bl.length() << "\n";
+ //bl.hexdump(std::cout);
+ //std::cout << std::endl;
+
+ auto p = bl.cbegin();
+ decode(hitsets[i], p);
+
+ // cope with racing splits by refreshing pg_num
+ if (i == num_pg - 1)
+ num_pg = _get_pg_num(cluster, pool_name);
+ }
+
+ for (int i=0; i<1000; ++i) {
+ string n = stringify(i);
+ uint32_t hash = ioctx.get_object_hash_position(n);
+ hobject_t oid(sobject_t(n, CEPH_NOSNAP), "", hash,
+ cluster.pool_lookup(pool_name.c_str()), "");
+ std::cout << "checking for " << oid << std::endl;
+ bool found = false;
+ for (int p=0; p<num_pg; ++p) {
+ if (hitsets[p].contains(oid)) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(found);
+ }
+}
+#endif
+
+TEST_F(LibRadosTwoPoolsECPP, HitSetTrim) {
+ unsigned count = 3;
+ unsigned period = 3;
+
+ // make it a tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_count", count),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_period", period),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(set_pool_str(cache_pool_name, "hit_set_fpp", ".01"),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ cache_ioctx.set_namespace("");
+
+ // do a bunch of writes and make sure the hitsets rotate
+ utime_t start = ceph_clock_now();
+ utime_t hard_stop = start + utime_t(count * period * 50, 0);
+
+ time_t first = 0;
+ int bsize = alignment;
+ char *buf = (char *)new char[bsize];
+ memset(buf, 'f', bsize);
+
+ while (true) {
+ string name = "foo";
+ uint32_t hash;
+ ASSERT_EQ(0, cache_ioctx.get_object_hash_position2(name, &hash));
+ hobject_t oid(sobject_t(name, CEPH_NOSNAP), "", hash, -1, "");
+
+ bufferlist bl;
+ bl.append(buf, bsize);
+ ASSERT_EQ(0, cache_ioctx.append("foo", bl, bsize));
+
+ list<pair<time_t, time_t> > ls;
+ AioCompletion *c = librados::Rados::aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.hit_set_list(hash, c, &ls));
+ c->wait_for_complete();
+ c->release();
+
+ cout << " got ls " << ls << std::endl;
+ if (!ls.empty()) {
+ if (!first) {
+ first = ls.front().first;
+ cout << "first is " << first << std::endl;
+ } else {
+ if (ls.front().first != first) {
+ cout << "first now " << ls.front().first << ", trimmed" << std::endl;
+ break;
+ }
+ }
+ }
+
+ utime_t now = ceph_clock_now();
+ ASSERT_TRUE(now < hard_stop);
+
+ sleep(1);
+ }
+ delete[] buf;
+}
+
+TEST_F(LibRadosTwoPoolsECPP, PromoteOn2ndRead) {
+ // create object
+ for (int i=0; i<20; ++i) {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo" + stringify(i), &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // enable hitset tracking for this pool
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_grade_decay_rate", 20),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_search_last_n", 1),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ int fake = 0; // set this to non-zero to test spurious promotion,
+ // e.g. from thrashing
+ int attempt = 0;
+ string obj;
+ while (true) {
+ // 1st read, don't trigger a promote
+ obj = "foo" + stringify(attempt);
+ cout << obj << std::endl;
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
+ if (--fake >= 0) {
+ sleep(1);
+ ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
+ sleep(1);
+ }
+ }
+
+ // verify the object is NOT present in the cache tier
+ {
+ bool found = false;
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ while (it != cache_ioctx.nobjects_end()) {
+ cout << " see " << it->get_oid() << std::endl;
+ if (it->get_oid() == string(obj.c_str())) {
+ found = true;
+ break;
+ }
+ ++it;
+ }
+ if (!found)
+ break;
+ }
+
+ ++attempt;
+ ASSERT_LE(attempt, 20);
+ cout << "hrm, object is present in cache on attempt " << attempt
+ << ", retrying" << std::endl;
+ }
+
+ // Read until the object is present in the cache tier
+ cout << "verifying " << obj << " is eventually promoted" << std::endl;
+ while (true) {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read(obj.c_str(), bl, 1, 0));
+
+ bool there = false;
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ while (it != cache_ioctx.nobjects_end()) {
+ if (it->get_oid() == string(obj.c_str())) {
+ there = true;
+ break;
+ }
+ ++it;
+ }
+ if (there)
+ break;
+
+ sleep(1);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsECPP, ProxyRead) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"readproxy\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('h', bl[0]);
+ }
+
+ // Verify 10 times the object is NOT present in the cache tier
+ uint32_t i = 0;
+ while (i++ < 10) {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ sleep(1);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsECPP, CachePin) {
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("baz", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("bam", &op));
+ }
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // read, trigger promote
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ(1, ioctx.read("bar", bl, 1, 0));
+ ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
+ ASSERT_EQ(1, ioctx.read("bam", bl, 1, 0));
+ }
+
+ // verify the objects are present in the cache tier
+ {
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ ASSERT_TRUE(it != cache_ioctx.nobjects_end());
+ for (uint32_t i = 0; i < 4; i++) {
+ ASSERT_TRUE(it->get_oid() == string("foo") ||
+ it->get_oid() == string("bar") ||
+ it->get_oid() == string("baz") ||
+ it->get_oid() == string("bam"));
+ ++it;
+ }
+ ASSERT_TRUE(it == cache_ioctx.nobjects_end());
+ }
+
+ // pin objects
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ {
+ ObjectWriteOperation op;
+ op.cache_pin();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, cache_ioctx.aio_operate("baz", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // enable agent
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_count", 2),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "min_read_recency_for_promote", 1),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "target_max_objects", 1),
+ inbl, NULL, NULL));
+
+ sleep(10);
+
+ // Verify the pinned object 'foo' is not flushed/evicted
+ uint32_t count = 0;
+ while (true) {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("baz", bl, 1, 0));
+
+ count = 0;
+ NObjectIterator it = cache_ioctx.nobjects_begin();
+ while (it != cache_ioctx.nobjects_end()) {
+ ASSERT_TRUE(it->get_oid() == string("foo") ||
+ it->get_oid() == string("bar") ||
+ it->get_oid() == string("baz") ||
+ it->get_oid() == string("bam"));
+ ++count;
+ ++it;
+ }
+ if (count == 2) {
+ ASSERT_TRUE(it->get_oid() == string("foo") ||
+ it->get_oid() == string("baz"));
+ break;
+ }
+
+ sleep(1);
+ }
+
+ // tear down tiers
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove-overlay\", \"pool\": \"" + pool_name +
+ "\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+TEST_F(LibRadosTwoPoolsECPP, SetRedirectRead) {
+ // skip test if not yet luminous
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("luminous") == std::string::npos) {
+ cout << "cluster is not yet luminous, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+
+ // configure tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ {
+ ObjectWriteOperation op;
+ op.set_redirect("bar", cache_ioctx, 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('t', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsECPP, SetChunkRead) {
+ // skip test if not yet mimic
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("mimic") == std::string::npos) {
+ cout << "cluster is not yet mimic, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ ObjectWriteOperation op;
+ op.create(true);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+
+ // configure tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set_chunk
+ {
+ ObjectWriteOperation op;
+ op.set_chunk(0, 8, cache_ioctx, "bar", 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+
+ // make all chunks dirty --> full flush --> all chunks are evicted
+ {
+ bufferlist bl;
+ bl.append("There hi");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('T', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsECPP, ManifestPromoteRead) {
+ // skip test if not yet mimic
+ {
+ bufferlist inbl, outbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd dump\"}",
+ inbl, &outbl, NULL));
+ string s(outbl.c_str(), outbl.length());
+ if (s.find("mimic") == std::string::npos) {
+ cout << "cluster is not yet mimic, skipping test" << std::endl;
+ return;
+ }
+ }
+
+ // create object
+ {
+ bufferlist bl;
+ bl.append("hi there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, ioctx.operate("foo", &op));
+ }
+ {
+ ObjectWriteOperation op;
+ op.create(true);
+ ASSERT_EQ(0, ioctx.operate("foo-chunk", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("HI there");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar", &op));
+ }
+ {
+ bufferlist bl;
+ bl.append("BASE CHUNK");
+ ObjectWriteOperation op;
+ op.write_full(bl);
+ ASSERT_EQ(0, cache_ioctx.operate("bar-chunk", &op));
+ }
+
+ // configure tier
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // set-redirect
+ {
+ ObjectWriteOperation op;
+ op.set_redirect("bar", cache_ioctx, 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // set-chunk
+ {
+ ObjectWriteOperation op;
+ op.set_chunk(0, 10, cache_ioctx, "bar-chunk", 0);
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // promote
+ {
+ ObjectWriteOperation op;
+ op.tier_promote();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // read and verify the object (redirect)
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo", bl, 1, 0));
+ ASSERT_EQ('H', bl[0]);
+ }
+ // promote
+ {
+ ObjectWriteOperation op;
+ op.tier_promote();
+ librados::AioCompletion *completion = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_operate("foo-chunk", completion, &op));
+ completion->wait_for_safe();
+ ASSERT_EQ(0, completion->get_return_value());
+ completion->release();
+ }
+ // read and verify the object
+ {
+ bufferlist bl;
+ ASSERT_EQ(1, ioctx.read("foo-chunk", bl, 1, 0));
+ ASSERT_EQ('B', bl[0]);
+ }
+
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier remove\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ // wait for maps to settle before next test
+ cluster.wait_for_latest_osdmap();
+}
+
+TEST_F(LibRadosTwoPoolsPP, PropagateBaseTierError) {
+ // write object to base tier
+ bufferlist omap_bl;
+ encode(static_cast<uint32_t>(0U), omap_bl);
+
+ ObjectWriteOperation op1;
+ op1.omap_set({{"somekey", omap_bl}});
+ ASSERT_EQ(0, ioctx.operate("propagate-base-tier-error", &op1));
+
+ // configure cache
+ bufferlist inbl;
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier add\", \"pool\": \"" + pool_name +
+ "\", \"tierpool\": \"" + cache_pool_name +
+ "\", \"force_nonempty\": \"--force-nonempty\" }",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier cache-mode\", \"pool\": \"" + cache_pool_name +
+ "\", \"mode\": \"writeback\"}",
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ "{\"prefix\": \"osd tier set-overlay\", \"pool\": \"" + pool_name +
+ "\", \"overlaypool\": \"" + cache_pool_name + "\"}",
+ inbl, NULL, NULL));
+
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_type", "bloom"),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_count", 1),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "hit_set_period", 600),
+ inbl, NULL, NULL));
+ ASSERT_EQ(0, cluster.mon_command(
+ set_pool_str(cache_pool_name, "target_max_objects", 250),
+ inbl, NULL, NULL));
+
+ // wait for maps to settle
+ cluster.wait_for_latest_osdmap();
+
+ // guarded op should fail so expect error to propagate to cache tier
+ bufferlist test_omap_bl;
+ encode(static_cast<uint32_t>(1U), test_omap_bl);
+
+ ObjectWriteOperation op2;
+ op2.omap_cmp({{"somekey", {test_omap_bl, CEPH_OSD_CMPXATTR_OP_EQ}}}, nullptr);
+ op2.omap_set({{"somekey", test_omap_bl}});
+
+ ASSERT_EQ(-ECANCELED, ioctx.operate("propagate-base-tier-error", &op2));
+}
#include "include/rados/librados.h"
-#include "include/rados/librados.hpp"
#include "include/rados/rados_types.h"
#include "test/librados/test.h"
#include "test/librados/TestCase.h"
#include <set>
#include <map>
-using namespace librados;
-
typedef RadosTestEC LibRadosWatchNotifyEC;
-typedef RadosTestECPP LibRadosWatchNotifyECPP;
int notify_sleep = 0;
sem_post(sem);
}
-class WatchNotifyTestCtx : public WatchCtx
-{
-public:
- void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) override
- {
- std::cout << __func__ << std::endl;
- sem_post(sem);
- }
-};
-
class LibRadosWatchNotify : public RadosTest
{
protected:
}
class WatchNotifyTestCtx2;
-class LibRadosWatchNotifyPP : public RadosTestParamPP
-{
-protected:
- bufferlist notify_bl;
- std::set<uint64_t> notify_cookies;
- rados_ioctx_t notify_io;
- const char *notify_oid = nullptr;
- int notify_err = 0;
-
- friend class WatchNotifyTestCtx2;
-};
-
-IoCtx *notify_ioctx;
-
-class WatchNotifyTestCtx2 : public WatchCtx2
-{
- LibRadosWatchNotifyPP *notify;
-
-public:
- WatchNotifyTestCtx2(LibRadosWatchNotifyPP *notify)
- : notify(notify)
- {}
-
- void handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_gid,
- bufferlist& bl) override {
- std::cout << __func__ << " cookie " << cookie << " notify_id " << notify_id
- << " notifier_gid " << notifier_gid << std::endl;
- notify->notify_bl = bl;
- notify->notify_cookies.insert(cookie);
- bufferlist reply;
- reply.append("reply", 5);
- if (notify_sleep)
- sleep(notify_sleep);
- notify_ioctx->notify_ack(notify->notify_oid, notify_id, cookie, reply);
- }
-
- void handle_error(uint64_t cookie, int err) override {
- std::cout << __func__ << " cookie " << cookie
- << " err " << err << std::endl;
- ceph_assert(cookie > 1000);
- notify->notify_err = err;
- }
-};
// --
sem_close(sem);
}
-TEST_P(LibRadosWatchNotifyPP, WatchNotify) {
- ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- uint64_t handle;
- WatchNotifyTestCtx ctx;
- ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers("foo", &watches));
- ASSERT_EQ(1u, watches.size());
- bufferlist bl2;
- ASSERT_EQ(0, ioctx.notify("foo", 0, bl2));
- TestAlarm alarm;
- sem_wait(sem);
- ioctx.unwatch("foo", handle);
- sem_close(sem);
-}
-
TEST_F(LibRadosWatchNotifyEC, WatchNotify) {
ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
char buf[128];
sem_close(sem);
}
-TEST_F(LibRadosWatchNotifyECPP, WatchNotify) {
- ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
- uint64_t handle;
- WatchNotifyTestCtx ctx;
- ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers("foo", &watches));
- ASSERT_EQ(1u, watches.size());
- bufferlist bl2;
- ASSERT_EQ(0, ioctx.notify("foo", 0, bl2));
- TestAlarm alarm;
- sem_wait(sem);
- ioctx.unwatch("foo", handle);
- sem_close(sem);
-}
-
-// --
-
-TEST_P(LibRadosWatchNotifyPP, WatchNotifyTimeout) {
- ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
- ioctx.set_notify_timeout(1);
- uint64_t handle;
- WatchNotifyTestCtx ctx;
-
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
- sem_close(sem);
- ASSERT_EQ(0, ioctx.unwatch("foo", handle));
-}
-
-TEST_F(LibRadosWatchNotifyECPP, WatchNotifyTimeout) {
- ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
- ioctx.set_notify_timeout(1);
- uint64_t handle;
- WatchNotifyTestCtx ctx;
-
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
-
- ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
- sem_close(sem);
- ASSERT_EQ(0, ioctx.unwatch("foo", handle));
-}
-
#pragma GCC diagnostic pop
#pragma GCC diagnostic warning "-Wpragmas"
rados_watch_flush(cluster);
}
-TEST_P(LibRadosWatchNotifyPP, WatchNotify2) {
- notify_oid = "foo";
- notify_ioctx = &ioctx;
- notify_cookies.clear();
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
- uint64_t handle;
- WatchNotifyTestCtx2 ctx(this);
- ASSERT_EQ(0, ioctx.watch2(notify_oid, &handle, &ctx));
- ASSERT_GT(ioctx.watch_check(handle), 0);
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
- ASSERT_EQ(watches.size(), 1u);
- bufferlist bl2, bl_reply;
- ASSERT_EQ(0, ioctx.notify2(notify_oid, bl2, 300000, &bl_reply));
- auto p = bl_reply.cbegin();
- std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
- std::set<std::pair<uint64_t,uint64_t> > missed_map;
- decode(reply_map, p);
- decode(missed_map, p);
- ASSERT_EQ(1u, notify_cookies.size());
- ASSERT_EQ(1u, notify_cookies.count(handle));
- ASSERT_EQ(1u, reply_map.size());
- ASSERT_EQ(5u, reply_map.begin()->second.length());
- ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
- ASSERT_EQ(0u, missed_map.size());
- ASSERT_GT(ioctx.watch_check(handle), 0);
- ioctx.unwatch2(handle);
-}
-
-TEST_P(LibRadosWatchNotifyPP, AioWatchNotify2) {
- notify_oid = "foo";
- notify_ioctx = &ioctx;
- notify_cookies.clear();
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
-
- uint64_t handle;
- WatchNotifyTestCtx2 ctx(this);
- librados::AioCompletion *comp = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_watch(notify_oid, comp, &handle, &ctx));
- ASSERT_EQ(0, comp->wait_for_complete());
- ASSERT_EQ(0, comp->get_return_value());
- comp->release();
-
- ASSERT_GT(ioctx.watch_check(handle), 0);
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
- ASSERT_EQ(watches.size(), 1u);
- bufferlist bl2, bl_reply;
- ASSERT_EQ(0, ioctx.notify2(notify_oid, bl2, 300000, &bl_reply));
- auto p = bl_reply.cbegin();
- std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
- std::set<std::pair<uint64_t,uint64_t> > missed_map;
- decode(reply_map, p);
- decode(missed_map, p);
- ASSERT_EQ(1u, notify_cookies.size());
- ASSERT_EQ(1u, notify_cookies.count(handle));
- ASSERT_EQ(1u, reply_map.size());
- ASSERT_EQ(5u, reply_map.begin()->second.length());
- ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
- ASSERT_EQ(0u, missed_map.size());
- ASSERT_GT(ioctx.watch_check(handle), 0);
-
- comp = cluster.aio_create_completion();
- ioctx.aio_unwatch(handle, comp);
- ASSERT_EQ(0, comp->wait_for_complete());
- comp->release();
-}
-
-
-TEST_P(LibRadosWatchNotifyPP, AioNotify) {
- notify_oid = "foo";
- notify_ioctx = &ioctx;
- notify_cookies.clear();
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
- uint64_t handle;
- WatchNotifyTestCtx2 ctx(this);
- ASSERT_EQ(0, ioctx.watch2(notify_oid, &handle, &ctx));
- ASSERT_GT(ioctx.watch_check(handle), 0);
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
- ASSERT_EQ(watches.size(), 1u);
- bufferlist bl2, bl_reply;
- librados::AioCompletion *comp = cluster.aio_create_completion();
- ASSERT_EQ(0, ioctx.aio_notify(notify_oid, comp, bl2, 300000, &bl_reply));
- ASSERT_EQ(0, comp->wait_for_complete());
- ASSERT_EQ(0, comp->get_return_value());
- comp->release();
- auto p = bl_reply.cbegin();
- std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
- std::set<std::pair<uint64_t,uint64_t> > missed_map;
- decode(reply_map, p);
- decode(missed_map, p);
- ASSERT_EQ(1u, notify_cookies.size());
- ASSERT_EQ(1u, notify_cookies.count(handle));
- ASSERT_EQ(1u, reply_map.size());
- ASSERT_EQ(5u, reply_map.begin()->second.length());
- ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
- ASSERT_EQ(0u, missed_map.size());
- ASSERT_GT(ioctx.watch_check(handle), 0);
- ioctx.unwatch2(handle);
- cluster.watch_flush();
-}
-
// --
TEST_F(LibRadosWatchNotify, WatchNotify2Multi) {
}
-TEST_P(LibRadosWatchNotifyPP, WatchNotify2Timeout) {
- notify_oid = "foo";
- notify_ioctx = &ioctx;
- notify_sleep = 3; // 3s
- notify_cookies.clear();
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
- uint64_t handle;
- WatchNotifyTestCtx2 ctx(this);
- ASSERT_EQ(0, ioctx.watch2(notify_oid, &handle, &ctx));
- ASSERT_GT(ioctx.watch_check(handle), 0);
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
- ASSERT_EQ(watches.size(), 1u);
- ASSERT_EQ(0u, notify_cookies.size());
- bufferlist bl2, bl_reply;
- std::cout << " trying..." << std::endl;
- ASSERT_EQ(-ETIMEDOUT, ioctx.notify2(notify_oid, bl2, 1000 /* 1s */,
- &bl_reply));
- std::cout << " timed out" << std::endl;
- ASSERT_GT(ioctx.watch_check(handle), 0);
- ioctx.unwatch2(handle);
-
- std::cout << " flushing" << std::endl;
- librados::AioCompletion *comp = cluster.aio_create_completion();
- cluster.aio_watch_flush(comp);
- ASSERT_EQ(0, comp->wait_for_complete());
- ASSERT_EQ(0, comp->get_return_value());
- std::cout << " flushed" << std::endl;
- comp->release();
-}
-
-TEST_P(LibRadosWatchNotifyPP, WatchNotify3) {
- notify_oid = "foo";
- notify_ioctx = &ioctx;
- notify_cookies.clear();
- uint32_t timeout = 12; // configured timeout
- char buf[128];
- memset(buf, 0xcc, sizeof(buf));
- bufferlist bl1;
- bl1.append(buf, sizeof(buf));
- ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
- uint64_t handle;
- WatchNotifyTestCtx2 ctx(this);
- ASSERT_EQ(0, ioctx.watch3(notify_oid, &handle, &ctx, timeout));
- ASSERT_GT(ioctx.watch_check(handle), 0);
- std::list<obj_watch_t> watches;
- ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
- ASSERT_EQ(watches.size(), 1u);
- std::cout << "List watches" << std::endl;
- for (std::list<obj_watch_t>::iterator it = watches.begin();
- it != watches.end(); ++it) {
- ASSERT_EQ(it->timeout_seconds, timeout);
- }
- bufferlist bl2, bl_reply;
- std::cout << "notify2" << std::endl;
- ASSERT_EQ(0, ioctx.notify2(notify_oid, bl2, 300000, &bl_reply));
- std::cout << "notify2 done" << std::endl;
- auto p = bl_reply.cbegin();
- std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
- std::set<std::pair<uint64_t,uint64_t> > missed_map;
- decode(reply_map, p);
- decode(missed_map, p);
- ASSERT_EQ(1u, notify_cookies.size());
- ASSERT_EQ(1u, notify_cookies.count(handle));
- ASSERT_EQ(1u, reply_map.size());
- ASSERT_EQ(5u, reply_map.begin()->second.length());
- ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
- ASSERT_EQ(0u, missed_map.size());
- std::cout << "watch_check" << std::endl;
- ASSERT_GT(ioctx.watch_check(handle), 0);
- std::cout << "unwatch2" << std::endl;
- ioctx.unwatch2(handle);
-
- std::cout << " flushing" << std::endl;
- cluster.watch_flush();
- std::cout << "done" << std::endl;
-}
-
TEST_F(LibRadosWatchNotify, Watch3Timeout) {
notify_io = ioctx;
notify_oid = "foo";
ASSERT_EQ(-ENOENT, rados_aio_get_return_value(comp));
rados_aio_release(comp);
}
-// --
-
-INSTANTIATE_TEST_CASE_P(LibRadosWatchNotifyPPTests, LibRadosWatchNotifyPP,
- ::testing::Values("", "cache"));
--- /dev/null
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <set>
+#include <map>
+
+#include "gtest/gtest.h"
+
+#include "include/encoding.h"
+#include "include/rados/librados.hpp"
+#include "include/rados/rados_types.h"
+#include "test/librados/test_cxx.h"
+#include "test/librados/testcase_cxx.h"
+
+
+using namespace librados;
+
+typedef RadosTestECPP LibRadosWatchNotifyECPP;
+
+int notify_sleep = 0;
+
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+class LibRadosWatchNotifyPP : public RadosTestParamPP
+{
+protected:
+ bufferlist notify_bl;
+ std::set<uint64_t> notify_cookies;
+ rados_ioctx_t notify_io;
+ const char *notify_oid = nullptr;
+ int notify_err = 0;
+
+ friend class WatchNotifyTestCtx2;
+};
+
+IoCtx *notify_ioctx;
+
+class WatchNotifyTestCtx2 : public WatchCtx2
+{
+ LibRadosWatchNotifyPP *notify;
+
+public:
+ WatchNotifyTestCtx2(LibRadosWatchNotifyPP *notify)
+ : notify(notify)
+ {}
+
+ void handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_gid,
+ bufferlist& bl) override {
+ std::cout << __func__ << " cookie " << cookie << " notify_id " << notify_id
+ << " notifier_gid " << notifier_gid << std::endl;
+ notify->notify_bl = bl;
+ notify->notify_cookies.insert(cookie);
+ bufferlist reply;
+ reply.append("reply", 5);
+ if (notify_sleep)
+ sleep(notify_sleep);
+ notify_ioctx->notify_ack(notify->notify_oid, notify_id, cookie, reply);
+ }
+
+ void handle_error(uint64_t cookie, int err) override {
+ std::cout << __func__ << " cookie " << cookie
+ << " err " << err << std::endl;
+ ceph_assert(cookie > 1000);
+ notify->notify_err = err;
+ }
+};
+
+// notify
+static sem_t *sem;
+
+class WatchNotifyTestCtx : public WatchCtx
+{
+public:
+ void notify(uint8_t opcode, uint64_t ver, bufferlist& bl) override
+ {
+ std::cout << __func__ << std::endl;
+ sem_post(sem);
+ }
+};
+
+TEST_P(LibRadosWatchNotifyPP, WatchNotify) {
+ ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ uint64_t handle;
+ WatchNotifyTestCtx ctx;
+ ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers("foo", &watches));
+ ASSERT_EQ(1u, watches.size());
+ bufferlist bl2;
+ ASSERT_EQ(0, ioctx.notify("foo", 0, bl2));
+ TestAlarm alarm;
+ sem_wait(sem);
+ ioctx.unwatch("foo", handle);
+ sem_close(sem);
+}
+
+TEST_F(LibRadosWatchNotifyECPP, WatchNotify) {
+ ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+ uint64_t handle;
+ WatchNotifyTestCtx ctx;
+ ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers("foo", &watches));
+ ASSERT_EQ(1u, watches.size());
+ bufferlist bl2;
+ ASSERT_EQ(0, ioctx.notify("foo", 0, bl2));
+ TestAlarm alarm;
+ sem_wait(sem);
+ ioctx.unwatch("foo", handle);
+ sem_close(sem);
+}
+
+// --
+
+TEST_P(LibRadosWatchNotifyPP, WatchNotifyTimeout) {
+ ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
+ ioctx.set_notify_timeout(1);
+ uint64_t handle;
+ WatchNotifyTestCtx ctx;
+
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
+ sem_close(sem);
+ ASSERT_EQ(0, ioctx.unwatch("foo", handle));
+}
+
+TEST_F(LibRadosWatchNotifyECPP, WatchNotifyTimeout) {
+ ASSERT_NE(SEM_FAILED, (sem = sem_open("/test_watch_notify_sem", O_CREAT, 0644, 0)));
+ ioctx.set_notify_timeout(1);
+ uint64_t handle;
+ WatchNotifyTestCtx ctx;
+
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
+
+ ASSERT_EQ(0, ioctx.watch("foo", 0, &handle, &ctx));
+ sem_close(sem);
+ ASSERT_EQ(0, ioctx.unwatch("foo", handle));
+}
+
+#pragma GCC diagnostic pop
+#pragma GCC diagnostic warning "-Wpragmas"
+
+TEST_P(LibRadosWatchNotifyPP, WatchNotify2) {
+ notify_oid = "foo";
+ notify_ioctx = &ioctx;
+ notify_cookies.clear();
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
+ uint64_t handle;
+ WatchNotifyTestCtx2 ctx(this);
+ ASSERT_EQ(0, ioctx.watch2(notify_oid, &handle, &ctx));
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
+ ASSERT_EQ(watches.size(), 1u);
+ bufferlist bl2, bl_reply;
+ ASSERT_EQ(0, ioctx.notify2(notify_oid, bl2, 300000, &bl_reply));
+ auto p = bl_reply.cbegin();
+ std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
+ std::set<std::pair<uint64_t,uint64_t> > missed_map;
+ decode(reply_map, p);
+ decode(missed_map, p);
+ ASSERT_EQ(1u, notify_cookies.size());
+ ASSERT_EQ(1u, notify_cookies.count(handle));
+ ASSERT_EQ(1u, reply_map.size());
+ ASSERT_EQ(5u, reply_map.begin()->second.length());
+ ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
+ ASSERT_EQ(0u, missed_map.size());
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ ioctx.unwatch2(handle);
+}
+
+TEST_P(LibRadosWatchNotifyPP, AioWatchNotify2) {
+ notify_oid = "foo";
+ notify_ioctx = &ioctx;
+ notify_cookies.clear();
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
+
+ uint64_t handle;
+ WatchNotifyTestCtx2 ctx(this);
+ librados::AioCompletion *comp = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_watch(notify_oid, comp, &handle, &ctx));
+ ASSERT_EQ(0, comp->wait_for_complete());
+ ASSERT_EQ(0, comp->get_return_value());
+ comp->release();
+
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
+ ASSERT_EQ(watches.size(), 1u);
+ bufferlist bl2, bl_reply;
+ ASSERT_EQ(0, ioctx.notify2(notify_oid, bl2, 300000, &bl_reply));
+ auto p = bl_reply.cbegin();
+ std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
+ std::set<std::pair<uint64_t,uint64_t> > missed_map;
+ decode(reply_map, p);
+ decode(missed_map, p);
+ ASSERT_EQ(1u, notify_cookies.size());
+ ASSERT_EQ(1u, notify_cookies.count(handle));
+ ASSERT_EQ(1u, reply_map.size());
+ ASSERT_EQ(5u, reply_map.begin()->second.length());
+ ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
+ ASSERT_EQ(0u, missed_map.size());
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+
+ comp = cluster.aio_create_completion();
+ ioctx.aio_unwatch(handle, comp);
+ ASSERT_EQ(0, comp->wait_for_complete());
+ comp->release();
+}
+
+
+TEST_P(LibRadosWatchNotifyPP, AioNotify) {
+ notify_oid = "foo";
+ notify_ioctx = &ioctx;
+ notify_cookies.clear();
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
+ uint64_t handle;
+ WatchNotifyTestCtx2 ctx(this);
+ ASSERT_EQ(0, ioctx.watch2(notify_oid, &handle, &ctx));
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
+ ASSERT_EQ(watches.size(), 1u);
+ bufferlist bl2, bl_reply;
+ librados::AioCompletion *comp = cluster.aio_create_completion();
+ ASSERT_EQ(0, ioctx.aio_notify(notify_oid, comp, bl2, 300000, &bl_reply));
+ ASSERT_EQ(0, comp->wait_for_complete());
+ ASSERT_EQ(0, comp->get_return_value());
+ comp->release();
+ auto p = bl_reply.cbegin();
+ std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
+ std::set<std::pair<uint64_t,uint64_t> > missed_map;
+ decode(reply_map, p);
+ decode(missed_map, p);
+ ASSERT_EQ(1u, notify_cookies.size());
+ ASSERT_EQ(1u, notify_cookies.count(handle));
+ ASSERT_EQ(1u, reply_map.size());
+ ASSERT_EQ(5u, reply_map.begin()->second.length());
+ ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
+ ASSERT_EQ(0u, missed_map.size());
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ ioctx.unwatch2(handle);
+ cluster.watch_flush();
+}
+
+// --
+TEST_P(LibRadosWatchNotifyPP, WatchNotify2Timeout) {
+ notify_oid = "foo";
+ notify_ioctx = &ioctx;
+ notify_sleep = 3; // 3s
+ notify_cookies.clear();
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
+ uint64_t handle;
+ WatchNotifyTestCtx2 ctx(this);
+ ASSERT_EQ(0, ioctx.watch2(notify_oid, &handle, &ctx));
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
+ ASSERT_EQ(watches.size(), 1u);
+ ASSERT_EQ(0u, notify_cookies.size());
+ bufferlist bl2, bl_reply;
+ std::cout << " trying..." << std::endl;
+ ASSERT_EQ(-ETIMEDOUT, ioctx.notify2(notify_oid, bl2, 1000 /* 1s */,
+ &bl_reply));
+ std::cout << " timed out" << std::endl;
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ ioctx.unwatch2(handle);
+
+ std::cout << " flushing" << std::endl;
+ librados::AioCompletion *comp = cluster.aio_create_completion();
+ cluster.aio_watch_flush(comp);
+ ASSERT_EQ(0, comp->wait_for_complete());
+ ASSERT_EQ(0, comp->get_return_value());
+ std::cout << " flushed" << std::endl;
+ comp->release();
+}
+
+TEST_P(LibRadosWatchNotifyPP, WatchNotify3) {
+ notify_oid = "foo";
+ notify_ioctx = &ioctx;
+ notify_cookies.clear();
+ uint32_t timeout = 12; // configured timeout
+ char buf[128];
+ memset(buf, 0xcc, sizeof(buf));
+ bufferlist bl1;
+ bl1.append(buf, sizeof(buf));
+ ASSERT_EQ(0, ioctx.write(notify_oid, bl1, sizeof(buf), 0));
+ uint64_t handle;
+ WatchNotifyTestCtx2 ctx(this);
+ ASSERT_EQ(0, ioctx.watch3(notify_oid, &handle, &ctx, timeout));
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ std::list<obj_watch_t> watches;
+ ASSERT_EQ(0, ioctx.list_watchers(notify_oid, &watches));
+ ASSERT_EQ(watches.size(), 1u);
+ std::cout << "List watches" << std::endl;
+ for (std::list<obj_watch_t>::iterator it = watches.begin();
+ it != watches.end(); ++it) {
+ ASSERT_EQ(it->timeout_seconds, timeout);
+ }
+ bufferlist bl2, bl_reply;
+ std::cout << "notify2" << std::endl;
+ ASSERT_EQ(0, ioctx.notify2(notify_oid, bl2, 300000, &bl_reply));
+ std::cout << "notify2 done" << std::endl;
+ auto p = bl_reply.cbegin();
+ std::map<std::pair<uint64_t,uint64_t>,bufferlist> reply_map;
+ std::set<std::pair<uint64_t,uint64_t> > missed_map;
+ decode(reply_map, p);
+ decode(missed_map, p);
+ ASSERT_EQ(1u, notify_cookies.size());
+ ASSERT_EQ(1u, notify_cookies.count(handle));
+ ASSERT_EQ(1u, reply_map.size());
+ ASSERT_EQ(5u, reply_map.begin()->second.length());
+ ASSERT_EQ(0, strncmp("reply", reply_map.begin()->second.c_str(), 5));
+ ASSERT_EQ(0u, missed_map.size());
+ std::cout << "watch_check" << std::endl;
+ ASSERT_GT(ioctx.watch_check(handle), 0);
+ std::cout << "unwatch2" << std::endl;
+ ioctx.unwatch2(handle);
+
+ std::cout << " flushing" << std::endl;
+ cluster.watch_flush();
+ std::cout << "done" << std::endl;
+}
+// --
+
+INSTANTIATE_TEST_CASE_P(LibRadosWatchNotifyPPTests, LibRadosWatchNotifyPP,
+ ::testing::Values("", "cache"));
add_library(rados_striper_test STATIC TestCase.cc)
target_link_libraries(rados_striper_test
radostest
+ radostest-cxx
GTest::GTest)
add_executable(ceph_test_rados_striper_api_striping
striping.cc
)
-target_link_libraries(ceph_test_rados_striper_api_striping librados radosstriper
- ${UNITTEST_LIBS} rados_striper_test)
+target_link_libraries(ceph_test_rados_striper_api_striping
+ ${UNITTEST_LIBS} rados_striper_test
+ radosstriper
+ librados
+ librados-cxx)
install(TARGETS ceph_test_rados_striper_api_striping
DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(ceph_test_rados_striper_api_io
io.cc)
-target_link_libraries(ceph_test_rados_striper_api_io librados radosstriper
- ${UNITTEST_LIBS} rados_striper_test)
+target_link_libraries(ceph_test_rados_striper_api_io
+ ${UNITTEST_LIBS} rados_striper_test
+ radosstriper
+ librados
+ librados-cxx)
install(TARGETS ceph_test_rados_striper_api_io
DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(ceph_test_rados_striper_api_aio
aio.cc)
-target_link_libraries(ceph_test_rados_striper_api_aio librados radosstriper
+target_link_libraries(ceph_test_rados_striper_api_aio librados-cxx radosstriper
${UNITTEST_LIBS} rados_striper_test)
install(TARGETS ceph_test_rados_striper_api_aio
DESTINATION ${CMAKE_INSTALL_BINDIR})
#include <errno.h>
#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "test/libradosstriper/TestCase.h"
using namespace libradosstriper;
add_library(rbd_test STATIC ${librbd_test})
target_link_libraries(rbd_test PRIVATE
rbd_test_support
+ radostest
+ radostest-cxx
+ librados
Boost::thread
GMock::GMock
GTest::GTest)
osdc
ceph-common
global
- ${UNITTEST_LIBS}
- radostest)
+ ${UNITTEST_LIBS})
add_executable(ceph_test_librbd
test_main.cc
cls_journal_client
cls_rbd_client
librados
+ librados-cxx
${UNITTEST_LIBS}
radostest)
target_compile_definitions(ceph_test_librbd PRIVATE "TEST_LIBRBD_INTERNALS")
test_support.cc
test_librbd.cc
test_main.cc
- $<TARGET_OBJECTS:libradostest_obj>
$<TARGET_OBJECTS:common_texttable_obj>)
target_link_libraries(ceph_test_librbd_api
ceph-common
+ radostest
+ radostest-cxx
librbd
librados
+ librados-cxx
${UNITTEST_LIBS})
add_executable(ceph_test_librbd_fsx
target_link_libraries(ceph_test_librbd_fsx
librbd
librados
+ librados-cxx
journal
global
m
#include "cls/rbd/cls_rbd_types.h"
#include "librbd/internal.h"
#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <vector>
#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "test/librbd/test_support.h"
#include "common/event_socket.h"
#include "include/interval_set.h"
#include "include/rados/librados.hpp"
#include "global/global_context.h"
#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
#include <iostream>
#include <string>
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
#include "include/rados/librados.h"
#include "include/rados/librados.hpp"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include <semaphore.h>
#include <errno.h>
RadosModel.cc
)
target_link_libraries(ceph_test_rados
- librados
+ librados-cxx
global
${BLKID_LIBRARIES}
${CMAKE_DL_LIBS}
librados
osdc
global
- radostest
+ radostest-cxx
)
add_executable(ceph_test_rbd_mirror
cls_rbd_client
cls_journal_client
rbd_types
- librados
- radostest
+ librados-cxx
+ radostest-cxx
${UNITTEST_LIBS}
)
add_executable(ceph_test_rbd_mirror_random_write
random_write.cc)
target_link_libraries(ceph_test_rbd_mirror_random_write
- librbd librados global)
+ librbd librados-cxx global)
install(TARGETS
ceph_test_rbd_mirror
#include "tools/rbd_mirror/ServiceDaemon.h"
#include "tools/rbd_mirror/Types.h"
#include "test/rbd_mirror/test_fixture.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "test/librbd/test_support.h"
#include "gtest/gtest.h"
#include <boost/scope_exit.hpp>
#include "tools/rbd_mirror/Threads.h"
#include "tools/rbd_mirror/Types.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
using rbd::mirror::RadosRef;
#include "tools/rbd_mirror/InstanceWatcher.h"
#include "tools/rbd_mirror/Threads.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
using rbd::mirror::InstanceWatcher;
#include "tools/rbd_mirror/LeaderWatcher.h"
#include "tools/rbd_mirror/Threads.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
using librbd::util::unique_lock_name;
#include "tools/rbd_mirror/Threads.h"
#include "tools/rbd_mirror/Types.h"
#include "tools/rbd_mirror/pool_watcher/Types.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
#include <boost/scope_exit.hpp>
#include <iostream>
#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
#include "librbd/Operations.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "tools/rbd_mirror/Threads.h"
namespace rbd {
#include "include/rados/librados.hpp"
#include "global/global_context.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
#include <iostream>
#include <string>
#include "librados/AioCompletionImpl.h"
#include "librbd/ManagedLock.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
#include "test/librados_test_stub/MockTestMemRadosClient.h"
#include "test/librbd/mock/MockImageCtx.h"
#include "include/utime.h"
#include "common/Thread.h"
#include "common/Clock.h"
-#include "test/librados/test.h"
+#include "test/librados/test_cxx.h"
#include "gtest/gtest.h"
#include <semaphore.h>
#include <string>
#include <atomic>
-#include "test/librados/TestCase.h"
+#include "test/librados/testcase_cxx.h"
using namespace librados;
${PROJECT_SOURCE_DIR}/src/osd/ECUtil.cc)
add_executable(rados ${rados_srcs})
-target_link_libraries(rados librados global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
+target_link_libraries(rados librados-cxx global ${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
if(WITH_LIBRADOSSTRIPER)
target_link_libraries(rados radosstriper)
else()
install(TARGETS ceph_scratchtool DESTINATION bin)
add_executable(ceph_scratchtoolpp scratchtoolpp.cc)
-target_link_libraries(ceph_scratchtoolpp librados global)
+target_link_libraries(ceph_scratchtoolpp librados-cxx global)
install(TARGETS ceph_scratchtoolpp DESTINATION bin)
add_executable(ceph_radosacl radosacl.cc)
-target_link_libraries(ceph_radosacl librados global)
+target_link_libraries(ceph_radosacl librados-cxx global)
install(TARGETS ceph_radosacl DESTINATION bin)
install(PROGRAMS
RoleSelector.cc
MDSUtility.cc)
add_executable(cephfs-journal-tool ${cephfs_journal_tool_srcs})
-target_link_libraries(cephfs-journal-tool librados mds osdc global
+target_link_libraries(cephfs-journal-tool librados-cxx mds osdc global
${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
set(cephfs_table_tool_srcs
RoleSelector.cc
MDSUtility.cc)
add_executable(cephfs-table-tool ${cephfs_table_tool_srcs})
-target_link_libraries(cephfs-table-tool librados mds osdc global
+target_link_libraries(cephfs-table-tool librados-cxx mds osdc global
${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
set(cephfs_data_scan_srcs
PgFiles.cc
MDSUtility.cc)
add_executable(cephfs-data-scan ${cephfs_data_scan_srcs})
-target_link_libraries(cephfs-data-scan librados cephfs mds osdc global
+target_link_libraries(cephfs-data-scan librados-cxx cephfs mds osdc global
cls_cephfs_client
${BLKID_LIBRARIES} ${CMAKE_DL_LIBS})
add_executable(rbd ${rbd_srcs}
$<TARGET_OBJECTS:common_texttable_obj>)
set_target_properties(rbd PROPERTIES OUTPUT_NAME rbd)
-target_link_libraries(rbd librbd librados
+target_link_libraries(rbd librbd librados-cxx
cls_journal_client cls_rbd_client
rbd_types
journal
rbd_internal
rbd_types
journal
- librados
+ librados-cxx
osdc
cls_rbd_client
cls_lock_client
add_executable(rbd-nbd rbd-nbd.cc)
-target_link_libraries(rbd-nbd librbd librados global)
+target_link_libraries(rbd-nbd librbd librados-cxx global)
install(TARGETS rbd-nbd DESTINATION bin)