[sheepdog] [PATCH v4 10/10] sheep: recover from local when target node has same content

MORITA Kazutaka morita.kazutaka at gmail.com
Tue May 14 09:00:19 CEST 2013


From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>

This checks the hash value of the target object before reading the
entire data, and recovers from local if there is a same object in the
stale directory.

Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
 sheep/recovery.c |  139 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 86 insertions(+), 53 deletions(-)

diff --git a/sheep/recovery.c b/sheep/recovery.c
index 7876935..11253a0 100644
--- a/sheep/recovery.c
+++ b/sheep/recovery.c
@@ -47,6 +47,10 @@ struct recovery_obj_work {
 
 	uint64_t oid; /* the object to be recovered */
 	bool stop;
+
+	/* local replica in the stale directory */
+	uint32_t local_epoch;
+	uint8_t local_sha1[SHA1_LEN];
 };
 
 /*
@@ -99,29 +103,78 @@ static int obj_cmp(const void *oid1, const void *oid2)
 	return 0;
 }
 
-/*
- * A virtual node that does not match any node in current node list
- * means the node has left the cluster, then it's an invalid virtual node.
- */
-static bool is_invalid_vnode(const struct sd_vnode *entry,
-			     struct sd_node *nodes, int nr_nodes)
+/* recover object from vnode */
+static int recover_object_from(struct recovery_obj_work *row,
+			       const struct sd_vnode *vnode, uint32_t tgt_epoch)
 {
-	if (bsearch(entry, nodes, nr_nodes, sizeof(struct sd_node),
-		    node_id_cmp))
-		return false;
-	return true;
+	uint64_t oid = row->oid;
+	uint32_t local_epoch = row->local_epoch;
+	uint8_t *sha1 = row->local_sha1;
+	uint32_t epoch = row->base.epoch;
+	int ret;
+	unsigned rlen;
+	void *buf = NULL;
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+	struct siocb iocb = { 0 };
+
+	if (vnode_is_local(vnode)) {
+		if (tgt_epoch < sys_epoch())
+			return sd_store->link(oid, tgt_epoch);
+
+		return SD_RES_NO_OBJ;
+	}
+
+	/* compare sha1 hash value first */
+	if (local_epoch > 0) {
+		sd_init_req(&hdr, SD_OP_GET_HASH);
+		hdr.obj.oid = oid;
+		hdr.obj.tgt_epoch = tgt_epoch;
+		ret = sheep_exec_req(&vnode->nid, &hdr, NULL);
+		if (ret != SD_RES_SUCCESS)
+			return ret;
+
+		if (memcmp(rsp->hash.digest, sha1, sizeof(SHA1_LEN)) == 0) {
+			sd_dprintf("use local replica at epoch %d",
+				   local_epoch);
+			ret = sd_store->link(oid, local_epoch);
+			if (ret == SD_RES_SUCCESS)
+				return ret;
+		}
+	}
+
+	rlen = get_objsize(oid);
+	buf = xvalloc(rlen);
+
+	/* recover from remote replica */
+	sd_init_req(&hdr, SD_OP_READ_PEER);
+	hdr.epoch = epoch;
+	hdr.flags = SD_FLAG_CMD_RECOVERY;
+	hdr.data_length = rlen;
+	hdr.obj.oid = oid;
+	hdr.obj.tgt_epoch = tgt_epoch;
+
+	ret = sheep_exec_req(&vnode->nid, &hdr, buf);
+	if (ret == SD_RES_SUCCESS) {
+		iocb.epoch = epoch;
+		iocb.length = rsp->data_length;
+		iocb.offset = rsp->obj.offset;
+		iocb.buf = buf;
+		ret = sd_store->create_and_write(oid, &iocb);
+	}
+
+	free(buf);
+	return ret;
 }
 
-static int recover_object_from_replica(uint64_t oid, struct vnode_info *old,
+static int recover_object_from_replica(struct recovery_obj_work *row,
+				       struct vnode_info *old,
 				       struct vnode_info *cur,
-				       uint32_t epoch, uint32_t tgt_epoch)
+				       uint32_t tgt_epoch)
 {
-	struct sd_req hdr;
-	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-	unsigned rlen;
+	uint64_t oid = row->oid;
+	uint32_t epoch = row->base.epoch;
 	int nr_copies, ret = SD_RES_SUCCESS, start = 0;
-	void *buf = NULL;
-	struct siocb iocb = { 0 };
 	bool fully_replicated = true;
 
 	nr_copies = get_obj_copy_number(oid, old->nr_zones);
@@ -138,9 +191,6 @@ static int recover_object_from_replica(uint64_t oid, struct vnode_info *old,
 		}
 	}
 
