<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">2013/12/23 Liu Yuan <span dir="ltr"><<a href="mailto:namei.unix@gmail.com" target="_blank">namei.unix@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
We duplicately call vdi_lookup twice for every object operation, which isn't<br>
necessary. This patch reduce it to a single call of vdi_lookup.<br>
<br>
Also rename kv_list_{objects, buckets} as kv_iterate_{object, bucket}<br>
<br>
Signed-off-by: Liu Yuan <<a href="mailto:namei.unix@gmail.com">namei.unix@gmail.com</a>><br>
---<br>
 sheep/http/http.h  |  18 ++-<br>
 sheep/http/kv.c    | 361 +++++++++++++++++++++++++++--------------------------<br>
 sheep/http/s3.c    |  64 +---------<br>
 sheep/http/swift.c |  19 ++-<br>
 4 files changed, 200 insertions(+), 262 deletions(-)<br>
<br>
diff --git a/sheep/http/http.h b/sheep/http/http.h<br>
index 3141c09..dea34e0 100644<br>
--- a/sheep/http/http.h<br>
+++ b/sheep/http/http.h<br>
@@ -129,23 +129,19 @@ int kv_create_bucket(const char *account, const char *bucket);<br>
 int kv_read_bucket(const char *account, const char *bucket);<br>
 int kv_update_bucket(const char *account, const char *bucket);<br>
 int kv_delete_bucket(const char *account, const char *bucket);<br>
-int kv_list_buckets(struct http_request *req, const char *account,<br>
-                   void (*cb)(struct http_request *req, const char *bucket,<br>
-                              void *opaque),<br>
-                   void *opaque);<br>
+int kv_iterate_bucket(const char *account,<br>
+                     void (*cb)(const char *bucket, void *opaque),<br>
+                     void *opaque);<br>
<br>
 /* Object operations */<br>
 int kv_create_object(struct http_request *req, const char *account,<br>
                     const char *bucket, const char *object);<br>
 int kv_read_object(struct http_request *req, const char *account,<br>
                   const char *bucket, const char *object);<br>
-int kv_delete_object(struct http_request *req, const char *account,<br>
-                    const char *bucket, const char *object);<br>
-int kv_list_objects(struct http_request *req, const char *account,<br>
-                   const char *bucket,<br>
-                   void (*cb)(struct http_request *req, const char *bucket,<br>
-                              const char *object, void *opaque),<br>
-                   void *opaque);<br>
+int kv_delete_object(const char *account, const char *bucket, const char *);<br>
+int kv_iterate_object(const char *account, const char *bucket,<br>
+                     void (*cb)(const char *object, void *opaque),<br>
+                     void *opaque);<br>
<br>
 /* object_allocator.c */<br>
 int oalloc_new_prepare(uint32_t vid, uint64_t *start, uint64_t count);<br>
diff --git a/sheep/http/kv.c b/sheep/http/kv.c<br>
index ed2f999..64a6e05 100644<br>
--- a/sheep/http/kv.c<br>
+++ b/sheep/http/kv.c<br>
@@ -23,6 +23,42 @@ struct kv_bnode {<br>
        uint64_t oid;<br>
 };<br>
<br>
+struct onode_extent {<br>
+       uint64_t start;<br>
+       uint64_t count;<br>
+};<br>
+<br>
+struct kv_onode {<br>
+       union {<br>
+               struct {<br>
+                       char name[SD_MAX_OBJECT_NAME];<br>
+                       /* a hash value for etag */<br>
+                       uint8_t sha1[round_up(SHA1_DIGEST_SIZE, 8)];<br>
+                       uint64_t size;<br>
+                       uint64_t ctime;<br>
+                       uint64_t mtime;<br>
+                       uint32_t data_vid;<br>
+                       uint32_t nr_extent;<br>
+                       uint64_t oid;<br>
+                       uint8_t inlined;<br>
+               };<br>
+<br>
+               uint8_t __pad[BLOCK_SIZE];<br>
+       };<br>
+       union {<br>
+               uint8_t data[SD_DATA_OBJ_SIZE - BLOCK_SIZE];<br>
+               struct onode_extent o_extent[0];<br>
+       };<br>
+};<br>
+<br>
+typedef void (*b_iter_cb)(const char *bucket, void *opaque);<br></blockquote><div><br></div><div>I think "bucket_iter_cb" is better than "b_iter_cb".</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+<br>
+struct bucket_iterater_arg {<br>
+       void *opaque;<br>
+       b_iter_cb cb;<br>
+       uint32_t count;<br>
+};<br>
+<br>
 static int kv_create_hyper_volume(const char *name, uint32_t *vdi_id)<br>
 {<br>
        struct sd_req hdr;<br>
@@ -143,20 +179,10 @@ int kv_create_account(const char *account)<br>
        return kv_create_hyper_volume(account, &vdi_id);<br>
 }<br>
