[sheepdog] [PATCH v3 4/6] sheep/http: add flag for onode

Robin Dong robin.k.dong at gmail.com
Tue Feb 25 08:59:29 CET 2014


From: Robin Dong <sanbai at taobao.com>

The processes of creating object is:

1. lock container
2. check whether the onode is exists.
3. allocate data space for object, and create onode, then write it done
4. unlock container
5. upload object

This routine will avoid uploading duplicated objects but have  an exception:
if the client halt the uploading progress, we will have a
"uploading incompleted" onode.

The solution is: we can add code for onode to identify its status.
A new onode will be set to "INIT", and after uploading completed, the onode will
be set to  "COMPLETED". So, when users try to use swift interface to GET a
"incompleted" object, sheep will find out the onode is "INIT" which means
"not completed", so sheep will return "partial content"for http request, and
user could remove the object and upload it again.

Signed-off-by: Robin Dong <sanbai at taobao.com>
---
 include/sheepdog_proto.h |  1 +
 sheep/http/kv.c          | 65 +++++++++++++++++++++++++++++++++++++++++++++---
 sheep/http/swift.c       | 10 ++++++++
 3 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/include/sheepdog_proto.h b/include/sheepdog_proto.h
index d553da9..3c48785 100644
--- a/include/sheepdog_proto.h
+++ b/include/sheepdog_proto.h
@@ -74,6 +74,7 @@
 #define SD_RES_JOIN_FAILED   0x18 /* Target node had failed to join sheepdog */
 #define SD_RES_HALT          0x19 /* Sheepdog is stopped doing IO */
 #define SD_RES_READONLY      0x1A /* Object is read-only */
+#define SD_RES_INCOMPLETE    0x1B /* Object (in kv) is incomplete uploading */
 
 /* errors above 0x80 are sheepdog-internal */
 
diff --git a/sheep/http/kv.c b/sheep/http/kv.c
index a2dc84c..07670cb 100644
--- a/sheep/http/kv.c
+++ b/sheep/http/kv.c
@@ -30,6 +30,30 @@ struct onode_extent {
 	uint64_t count;
 };
 
