[Ocfs2-tools-devel] [PATCH 38/39] ocfs2_controld: read and write ckpt sections

Joel Becker joel.becker at oracle.com
Fri Mar 14 16:53:01 PDT 2008


Data on checkpoints is stored in sections.  The access to section data
will be via simple accessor functions.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 ocfs2_controld/ckpt.c |  278 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 275 insertions(+), 3 deletions(-)

diff --git a/ocfs2_controld/ckpt.c b/ocfs2_controld/ckpt.c
index 8eb881b..87b94e0 100644
--- a/ocfs2_controld/ckpt.c
+++ b/ocfs2_controld/ckpt.c
@@ -36,6 +36,7 @@
 #define SERIOUS_RETRY_TRIES	5
 
 
+
 struct ckpt_handle {
 	SaNameT			ch_name;
 	SaCkptCheckpointHandleT	ch_handle;
@@ -65,13 +66,16 @@ static SaCkptCallbacksT callbacks = {
  * characters) plus something extra.  We don't use uuids in section names
  * yet, but just in case.
  */
+#define CKPT_MAX_SECTION_SIZE	128
+#define CKPT_MAX_SECTIONS	32
+#define CKPT_MAX_SECTION_ID	40
 static SaCkptCheckpointCreationAttributesT ckpt_attributes = {
 	.creationFlags		= SA_CKPT_WR_ALL_REPLICAS,
 	.checkpointSize		= 4096,
 	.retentionDuration	= 0LL,
-	.maxSections		= 32,
-	.maxSectionSize		= 128,
-	.maxSectionIdSize	= 40,
+	.maxSections		= CKPT_MAX_SECTIONS,
+	.maxSectionSize		= CKPT_MAX_SECTION_SIZE,
+	.maxSectionIdSize	= CKPT_MAX_SECTION_ID,
 };
 
 static void ais_err_to_errno(SaAisErrorT error, int *rc, char **reason)
@@ -234,6 +238,247 @@ static void call_ckpt_close(struct ckpt_handle *handle)
 }
 
 /*
+ * All of our sections live for the life of the checkpoint.  We don't need
+ * to delete them.
+ */
+static int call_section_create(struct ckpt_handle *handle, const char *name,
+			       const char *data, size_t data_len)
+{
+	int rc, retrycount;
+	char *reason;
+	SaAisErrorT error;
+	SaCkptSectionIdT id = {
+		.idLen = strlen(name),
+		.id = (SaUint8T *)name,
+	};
+	SaCkptSectionCreationAttributesT attrs = {
+		.sectionId = &id,
+		.expirationTime = SA_TIME_END,
+	};
+
+	for (retrycount = 0; retrycount < TENTATIVE_RETRY_TRIES; retrycount++) {
+		log_debug("Creating section \"%s\" on checkpoint "
+			  "\"%.*s\" (try %d)",
+			  name, handle->ch_name.length,
+			  handle->ch_name.value, retrycount + 1);
+		error = saCkptSectionCreate(handle->ch_handle, &attrs,
+					    data, data_len);
+		ais_err_to_errno(error, &rc, &reason);
+		if (!rc) {
+			log_debug("Created section \"%s\" on checkpoint "
+				  "\"%.*s\"",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value);
+			break;
+		}
+		if (rc != -EAGAIN) {
+			log_error("Unable to create section \"%s\" on "
+				  "checkpoint \"%.*s\": %s",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value, reason);
+			break;
+		}
+
+		if ((retrycount + 1) < TENTATIVE_RETRY_TRIES)
+			sleep(1);
+		else
+			log_error("Unable to create section \"%s\" on "
+				  "checkpoint \"%.*s\": too many tries",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value);
+	}
+
+	return rc;
+}
+
+static int call_section_write(struct ckpt_handle *handle, const char *name,
+			      const char *data, size_t data_len)
+{
+	int rc, retrycount;
+	char *reason;
+	SaAisErrorT error;
+	SaCkptSectionIdT id = {
+		.idLen = strlen(name),
+		.id = (SaUint8T *)name,
+	};
+
+	for (retrycount = 0; retrycount < TENTATIVE_RETRY_TRIES; retrycount++) {
+		log_debug("Writing to section \"%s\" on checkpoint "
+			  "\"%.*s\" (try %d)",
+			  name, handle->ch_name.length,
+			  handle->ch_name.value, retrycount + 1);
+		error = saCkptSectionOverwrite(handle->ch_handle, &id,
+					       data, data_len);
+		ais_err_to_errno(error, &rc, &reason);
+		if (!rc) {
+			log_debug("Stored section \"%s\" on checkpoint "
+				  "\"%.*s\"",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value);
+			break;
+		}
+
+		/* If it doesn't exist, create it. */
+		if (rc == -ENOENT) {
+			rc = call_section_create(handle, name, data, data_len);
+			break;
+		}
+
+		if (rc != -EAGAIN) {
+			log_error("Unable to write section \"%s\" on "
+				  "checkpoint \"%.*s\": %s",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value, reason);
+			break;
+		}
+
+		if ((retrycount + 1) < TENTATIVE_RETRY_TRIES)
+			sleep(1);
+		else
+			log_error("Unable to write section \"%s\" on "
+				  "checkpoint \"%.*s\": too many tries",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value);
+	}
+
+	return rc;
+}
+
+static int call_section_read(struct ckpt_handle *handle, const char *name,
+			     char **data, size_t *data_len)
+{
+	int rc, retrycount;
+	char *reason, *p;
+	char readbuf[CKPT_MAX_SECTION_SIZE];
+	SaAisErrorT error;
+	SaCkptIOVectorElementT readvec[] = {
+		{
+			.sectionId = {
+				.idLen = strlen(name),
+				.id = (SaUint8T *)name,
+			},
+			.dataBuffer = readbuf,
+			.dataSize = CKPT_MAX_SECTION_SIZE,
+		}
+	};
+
+
+	for (retrycount = 0; retrycount < TENTATIVE_RETRY_TRIES; retrycount++) {
+		log_debug("Reading from section \"%s\" on checkpoint "
+			  "\"%.*s\" (try %d)",
+			  name, handle->ch_name.length,
+			  handle->ch_name.value, retrycount + 1);
+		error = saCkptCheckpointRead(handle->ch_handle, readvec, 1,
+					     NULL);
+		ais_err_to_errno(error, &rc, &reason);
+		if (!rc) {
+			log_debug("Read section \"%s\" from checkpoint "
+				  "\"%.*s\"",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value);
+			break;
+		}
+
+		/* -ENOENT is a clean error for the caller to handle */
+		if (rc == -ENOENT) {
+			log_debug("Checkpoint \"%.*s\" does not have a "
+				  "section named \"%s\"",
+				  handle->ch_name.length,
+				  handle->ch_name.value, name);
+			break;
+		}
+
+		if (rc != -EAGAIN) {
+			log_error("Unable to read section \"%s\" from "
+				  "checkpoint \"%.*s\": %s",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value, reason);
+			break;
+		}
+
+		if ((retrycount + 1) < TENTATIVE_RETRY_TRIES)
+			sleep(1);
+		else
+			log_error("Unable to read section \"%s\" from "
+				  "checkpoint \"%.*s\": too many tries",
+				  name, handle->ch_name.length,
+				  handle->ch_name.value);
+	}
+
+	if (rc)
+		goto out;
+
+	p = malloc(sizeof(char) * readvec[0].readSize);
+	if (p) {
+		memcpy(p, readbuf, readvec[0].readSize);
+		*data = p;
+		*data_len = readvec[0].readSize;
+	} else {
+		log_error("Unable to allocate memory while reading section "
+			  "\"%s\" from checkpoint \"%.*s\"",
+			  name, handle->ch_name.length,
+			  handle->ch_name.value);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+out:
+	return rc;
+}
+
+int ckpt_section_store(struct ckpt_handle *handle, const char *section,
+		       const char *data, size_t data_len)
+{
+	if (strlen(section) > CKPT_MAX_SECTION_ID) {
+		log_error("Error: section id \"%s\" is too long "
+			  "(max is %d)",
+			  section, CKPT_MAX_SECTION_ID);
+		return -EINVAL;
+	}
+	if (data_len > CKPT_MAX_SECTION_SIZE) {
+		log_error("Error: attempt to store %d bytes in a section "
+			  "(max is %d)",
+			  data_len, CKPT_MAX_SECTION_SIZE);
+		return -EINVAL;
+	}
+
+	return call_section_write(handle, section, data, data_len);
+}
+
+int ckpt_global_store(const char *section, const char *data, size_t data_len)
+{
+	if (!global_handle) {
+		log_error("Error: The global checkpoint is not initialized");
+		return -EINVAL;
+	}
+
+	return ckpt_section_store(global_handle, section, data, data_len);
+}
+
+int ckpt_section_get(struct ckpt_handle *handle, const char *section,
+		     char **data, size_t *data_len)
+{
+	if (strlen(section) > CKPT_MAX_SECTION_ID) {
+		log_error("Error: section id \"%s\" is too long "
+			  "(max is %d)",
+			  section, CKPT_MAX_SECTION_ID);
+		return -EINVAL;
+	}
+
+	return call_section_read(handle, section, data, data_len);
+}
+
+int ckpt_global_get(const char *section, char **data, size_t *data_len)
+{
+	if (!global_handle) {
+		log_error("Error: The global checkpoint is not initialized");
+		return -EINVAL;
+	}
+
+	return call_section_read(global_handle, section, data, data_len);
+}
+
+/*
  * We name our ckeckpoints in one of three ways, all prefixed with 'ocfs2:'.
  *
  * The global checkpoint is named 'ocfs2:controld'.
@@ -402,6 +647,8 @@ int our_nodeid = 2;
 int main(int argc, char *argv[])
 {
 	int rc;
+	char *buf;
+	size_t buflen;
 	struct ckpt_handle *h;
 
 	rc = setup_ckpt();
@@ -411,12 +658,37 @@ int main(int argc, char *argv[])
 	rc = ckpt_open_global(1);
 	if (rc)
 		goto out_exit;
+	rc = ckpt_global_store("version", "1.0", strlen("1.0"));
+	if (!rc) {
+		rc = ckpt_global_get("foo", &buf, &buflen);
+		if (rc != -ENOENT) {
+			log_error("read should not have found anything");
+			rc = -EIO;
+		} else
+			rc = 0;
+	}
 	ckpt_close_global();
+	if (rc)
+		goto out_exit;
 	
 	rc = ckpt_open_this_node(&h);
 	if (rc)
 		goto out_exit;
+	rc = ckpt_section_store(h, "foo", "bar", strlen("bar"));
+	if (!rc) {
+		rc = ckpt_section_get(h, "foo", &buf, &buflen);
+		if (!rc) {
+			if ((buflen != strlen("bar")) ||
+			    memcmp(buf, "bar", strlen("bar"))) {
+				log_error("read returned bad value");
+				rc = -EIO;
+			}
+			free(buf);
+		}
+	}
 	ckpt_close(h);
+	if (rc)
+		goto out_exit;
 
 	rc = ckpt_open_node(4, &h);
 	if (rc)
-- 
1.5.3.8




More information about the Ocfs2-tools-devel mailing list