<br>
-typedef void (*list_bucket_cb)(struct http_request *req, const char *bucket,<br>
-                              void *opaque);<br>
-<br>
-struct list_buckets_arg {<br>
-       struct http_request *req;<br>
-       void *opaque;<br>
-       list_bucket_cb cb;<br>
-       uint32_t bucket_counter;<br>
-};<br>
-<br>
-static void list_buckets_cb(void *data, enum btree_node_type type, void *arg)<br>
+static void bucket_iterater(void *data, enum btree_node_type type, void *arg)<br>
 {<br>
        struct sd_extent *ext;<br>
-       struct list_buckets_arg *lbarg = arg;<br>
+       struct bucket_iterater_arg *biarg = arg;<br>
        struct kv_bnode bnode;<br>
        uint64_t oid;<br>
        int ret;<br>
@@ -175,9 +201,9 @@ static void list_buckets_cb(void *data, enum btree_node_type type, void *arg)<br>
<br>
                if (<a href="http://bnode.name" target="_blank">bnode.name</a>[0] == 0)<br>
                        return;<br>
-               if (lbarg->cb)<br>
-                       lbarg->cb(lbarg->req, <a href="http://bnode.name" target="_blank">bnode.name</a>, lbarg->opaque);<br>
-               lbarg->bucket_counter++;<br>
+               if (biarg->cb)<br>
+                       biarg->cb(<a href="http://bnode.name" target="_blank">bnode.name</a>, biarg->opaque);<br>
+               biarg->count++;<br>
        }<br>
 }<br>
<br>
@@ -187,7 +213,7 @@ static int kv_get_account(const char *account, uint32_t *nr_buckets)<br>
        struct sd_inode inode;<br>
        uint64_t oid;<br>
        uint32_t account_vid;<br>
-       struct list_buckets_arg arg = {NULL, NULL, NULL, 0};<br>
+       struct bucket_iterater_arg arg = {NULL, NULL, 0};<br>
        int ret;<br>
<br>
        ret = sd_lookup_vdi(account, &account_vid);<br>
@@ -202,9 +228,9 @@ static int kv_get_account(const char *account, uint32_t *nr_buckets)<br>
                goto out;<br>
        }<br>
<br>
-       traverse_btree(sheep_bnode_reader, &inode, list_buckets_cb, &arg);<br>
+       traverse_btree(sheep_bnode_reader, &inode, bucket_iterater, &arg);<br>
        if (nr_buckets)<br>
-               *nr_buckets = arg.bucket_counter;<br>
+               *nr_buckets = arg.count;<br>
 out:<br>
        return ret;<br>
 }<br>
@@ -257,7 +283,7 @@ int kv_delete_account(const char *account)<br>
  *         |            |                                                    |<br>
  *          \           v                                                    v<br>
  *          \       +---------------------------------------------------------+<br>
- * onode_vdi  \----> |coly/fruit | ... | kv_onode: banana | kv_onode: apple    |<br>
+ * bucket_vdi  \---> |coly/fruit | ... | kv_onode: banana | kv_onode: apple    |<br>
  *                   +---------------------------------------------------------+<br>
  *                                                    |             |<br>
  *      oalloc.c manages allocation and deallocation  |             |<br>
@@ -371,6 +397,66 @@ static int bucket_delete(const char *account, uint32_t avid, const char *bucket)<br>
        return SD_RES_SUCCESS;<br>
 }<br>