-	rlen = get_objsize(oid);
-	buf = xvalloc(rlen);
-
 	/* Let's do a breadth-first search */
 	for (int i = 0; i < nr_copies; i++) {
 		const struct sd_vnode *vnode;
@@ -148,41 +198,16 @@ static int recover_object_from_replica(uint64_t oid, struct vnode_info *old,
 
 		vnode = oid_to_vnode(old->vnodes, old->nr_vnodes, oid, idx);
 
-		if (is_invalid_vnode(vnode, cur->nodes, cur->nr_nodes))
-			continue;
-
-		if (vnode_is_local(vnode)) {
-			if (tgt_epoch < sys_epoch())
-				ret = sd_store->link(oid, tgt_epoch);
-			else
-				ret = SD_RES_NO_OBJ;
-		} else {
-			sd_init_req(&hdr, SD_OP_READ_PEER);
-			hdr.epoch = epoch;
-			hdr.flags = SD_FLAG_CMD_RECOVERY;
-			hdr.data_length = rlen;
-			hdr.obj.oid = oid;
-			hdr.obj.tgt_epoch = tgt_epoch;
-
-			ret = sheep_exec_req(&vnode->nid, &hdr, buf);
-			if (ret == SD_RES_SUCCESS) {
-				iocb.epoch = epoch;
-				iocb.length = rsp->data_length;
-				iocb.offset = rsp->obj.offset;
-				iocb.buf = buf;
-				ret = sd_store->create_and_write(oid, &iocb);
-			}
-		}
-
+		ret = recover_object_from(row, vnode, tgt_epoch);
 		switch (ret) {
 		case SD_RES_SUCCESS:
 			sd_dprintf("recovered oid %"PRIx64" from %d "
 				   "to epoch %d", oid, tgt_epoch, epoch);
 			objlist_cache_insert(oid);
-			goto out;
+			return ret;
 		case SD_RES_OLD_NODE_VER:
 			/* move to the next epoch recovery */
-			goto out;
+			return ret;
 		case SD_RES_NO_OBJ:
 			fully_replicated = false;
 			/* fall through */
@@ -200,8 +225,6 @@ static int recover_object_from_replica(uint64_t oid, struct vnode_info *old,
 	if (fully_replicated && ret != SD_RES_SUCCESS)
 		ret = SD_RES_STALE_OBJ;
 
-out:
-	free(buf);
 	return ret;
 }
 
@@ -215,7 +238,7 @@ static int do_recover_object(struct recovery_obj_work *row)
 	struct recovery_work *rw = &row->base;
 	struct vnode_info *old, *cur;
 	uint64_t oid = row->oid;
-	uint32_t epoch = rw->epoch, tgt_epoch = rw->epoch;
+	uint32_t tgt_epoch = rw->epoch;
 	int ret;
 	struct vnode_info *new_old;
 
@@ -225,7 +248,7 @@ again:
 	sd_dprintf("try recover object %"PRIx64" from epoch %"PRIu32, oid,
 		   tgt_epoch);
 
-	ret = recover_object_from_replica(oid, old, cur, epoch, tgt_epoch);
+	ret = recover_object_from_replica(row, old, cur, tgt_epoch);
 
 	switch (ret) {
 	case SD_RES_SUCCESS:
@@ -276,13 +299,23 @@ static void recover_object_work(struct work *work)
 						     struct recovery_obj_work,
 						     base);
 	uint64_t oid = row->oid;
-	int ret;
+	int ret, epoch;
 
 	if (sd_store->exist(oid)) {
 		sd_dprintf("the object is already recovered");
 		return;
 	}
 
+	/* find object in the stale directory */
+	for (epoch = sys_epoch() - 1; epoch > 0; epoch--) {
+		ret = sd_store->get_hash(oid, epoch, row->local_sha1);
+		if (ret == SD_RES_SUCCESS) {
+			sd_dprintf("replica found in local at epoch %d", epoch);
+			row->local_epoch = epoch;
+			break;
+		}
+	}
+
 	ret = do_recover_object(row);
 	if (ret < 0)
 		sd_eprintf("failed to recover object %"PRIx64, oid);
-- 
1.7.9.5




More information about the sheepdog mailing list