<div dir="ltr">Reviewed-by: Robin Dong <<a href="mailto:sanbai@taobao.com">sanbai@taobao.com</a>></div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/12/22 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">This patch simplify the code for bucket operations and alos also fixes potential<br>
buggy error handlings.<br>
<br>
Now we use the whole object in the account_vdi to represent the bucket because<br>
<br>
- shares many codes with object operations.<br>
- kv_bnode need space to hold meta data in the form of X-Container-Meta-*<br>
<br>
This patch also fixes account create and delete:<br>
 - we should use GET to create the account and DELETE to delete the account<br>
 - POST is used to update the account metadata in the form of X-Account-Meta-*<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        |   2 +-<br>
 sheep/http/kv.c          | 812 ++++++++++++++++-------------------------------<br>
 sheep/http/swift.c       |  35 +-<br>
 tests/functional/081     |   4 +-<br>
 tests/functional/081.out |   2 +-<br>
 tests/functional/082     |   4 +-<br>
 tests/functional/082.out |   2 +-<br>
 7 files changed, 302 insertions(+), 559 deletions(-)<br>
<br>
diff --git a/sheep/http/http.h b/sheep/http/http.h<br>
index a2f404c..3141c09 100644<br>
--- a/sheep/http/http.h<br>
+++ b/sheep/http/http.h<br>
@@ -111,7 +111,7 @@ int http_request_writef(struct http_request *req, const char *fmt, ...);<br>
<br>
 /* For kv.c */<br>
<br>
-#define SD_MAX_BUCKET_NAME 64<br>
+#define SD_MAX_BUCKET_NAME 256<br>
 #define SD_MAX_OBJECT_NAME 1024<br>
<br>
 /* Account operations */<br>
diff --git a/sheep/http/kv.c b/sheep/http/kv.c<br>
index 91f759b..5d28348 100644<br>
--- a/sheep/http/kv.c<br>
+++ b/sheep/http/kv.c<br>
@@ -16,48 +16,13 @@<br>
 #include "sheep_priv.h"<br>
 #include "http.h"<br>