<br>
+typedef void (*o_iter_cb)(const char *object, void *opaque);<br></blockquote><div><br></div><div>May be "object_iter_cb" better ?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+<br>
+struct object_iterater_arg {<br>
+       void *opaque;<br>
+       o_iter_cb cb;<br>
+       uint32_t count;<br>
+};<br>
+<br>
+static void object_iterater(void *data, enum btree_node_type type, void *arg)<br>
+{<br>
+       struct sd_extent *ext;<br>
+       struct object_iterater_arg *oiarg = arg;<br>
+       struct kv_onode *onode = NULL;<br>
+       uint64_t oid;<br>
+       int ret;<br>
+<br>
+       if (type == BTREE_EXT) {<br>
+               ext = (struct sd_extent *)data;<br>
+               if (!ext->vdi_id)<br>
+                       goto out;<br>
+<br>
+               onode = xmalloc(SD_DATA_OBJ_SIZE);<br>
+               oid = vid_to_data_oid(ext->vdi_id, ext->idx);<br>
+               ret = sd_read_object(oid, (char *)onode, SD_DATA_OBJ_SIZE, 0);<br>
+               if (ret != SD_RES_SUCCESS) {<br>
+                       sd_err("Failed to read data object %lx", oid);<br>
+                       goto out;<br>
+               }<br>
+<br>
+               if (onode->name[0] == '\0')<br>
+                       goto out;<br>
+               if (oiarg->cb)<br>
+                       oiarg->cb(onode->name, oiarg->opaque);<br>
+               oiarg->count++;<br>
+       }<br>
+out:<br>
+       free(onode);<br>
+}<br>
+<br>
+static int bucket_iterate_object(uint32_t bucket_vid, o_iter_cb cb,<br>
+                                void *opaque)<br>
+{<br>
+       struct object_iterater_arg arg = {opaque, cb, 0};<br>
+       struct sd_inode *inode;<br>
+       int ret;<br>
+<br>
+       inode = xmalloc(sizeof(*inode));<br>
+       ret = sd_read_object(vid_to_vdi_oid(bucket_vid), (char *)inode,<br>
+                            sizeof(struct sd_inode), 0);<br>
+       if (ret != SD_RES_SUCCESS) {<br>
+               sd_err("failed to read inode %s", sd_strerror(ret));<br>
+               goto out;<br>
+       }<br>
+<br>
+       traverse_btree(sheep_bnode_reader, inode, object_iterater, &arg);<br>
+out:<br>
+       free(inode);<br>
+       return ret;<br>
+}<br>
+<br>
 int kv_create_bucket(const char *account, const char *bucket)<br>
 {<br>
        uint32_t account_vid, vid;<br>
@@ -437,11 +523,10 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-int kv_list_buckets(struct http_request *req, const char *account,<br>
-                   list_bucket_cb cb, void *opaque)<br>
+int kv_iterate_bucket(const char *account, b_iter_cb cb, void *opaque)<br>
 {<br>
        struct sd_inode account_inode;<br>
-       struct list_buckets_arg arg = {req, opaque, cb, 0};<br>
+       struct bucket_iterater_arg arg = {opaque, cb, 0};<br>
        uint32_t account_vid;<br>
        uint64_t oid;<br>
        int ret;<br>
@@ -462,7 +547,7 @@ int kv_list_buckets(struct http_request *req, const char *account,<br>
        }<br>
<br>
        traverse_btree(sheep_bnode_reader, &account_inode,<br>
-                      list_buckets_cb, &arg);<br>
+                      bucket_iterater, &arg);<br>
 out:<br>
        sys->cdrv->unlock(account_vid);<br>
        return ret;<br>
@@ -470,101 +555,6 @@ out:<br>
<br>
 /* Object operations */<br>
<br>
-/* 4 KB header of kv object index node */<br>
-struct onode_extent {<br>
-       uint64_t start;<br>
-       uint64_t count;<br>
-};<br>
-<br>
-struct kv_onode {<br>
-       union {<br>
-               struct {<br>
-                       char name[SD_MAX_OBJECT_NAME];<br>
-                       /* a hash value for etag */<br>
-                       uint8_t sha1[round_up(SHA1_DIGEST_SIZE, 8)];<br>
-                       uint64_t size;<br>
-                       uint64_t ctime;<br>
-                       uint64_t mtime;<br>
-                       uint32_t data_vid;<br>
-                       uint32_t nr_extent;<br>
-                       uint64_t oid;<br>
-                       uint8_t inlined;<br>
-               };<br>
-<br>
-               uint8_t __pad[BLOCK_SIZE];<br>
-       };<br>
-       union {<br>
-               uint8_t data[SD_DATA_OBJ_SIZE - BLOCK_SIZE];<br>
-               struct onode_extent o_extent[0];<br>
-       };<br>
-};<br>
-<br>
-typedef void (*list_object_cb)(struct http_request *req, const char *bucket,<br>
-                              const char *object, void *opaque);<br>
-<br>
-struct list_objects_arg {<br>
-       struct http_request *req;<br>
-       void *opaque;<br>
-       const char *bucket;<br>
-       list_object_cb cb;<br>
-       uint32_t object_counter;<br>
-};<br>
-<br>
-static void list_objects_cb(void *data, enum btree_node_type type, void *arg)<br>
-{<br>
-       struct sd_extent *ext;<br>
-       struct list_objects_arg *loarg = arg;<br>
-       struct kv_onode *onode = NULL;<br>
-       uint64_t oid;<br>
-       int ret;<br>
-<br>
-       if (type == BTREE_EXT) {<br>
-               ext = (struct sd_extent *)data;<br>
-               if (!ext->vdi_id)<br>
-                       goto out;<br>
-<br>
-               onode = xmalloc(SD_DATA_OBJ_SIZE);<br>
-<br>
-               oid = vid_to_data_oid(ext->vdi_id, ext->idx);<br>
-               ret = sd_read_object(oid, (char *)onode, SD_DATA_OBJ_SIZE, 0);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to read data object %lx", oid);<br>
-                       goto out;<br>
-               }<br>
-<br>
-               if (onode->name[0] == '\0')<br>
-                       goto out;<br>
-               if (loarg->cb)<br>
-                       loarg->cb(loarg->req, loarg->bucket, onode->name,<br>
-                                 loarg->opaque);<br>
-               loarg->object_counter++;<br>
-       }<br>
-out:<br>
-       free(onode);<br>
-}<br>
-<br>
-struct find_object_arg {<br>
-       bool found;<br>
-       const char *object_name;<br>
-};<br>
-<br>
-static void find_object_cb(struct http_request *req, const char *bucket,<br>
-                          const char *name, void *opaque)<br>
-{<br>
-       struct find_object_arg *foarg = (struct find_object_arg *)opaque;<br>
-<br>
-       if (!strncmp(foarg->object_name, name, SD_MAX_OBJECT_NAME))<br>
-               foarg->found = true;<br>
-}<br>
-<br>
-static bool kv_find_object(struct http_request *req, const char *account,<br>
-                          const char *bucket, const char *name)<br>
-{<br>
-       struct find_object_arg arg = {false, name};<br>
-       kv_list_objects(req, account, bucket, find_object_cb, &arg);<br>
-       return arg.found;<br>
-}<br>
-<br>
 #define KV_ONODE_INLINE_SIZE (SD_DATA_OBJ_SIZE - BLOCK_SIZE)<br>