+/*
+ * The processes of creating object is:
+ *
+ *   1. lock container
+ *   2. check whether the onode is exists.
+ *   3. allocate data space for object, and create onode, then write it done
+ *   4. unlock container
+ *   5. upload object
+ *
+ * This routine will avoid uploading duplicated objects but have  an exception:
+ * if the client halt the uploading progress, we will have a
+ * "uploading incompleted" onode.
+ *
+ * The solution is: we can add code for onode to identify its status.
+ * A new onode will be set to "ONODE_INIT", and after uploading completed, the
+ * onode will be set to  "ONODE_COMPLETE". So, when users try to use swift
+ * interface to GET a "incompleted" object, sheep will find out the onode is
+ * "ONODE_INIT" which means "not completed", so sheep will return
+ * "partial content" for http request, and user could remove the object and
+ * upload it again.
+ */
+#define ONODE_INIT	1	/* created and allocated space, but no data */
+#define ONODE_COMPLETE	2	/* data upload complete */
+
 struct kv_onode {
 	union {
 		struct {
@@ -42,6 +66,7 @@ struct kv_onode {
 			uint32_t nr_extent;
 			uint64_t oid;
 			uint8_t inlined;
+			uint8_t flags;
 		};
 
 		uint8_t pad[BLOCK_SIZE];
@@ -748,7 +773,7 @@ out:
 static int onode_populate_data(struct kv_onode *onode, struct http_request *req)
 {
 	ssize_t size;
-	int ret = SD_RES_SUCCESS;
+	int ret = SD_RES_SUCCESS, offset;
 
 	if (req->data_length <= KV_ONODE_INLINE_SIZE) {
 		size = http_request_read(req, onode->data, sizeof(onode->data));
@@ -767,6 +792,13 @@ static int onode_populate_data(struct kv_onode *onode, struct http_request *req)
 		if (ret != SD_RES_SUCCESS)
 			goto out;
 	}
+	/* write ONODE_COMPLETE to onode->flags */
+	onode->flags = ONODE_COMPLETE;
+	offset = offsetof(struct kv_onode, flags);
+	ret = sd_write_object(onode->oid, (char *)onode + offset,
+			      sizeof(uint8_t), offset, false);
+	if (ret != SD_RES_SUCCESS)
+		sd_err("Failed to write flags of onode %s", onode->name);
 out:
 	return ret;
 }
@@ -1054,6 +1086,12 @@ static int onode_allocate_space(struct http_request *req, const char *account,
 	sys->cdrv->lock(bucket_vid);
 	ret = onode_lookup_nolock(onode, bucket_vid, name);
 	if (ret == SD_RES_SUCCESS) {
+		/* if the exists onode has not been uploaded complete */
+		if (onode->flags != ONODE_COMPLETE) {
+			ret = SD_RES_INCOMPLETE;
+			sd_err("The exists onode %s is incomplete", name);
+			goto out;
+		}
 		/* For overwrite, we delete old object and then create */
 		ret = onode_delete(onode);
 		if (ret != SD_RES_SUCCESS) {
@@ -1065,8 +1103,10 @@ static int onode_allocate_space(struct http_request *req, const char *account,
 			sd_err("Failed to update bnode for %s", name);
 			goto out;
 		}
-	} else if (ret != SD_RES_NO_OBJ)
+	} else if (ret != SD_RES_NO_OBJ) {
+		sd_err("Failed to lookup onode %s %s", name, sd_strerror(ret));
 		goto out;
+	}
 
 	snprintf(vdi_name, SD_MAX_VDI_LEN, "%s/%s/allocator", account, bucket);
 	ret = sd_lookup_vdi(vdi_name, &data_vid);
@@ -1076,6 +1116,7 @@ static int onode_allocate_space(struct http_request *req, const char *account,
 	memset(onode, 0, sizeof(*onode));
 	pstrcpy(onode->name, sizeof(onode->name), name);
 	onode->data_vid = data_vid;
+	onode->flags = ONODE_INIT;
 
 	ret = onode_allocate_data(onode, req);
 	if (ret != SD_RES_SUCCESS) {
@@ -1185,9 +1226,15 @@ int kv_read_object(struct http_request *req, const char *account,
 	if (ret != SD_RES_SUCCESS)
 		goto out;
 
+	/* this object has not been uploaded complete */
+	if (onode->flags != ONODE_COMPLETE) {
+		ret = SD_RES_EIO;
+		goto out;
+	}
+
 	ret = onode_read_data(onode, req);
 	if (ret != SD_RES_SUCCESS)
-		sd_err("failed to read data for %s", name);
+		sd_err("failed to read data for %s ret %d", name, ret);
 out:
 	free(onode);
 	return ret;
@@ -1210,6 +1257,12 @@ int kv_delete_object(const char *account, const char *bucket, const char *name)
 	if (ret != SD_RES_SUCCESS)
 		goto out;
 
+	/* this object has not been uploaded complete */
+	if (onode->flags != ONODE_COMPLETE) {
+		ret = SD_RES_INCOMPLETE;
+		goto out;
+	}
+
 	ret = onode_delete(onode);
 	if (ret != SD_RES_SUCCESS) {
 		sd_err("failed to delete bnode for %s", name);
@@ -1274,6 +1327,12 @@ int kv_read_object_meta(struct http_request *req, const char *account,
 	req->data_length = onode->size;
 	http_request_writef(req, "Last-Modified: %s\n",
 			    http_time(onode->mtime));
+
+	/* this object has not been uploaded complete */
+	if (onode->flags != ONODE_COMPLETE) {
+		ret = SD_RES_INCOMPLETE;
+		goto out;
+	}
 out:
 	free(onode);
 	return ret;
diff --git a/sheep/http/swift.c b/sheep/http/swift.c
index 7b9685a..aff0f09 100644
--- a/sheep/http/swift.c
+++ b/sheep/http/swift.c
@@ -210,6 +210,9 @@ static void swift_head_object(struct http_request *req, const char *account,
 	case SD_RES_NO_OBJ:
 		http_response_header(req, NOT_FOUND);
 		break;
+	case SD_RES_INCOMPLETE:
+		http_response_header(req, PARTIAL_CONTENT);
+		break;
 	default:
 		http_response_header(req, INTERNAL_SERVER_ERROR);
 		break;
@@ -256,6 +259,10 @@ static void swift_put_object(struct http_request *req, const char *account,
 		break;
 	case SD_RES_NO_SPACE:
 		http_response_header(req, SERVICE_UNAVAILABLE);
+		break;
+	case SD_RES_INCOMPLETE:
+		http_response_header(req, CONFLICT);
+		break;
 	default:
 		http_response_header(req, INTERNAL_SERVER_ERROR);
 		break;
@@ -282,6 +289,9 @@ static void swift_delete_object(struct http_request *req, const char *account,
 	case SD_RES_NO_OBJ:
 		http_response_header(req, NOT_FOUND);
 		break;
+	case SD_RES_INCOMPLETE:
+		http_response_header(req, CONFLICT);
+		break;
 	default:
 		http_response_header(req, INTERNAL_SERVER_ERROR);
 		break;
-- 
1.7.12.4




More information about the sheepdog mailing list