<br>
-struct bucket_inode_hdr {<br>
-       char bucket_name[SD_MAX_BUCKET_NAME];<br>
+struct kv_bnode {<br>
+       char name[SD_MAX_BUCKET_NAME];<br>
        uint64_t obj_count;<br>
        uint64_t bytes_used;<br>
-       uint32_t onode_vid;<br>
-       uint32_t data_vid;              /* data of objects store in this vdi */<br>
-};<br>
-<br>
-struct bucket_inode {<br>
-       union {<br>
-               struct bucket_inode_hdr hdr;<br>
-               uint8_t data[BLOCK_SIZE];<br>
-       };<br>
+       uint64_t oid;<br>
 };<br>
<br>
-#define MAX_BUCKETS (SD_MAX_VDI_SIZE / sizeof(struct bucket_inode))<br>
-#define BUCKETS_PER_SD_OBJ (SD_DATA_OBJ_SIZE / sizeof(struct bucket_inode))<br>
-<br>
-static int lookup_vdi(const char *name, uint32_t *vid)<br>
-{<br>
-       int ret;<br>
-       struct vdi_info info = {};<br>
-       struct vdi_iocb iocb = {<br>
-               .name = name,<br>
-               .data_len = strlen(name),<br>
-       };<br>
-<br>
-       ret = vdi_lookup(&iocb, &info);<br>
-       switch (ret) {<br>
-       case SD_RES_SUCCESS:<br>
-               *vid = info.vid;<br>
-               break;<br>
-       case SD_RES_NO_VDI:<br>
-               sd_info("no such vdi %s", name);<br>
-               break;<br>
-       default:<br>
-               sd_err("Failed to find vdi %s %s", name, sd_strerror(ret));<br>
-       }<br>
-<br>
-       return ret;<br>
-}<br>
-<br>
 static int kv_create_hyper_volume(const char *name, uint32_t *vdi_id)<br>
 {<br>
        struct sd_req hdr;<br>
@@ -103,16 +68,34 @@ static int discard_data_obj(uint64_t oid)<br>
        return ret;<br>
 }<br>
<br>
-static int kv_delete_vdi(const char *name)<br>
+static int kv_lookup_vdi(const char *name, uint32_t *vid)<br>
 {<br>
        int ret;<br>
+       struct vdi_info info = {};<br>
+       struct vdi_iocb iocb = {<br>
+               .name = name,<br>
+               .data_len = strlen(name),<br>
+       };<br>
+<br>
+       ret = vdi_lookup(&iocb, &info);<br>
+       switch (ret) {<br>
+       case SD_RES_SUCCESS:<br>
+               *vid = info.vid;<br>
+               break;<br>
+       case SD_RES_NO_VDI:<br>
+               break;<br>
+       default:<br>
+               sd_err("Failed to lookup name %s, %s", name, sd_strerror(ret));<br>
+       }<br>
+<br>
+       return ret;<br>
+}<br>
+<br>
+static int kv_delete_vdi(const char *name)<br>
+{<br>
        struct sd_req hdr;<br>
        char data[SD_MAX_VDI_LEN] = {0};<br>
-       uint32_t vid;<br>
-<br>
-       ret = lookup_vdi(name, &vid);<br>
-       if (ret != SD_RES_SUCCESS)<br>
-               return ret;<br>
+       int ret;<br>
<br>
        sd_init_req(&hdr, SD_OP_DEL_VDI);<br>
        hdr.flags = SD_FLAG_CMD_WRITE;<br>
@@ -127,33 +110,90 @@ static int kv_delete_vdi(const char *name)<br>
 }<br>
<br>
 /*<br>
- * An account is actually a hyper volume vdi (up to 16PB),<br>
- * all the buckets (or containers, identified by 'struct bucket_inode') are<br>
- * stores in this hyper vdi using hashing algorithm.<br>
- * The bucket also has a hyper vdi named "account/bucket" which stores<br>
- * 'struct kv_onodes'.<br>
+ * Find an free object index by hash of name in the vid and create an object<br>
+ * that holds the kv node{kv_bnode, kv_onode}.<br>
+ */<br>
+#define kv_generic_object_create(node, vid, node_do_create)            \<br>
+({                                                                     \<br>
+       struct sd_inode *__inode = xmalloc(sizeof(struct sd_inode));    \<br>
+       uint32_t __tmp_vid, __idx, __i;                                 \<br>
+       uint64_t __hval;                                                \<br>
+       int __ret;                                                      \<br>
+                                                                       \<br>
+       __ret = sd_read_object(vid_to_vdi_oid(vid), (char *)__inode,    \<br>
+                              sizeof(*__inode), 0);                    \<br>
+       if (__ret != SD_RES_SUCCESS) {                                  \<br>
+               sd_err("failed to read %" PRIx32 " %s", vid,            \<br>
+                      sd_strerror(__ret));                             \<br>
+               goto out;                                               \<br>
+       }                                                               \<br>
+                                                                       \<br>
+       __hval = sd_hash(node->name, strlen(node->name));               \<br>
+       for (__i = 0; __i < MAX_DATA_OBJS; __i++) {                     \<br>
+               __idx = (__hval + __i) % MAX_DATA_OBJS;                 \<br>
+               __tmp_vid = INODE_GET_VID(__inode, __idx);              \<br>
+               if (__tmp_vid)                                          \<br>
+                       continue;                                       \<br>
+               else                                                    \<br>
+                       break;                                          \<br>
+       }                                                               \<br>
+       if (__i == MAX_DATA_OBJS) {                                     \<br>
+               __ret = SD_RES_NO_SPACE;                                \<br>
+               goto out;                                               \<br>
+       }                                                               \<br>
+       __ret = node_do_create(node, __inode, __idx);                   \<br>
+out:                                                                   \<br>
+       free(__inode);                                                  \<br>
+       __ret;                                                          \<br>
+})<br>
+<br>
+/* Find the object in the vid which holds the 'node' that matches 'name' */<br>
+#define kv_generic_object_lookup(node, vid, name)                      \<br>
+({                                                                     \<br>
+       uint64_t __hval;                                                \<br>
+       uint32_t __i;                                                   \<br>
+       int __ret;                                                      \<br>
+                                                                       \<br>
+       __hval = sd_hash(name, strlen(name));                           \<br>
+       for (__i = 0; __i < MAX_DATA_OBJS; __i++) {                     \<br>
+               uint32_t __idx = (__hval + __i) % MAX_DATA_OBJS;        \<br>
+               uint64_t __oid = vid_to_data_oid(vid, __idx);           \<br>
+                                                                       \<br>
+               __ret = sd_read_object(__oid, (char *)node, sizeof(*node), 0); \<br>
+               if (__ret != SD_RES_SUCCESS)                            \<br>
+                       goto out;                                       \<br>
+               if (strcmp(node->name, name) == 0)                      \<br>
+                       break;                                          \<br>
+       }                                                               \<br>
+                                                                       \<br>
+       if (__i == MAX_DATA_OBJS)                                       \<br>
+               __ret = SD_RES_NO_OBJ;                                  \<br>
+out:                                                                   \<br>
+       __ret;                                                          \<br>
+})<br>
+<br>
+/* Account operations */<br>
+<br>
+/*<br>
+ * Account can have unlimited buckets, each of which can contain unlimited user<br>
+ * KV objects.<br>
  *<br>
- * For example: account "coly" has two buckets "jetta" and "volvo"<br>
+ * For a URI such as /$account/$bucket/$object:<br>
  *<br>
+ *      kv_bnode helps us find the desired bucket by $bucket<br>
+ *             |<br>
+ *             V<br>
+ *   $account --> [bucket1, bucket2, bucket3, ...]<br>
+ *                    |<br>
+ *                    | kv_onode helps us find the desired object by $object<br>
+ *                    V<br>
+ *                  [object1, object2, ...]<br>
  *<br>
- * account vdi<br>
- * +-----------+---+--------------------------+---+--------------------------+--<br>
- * |name: coly |...|bucket_inode (name: jetta)|...|bucket_inode (name: volvo)|..<br>
- * +-----------+---+--------------------------+---+--------------------------+--<br>
- *                                  |                             |<br>
- *                                 /                              |<br>
- * bucket vdi                     /                               |<br>
- * +-----------------+-------+ <--                                |<br>
- * |name: coly/jetta |.......|                                    |<br>
- * +-----------------+-------+                                   /<br>
- *                              bucket vdi                      /<br>
- *                              +-----------------+------+ <----<br>
- *                              | name: coly/volvo|......|<br>
- *                              +-----------------+------+<br>
+ * We assign a hyper volume for each account to hold the kv_bnodes(bucket index<br>
+ * node), each of which point to a bucket(also a hyper volume), into which we<br>
+ * store kv_onodes, that maps to user kv data objects.<br>
  */<br>
<br>
-/* Account operations */<br>
-<br>
 int kv_create_account(const char *account)<br>
 {<br>
        uint32_t vdi_id;<br>
@@ -174,9 +214,8 @@ static void list_buckets_cb(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_inode *bnode;<br>
+       struct kv_bnode bnode;<br>
        uint64_t oid;<br>
-       char *buf = NULL;<br>
        int ret;<br>
<br>
        if (type == BTREE_EXT) {<br>
@@ -184,28 +223,19 @@ static void list_buckets_cb(void *data, enum btree_node_type type, void *arg)<br>
                if (!ext->vdi_id)<br>
                        return;<br>
<br>
-               buf = xzalloc(SD_DATA_OBJ_SIZE);<br>
-<br>
                oid = vid_to_data_oid(ext->vdi_id, ext->idx);<br>
-               ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0);<br>
+               ret = sd_read_object(oid, (char *)&bnode, sizeof(bnode), 0);<br>
                if (ret != SD_RES_SUCCESS) {<br>
                        sd_err("Failed to read data object %lx", oid);<br>
-                       goto out;<br>
-               }<br>
-               /* loop all bucket_inodes in this data-object */<br>
-               for (int i = 0; i < BUCKETS_PER_SD_OBJ; i++) {<br>
-                       bnode = (struct bucket_inode *)<br>
-                               (buf + i * sizeof(struct bucket_inode));<br>
-                       if (bnode->hdr.onode_vid == 0)<br>
-                               continue;<br>
-                       if (lbarg->cb)<br>
-                               lbarg->cb(lbarg->req, bnode->hdr.bucket_name,<br>
-                                         (void *)lbarg->opaque);<br>
-                       lbarg->bucket_counter++;<br>
+                       return;<br>
                }<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>
        }<br>
-out:<br>
-       free(buf);<br>
 }<br>
<br>
 /* get number of buckets in this account */<br>
@@ -214,9 +244,10 @@ 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>
        int ret;<br>
<br>
-       ret = lookup_vdi(account, &account_vid);<br>
+       ret = kv_lookup_vdi(account, &account_vid);<br>
        if (ret != SD_RES_SUCCESS)<br>
                goto out;<br>
<br>
@@ -228,7 +259,6 @@ static int kv_get_account(const char *account, uint32_t *nr_buckets)<br>
                goto out;<br>
        }<br>
<br>
-       struct list_buckets_arg arg = {NULL, NULL, NULL, 0};<br>
        traverse_btree(sheep_bnode_reader, &inode, list_buckets_cb, &arg);<br>
        if (nr_buckets)<br>
                *nr_buckets = arg.bucket_counter;<br>
@@ -265,296 +295,143 @@ int kv_delete_account(const char *account)<br>
<br>
 /* Bucket operations */<br>