<br>
 static int vdi_read_write(uint32_t vid, char *data, size_t length,<br>
@@ -693,25 +683,6 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-static int get_onode_data_vid(const char *account, const char *bucket,<br>
-                             uint32_t *onode_vid, uint32_t *data_vid)<br>
-{<br>
-       char vdi_name[SD_MAX_VDI_LEN];<br>
-       int ret;<br>
-<br>
-       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
-       ret = sd_lookup_vdi(vdi_name, onode_vid);<br>
-       if (ret != SD_RES_SUCCESS)<br>
-               return ret;<br>
-<br>
-       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s/allocator", account, bucket);<br>
-       ret = sd_lookup_vdi(vdi_name, data_vid);<br>
-       if (ret != SD_RES_SUCCESS)<br>
-               return ret;<br>
-<br>
-       return SD_RES_SUCCESS;<br>
-}<br>
-<br>
 static int onode_do_create(struct kv_onode *onode, struct sd_inode *inode,<br>
                           uint32_t idx)<br>
 {<br>
@@ -743,13 +714,13 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-static int onode_create(struct kv_onode *onode, uint32_t onode_vid)<br>
+static int onode_create(struct kv_onode *onode, uint32_t bucket_vid)<br>
 {<br>
        int ret;<br>
<br>
-       sys->cdrv->lock(onode_vid);<br>
-       ret = kv_generic_object_create(onode, onode_vid, onode_do_create);<br>
-       sys->cdrv->unlock(onode_vid);<br>
+       sys->cdrv->lock(bucket_vid);<br>
+       ret = kv_generic_object_create(onode, bucket_vid, onode_do_create);<br>
+       sys->cdrv->unlock(bucket_vid);<br>
<br>
        return ret;<br>
 }<br>
@@ -854,6 +825,36 @@ static int onode_delete(struct kv_onode *onode)<br>
        return SD_RES_SUCCESS;<br>
 }<br>
<br>
+struct find_object_arg {<br>
+       const char *object_name;<br>
+       int ret;<br>
+};<br>
+<br>
+static void find_object_cb(const char *name, void *opaque)<br>
+{<br>
+       struct find_object_arg *foarg = (struct find_object_arg *)opaque;<br>
+<br>
+       if (!strncmp(foarg->object_name, name, SD_MAX_OBJECT_NAME))<br>
+               foarg->ret = SD_RES_SUCCESS;<br>
+}<br>
+<br>
+/*<br>
+ * If we don't know if object exists in the bucket, we should use onode_find,<br>
+ * which iterate effeciently the bucket, instead of onode_lookup(), that assumes<br>
+ * object alrady exists and tries to look it up.<br>
+ */<br>
+static int onode_find(uint32_t ovid, const char *name)<br>
+{<br>
+       struct find_object_arg arg = {name, SD_RES_NO_OBJ};<br>
+       int ret;<br>
+<br>
+       ret = bucket_iterate_object(ovid, find_object_cb, &arg);<br>
+       if (ret != SD_RES_SUCCESS)<br>
+               return ret;<br>
+<br>
+       return arg.ret;<br>
+}<br>
+<br>
 /*<br>
  * user object name -> struct kv_onode -> sheepdog objects -> user data<br>
  *<br>
@@ -863,20 +864,29 @@ static int onode_delete(struct kv_onode *onode)<br>
 int kv_create_object(struct http_request *req, const char *account,<br>
                     const char *bucket, const char *name)<br>
 {<br>
+       char vdi_name[SD_MAX_VDI_LEN];<br>
        struct kv_onode *onode;<br>
-       uint32_t onode_vid, data_vid;<br>
+       uint32_t bucket_vid, data_vid;<br>
        int ret;<br>
<br>
-       if (kv_find_object(req, account, bucket, name)) {<br>
+       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
+       ret = sd_lookup_vdi(vdi_name, &bucket_vid);<br>
+       if (ret != SD_RES_SUCCESS)<br>
+               return ret;<br>
+<br>
+       ret = onode_find(bucket_vid, name);<br>
+       if (ret == SD_RES_SUCCESS) {<br>
                /* For overwrite, we delete old object and then create */<br>
-               ret = kv_delete_object(req, account, bucket, name);<br>
+               ret = kv_delete_object(account, bucket, name);<br>
                if (ret != SD_RES_SUCCESS) {<br>
                        sd_err("Failed to delete exists object %s", name);<br>
                        return ret;<br>
                }<br>
-       }<br>
+       } else if (ret != SD_RES_NO_OBJ)<br>
+               return ret;<br>
<br>
-       ret = get_onode_data_vid(account, bucket, &onode_vid, &data_vid);<br>
+       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s/allocator", account, bucket);<br>
+       ret = sd_lookup_vdi(vdi_name, &data_vid);<br>
        if (ret != SD_RES_SUCCESS)<br>
                return ret;<br>
