librados部分代码走读

本文内容

本文主要介绍librados中关于C++部分的接口API调用。但并未深入到如何实现,有助于浅尝辄止的大概了解。

  1. RadosClient.h和RadosClient.cc是用于初始化RadosClient对象,一般用于客户端进行访问,主要操作:
  • 连接、断链存储集群
    int ping_monitor(std::string mon_id, std::string *result);
    //根据poolctx初始化monclient、msgr、objecter等
    int connect();
    void shutdown();
  • 存储池系列操作。RadosClient内部有poolctx对象
    //*io = new librados::IoCtxImpl(this, objecter, poolid, CEPH_NOSNAP);
    int create_ioctx(const char *name, IoCtxImpl **io);
    int create_ioctx(int64_t, IoCtxImpl **io);

    int get_fsid(std::string *s);
    int64_t lookup_pool(const char *name);
    bool pool_requires_alignment(int64_t pool_id);
    int pool_requires_alignment2(int64_t pool_id, bool *requires);
    uint64_t pool_required_alignment(int64_t pool_id);
    int pool_required_alignment2(int64_t pool_id, uint64_t *alignment);
    int pool_get_name(uint64_t pool_id, std::string *name, bool wait_latest_map = false);
    //列举存储池。
    int pool_list(std::list<std::pair<int64_t, std::string> >& ls);
    int get_pool_stats(std::list<std::string>& ls, std::map<std::string,::pool_stat_t> *result,
    bool *per_pool);
    int get_fs_stats(ceph_statfs& result);
    bool get_pool_is_selfmanaged_snaps_mode(const std::string& pool);
    //创建、删除存储池
    int pool_create(std::string& name, int16_t crush_rule=-1);
    int pool_create_async(std::string& name, PoolAsyncCompletionImpl *c, int16_t crush_rule=-1);
    int pool_get_base_tier(int64_t pool_id, int64_t* base_tier);
    int pool_delete(const char *name);

    int pool_delete_async(const char *name, PoolAsyncCompletionImpl *c);
  • commond操作。mgr、mon等操作接口,处理mon、mgr、log等命令
    int mon_command(const std::vector<std::string>& cmd, const bufferlist &inbl,
                bufferlist *outbl, std::string *outs);
    void mon_command_async(const std::vector<std::string>& cmd, const bufferlist &inbl,
                            bufferlist *outbl, std::string *outs, Context *on_finish);
    int mon_command(int rank,
            const std::vector<std::string>& cmd, const bufferlist &inbl,
                bufferlist *outbl, std::string *outs);
    int mon_command(std::string name,
            const std::vector<std::string>& cmd, const bufferlist &inbl,
                bufferlist *outbl, std::string *outs);
    int mgr_command(const std::vector<std::string>& cmd, const bufferlist &inbl,
                bufferlist *outbl, std::string *outs);
    int mgr_command(
    const std::string& name,
    const std::vector<std::string>& cmd, const bufferlist &inbl,
    bufferlist *outbl, std::string *outs);
    int osd_command(int osd, std::vector<std::string>& cmd, const bufferlist& inbl,
                    bufferlist *poutbl, std::string *prs);
    int pg_command(pg_t pgid, std::vector<std::string>& cmd, const bufferlist& inbl,
                bufferlist *poutbl, std::string *prs);

    void handle_log(MLog *m);
    int monitor_log(const std::string& level, rados_log_callback_t cb,
            rados_log_callback2_t cb2, void *arg);
  • 我们再看一个python的demo,就能明白上述接口
    import rados, sys
    //初始化Client对象,连接集群
    cluster = rados.Rados(conffile='ceph.conf')
    cluster.connect()
    cluster_stats = cluster.get_cluster_stats()
    //存储池的增删改查
    pools = cluster.list_pools()
    for pool in pools:
            print(pool)

    print("\nCreate 'test' Pool")
    print("------------------")
    cluster.create_pool('test')

    print("\nPool named 'test' exists: {}".format(str(cluster.pool_exists('test'))))
    print("\nVerify 'test' Pool Exists")
    print("-------------------------")
    pools = cluster.list_pools()

    for pool in pools:
            print(pool)

    print("\nDelete 'test' Pool")
    print("------------------")
    cluster.delete_pool('test')
    print("\nPool named 'test' exists: {}".format(str(cluster.pool_exists('test'))))

    //打开存储池的ioctx,并进行对象及其xattr的增删改查
    ioctx = cluster.open_ioctx2(pool_id)
    print("\nWriting object 'hw' with contents 'Hello World!' to pool 'data'.")
    ioctx.write_full("hw", "Hello World!")

    print("\n\nContents of object 'hw'\n------------------------\n")
    print(ioctx.read("hw"))

    print("\nRemoving object 'hw'")
    ioctx.remove_object("hw")
    print("\n\nWriting XATTR 'lang' with value 'en_US' to object 'hw'")
    ioctx.set_xattr("hw", "lang", "en_US")

    print("\n\nGetting XATTR 'lang' from object 'hw'\n")
    print(ioctx.get_xattr("hw", "lang"))
    object_iterator = ioctx.list_objects()

    while True :

            try :
                    rados_object = object_iterator.__next__()
                    print("Object contents = {}".format(rados_object.read()))

            except StopIteration :
                    break
    //关闭ioctx连接
    print("\nClosing the connection.")
    ioctx.close()
  • 另外在官方的test中,也能看到类似的接口访问,示例为测试mon的commond命令。