<br>
-static int kv_lookup_vdi(const char *name, uint32_t *vid)<br>
-{<br>
-       int ret;<br>
-       struct vdi_info info = {};<br>
-       struct vdi_iocb iocb = {<br>
-               .name = name,<br>
-               .data_len = strlen(name),<br>
-       };<br>
-<br>
-       ret = vdi_lookup(&iocb, &info);<br>
-       switch (ret) {<br>
-       case SD_RES_SUCCESS:<br>
-               *vid = info.vid;<br>
-               break;<br>
-       case SD_RES_NO_VDI:<br>
-               sd_info("no such bucket %s", name);<br>
-               break;<br>
-       default:<br>
-               sd_err("Failed to lookup name %s, %s", name, sd_strerror(ret));<br>
-       }<br>
-<br>
-       return ret;<br>
-}<br>
-<br>
 /*<br>
- * Delete bucket(container) inode in account vdi.<br>
- * idx: the target hash positon of bucket<br>
- * Return the position of bucket_inode in sd-data-object if success<br>
- * Return BUCKETS_PER_SD_OBJ if bucket_inode is not found<br>
- * Return -1 if some errors happend<br>
+ * We use two VDIs to implement bucket abstraction: one stores 'struct kv_onode'<br>
+ * which is an index node for user data and the other actually stores kv data,<br>
+ * which use oalloc.c to manage free space.<br>
+ *<br>
+ * The first vdi is named as "$account/$bucket" and the second vdi as<br>
+ * "$account/$bucket/allocator".<br>
+ *<br>
+ * For example: bucket "fruit" with account 'coly' has two objects "banana"<br>
+ *              and "apple"<br>
+ *<br>
+ * Account: coly<br>
+ * +-----------------------+<br>
+ * | kv_bnode: fruit | ... |    <--- account_vid<br>
+ * +-----------------------+<br>
+ *         |            +--------------------- kv_onode ---------------------+<br>
+ *         |            |                                                    |<br>
+ *          \           v                                                    v<br>
+ *          \       +---------------------------------------------------------+<br>
+ * onode_vdi  \----> |coly/fruit | ... | kv_onode: banana | kv_onode: apple    |<br>
+ *                   +---------------------------------------------------------+<br>
+ *                                                    |             |<br>
+ *      oalloc.c manages allocation and deallocation  |             |<br>
+ *                                                   v             v<br>
+ *                   +---------------------------+---+-----------------+<br>
+ * data_vid          |coly/fruit/allocator       |...|       data      |<br>
+ *                   +---------------------------+---+-----------------+<br>
  */<br>
-static int delete_bucket(struct sd_inode *account_inode, uint64_t idx,<br>
-                        const char *bucket)<br>
+<br>
+static int bnode_do_create(struct kv_bnode *bnode, struct sd_inode *inode,<br>
+                          uint32_t idx)<br>
 {<br>
-       struct bucket_inode *bnode;<br>
-       char *buf = NULL;<br>
-       uint32_t vdi_id;<br>
-       uint64_t oid;<br>
-       uint64_t data_index = idx / BUCKETS_PER_SD_OBJ;<br>
-       int offset = idx % BUCKETS_PER_SD_OBJ;<br>
-       int ret, i, empty_buckets = 0, found = 0;<br>
-<br>
-       vdi_id = INODE_GET_VID(account_inode, data_index);<br>
-       if (!vdi_id) {<br>
-               sd_err("the %lu in vdi %s is not exists", data_index,<br>
-                      account_inode->name);<br>
-               ret = -1;<br>
-               goto out;<br>
-       }<br>
+       uint32_t vid = inode->vdi_id;<br>
+       uint64_t oid = vid_to_data_oid(vid, idx);<br>
+       int ret;<br>
<br>
-       oid = vid_to_data_oid(account_inode->vdi_id, data_index);<br>
-       buf = xzalloc(SD_DATA_OBJ_SIZE);<br>
-       ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0);<br>
+       bnode->oid = oid;<br>
+       ret = sd_write_object(oid, (char *)bnode, sizeof(*bnode), 0, true);<br>
        if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("Failed to read inode header %lx", oid);<br>
-               ret = -1;<br>
+               sd_err("failed to create object, %" PRIx64, oid);<br>
                goto out;<br>
        }<br>
-<br>
-       for (i = 0; i < BUCKETS_PER_SD_OBJ; i++) {<br>
-               char vdi_name[SD_MAX_VDI_LEN];<br>
-               bnode = (struct bucket_inode *)<br>
-                       (buf + i * sizeof(struct bucket_inode));<br>
-               /* count all empty buckets in this sd-data-obj */<br>
-               if (bnode->hdr.onode_vid == 0) {<br>
-                       empty_buckets++;<br>
-                       continue;<br>
-               }<br>
-               if (strncmp(bnode->hdr.bucket_name, bucket, SD_MAX_BUCKET_NAME))<br>
-                       continue;<br>
-<br>
-               if (i < offset)<br>
-                       panic("postion of bucket inode %d is smaller than %d",<br>
-                             i, offset);<br>
-<br>
-               found = i;<br>
-               /* find the bnode */<br>
-               bnode->hdr.onode_vid = 0;<br>
-               snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s",<br>
-                        account_inode->name, bucket);<br>
-               /* delete vdi which store kv_onode */<br>
-               ret = kv_delete_vdi(vdi_name);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to delete vdi %s", vdi_name);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               /* delete vdi which store object data */<br>
-               snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s/allocator",<br>
-                        account_inode->name, bucket);<br>
-               ret = kv_delete_vdi(vdi_name);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to delete vdi %s", vdi_name);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               sd_debug("delete vdi %s success", vdi_name);<br>
-       }<br>
-<br>
-       if (!found) {<br>
-               ret = BUCKETS_PER_SD_OBJ;<br>
+       INODE_SET_VID(inode, idx, vid);<br>
+       ret = sd_inode_write_vid(sheep_bnode_writer, inode, idx,<br>
+                                vid, vid, 0, false, false);<br>
+       if (ret != SD_RES_SUCCESS) {<br>
+               sd_err("failed to update inode, %" PRIx64,<br>
+                      vid_to_vdi_oid(vid));<br>
                goto out;<br>
        }<br>
-<br>
-       /*<br>
-        * if only this bucket_inode is in the sd-data-obj,<br>
-        * then delete this sd-data-obj<br>
-        */<br>
-       if (empty_buckets == BUCKETS_PER_SD_OBJ - 1) {<br>
-               ret = discard_data_obj(oid);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               INODE_SET_VID(account_inode, data_index, 0);<br>
-               ret = sd_inode_write_vid(sheep_bnode_writer, account_inode,<br>
-                                        data_index, vdi_id, vdi_id, 0, false,<br>
-                                        false);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to write inode %x", vdi_id);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               sd_debug("discard obj %lx and update vdi %x success",<br>
-                        oid, vdi_id);<br>
-       } else {<br>
-               ret = sd_write_object(oid, buf, sizeof(struct bucket_inode),<br>
-                                     i * sizeof(struct bucket_inode), false);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to write object %lx", oid);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-       }<br>
-<br>
-       sd_debug("write object oid %lx success", oid);<br>
-       ret = found;<br>
 out:<br>
-       free(buf);<br>
        return ret;<br>
 }<br>