<br>
@@ -890,7 +900,7 @@ int kv_create_object(struct http_request *req, const char *account,<br>
                goto out;<br>
        }<br>
<br>
-       ret = onode_create(onode, onode_vid);<br>
+       ret = onode_create(onode, bucket_vid);<br>
        if (ret != SD_RES_SUCCESS) {<br>
                sd_err("failed to create onode for %s", name);<br>
                onode_free_data(onode);<br>
@@ -905,19 +915,20 @@ int kv_read_object(struct http_request *req, const char *account,<br>
 {<br>
        struct kv_onode *onode = NULL;<br>
        char vdi_name[SD_MAX_VDI_LEN];<br>
-       uint32_t onode_vid;<br>
+       uint32_t bucket_vid;<br>
        int ret;<br>
<br>
-       if (!kv_find_object(req, account, bucket, name))<br>
-               return SD_RES_NO_OBJ;<br>
-<br>
        snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
-       ret = sd_lookup_vdi(vdi_name, &onode_vid);<br>
+       ret = sd_lookup_vdi(vdi_name, &bucket_vid);<br>
+       if (ret != SD_RES_SUCCESS)<br>
+               return ret;<br>
+<br>
+       ret = onode_find(bucket_vid, name);<br>
        if (ret != SD_RES_SUCCESS)<br>
                return ret;<br>
<br>
        onode = xzalloc(sizeof(*onode));<br>
-       ret = onode_lookup(onode, onode_vid, name);<br>
+       ret = onode_lookup(onode, bucket_vid, name);<br>
        if (ret != SD_RES_SUCCESS)<br>
                goto out;<br>
<br>
@@ -931,24 +942,24 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-int kv_delete_object(struct http_request *req, const char *account,<br>
-                    const char *bucket, const char *name)<br>
+int kv_delete_object(const char *account, const char *bucket, const char *name)<br>
 {<br>
        char vdi_name[SD_MAX_VDI_LEN];<br>
-       uint32_t onode_vid;<br>
+       uint32_t bucket_vid;<br>
        struct kv_onode *onode = NULL;<br>
        int ret;<br>
<br>
-       if (!kv_find_object(req, account, bucket, name))<br>
-               return SD_RES_NO_OBJ;<br>
-<br>
        snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
-       ret = sd_lookup_vdi(vdi_name, &onode_vid);<br>
+       ret = sd_lookup_vdi(vdi_name, &bucket_vid);<br>
+       if (ret != SD_RES_SUCCESS)<br>
+               return ret;<br>
+<br>
+       ret = onode_find(bucket_vid, name);<br>
        if (ret != SD_RES_SUCCESS)<br>
                return ret;<br>
<br>
        onode = xzalloc(sizeof(*onode));<br>
-       ret = onode_lookup(onode, onode_vid, name);<br>
+       ret = onode_lookup(onode, bucket_vid, name);<br>
        if (ret != SD_RES_SUCCESS)<br>
                goto out;<br>
<br>
@@ -958,31 +969,21 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-int kv_list_objects(struct http_request *req, const char *account,<br>
-                   const char *bucket, list_object_cb cb, void *opaque)<br>
+int kv_iterate_object(const char *account, const char *bucket, o_iter_cb cb,<br>
+                     void *opaque)<br>
 {<br>
-       int ret;<br>
-       uint32_t vid;<br>
-       struct sd_inode *inode = NULL;<br>
        char vdi_name[SD_MAX_VDI_LEN];<br>
+       uint32_t bucket_vid;<br>
+       int ret;<br>
<br>
        snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
-       ret = sd_lookup_vdi(vdi_name, &vid);<br>
+       ret = sd_lookup_vdi(vdi_name, &bucket_vid);<br>
        if (ret != SD_RES_SUCCESS)<br>
-               goto out;<br>
+               return ret;<br>
<br>
-       inode = xmalloc(sizeof(*inode));<br>
-       ret = sd_read_object(vid_to_vdi_oid(vid), (char *)inode,<br>
-                            sizeof(struct sd_inode), 0);<br>
-       if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("%s: bucket %s", sd_strerror(ret), bucket);<br>
-               http_response_header(req, INTERNAL_SERVER_ERROR);<br>
-               goto out;<br>
-       }<br>
+       sys->cdrv->lock(bucket_vid);<br>
+       ret = bucket_iterate_object(bucket_vid, cb, opaque);<br>
+       sys->cdrv->unlock(bucket_vid);<br>
<br>
-       struct list_objects_arg arg = {req, opaque, bucket, cb, 0};<br>
-       traverse_btree(sheep_bnode_reader, inode, list_objects_cb, &arg);<br>
-out:<br>
-       free(inode);<br>
        return ret;<br>
 }<br>
diff --git a/sheep/http/s3.c b/sheep/http/s3.c<br>
index 6a41308..aab1d1c 100644<br>
--- a/sheep/http/s3.c<br>
+++ b/sheep/http/s3.c<br>
@@ -13,13 +13,6 @@<br>
<br>
 #define MAX_BUCKET_LISTING 1000<br>
<br>
-/* Escape 'str' for use in XML. */<br>
-static const char *xml_escape(const char *str)<br>
-{<br>
-       /* FIXME: implement this function */<br>
-       return str;<br>
-}<br>
-<br>
 static void s3_write_err_response(struct http_request *req, const char *code,<br>
                                  const char *desc)<br>
 {<br>
@@ -32,32 +25,15 @@ static void s3_write_err_response(struct http_request *req, const char *code,<br>
<br>
 /* Operations on the Service */<br>
<br>
-static void s3_get_service_cb(struct http_request *req, const char *bucket,<br>
-                             void *opaque)<br>
+static void s3_get_service_cb(const char *bucket, void *opaque)<br>
 {<br>
-       bool *print_header = opaque;<br>
-<br>
-       if (*print_header) {<br>
-               *print_header = false;<br>
-<br>
-               http_request_writes(req,<br>
-                       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<br>
-                       "<ListAllMyBucketsResult "<br>
-                       "xmlns=\"<a href="http://doc.s3.amazonaws.com/2006-03-01\" target="_blank">http://doc.s3.amazonaws.com/2006-03-01\</a>">"<br>
-                       "<Buckets>");<br>
-       }<br>
-<br>
-       /* FIXME: set the correct creation date */<br>
-       http_request_writef(req, "<Bucket><Name>%s</Name><CreationDate>"<br>
-                           "2009-02-03T16:45:09.000Z</CreationDate></Bucket>",<br>
-                           xml_escape(bucket));<br>
 }<br>
<br>
 static void s3_get_service(struct http_request *req)<br>
 {<br>
        bool print_header = true;<br>
<br>
-       kv_list_buckets(req, "s3", s3_get_service_cb, &print_header);<br>
+       kv_iterate_bucket("s3", s3_get_service_cb, &print_header);<br>
<br>
        http_request_writes(req, "</Buckets></ListAllMyBucketsResult>\r\n");<br>
 }<br>
@@ -69,45 +45,15 @@ static void s3_head_bucket(struct http_request *req, const char *bucket)<br>
        http_response_header(req, NOT_IMPLEMENTED);<br>
 }<br>
<br>
-static void s3_get_bucket_cb(struct http_request *req, const char *bucket,<br>
-                            const char *object, void *opaque)<br>
+static void s3_get_bucket_cb(const char *object, void *opaque)<br>
 {<br>
-       bool *print_header = opaque;<br>
-<br>
-       if (*print_header) {<br>
-               *print_header = false;<br>
-<br>
-               http_request_writef(req,<br>
-                       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<br>
-                       "<ListBucketResult "<br>
-                       "xmlns=\"<a href="http://s3.amazonaws.com/doc/2006-03-01\" target="_blank">http://s3.amazonaws.com/doc/2006-03-01\</a>">"<br>
-                       "<Prefix></Prefix>"<br>
-                       "<Marker></Marker>"<br>
-                       "<Delimiter></Delimiter>"<br>
-                       "<IsTruncated>false</IsTruncated>"<br>
-                       "<MaxKeys>%d</MaxKeys>"<br>
-                       "<Name>%s</Name>", MAX_BUCKET_LISTING,<br>
-                       xml_escape(bucket));<br>
-       }<br>
-<br>
-       /* FIXME: set the correct metadata info */<br>
-       http_request_writef(req, "<Contents>"<br>
-               "<Key>%s</Key>"<br>
-               "<LastModified>2006-01-01T12:00:00.000Z</LastModified>"<br>
-               "<ETag>&quot;828ef3fdfa96f00ad9f27c383fc9ac7f&quot;</ETag>"<br>
-               "<Size>4</Size>"<br>
-               "<StorageClass>STANDARD</StorageClass>"<br>
-               "<Owner>"<br>
-               "<ID>bcaf1ffd86a5fb16fd081034f</ID>"<br>
-               "<DisplayName>webfile</DisplayName>"<br>
-               "</Owner></Contents>", xml_escape(object));<br>
 }<br>
<br>
 static void s3_get_bucket(struct http_request *req, const char *bucket)<br>
 {<br>
        bool print_header = true;<br>
<br>
-       kv_list_objects(req, "s3", bucket, s3_get_bucket_cb, &print_header);<br>
+       kv_iterate_object("s3", bucket, s3_get_bucket_cb, &print_header);<br>
<br>
        switch (req->status) {<br>
        case OK:<br>
@@ -191,7 +137,7 @@ static void s3_post_object(struct http_request *req, const char *bucket,<br>
 static void s3_delete_object(struct http_request *req, const char *bucket,<br>
                             const char *object)<br>
 {<br>
-       kv_delete_object(req, "s3", bucket, object);<br>
+       kv_delete_object("s3", bucket, object);<br>
<br>
        if (req->status == NOT_FOUND)<br>
                s3_write_err_response(req, "NoSuchKey",<br>
diff --git a/sheep/http/swift.c b/sheep/http/swift.c<br>
index 038945d..01e864a 100644<br>
--- a/sheep/http/swift.c<br>
+++ b/sheep/http/swift.c<br>
@@ -29,20 +29,18 @@ static void swift_head_account(struct http_request *req, const char *account)<br>
        }<br>
 }<br>
<br>
-static void swift_get_account_cb(struct http_request *req, const char *bucket,<br>
-                                void *opaque)<br>
+static void swift_get_account_cb(const char *bucket, void *opaque)<br>
 {<br>
        struct strbuf *buf = (struct strbuf *)opaque;<br>
<br>
-       if (bucket)<br>
-               strbuf_addf(buf, "%s\n", bucket);<br>
+       strbuf_addf(buf, "%s\n", bucket);<br>
 }<br>
<br>
 static void swift_get_account(struct http_request *req, const char *account)<br>
 {<br>
        struct strbuf buf = STRBUF_INIT;<br>
<br>
-       kv_list_buckets(req, account, swift_get_account_cb, (void *)&buf);<br>
+       kv_iterate_bucket(account, swift_get_account_cb, &buf);<br>
        req->data_length = buf.len;<br>
        http_response_header(req, OK);<br>
        http_request_write(req, buf.buf, buf.len);<br>
@@ -100,13 +98,11 @@ static void swift_head_container(struct http_request *req, const char *account,<br>
        http_response_header(req, NOT_IMPLEMENTED);<br>
 }<br>
<br>
-static void swift_get_container_cb(struct http_request *req, const char *bucket,<br>
-                                  const char *object, void *opaque)<br>
+static void swift_get_container_cb(const char *object, void *opaque)<br>
 {<br>
        struct strbuf *buf = (struct strbuf *)opaque;<br>
<br>
-       if (bucket && object)<br>
-               strbuf_addf(buf, "%s\n", object);<br>
+       strbuf_addf(buf, "%s\n", object);<br>
 }<br>
<br>
 static void swift_get_container(struct http_request *req, const char *account,<br>
@@ -114,8 +110,7 @@ static void swift_get_container(struct http_request *req, const char *account,<br>
 {<br>
        struct strbuf buf = STRBUF_INIT;<br>
<br>
-       kv_list_objects(req, account, container, swift_get_container_cb,<br>
-                       (void *)&buf);<br>
+       kv_iterate_object(account, container, swift_get_container_cb, &buf);<br>
        req->data_length = buf.len;<br>
        http_response_header(req, OK);<br>
        http_request_write(req, buf.buf, buf.len);<br>
@@ -216,7 +211,7 @@ static void swift_delete_object(struct http_request *req, const char *account,<br>
 {<br>
        int ret;<br>
<br>
-       ret = kv_delete_object(req, account, container, object);<br>
+       ret = kv_delete_object(account, container, object);<br>
        switch (ret) {<br>
        case SD_RES_SUCCESS:<br>
                http_response_header(req, NO_CONTENT);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.1.2<br>
<br>
--<br>
sheepdog mailing list<br>
<a href="mailto:sheepdog@lists.wpkg.org">sheepdog@lists.wpkg.org</a><br>
<a href="http://lists.wpkg.org/mailman/listinfo/sheepdog" target="_blank">http://lists.wpkg.org/mailman/listinfo/sheepdog</a><br>
</font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br>--<br>Best Regard<br>Robin Dong
</div></div>