//src/test/librados/cmd.cc
TEST(LibRadosCmd, MonDescribe) {
  rados_t cluster;
  ASSERT_EQ("", connect_cluster(&cluster));

  char *buf, *st;
  size_t buflen, stlen;
  char *cmd[2];

  cmd[1] = NULL;

  cmd[0] = (char *)"{\"prefix\":\"get_command_descriptions\"}";
  ASSERT_EQ(0, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen));
  ASSERT_LT(0u, buflen);
  rados_buffer_free(buf);
  rados_buffer_free(st);

  cmd[0] = (char *)"get_command_descriptions";
  ASSERT_EQ(-EINVAL, rados_mon_command(cluster, (const char **)cmd, 1, "", 0, &buf, &buflen, &st, &stlen));
  rados_buffer_free(buf);
  rados_buffer_free(st);

  //ASSERT_LT(0u, stlen);
  rados_buffer_free(buf);
  rados_buffer_free(st);
  rados_shutdown(cluster);
}
  1. IoctxImpl.cc。原名为PoolCtx。针对存储池的上下文操作,从上文例子中我们可以看到,RadosClient中有create_ioctx接口。在操作对象的时候,会大量使用。
  • 先看示例,init中连接集群,然后调用ioctx的aio_write函数进行写操作
//test/librados/aio_cxx.cc
    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());
        auto my_completion = std::unique_ptr<AioCompletion>{Rados::aio_create_completion()};
        ASSERT_TRUE(my_completion);
        //写对象
        ASSERT_EQ(0, test_data.m_ioctx.aio_write("foo", my_completion.get(), bl1, sizeof(buf), 0));
    }
  • 常规接口
  void queue_aio_write(struct AioCompletionImpl *c);
  void complete_aio_write(struct AioCompletionImpl *c);
  void flush_aio_writes_async(AioCompletionImpl *c);
  void flush_aio_writes();

  int64_t get_id() {
    return poolid;
  }

  std::string get_cached_pool_name();

  int get_object_hash_position(const std::string& oid, uint32_t *hash_position);
  int get_object_pg_hash_position(const std::string& oid, uint32_t *pg_hash_position);

  ::ObjectOperation *prepare_assert_ops(::ObjectOperation *op);

  // snaps
  int snap_list(std::vector<uint64_t> *snaps);
  int snap_lookup(const char *name, uint64_t *snapid);
  int snap_get_name(uint64_t snapid, std::string *s);
  int snap_get_stamp(uint64_t snapid, time_t *t);
  int snap_create(const char* snapname);
  int selfmanaged_snap_create(uint64_t *snapid);
  void aio_selfmanaged_snap_create(uint64_t *snapid, AioCompletionImpl *c);
  int snap_remove(const char* snapname);
  int rollback(const object_t& oid, const char *snapName);
  int selfmanaged_snap_remove(uint64_t snapid);
  void aio_selfmanaged_snap_remove(uint64_t snapid, AioCompletionImpl *c);
  int selfmanaged_snap_rollback_object(const object_t& oid,
                                       ::SnapContext& snapc, uint64_t snapid);

  // 对象、对象xattr属性接口
  int nlist(Objecter::NListContext *context, int max_entries);
  uint32_t nlist_seek(Objecter::NListContext *context, uint32_t pos);
  uint32_t nlist_seek(Objecter::NListContext *context, const rados_object_list_cursor& cursor);
  rados_object_list_cursor nlist_get_cursor(Objecter::NListContext *context);
  void object_list_slice(
    const hobject_t start,
    const hobject_t finish,
    const size_t n,
    const size_t m,
    hobject_t *split_start,
    hobject_t *split_finish);

  int create(const object_t& oid, bool exclusive);
  int write(const object_t& oid, bufferlist& bl, size_t len, uint64_t off);
  int append(const object_t& oid, bufferlist& bl, size_t len);
  int write_full(const object_t& oid, bufferlist& bl);
  int writesame(const object_t& oid, bufferlist& bl,
        size_t write_len, uint64_t offset);
  int read(const object_t& oid, bufferlist& bl, size_t len, uint64_t off);
  int mapext(const object_t& oid, uint64_t off, size_t len,
         std::map<uint64_t,uint64_t>& m);
  int sparse_read(const object_t& oid, std::map<uint64_t,uint64_t>& m,
          bufferlist& bl, size_t len, uint64_t off);
  int checksum(const object_t& oid, uint8_t type, const bufferlist &init_value,
           size_t len, uint64_t off, size_t chunk_size, bufferlist *pbl);
  int remove(const object_t& oid);
  int remove(const object_t& oid, int flags);
  int stat(const object_t& oid, uint64_t *psize, time_t *pmtime);
  int stat2(const object_t& oid, uint64_t *psize, struct timespec *pts);
  int trunc(const object_t& oid, uint64_t size);
  int cmpext(const object_t& oid, uint64_t off, bufferlist& cmp_bl);

  int tmap_update(const object_t& oid, bufferlist& cmdbl);

  int exec(const object_t& oid, const char *cls, const char *method, bufferlist& inbl, bufferlist& outbl);

  int getxattr(const object_t& oid, const char *name, bufferlist& bl);
  int setxattr(const object_t& oid, const char *name, bufferlist& bl);
  int getxattrs(const object_t& oid, std::map<std::string, bufferlist>& attrset);
  int rmxattr(const object_t& oid, const char *name);

  int operate(const object_t& oid, ::ObjectOperation *o, ceph::real_time *pmtime, int flags=0);
  int operate_read(const object_t& oid, ::ObjectOperation *o, bufferlist *pbl, int flags=0);
  int aio_operate(const object_t& oid, ::ObjectOperation *o,
          AioCompletionImpl *c, const SnapContext& snap_context,
          int flags, const blkin_trace_info *trace_info = nullptr);
  int aio_operate_read(const object_t& oid, ::ObjectOperation *o,
               AioCompletionImpl *c, int flags, bufferlist *pbl, const blkin_trace_info *trace_info = nullptr);

  1. librados.hpp和librados_cxx.cc是针对ceph api的c++接口的实现。主要类为:ListObject、ObjectOperation、ObjectWriteOperation、ObjectReadOperation、IoCtx、Rados等等
  • 先看示例。读取配置,连接集群,初始化某个存储池的ioctx,即可调用io中的相关函数进行对象级别的操作。
    C代码demo
    err = rados_conf_read_file(cluster, "/path/to/myceph.conf");
    err = rados_connect(cluster);
    rados_ioctx_t io;
    char *poolname = "mypool";
    err = rados_ioctx_create(cluster, poolname, &io);
    err = rados_write_full(io, "greeting", "hello", 5);
    rados_ioctx_destroy(io);
    rados_shutdown(cluster);

C++代码demo

    //test/librados/aio_cxx.cc
    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);

    auto my_completion1 = std::unique_ptr<AioCompletion>{Rados::aio_create_completion()};
    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());

    auto my_completion2 = std::unique_ptr<AioCompletion>{Rados::aio_create_completion()};
    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);
    }
  • ListObject主要实现了object的list功能
    class CEPH_RADOS_API ListObject
    {
        public:
        const std::string& get_nspace() const;
        const std::string& get_oid() const;
        const std::string& get_locator() const;

        ListObject();
        ~ListObject();
        ListObject( const ListObject&);
        ListObject& operator=(const ListObject& rhs);
        private:
        ListObject(ListObjectImpl *impl);

        friend class librados::NObjectIteratorImpl;
        friend std::ostream& operator<<(std::ostream& out, const ListObject& lop);

        ListObjectImpl *impl;
    };
  • ObjectOperation,父类,由WriteOperation和ReadOperation继承并负责某些函数的具体实现
  • ObjectWriteOperation,负责写对象
  • ObjectReadOperation,负责读对象
  • IoCtx,负责对外接口,完成上述operation的op调用。

posted on 2024-08-15 15:54  陶大先生  阅读(23)  评论(0编辑  收藏  举报

导航