<br>
-/*<br>
- * Add bucket(container) inode into account vdi.<br>
- * idx: the target hash positon of bucket<br>
- * Return the position of bucket_inode in sd-data-object if success<br>
- * Return BUCKETS_PER_SD_OBJ if the data-object is full of bucket_inode<br>
- * Return -1 if some error happend<br>
- */<br>
-static int add_bucket(struct sd_inode *account_inode, uint64_t idx,<br>
-                     const char *bucket)<br>
+static int bnode_create(struct kv_bnode *bnode, uint32_t account_vid)<br>
 {<br>
-       struct bucket_inode *bnode;<br>
-       char *buf = NULL;<br>
-       uint32_t vdi_id;<br>
-       uint64_t oid;<br>
-       uint64_t data_index = idx / BUCKETS_PER_SD_OBJ;<br>
-       int offset = idx % BUCKETS_PER_SD_OBJ;<br>
-       int ret, i;<br>
-       bool create = false;<br>
-<br>
-       buf = xzalloc(SD_DATA_OBJ_SIZE);<br>
-<br>
-       vdi_id = INODE_GET_VID(account_inode, data_index);<br>
-       oid = vid_to_data_oid(account_inode->vdi_id, data_index);<br>
-       sd_debug("oid %x %lx %lx", account_inode->vdi_id, data_index, oid);<br>
-       /* the data object is exists */<br>
-       if (vdi_id) {<br>
-               ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to read inode header %lx", oid);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-       } else<br>
-               create = true;<br>
-<br>
-       sd_debug("bucket_inode offset %d %lu", offset, BUCKETS_PER_SD_OBJ);<br>
-       for (i = offset; i < BUCKETS_PER_SD_OBJ; i++) {<br>
-               char vdi_name[SD_MAX_VDI_LEN];<br>
-               bnode = (struct bucket_inode *)<br>
-                       (buf + i * sizeof(struct bucket_inode));<br>
-               if (bnode->hdr.onode_vid != 0)<br>
-                       continue;<br>
-<br>
-               /* the bnode not used */<br>
-               strncpy(bnode->hdr.bucket_name, bucket, SD_MAX_BUCKET_NAME);<br>
-               bnode->hdr.obj_count = 0;<br>
-               bnode->hdr.bytes_used = 0;<br>
-               snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s",<br>
-                        account_inode->name, bucket);<br>
-               /* create vdi to store kv_onode */<br>
-               ret = kv_create_hyper_volume(vdi_name, &(bnode->hdr.onode_vid));<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to create hyper volume %d", ret);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s/allocator",<br>
-                        account_inode->name, bucket);<br>
-               /* create vdi to store objects */<br>
-               ret = kv_create_hyper_volume(vdi_name, &(bnode->hdr.data_vid));<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to create hyper volume %d", ret);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               ret = oalloc_init(bnode->hdr.data_vid);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to init allocator on %x",<br>
-                              bnode->hdr.data_vid);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               sd_debug("create hyper volume %s success", vdi_name);<br>
-               break;<br>
-       }<br>
-<br>
-       if (i >= BUCKETS_PER_SD_OBJ) {<br>
-               ret = BUCKETS_PER_SD_OBJ;<br>
-               goto out;<br>
-       }<br>
+       return kv_generic_object_create(bnode, account_vid, bnode_do_create);<br>
+}<br>
<br>
-       /* write bnode back to account-vdi */<br>
-       if (create)<br>
-               ret = sd_write_object(oid, buf, SD_DATA_OBJ_SIZE, 0, create);<br>
-       else<br>
-               ret = sd_write_object(oid, buf, sizeof(struct bucket_inode),<br>
-                                     i * sizeof(struct bucket_inode), create);<br>
+static int bucket_create(const char *account, uint32_t account_vid,<br>
+                        const char *bucket)<br>
+{<br>
+       char onode_name[SD_MAX_VDI_LEN];<br>
+       char alloc_name[SD_MAX_VDI_LEN];<br>
+       struct kv_bnode bnode;<br>
+       uint32_t vid;<br>
+       int ret;<br>
<br>
+       snprintf(onode_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
+       ret = kv_create_hyper_volume(onode_name, &vid);<br>
        if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("Failed to write object %lx", oid);<br>
-               ret = -1;<br>
-               goto out;<br>
+               sd_err("Failed to create bucket %s onode vid", bucket);<br>
+               return ret;<br>
        }<br>
-<br>
-       sd_debug("write object oid %lx success", oid);<br>
-<br>
-       /* update index of vdi */<br>
-       if (create) {<br>
-               vdi_id = account_inode->vdi_id;<br>
-               INODE_SET_VID(account_inode, data_index, vdi_id);<br>
-               ret = sd_inode_write_vid(sheep_bnode_writer, account_inode,<br>
-                                        data_index, vdi_id, vdi_id, 0, false,<br>
-                                        false);<br>
-               if (ret != SD_RES_SUCCESS) {<br>
-                       sd_err("Failed to write inode %x", vdi_id);<br>
-                       ret = -1;<br>
-                       goto out;<br>
-               }<br>
-               sd_debug("write account inode success");<br>
+       snprintf(alloc_name, SD_MAX_VDI_LEN, "%s/%s/allocator", account,<br>
+                bucket);<br>
+       ret = kv_create_hyper_volume(alloc_name, &vid);<br>
+       if (ret != SD_RES_SUCCESS) {<br>
+               sd_err("Failed to create bucket %s data vid", bucket);<br>
+               kv_delete_vdi(onode_name);<br>
+               return ret;<br>
+       }<br>
+       ret = oalloc_init(vid);<br>
+       if (ret != SD_RES_SUCCESS) {<br>
+               sd_err("Failed to init allocator for bucket %s", bucket);<br>
+               goto err;<br>
        }<br>
<br>
-       ret = i;<br>
-out:<br>
-       free(buf);<br>
+       pstrcpy(<a href="http://bnode.name" target="_blank">bnode.name</a>, sizeof(<a href="http://bnode.name" target="_blank">bnode.name</a>), bucket);<br>
+       bnode.bytes_used = 0;<br>
+       bnode.obj_count = 0;<br>
+       ret = bnode_create(&bnode, account_vid);<br>
+       if (ret != SD_RES_SUCCESS)<br>
+               goto err;<br>
+<br>
+       return SD_RES_SUCCESS;<br>
+err:<br>
+       kv_delete_vdi(onode_name);<br>
+       kv_delete_vdi(alloc_name);<br>
        return ret;<br>
 }<br>
<br>
-static int kv_get_lock_bucket(struct sd_inode *account_inode,<br>
-                             uint32_t account_vid, const char *account,<br>
-                             const char *bucket)<br>
+static int bucket_lookup(struct kv_bnode *bnode, uint32_t vid, const char *name)<br>
 {<br>
-       char vdi_name[SD_MAX_VDI_LEN];<br>
-       uint64_t oid;<br>
-       uint32_t bucket_vid;<br>
+       return kv_generic_object_lookup(bnode, vid, name);<br>
+}<br>
+<br>
+static int bucket_delete(const char *account, uint32_t avid, const char *bucket)<br>
+{<br>
+       struct kv_bnode bnode;<br>
+       char onode_name[SD_MAX_VDI_LEN];<br>
+       char alloc_name[SD_MAX_VDI_LEN];<br>
        int ret;<br>
<br>
-       sys->cdrv->lock(account_vid);<br>
-       /* read account vdi out */<br>
-       oid = vid_to_vdi_oid(account_vid);<br>
-       ret = sd_read_object(oid, (char *)account_inode,<br>
-                            sizeof(struct sd_inode), 0);<br>
+       snprintf(onode_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
+       snprintf(alloc_name, SD_MAX_VDI_LEN, "%s/%s/allocator", account,<br>
+                bucket);<br>
+<br>
+       ret = bucket_lookup(&bnode, avid, bucket);<br>
        if (ret != SD_RES_SUCCESS)<br>
-               goto out;<br>
+               return ret;<br>
<br>
-       /* find bucket vdi */<br>
-       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s",<br>
-                account_inode->name, bucket);<br>
+       ret = discard_data_obj(bnode.oid);<br>
+       if (ret != SD_RES_SUCCESS) {<br>
+               sd_err("failed to discard bnode for %s", bucket);<br>
+               return ret;<br>
+       }<br>
+       kv_delete_vdi(onode_name);<br>
+       kv_delete_vdi(alloc_name);<br>
<br>
-       ret = lookup_vdi(vdi_name, &bucket_vid);<br>
-out:<br>
-       return ret;<br>
+       return SD_RES_SUCCESS;<br>
 }<br>
<br>
 int kv_create_bucket(const char *account, const char *bucket)<br>
 {<br>
-       struct sd_inode inode;<br>
-       uint64_t hval, i;<br>
-       uint32_t account_vid;<br>
+       uint32_t account_vid, vid;<br>
+       char vdi_name[SD_MAX_VDI_LEN];<br>
        int ret;<br>
<br>
        ret = kv_lookup_vdi(account, &account_vid);<br>
@@ -563,47 +440,18 @@ int kv_create_bucket(const char *account, const char *bucket)<br>
                return ret;<br>
        }<br>
<br>
-       ret = kv_get_lock_bucket(&inode, account_vid, account, bucket);<br>
-       /*<br>
-        * if lookup bucket success, kv_get_bucket will return SD_RES_SUCCESS,<br>
-        * which means the bucket is already exists.<br>
-        */<br>
+       sys->cdrv->lock(account_vid);<br>
+       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
+       ret = kv_lookup_vdi(vdi_name, &vid);<br>
        if (ret == SD_RES_SUCCESS) {<br>
                sd_err("bucket %s is exists.", bucket);<br>
                ret = SD_RES_VDI_EXIST;<br>
                goto out;<br>
-       } else if (ret != SD_RES_NO_VDI)<br>
-               goto out;<br>
-<br>
-       /*<br>
-        * if kv_get_bucket() return SD_RES_NO_VDI, it means we can<br>
-        * create bucket normally now.<br>
-        */<br>
-<br>
-       sd_debug("read account inode success");<br>
-<br>
-       hval = sd_hash(bucket, strlen(bucket));<br>
-       for (i = 0; i < MAX_BUCKETS; i++) {<br>
-               uint64_t idx = (hval + i) % MAX_BUCKETS;<br>
-               ret = add_bucket(&inode, idx, bucket);<br>
-               /* data-object is full */<br>
-               if (ret == BUCKETS_PER_SD_OBJ) {<br>
-                       i += BUCKETS_PER_SD_OBJ;<br>
-                       continue;<br>
-               } else if (ret < 0) {<br>
-                       sd_err("Failed to add bucket");<br>
-                       goto out;<br>
-               }<br>
-               /* add bucket success */<br>
-               sd_debug("add bucket success");<br>
-               break;<br>
        }<br>
-<br>
-       if (i >= MAX_BUCKETS) {<br>
-               sd_err("Containers in vdi %s is full!", account);<br>
-               ret = -1;<br>
+       if (ret != SD_RES_NO_VDI)<br>
                goto out;<br>
-       }<br>
+<br>
+       ret = bucket_create(account, account_vid, bucket);<br>
 out:<br>
        sys->cdrv->unlock(account_vid);<br>
        return ret;<br>
@@ -624,9 +472,8 @@ int kv_update_bucket(const char *account, const char *bucket)<br>
 /* return SD_RES_NO_VDI if bucket is not existss */<br>
 int kv_delete_bucket(const char *account, const char *bucket)<br>
 {<br>
-       struct sd_inode inode;<br>
-       uint64_t hval, i;<br>
-       uint32_t account_vid;<br>
+       uint32_t account_vid, vid;<br>
+       char vdi_name[SD_MAX_VDI_LEN];<br>
        int ret;<br>
<br>
        ret = kv_lookup_vdi(account, &account_vid);<br>
@@ -635,33 +482,13 @@ int kv_delete_bucket(const char *account, const char *bucket)<br>
                return ret;<br>
        }<br>
<br>
-       ret = kv_get_lock_bucket(&inode, account_vid, account, bucket);<br>
-       if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("Failed to get bucket");<br>
-               goto out;<br>
-       }<br>
-<br>
-       hval = sd_hash(bucket, strlen(bucket));<br>
-       for (i = 0; i < MAX_BUCKETS; i++) {<br>
-               uint64_t idx = (hval + i) % MAX_BUCKETS;<br>
-               ret = delete_bucket(&inode, idx, bucket);<br>
-               if (ret == BUCKETS_PER_SD_OBJ) {<br>
-                       i += BUCKETS_PER_SD_OBJ;<br>
-                       continue;<br>
-               } else if (ret < 0) {<br>
-                       sd_err("Failed to delete bucket %d", ret);<br>
-                       goto out;<br>
-               }<br>
-               /* delete bucket success */<br>
-               sd_debug("delete bucket success");<br>
-               break;<br>
-       }<br>
+       sys->cdrv->lock(account_vid);<br>
+       snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s", account, bucket);<br>
<br>
-       if (i >= MAX_BUCKETS) {<br>
-               sd_err("Can't find bucket %s", bucket);<br>
-               ret = SD_RES_NO_VDI;<br>
+       ret = kv_lookup_vdi(vdi_name, &vid);<br>
+       if (ret != SD_RES_SUCCESS)<br>
                goto out;<br>
-       }<br>
+       ret = bucket_delete(account, account_vid, bucket);<br>
 out:<br>
        sys->cdrv->unlock(account_vid);<br>
        return ret;<br>
