summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/gfdb/gfdb_data_store_helper.c
diff options
context:
space:
mode:
authorJoseph Fernandes <josferna@redhat.com>2015-10-14 00:00:41 +0530
committerDan Lambright <dlambrig@redhat.com>2015-11-08 05:22:02 -0800
commit5c0e815f69a0fb1f9c3f9b5555642dcb2295f209 (patch)
tree621fde60b15813fc7529344004ed9a0891ffae4a /libglusterfs/src/gfdb/gfdb_data_store_helper.c
parentf0193ce9b6b76647483f1380e7a8d791a5e64e61 (diff)
tier/libgfdb: Replacing ASCII query file with binary
Earlier, when the database was queried we used to save all the queried records in an ASCII format in the query file. This caused issues like filename having ASCII delimiter and used to take a lot of space. The tier.c file also had a lot of parsing code. Here we changed the format of the query file to binary. All the logic of serialization and formating of query record is done by libgfdb. Libgfdb provides API, gfdb_write_query_record() and gfdb_read_query_record(), which the user i.e tier migrator and CTR xlator can use to write to and read from query file. With this binary format we save on disk space i.e reduce to 50% atleast as we are saving GFID's in binary format 16 bytes and not the string format which takes 36 bytes + We are not saving path of the file + we are also saving on ASCII delimiters. The on disk format of query record is as follows, +---------------------------------------------------------------------------+ | Length of serialized query record | Serialized Query Record | +---------------------------------------------------------------------------+ 4 bytes Length of serialized query record | | -------------------------------------------------| | | V Serialized Query Record Format: +---------------------------------------------------------------------------+ | GFID | Link count | <LINK INFO> |..... | FOOTER | +---------------------------------------------------------------------------+ 16 B 4 B Link Length 4 B | | | | -----------------------------| | | | | | V | Each <Link Info> will be serialized as | +-----------------------------------------------+ | | PGID | BASE_NAME_LENGTH | BASE_NAME | | +-----------------------------------------------+ | 16 B 4 B BASE_NAME_LENGTH | | | ------------------------------------------------------------------------| | | V FOOTER is a magic number 0xBAADF00D indicating the end of the record. This also serves as a serialized schema validator. Backport of http://review.gluster.org/#/c/12354/ > Change-Id: I9db7416fd421e118dd44eafab8b535caafe50d5a > BUG: 1272207 > Signed-off-by: Joseph Fernandes <josferna@redhat.com> > Reviewed-on: http://review.gluster.org/12354 > Reviewed-by: N Balachandran <nbalacha@redhat.com> > Tested-by: Gluster Build System <jenkins@build.gluster.com> > Reviewed-by: Dan Lambright <dlambrig@redhat.com> > Tested-by: Dan Lambright <dlambrig@redhat.com> Change-Id: I170c579027f2594a58706f826e3ddf89e34022f4 BUG: 1263619 Signed-off-by: Joseph Fernandes <josferna@redhat.com> Reviewed-on: http://review.gluster.org/12535 Tested-by: NetBSD Build System <jenkins@build.gluster.org> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Dan Lambright <dlambrig@redhat.com> Tested-by: Dan Lambright <dlambrig@redhat.com>
Diffstat (limited to 'libglusterfs/src/gfdb/gfdb_data_store_helper.c')
-rw-r--r--libglusterfs/src/gfdb/gfdb_data_store_helper.c605
1 files changed, 605 insertions, 0 deletions
diff --git a/libglusterfs/src/gfdb/gfdb_data_store_helper.c b/libglusterfs/src/gfdb/gfdb_data_store_helper.c
new file mode 100644
index 00000000000..ff85e17169d
--- /dev/null
+++ b/libglusterfs/src/gfdb/gfdb_data_store_helper.c
@@ -0,0 +1,605 @@
+#include "gfdb_data_store_helper.h"
+
+
+/*Create a single link info structure*/
+gfdb_link_info_t*
+gfdb_link_info_new ()
+{
+ gfdb_link_info_t *link_info = NULL;
+
+ link_info = GF_CALLOC (1, sizeof(gfdb_link_info_t),
+ gf_mt_gfdb_link_info_t);
+ if (!link_info) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY, "Memory allocation failed for "
+ "link_info ");
+ goto out;
+ }
+
+ INIT_LIST_HEAD (&link_info->list);
+
+out:
+
+ return link_info;
+}
+
+/*Destroy a link info structure*/
+void
+gfdb_link_info_free(gfdb_link_info_t *link_info)
+{
+ GF_FREE (link_info);
+}
+
+
+/*Function to create the query_record*/
+gfdb_query_record_t *
+gfdb_query_record_new()
+{
+ int ret = -1;
+ gfdb_query_record_t *query_record = NULL;
+
+ query_record = GF_CALLOC (1, sizeof(gfdb_query_record_t),
+ gf_mt_gfdb_query_record_t);
+ if (!query_record) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY, "Memory allocation failed for "
+ "query_record ");
+ goto out;
+ }
+
+ INIT_LIST_HEAD (&query_record->link_list);
+
+ ret = 0;
+out:
+ if (ret == -1) {
+ GF_FREE (query_record);
+ }
+ return query_record;
+}
+
+
+/*Function to delete a single linkinfo from list*/
+static void
+gfdb_delete_linkinfo_from_list (gfdb_link_info_t **link_info)
+{
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, link_info, out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, *link_info, out);
+
+ /*Remove hard link from list*/
+ list_del(&(*link_info)->list);
+ gfdb_link_info_free (*link_info);
+ link_info = NULL;
+out:
+ return;
+}
+
+
+/*Function to destroy link_info list*/
+void
+gfdb_free_link_info_list (gfdb_query_record_t *query_record)
+{
+ gfdb_link_info_t *link_info = NULL;
+ gfdb_link_info_t *temp = NULL;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+
+ list_for_each_entry_safe(link_info, temp,
+ &query_record->link_list, list)
+ {
+ gfdb_delete_linkinfo_from_list (&link_info);
+ link_info = NULL;
+ }
+
+out:
+ return;
+}
+
+
+
+/* Function to add linkinfo to the query record */
+int
+gfdb_add_link_to_query_record (gfdb_query_record_t *query_record,
+ uuid_t pgfid,
+ char *base_name)
+{
+ int ret = -1;
+ gfdb_link_info_t *link_info = NULL;
+ int base_name_len = 0;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, pgfid, out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, base_name, out);
+
+ link_info = gfdb_link_info_new ();
+ if (!link_info) {
+ goto out;
+ }
+
+ gf_uuid_copy (link_info->pargfid, pgfid);
+ base_name_len = strlen (base_name);
+ memcpy (link_info->file_name, base_name, base_name_len);
+ link_info->file_name[base_name_len] = '\0';
+
+ list_add_tail (&link_info->list,
+ &query_record->link_list);
+
+ query_record->link_count++;
+
+ ret = 0;
+out:
+ if (ret) {
+ gfdb_link_info_free (link_info);
+ link_info = NULL;
+ }
+ return ret;
+}
+
+
+
+/*Function to destroy query record*/
+void
+gfdb_query_record_free(gfdb_query_record_t *query_record)
+{
+ if (query_record) {
+ gfdb_free_link_info_list (query_record);
+ GF_FREE (query_record);
+ }
+}
+
+
+/******************************************************************************
+ SERIALIZATION/DE-SERIALIZATION OF QUERY RECORD
+*******************************************************************************/
+/******************************************************************************
+ The on disk format of query record is as follows,
+
++---------------------------------------------------------------------------+
+| Length of serialized query record | Serialized Query Record |
++---------------------------------------------------------------------------+
+ 4 bytes Length of serialized query record
+ |
+ |
+ -------------------------------------------------|
+ |
+ |
+ V
+ Serialized Query Record Format:
+ +---------------------------------------------------------------------------+
+ | GFID | Link count | <LINK INFO> |..... | FOOTER |
+ +---------------------------------------------------------------------------+
+ 16 B 4 B Link Length 4 B
+ | |
+ | |
+ -----------------------------| |
+ | |
+ | |
+ V |
+ Each <Link Info> will be serialized as |
+ +-----------------------------------------------+ |
+ | PGID | BASE_NAME_LENGTH | BASE_NAME | |
+ +-----------------------------------------------+ |
+ 16 B 4 B BASE_NAME_LENGTH |
+ |
+ |
+ ------------------------------------------------------------------------|
+ |
+ |
+ V
+ FOOTER is a magic number 0xBAADF00D indicating the end of the record.
+ This also serves as a serialized schema validator.
+ * ****************************************************************************/
+
+#define GFDB_QUERY_RECORD_FOOTER 0xBAADF00D
+#define UUID_LEN 16
+
+/*Function to get the potential length of the serialized buffer*/
+static int32_t
+gfdb_query_record_serialized_length (gfdb_query_record_t *query_record)
+{
+ int32_t len = -1;
+ gfdb_link_info_t *link_info = NULL;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+
+ /* Length of GFID */
+ len = UUID_LEN;
+
+ /* length of number of links*/
+ len += sizeof (int32_t);
+
+ list_for_each_entry (link_info, &query_record->link_list, list) {
+
+ /* length of PFID */
+ len += UUID_LEN;
+
+ /* Add size of base name length*/
+ len += sizeof (int32_t);
+
+ /* Length of base_name */
+ len += strlen (link_info->file_name);
+
+ }
+
+ /* length of footer */
+ len += sizeof (int32_t);
+out:
+ return len;
+}
+
+/* Function for serializing query record.
+ *
+ * Query Record Serialization Format
+ * +---------------------------------------------------------------------------+
+ * | GFID | Link count | <LINK INFO> |..... | FOOTER |
+ * +---------------------------------------------------------------------------+
+ * 16 B 4 B Link Length 4 B
+ *
+ *
+ * Each <Link Info> will be serialized as
+ * +-----------------------------------------------+
+ * | PGID | BASE_NAME_LENGTH | BASE_NAME |
+ * +-----------------------------------------------+
+ * 16 B 4 B BASE_NAME_LENGTH
+ *
+ *
+ * FOOTER is a magic number 0xBAADF00D indicating the end of the record.
+ * This also serves as a serialized schema validator.
+ *
+ * The function will allocate memory to the serialized buffer,
+ * the caller needs to free it.
+ * Returns the length of the serialized buffer on success
+ * or -1 on failure.
+ *
+ * */
+static int
+gfdb_query_record_serialize (gfdb_query_record_t *query_record,
+ char **in_buffer)
+{
+ gfdb_link_info_t *link_info = NULL;
+ int count = -1;
+ int base_name_len = 0;
+ int buffer_length = 0;
+ int footer = GFDB_QUERY_RECORD_FOOTER;
+ char *buffer = NULL;
+ char *ret_buffer = NULL;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE,
+ (query_record->link_count > 0), out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, in_buffer, out);
+
+
+ /* Calculate the total length of the serialized buffer */
+ buffer_length = gfdb_query_record_serialized_length (query_record);
+ if (buffer_length <= 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to calculate the length of "
+ "serialized buffer");
+ goto out;
+ }
+
+ /* Allocate memory to the serialized buffer */
+ ret_buffer = GF_CALLOC (1, buffer_length, gf_common_mt_char);
+ if (!ret_buffer) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Memory allocation failed for "
+ "serialized buffer.");
+ goto out;
+ }
+
+ buffer = ret_buffer;
+
+ count = 0;
+
+ /* Copying the GFID */
+ memcpy (buffer, query_record->gfid, UUID_LEN);
+ buffer += UUID_LEN;
+ count += UUID_LEN;
+
+ /* Copying the number of links */
+ memcpy (buffer, &query_record->link_count, sizeof (int32_t));
+ buffer += sizeof (int32_t);
+ count += sizeof (int32_t);
+
+ list_for_each_entry (link_info, &query_record->link_list, list) {
+
+ /* Copying the PFID */
+ memcpy(buffer, link_info->pargfid, UUID_LEN);
+ buffer += UUID_LEN;
+ count += UUID_LEN;
+
+ /* Copying base name length*/
+ base_name_len = strlen (link_info->file_name);
+ memcpy (buffer, &base_name_len, sizeof (int32_t));
+ buffer += sizeof (int32_t);
+ count += sizeof (int32_t);
+
+ /* Length of base_name */
+ memcpy(buffer, link_info->file_name, base_name_len);
+ buffer += base_name_len;
+ count += base_name_len;
+
+ }
+
+ /* Copying the Footer of the record */
+ memcpy (buffer, &footer, sizeof (int32_t));
+ buffer += sizeof (int32_t);
+ count += sizeof (int32_t);
+
+out:
+ if (count < 0) {
+ GF_FREE (ret_buffer);
+ ret_buffer = NULL;
+ }
+ *in_buffer = ret_buffer;
+ return count;
+}
+
+static gf_boolean_t
+is_serialized_buffer_valid (char *in_buffer, int buffer_length) {
+ gf_boolean_t ret = _gf_false;
+ int footer = 0;
+
+ /* Read the footer */
+ in_buffer += (buffer_length - sizeof (int32_t));
+ memcpy (&footer, in_buffer, sizeof (int32_t));
+
+ /*
+ * if the footer is not GFDB_QUERY_RECORD_FOOTER
+ * then the serialized record is invalid
+ *
+ * */
+ if (footer != GFDB_QUERY_RECORD_FOOTER) {
+ goto out;
+ }
+
+ ret = _gf_true;
+out:
+ return ret;
+}
+
+
+static int
+gfdb_query_record_deserialize (char *in_buffer,
+ int buffer_length,
+ gfdb_query_record_t **query_record)
+{
+ int ret = -1;
+ char *buffer = NULL;
+ int i = 0;
+ gfdb_link_info_t *link_info = NULL;
+ int count = 0;
+ int base_name_len = 0;
+ gfdb_query_record_t *ret_qrecord = NULL;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, in_buffer, out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, (buffer_length > 0), out);
+
+ if (!is_serialized_buffer_valid (in_buffer, buffer_length)) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Invalid serialized query record");
+ goto out;
+ }
+
+ buffer = in_buffer;
+
+ ret_qrecord = gfdb_query_record_new ();
+ if (!ret_qrecord) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to allocate space to "
+ "gfdb_query_record_t");
+ goto out;
+ }
+
+ /* READ GFID */
+ memcpy ((ret_qrecord)->gfid, buffer, UUID_LEN);
+ buffer += UUID_LEN;
+ count += UUID_LEN;
+
+ /* Read the number of link */
+ memcpy (&(ret_qrecord->link_count), buffer, sizeof (int32_t));
+ buffer += sizeof (int32_t);
+ count += sizeof (int32_t);
+
+ /* Read all the links */
+ for (i = 0; i < ret_qrecord->link_count; i++) {
+ if (count >= buffer_length) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Invalid serialized "
+ "query record");
+ ret = -1;
+ goto out;
+ }
+
+ link_info = gfdb_link_info_new ();
+ if (!link_info) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to create link_info");
+ goto out;
+ }
+
+ /* READ PGFID */
+ memcpy (link_info->pargfid, buffer, UUID_LEN);
+ buffer += UUID_LEN;
+ count += UUID_LEN;
+
+ /* Read base name length */
+ memcpy (&base_name_len, buffer, sizeof (int32_t));
+ buffer += sizeof (int32_t);
+ count += sizeof (int32_t);
+
+ /* READ basename */
+ memcpy (link_info->file_name, buffer, base_name_len);
+ buffer += base_name_len;
+ count += base_name_len;
+ link_info->file_name[base_name_len] = '\0';
+
+ /* Add link_info to the list */
+ list_add_tail (&link_info->list,
+ &(ret_qrecord->link_list));
+
+ /* Reseting link_info */
+ link_info = NULL;
+ }
+
+ ret = 0;
+out:
+ if (ret) {
+ gfdb_query_record_free (ret_qrecord);
+ ret_qrecord = NULL;
+ }
+ *query_record = ret_qrecord;
+ return ret;
+}
+
+
+
+
+
+/* Function to write query record to file
+ *
+ * Disk format
+ * +---------------------------------------------------------------------------+
+ * | Length of serialized query record | Serialized Query Record |
+ * +---------------------------------------------------------------------------+
+ * 4 bytes Length of serialized query record
+ *
+ * Please refer gfdb_query_record_serialize () for format of
+ * Serialized Query Record
+ *
+ * */
+int
+gfdb_write_query_record (int fd,
+ gfdb_query_record_t *query_record)
+{
+ int ret = -1;
+ int buffer_len = 0;
+ char *buffer = NULL;
+ int write_len = 0;
+ char *write_buffer = NULL;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, (fd >= 0), out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+
+ buffer_len = gfdb_query_record_serialize (query_record, &buffer);
+ if (buffer_len < 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to serialize query record");
+ goto out;
+ }
+
+ /* Serialize the buffer length and write to file */
+ ret = write (fd, &buffer_len, sizeof (int32_t));
+ if (ret < 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to write buffer length"
+ " to file");
+ goto out;
+ }
+
+ /* Write the serialized query record to file */
+ write_len = buffer_len;
+ write_buffer = buffer;
+ while ((ret = write (fd, write_buffer, write_len)) < write_len) {
+ if (ret < 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, errno,
+ LG_MSG_DB_ERROR, "Failed to write serialized "
+ "query record to file");
+ goto out;
+ }
+
+ write_buffer += ret;
+ write_len -= ret;
+ }
+
+ ret = 0;
+out:
+ GF_FREE (buffer);
+ return ret;
+}
+
+
+
+/* Function to read query record from file.
+ * Allocates memory to query record and
+ * returns length of serialized query record when successful
+ * Return -1 when failed.
+ * Return 0 when reached EOF.
+ * */
+int
+gfdb_read_query_record (int fd,
+ gfdb_query_record_t **query_record)
+{
+ int ret = -1;
+ int buffer_len = 0;
+ int read_len = 0;
+ char *buffer = NULL;
+ char *read_buffer = NULL;
+
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, (fd >= 0), out);
+ GF_VALIDATE_OR_GOTO (GFDB_DATA_STORE, query_record, out);
+
+
+ /* Read serialized query record length from the file*/
+ ret = read (fd, &buffer_len, sizeof (int32_t));
+ if (ret < 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed reading buffer length"
+ " from file");
+ goto out;
+ }
+ /* EOF */
+ else if (ret == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ /* Allocating memory to the serialization buffer */
+ buffer = GF_CALLOC (1, buffer_len, gf_common_mt_char);
+ if (!buffer) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to allocate space to "
+ "serialized buffer");
+ goto out;
+ }
+
+
+ /* Read the serialized query record from file */
+ read_len = buffer_len;
+ read_buffer = buffer;
+ while ((ret = read (fd, read_buffer, read_len)) < read_len) {
+
+ /*Any error */
+ if (ret < 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, errno,
+ LG_MSG_DB_ERROR, "Failed to read serialized "
+ "query record from file");
+ goto out;
+ }
+ /* EOF */
+ else if (ret == 0) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Invalid query record or "
+ "corrupted query file");
+ ret = -1;
+ goto out;
+ }
+
+ read_buffer += ret;
+ read_len -= ret;
+ }
+
+ ret = gfdb_query_record_deserialize (buffer, buffer_len,
+ query_record);
+ if (ret) {
+ gf_msg (GFDB_DATA_STORE, GF_LOG_ERROR, 0,
+ LG_MSG_DB_ERROR, "Failed to de-serialize query record");
+ goto out;
+ }
+
+ ret = buffer_len;
+out:
+ GF_FREE (buffer);
+ return ret;
+}