@@ -671,6 +498,7 @@ int kv_list_buckets(struct http_request *req, const char *account,<br>
                    list_bucket_cb cb, void *opaque)<br>
 {<br>
        struct sd_inode account_inode;<br>
+       struct list_buckets_arg arg = {req, opaque, cb, 0};<br>
        uint32_t account_vid;<br>
        uint64_t oid;<br>
        int ret;<br>
@@ -681,17 +509,15 @@ int kv_list_buckets(struct http_request *req, const char *account,<br>
                return ret;<br>
        }<br>
<br>
-       /* read account vdi out */<br>
        oid = vid_to_vdi_oid(account_vid);<br>
        sys->cdrv->lock(account_vid);<br>
        ret = sd_read_object(oid, (char *)&account_inode,<br>
                             sizeof(struct sd_inode), 0);<br>
        if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("Failed to read account inode header %lx", oid);<br>
+               sd_err("Failed to read account inode header %s", account);<br>
                goto out;<br>
        }<br>
<br>
-       struct list_buckets_arg arg = {req, opaque, cb, 0};<br>
        traverse_btree(sheep_bnode_reader, &account_inode,<br>
                       list_buckets_cb, &arg);<br>
 out:<br>
@@ -699,38 +525,15 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-/*<br>
- * A bucket contains two vdi: one (vdi_id)  stores 'struct kv_onode' by hash<br>
- * algorithm and another one (data_vid) stores data of objects.<br>
- * The first vdi names "account/bucket" and the second vdi names<br>
- * "account/bucket/allocator".<br>
- *<br>
- * It manage space in data vdi by algorithm in oalloc.c.<br>
- *<br>
- * For example: bucket "fruit" with account 'coly' has two objects "banana"<br>
- *              and "apple"<br>
- *<br>
- *<br>
- *                       --------------------- kv_onode -----------------------<br>
- *                      |                                                      |<br>
- * bucket vdi           v                                                      v<br>
- * +-----------------+--+---------------------------+--------------------------+<br>
- * |name: coly/fruit |..|kv_onode_hdr (name: banana)|onode_extent: start, count|<br>
- * +-----------------+--+---------------------------+--------------------------+<br>
- *                                                                  /<br>
- *                                                                 /<br>
- *                                                     ------------<br>
- *                                                    /<br>
- *                  data_vid                        v<br>
- *                   +---------------------------+---+-----------------+<br>
- *                   |name: coly/fruit/allocator |...|       data      |<br>
- *                   +---------------------------+---+-----------------+<br>
- */<br>
-<br>
 /* Object operations */<br>
<br>
 /* 4 KB header of kv object index node */<br>
-struct kv_onode_hdr {<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>
@@ -747,17 +550,8 @@ struct kv_onode_hdr {<br>
<br>
                uint8_t __pad[BLOCK_SIZE];<br>
        };<br>
-};<br>
-<br>
-struct onode_extent {<br>
-       uint64_t start;<br>
-       uint64_t count;<br>
-};<br>
-<br>
-struct kv_onode {<br>
-       struct kv_onode_hdr hdr;<br>
        union {<br>
-               uint8_t data[SD_DATA_OBJ_SIZE - sizeof(struct kv_onode_hdr)];<br>
+               uint8_t data[SD_DATA_OBJ_SIZE - BLOCK_SIZE];<br>
                struct onode_extent o_extent[0];<br>
        };<br>
 };<br>
@@ -795,10 +589,10 @@ static void list_objects_cb(void *data, enum btree_node_type type, void *arg)<br>
                        goto out;<br>
                }<br>
<br>
-               if (onode-><a href="http://hdr.name" target="_blank">hdr.name</a>[0] == '\0')<br>
+               if (onode->name[0] == '\0')<br>
                        goto out;<br>
                if (loarg->cb)<br>
-                       loarg->cb(loarg->req, loarg->bucket, onode-><a href="http://hdr.name" target="_blank">hdr.name</a>,<br>
+                       loarg->cb(loarg->req, loarg->bucket, onode->name,<br>
                                  loarg->opaque);<br>
                loarg->object_counter++;<br>
        }<br>
@@ -828,7 +622,7 @@ static bool kv_find_object(struct http_request *req, const char *account,<br>
        return arg.found;<br>
 }<br>
<br>
-#define KV_ONODE_INLINE_SIZE (SD_DATA_OBJ_SIZE - sizeof(struct kv_onode_hdr))<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>
                          off_t offset, bool read)<br>
@@ -883,14 +677,14 @@ static int onode_populate_extents(struct kv_onode *onode,<br>
        uint64_t start = 0, count, done = 0, total, offset;<br>
        int ret;<br>
        char *data_buf = NULL;<br>
-       uint32_t data_vid = onode->hdr.data_vid;<br>
+       uint32_t data_vid = onode->data_vid;<br>
<br>
        count = DIV_ROUND_UP(req->data_length, SD_DATA_OBJ_SIZE);<br>
        sys->cdrv->lock(data_vid);<br>
        ret = oalloc_new_prepare(data_vid, &start, count);<br>
        sys->cdrv->unlock(data_vid);<br>
        if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("oalloc_new_prepare failed for %s, %s", onode-><a href="http://hdr.name" target="_blank">hdr.name</a>,<br>
+               sd_err("oalloc_new_prepare failed for %s, %s", onode->name,<br>
                       sd_strerror(ret));<br>
                goto out;<br>
        }<br>
@@ -903,7 +697,7 @@ static int onode_populate_extents(struct kv_onode *onode,<br>
                ret = vdi_read_write(data_vid, data_buf, size, offset, false);<br>
                if (ret != SD_RES_SUCCESS) {<br>
                        sd_err("Failed to write data object for %s, %s",<br>
-                              onode-><a href="http://hdr.name" target="_blank">hdr.name</a>, sd_strerror(ret));<br>
+                              onode->name, sd_strerror(ret));<br>
                        goto out;<br>
                }<br>
                done += size;<br>
@@ -914,14 +708,14 @@ static int onode_populate_extents(struct kv_onode *onode,<br>
        ret = oalloc_new_finish(data_vid, start, count);<br>
        sys->cdrv->unlock(data_vid);<br>
        if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("oalloc_new_finish failed for %s, %s", onode-><a href="http://hdr.name" target="_blank">hdr.name</a>,<br>
+               sd_err("oalloc_new_finish failed for %s, %s", onode->name,<br>
                       sd_strerror(ret));<br>
                goto out;<br>
        }<br>
<br>
        onode->o_extent[0].start = start;<br>
        onode->o_extent[0].count = count;<br>
-       onode->hdr.nr_extent = 1;<br>
+       onode->nr_extent = 1;<br>
 out:<br>
        free(data_buf);<br>
        return ret;<br>
@@ -934,11 +728,11 @@ static int onode_populate_data(struct kv_onode *onode, struct http_request *req)<br>
        int ret;<br>
<br>
        if (req->data_length <= KV_ONODE_INLINE_SIZE) {<br>
-               onode->hdr.inlined = 1;<br>
+               onode->inlined = 1;<br>
                size = http_request_read(req, onode->data, sizeof(onode->data));<br>
                if (size < 0 || req->data_length != size) {<br>
                        sd_err("Failed to read from web server for %s",<br>
-                              onode-><a href="http://hdr.name" target="_blank">hdr.name</a>);<br>
+                              onode->name);<br>
                        ret = SD_RES_SYSTEM_ERROR;<br>
                        goto out;<br>
                }<br>
@@ -949,9 +743,9 @@ static int onode_populate_data(struct kv_onode *onode, struct http_request *req)<br>
        }<br>
<br>
        gettimeofday(&tv, NULL);<br>
-       onode->hdr.ctime = (uint64_t) tv.tv_sec << 32 | tv.tv_usec * 1000;<br>
-       onode->hdr.mtime = onode->hdr.ctime;<br>
-       onode->hdr.size = req->data_length;<br>
+       onode->ctime = (uint64_t) tv.tv_sec << 32 | tv.tv_usec * 1000;<br>
+       onode->mtime = onode->ctime;<br>
+       onode->size = req->data_length;<br>
 out:<br>
        return ret;<br>
 }<br>
@@ -982,13 +776,13 @@ static int onode_do_create(struct kv_onode *onode, struct sd_inode *inode,<br>
        uint64_t oid = vid_to_data_oid(vid, idx), len;<br>
        int ret;<br>
<br>
-       onode->hdr.oid = oid;<br>
-       if (onode->hdr.inlined)<br>
-               len = onode->hdr.size;<br>
+       onode->oid = oid;<br>
+       if (onode->inlined)<br>
+               len = onode->size;<br>
        else<br>
-               len = sizeof(struct onode_extent) * onode->hdr.nr_extent;<br>
+               len = sizeof(struct onode_extent) * onode->nr_extent;<br>
<br>
-       ret = sd_write_object(oid, (char *)onode, sizeof(onode->hdr) + len,<br>
+       ret = sd_write_object(oid, (char *)onode, BLOCK_SIZE + len,<br>
                              0, true);<br>
        if (ret != SD_RES_SUCCESS) {<br>
                sd_err("failed to create object, %" PRIx64, oid);<br>
@@ -1008,43 +802,18 @@ out:<br>
<br>
 static int onode_create(struct kv_onode *onode, uint32_t onode_vid)<br>
 {<br>
-       struct sd_inode *inode = xmalloc(sizeof(struct sd_inode));<br>
-       uint32_t tmp_vid, idx, i;<br>
-       uint64_t hval;<br>
        int ret;<br>
<br>
        sys->cdrv->lock(onode_vid);<br>
-       ret = sd_read_object(vid_to_vdi_oid(onode_vid), (char *)inode,<br>
-                            sizeof(*inode), 0);<br>
-       if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("failed to read %" PRIx32 " %s", onode_vid,<br>
-                      sd_strerror(ret));<br>
-               goto out;<br>
-       }<br>
-<br>
-       hval = sd_hash(onode-><a href="http://hdr.name" target="_blank">hdr.name</a>, strlen(onode-><a href="http://hdr.name" target="_blank">hdr.name</a>));<br>
-       for (i = 0; i < MAX_DATA_OBJS; i++) {<br>
-               idx = (hval + i) % MAX_DATA_OBJS;<br>
-               tmp_vid = INODE_GET_VID(inode, idx);<br>
-               if(tmp_vid)<br>
-                       continue;<br>
-               else<br>
-                       break;<br>
-       }<br>
-       if (i == MAX_DATA_OBJS) {<br>
-               ret = SD_RES_NO_SPACE;<br>
-               goto out;<br>
-       }<br>
-       ret = onode_do_create(onode, inode, idx);<br>
-out:<br>
+       ret = kv_generic_object_create(onode, onode_vid, onode_do_create);<br>
        sys->cdrv->unlock(onode_vid);<br>
-       free(inode);<br>
+<br>
        return ret;<br>
 }<br>
<br>
 static int onode_free_data(struct kv_onode *onode)<br>
 {<br>
-       uint32_t data_vid = onode->hdr.data_vid;<br>
+       uint32_t data_vid = onode->data_vid;<br>
        int ret;<br>
<br>
        sys->cdrv->lock(data_vid);<br>
@@ -1052,7 +821,7 @@ static int onode_free_data(struct kv_onode *onode)<br>
                          onode->o_extent[0].count);<br>
        sys->cdrv->unlock(data_vid);<br>
        if (ret != SD_RES_SUCCESS)<br>
-               sd_err("failed to free %s", onode-><a href="http://hdr.name" target="_blank">hdr.name</a>);<br>
+               sd_err("failed to free %s", onode->name);<br>
        return ret;<br>
 }<br>
<br>
@@ -1065,18 +834,18 @@ static int onode_read_extents(struct kv_onode *onode, struct http_request *req)<br>
        char *data_buf = NULL;<br>
<br>
        data_buf = xmalloc(READ_WRITE_BUFFER);<br>
-       total_size = onode->hdr.size;<br>
-       for (i = 0; i < onode->hdr.nr_extent; i++) {<br>
+       total_size = onode->size;<br>
+       for (i = 0; i < onode->nr_extent; i++) {<br>
                ext = onode->o_extent + i;<br>
                total = min(ext->count * SD_DATA_OBJ_SIZE, total_size);<br>
                offset = ext->start * SD_DATA_OBJ_SIZE;<br>
                while (done < total) {<br>
                        size = MIN(total - done, READ_WRITE_BUFFER);<br>
-                       ret = vdi_read_write(onode->hdr.data_vid, data_buf,<br>
+                       ret = vdi_read_write(onode->data_vid, data_buf,<br>
                                             size, offset, true);<br>
                        if (ret != SD_RES_SUCCESS) {<br>
                                sd_err("Failed to read for vid %"PRIx32,<br>
-                                      onode->hdr.data_vid);<br>
+                                      onode->data_vid);<br>
                                goto out;<br>
                        }<br>
                        http_request_write(req, data_buf, size);<br>
@@ -1090,30 +859,13 @@ out:<br>
        return ret;<br>
 }<br>
<br>
-static int onode_lookup(struct kv_onode *onode, uint32_t onode_vid,<br>
-                       const char *name)<br>
+static int onode_lookup(struct kv_onode *onode, uint32_t ovid, const char *name)<br>
 {<br>
-       uint64_t hval;<br>
-       uint32_t i;<br>
        int ret;<br>
<br>
-       sys->cdrv->lock(onode_vid);<br>
-       hval = sd_hash(name, strlen(name));<br>
-       for (i = 0; i < MAX_DATA_OBJS; i++) {<br>
-               uint32_t idx = (hval + i) % MAX_DATA_OBJS;<br>
-               uint64_t oid = vid_to_data_oid(onode_vid, idx);<br>
-<br>
-               ret = sd_read_object(oid, (char *)onode, sizeof(*onode), 0);<br>
-               if (ret != SD_RES_SUCCESS)<br>
-                       goto out;<br>
-               if (strcmp(onode-><a href="http://hdr.name" target="_blank">hdr.name</a>, name) == 0)<br>
-                       break;<br>
-       }<br>
-<br>
-       if (i == MAX_DATA_OBJS)<br>
-               ret = SD_RES_NO_OBJ;<br>
-out:<br>
-       sys->cdrv->unlock(onode_vid);<br>
+       sys->cdrv->lock(ovid);<br>
+       ret = kv_generic_object_lookup(onode, ovid, name);<br>
+       sys->cdrv->unlock(ovid);<br>
        return ret;<br>
 }<br>
<br>
@@ -1121,11 +873,11 @@ static int onode_read_data(struct kv_onode *onode, struct http_request *req)<br>
 {<br>
        int ret;<br>
<br>
-       if (!onode->hdr.inlined)<br>
+       if (!onode->inlined)<br>
                return onode_read_extents(onode, req);<br>
<br>
-       ret = http_request_write(req, onode->data, onode->hdr.size);<br>
-       if (ret != onode->hdr.size)<br>
+       ret = http_request_write(req, onode->data, onode->size);<br>
+       if (ret != onode->size)<br>
                return SD_RES_SYSTEM_ERROR;<br>
<br>
        return SD_RES_SUCCESS;<br>
@@ -1146,15 +898,15 @@ static int onode_delete(struct kv_onode *onode)<br>
 {<br>
        int ret;<br>
<br>
-       ret = discard_data_obj(onode->hdr.oid);<br>
+       ret = discard_data_obj(onode->oid);<br>
        if (ret != SD_RES_SUCCESS) {<br>
-               sd_err("failed to discard onode for %s", onode-><a href="http://hdr.name" target="_blank">hdr.name</a>);<br>
+               sd_err("failed to discard onode for %s", onode->name);<br>
                return ret;<br>
        }<br>
<br>
        ret = onode_free_data(onode);<br>
        if (ret != SD_RES_SUCCESS)<br>
-               sd_err("failed to free data for %s", onode-><a href="http://hdr.name" target="_blank">hdr.name</a>);<br>
+               sd_err("failed to free data for %s", onode->name);<br>
<br>
        return SD_RES_SUCCESS;<br>
 }<br>
@@ -1186,8 +938,8 @@ int kv_create_object(struct http_request *req, const char *account,<br>
                return ret;<br>
<br>
        onode = xzalloc(sizeof(*onode));<br>
-       pstrcpy(onode-><a href="http://hdr.name" target="_blank">hdr.name</a>, sizeof(onode-><a href="http://hdr.name" target="_blank">hdr.name</a>), name);<br>
-       onode->hdr.data_vid = data_vid;<br>
+       pstrcpy(onode->name, sizeof(onode->name), name);<br>
+       onode->data_vid = data_vid;<br>
<br>
        ret = onode_populate_data(onode, req);<br>
        if (ret != SD_RES_SUCCESS) {<br>
@@ -1226,7 +978,7 @@ int kv_read_object(struct http_request *req, const char *account,<br>
        if (ret != SD_RES_SUCCESS)<br>
                goto out;<br>
<br>
-       req->data_length = onode->hdr.size;<br>
+       req->data_length = onode->size;<br>
        http_response_header(req, OK);<br>
        ret = onode_read_data(onode, req);<br>
        if (ret != SD_RES_SUCCESS)<br>
diff --git a/sheep/http/swift.c b/sheep/http/swift.c<br>
index 3c6b127..038945d 100644<br>
--- a/sheep/http/swift.c<br>
+++ b/sheep/http/swift.c<br>
@@ -12,10 +12,6 @@<br>
 #include "strbuf.h"<br>
 #include "http.h"<br>
<br>
-#define HTTP_REMOVE_ACCOUNT "HTTP_X_REMOVE_ACCOUNT_META_BOOK"<br>
-<br>
-static void swift_delete_account(struct http_request *req, const char *account);<br>
-<br>
 /* Operations on Accounts */<br>
<br>
 static void swift_head_account(struct http_request *req, const char *account)<br>
@@ -55,23 +51,8 @@ static void swift_get_account(struct http_request *req, const char *account)<br>
<br>
 static void swift_put_account(struct http_request *req, const char *account)<br>
 {<br>
-       http_response_header(req, NOT_IMPLEMENTED);<br>
-}<br>
-<br>
-static void swift_post_account(struct http_request *req, const char *account)<br>
-{<br>
-       char *p;<br>
        int ret;<br>
<br>
-       for (int i = 0; (p = req->fcgx.envp[i]); ++i) {<br>
-               /* delete account */<br>
-               if (!strncmp(p, HTTP_REMOVE_ACCOUNT,<br>
-                            strlen(HTTP_REMOVE_ACCOUNT))) {<br>
-                       swift_delete_account(req, account);<br>
-                       return;<br>
-               }<br>
-       }<br>
-       /* create account */<br>
        ret = kv_create_account(account);<br>
        if (ret == SD_RES_SUCCESS)<br>
                http_response_header(req, CREATED);<br>
@@ -81,6 +62,11 @@ static void swift_post_account(struct http_request *req, const char *account)<br>
                http_response_header(req, INTERNAL_SERVER_ERROR);<br>
 }<br>
<br>
+static void swift_post_account(struct http_request *req, const char *account)<br>
+{<br>
+       http_response_header(req, NOT_IMPLEMENTED);<br>
+}<br>
+<br>
 static void swift_delete_account(struct http_request *req, const char *account)<br>
 {<br>
        uint32_t nr_buckets;<br>
@@ -141,12 +127,17 @@ static void swift_put_container(struct http_request *req, const char *account,<br>
 {<br>
        int ret;<br>
        ret = kv_create_bucket(account, container);<br>
-       if (ret == SD_RES_SUCCESS)<br>
+       switch (ret) {<br>
+       case SD_RES_SUCCESS:<br>
                http_response_header(req, CREATED);<br>
-       else if (ret == SD_RES_VDI_EXIST)<br>
+               break;<br>
+       case SD_RES_VDI_EXIST:<br>
                http_response_header(req, ACCEPTED);<br>
-       else<br>
+               break;<br>
+       default:<br>
                http_response_header(req, INTERNAL_SERVER_ERROR);<br>
+               break;<br>
+       }<br>
 }<br>
<br>
 static void swift_post_container(struct http_request *req, const char *account,<br>
diff --git a/tests/functional/081 b/tests/functional/081<br>
index c73bc35..11e1af6 100755<br>
--- a/tests/functional/081<br>
+++ b/tests/functional/081<br>
@@ -18,7 +18,7 @@ _wait_for_sheep 6<br>
<br>
 _cluster_format -c 4:2<br>
<br>
-curl -s -X POST <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a><br>
+curl -s -X PUT <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a><br>
 curl -s -X PUT <a href="http://localhost/v1/sd/sheep" target="_blank">http://localhost/v1/sd/sheep</a><br>
 curl -s -X PUT <a href="http://localhost/v1/sd/dog" target="_blank">http://localhost/v1/sd/dog</a><br>
<br>
@@ -48,7 +48,7 @@ done<br>
 wait<br>
<br>
 # list the container and objects<br>
-curl -s -X GET <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a><br>
+curl -s -X GET <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a> | sort<br>
 curl -s -X GET <a href="http://localhost/v1/sd/sheep" target="_blank">http://localhost/v1/sd/sheep</a> | sort<br>
 curl -s -X GET <a href="http://localhost/v1/sd/dog" target="_blank">http://localhost/v1/sd/dog</a> | sort<br>
<br>
diff --git a/tests/functional/081.out b/tests/functional/081.out<br>
index 95ab894..f0cc8f2 100644<br>
--- a/tests/functional/081.out<br>
+++ b/tests/functional/081.out<br>
@@ -1,7 +1,7 @@<br>
 QA output created by 081<br>
 using backend plain store<br>
-sheep<br>
 dog<br>
+sheep<br>
 checker.c<br>
 config.c<br>
 corosync.c<br>
diff --git a/tests/functional/082 b/tests/functional/082<br>
index dee8861..084ed64 100755<br>
--- a/tests/functional/082<br>
+++ b/tests/functional/082<br>
@@ -18,7 +18,7 @@ _wait_for_sheep 6<br>
<br>
 _cluster_format -c 4:2<br>
<br>
-curl -s -X POST <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a><br>
+curl -s -X PUT <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a><br>
 curl -s -X PUT <a href="http://localhost/v1/sd/sheep" target="_blank">http://localhost/v1/sd/sheep</a><br>
 curl -s -X PUT <a href="http://localhost/v1/sd/dog" target="_blank">http://localhost/v1/sd/dog</a><br>
<br>
@@ -51,7 +51,7 @@ done<br>
 wait<br>
<br>
 # list the container and objects<br>
-curl -s -X GET <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a><br>
+curl -s -X GET <a href="http://localhost/v1/sd" target="_blank">http://localhost/v1/sd</a> | sort<br>
 curl -s -X GET <a href="http://localhost/v1/sd/sheep" target="_blank">http://localhost/v1/sd/sheep</a> | sort<br>
 curl -s -X GET <a href="http://localhost/v1/sd/dog" target="_blank">http://localhost/v1/sd/dog</a> | sort<br>
<br>
diff --git a/tests/functional/082.out b/tests/functional/082.out<br>
index f1bbbfe..6d6a4dc 100644<br>
--- a/tests/functional/082.out<br>
+++ b/tests/functional/082.out<br>
@@ -1,7 +1,7 @@<br>
 QA output created by 082<br>
 using backend plain store<br>
-sheep<br>
 dog<br>
+sheep<br>
 checker.c<br>
 config.c<br>
 corosync.c<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>