summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/gfdb/gfdb_sqlite3_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-06 10:30:45 -0800
commit1d0402b25aa24e2076fb79cbeb4ba3ed3a9f3ede (patch)
treed40956ee33092f5be50cbd108cf9a31440aad64b /libglusterfs/src/gfdb/gfdb_sqlite3_helper.c
parentd51a33bae02245f8538c62b564f3fef49820790e (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. 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>
Diffstat (limited to 'libglusterfs/src/gfdb/gfdb_sqlite3_helper.c')
-rw-r--r--libglusterfs/src/gfdb/gfdb_sqlite3_helper.c197
1 files changed, 159 insertions, 38 deletions
diff --git a/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c b/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c
index 0cc294a5410..0e9ccdbb380 100644
--- a/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c
+++ b/libglusterfs/src/gfdb/gfdb_sqlite3_helper.c
@@ -1103,84 +1103,205 @@ gf_sql_query_function (sqlite3_stmt *prep_stmt,
gf_query_callback_t query_callback,
void *_query_cbk_args)
{
- int ret = -1;
- gfdb_query_record_t *gfdb_query_record = NULL;
- char *text_column = NULL;
- sqlite3 *db_conn = NULL;
+ int ret = -1;
+ gfdb_query_record_t *query_record = NULL;
+ char *text_column = NULL;
+ sqlite3 *db_conn = NULL;
+ uuid_t prev_gfid = {0};
+ uuid_t curr_gfid = {0};
+ uuid_t pgfid = {0};
+ char *base_name = NULL;
+ gf_boolean_t is_first_record = _gf_true;
+ gf_boolean_t is_query_empty = _gf_true;
GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, prep_stmt, out);
GF_VALIDATE_OR_GOTO (GFDB_STR_SQLITE3, query_callback, out);
db_conn = sqlite3_db_handle(prep_stmt);
- gfdb_query_record = gfdb_query_record_init ();
- if (!gfdb_query_record) {
- gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
- LG_MSG_CREATE_FAILED, "Failed to create "
- "gfdb_query_record");
- goto out;
- }
-
- /*Loop to access queried rows*/
+ /*
+ * Loop to access queried rows
+ * Each db record will have 3 columns
+ * GFID, PGFID, FILE_NAME
+ *
+ * For file with multiple hard links we will get multiple query rows
+ * with the same GFID, but different PGID and FILE_NAME Combination
+ * For Example if a file with
+ * GFID = 00000000-0000-0000-0000-000000000006
+ * has 3 hardlinks file1, file2 and file3 in 3 different folder
+ * with GFID's
+ * 00000000-0000-0000-0000-0000EFC00001,
+ * 00000000-0000-0000-0000-00000ABC0001 and
+ * 00000000-0000-0000-0000-00000ABC00CD
+ * Then there will be 3 records
+ * GFID : 00000000-0000-0000-0000-000000000006
+ * PGFID : 00000000-0000-0000-0000-0000EFC00001
+ * FILE_NAME : file1
+ *
+ * GFID : 00000000-0000-0000-0000-000000000006
+ * PGFID : 00000000-0000-0000-0000-00000ABC0001
+ * FILE_NAME : file2
+ *
+ * GFID : 00000000-0000-0000-0000-000000000006
+ * PGFID : 00000000-0000-0000-0000-00000ABC00CD
+ * FILE_NAME : file3
+ *
+ * This is retrieved and added to a single query_record
+ *
+ * query_record->gfid = 00000000-0000-0000-0000-000000000006
+ * ->link_info = {00000000-0000-0000-0000-0000EFC00001,
+ * "file1"}
+ * |
+ * V
+ * link_info = {00000000-0000-0000-0000-00000ABC0001,
+ * "file2"}
+ * |
+ * V
+ * link_info = {00000000-0000-0000-0000-00000ABC0001,
+ * "file3",
+ * list}
+ *
+ * This query record is sent to the registered query_callback()
+ *
+ * */
while ((ret = sqlite3_step (prep_stmt)) == SQLITE_ROW) {
- /*Clear the query record*/
- memset (gfdb_query_record, 0, sizeof(*gfdb_query_record));
-
if (sqlite3_column_count(prep_stmt) > 0) {
- /*Retriving GFID - column index is 0*/
+ is_query_empty = _gf_false;
+
+ /*Retrieving GFID - column index is 0*/
text_column = (char *)sqlite3_column_text
(prep_stmt, 0);
if (!text_column) {
gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
- LG_MSG_GET_ID_FAILED, "Failed "
- "retriving GF_ID");
+ LG_MSG_GET_ID_FAILED, "Failed to"
+ "retrieve GFID");
+ goto out;
+ }
+ ret = gf_uuid_parse (text_column, curr_gfid);
+ if (ret) {
+ gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
+ LG_MSG_PARSE_FAILED, "Failed to parse "
+ "GFID");
+ goto out;
+ }
+
+ /*
+ * if the previous record was not of the current gfid
+ * call the call_back function and send the
+ * query record, which will have all the link_info
+ * objects associated with this gfid
+ *
+ * */
+ if (gf_uuid_compare (curr_gfid, prev_gfid) != 0) {
+
+ /* If this is not the first record */
+ if (!is_first_record) {
+ /*Call the call_back function provided*/
+ ret = query_callback (query_record,
+ _query_cbk_args);
+ if (ret) {
+ gf_msg (GFDB_STR_SQLITE3,
+ GF_LOG_ERROR, 0,
+ LG_MSG_QUERY_CALL_BACK_FAILED,
+ "Query call back "
+ "failed");
+ goto out;
+ }
+
+ }
+
+ /*Clear the query record*/
+ gfdb_query_record_free (query_record);
+ query_record = NULL;
+ query_record = gfdb_query_record_new ();
+ if (!query_record) {
+ gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR,
+ 0, LG_MSG_CREATE_FAILED,
+ "Failed to create "
+ "query_record");
+ goto out;
+ }
+
+ gf_uuid_copy(query_record->gfid,
+ curr_gfid);
+ gf_uuid_copy(prev_gfid, curr_gfid);
+
+ }
+
+ /* Get PGFID */
+ text_column = (char *)sqlite3_column_text
+ (prep_stmt, 1);
+ if (!text_column) {
+ gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
+ LG_MSG_GET_ID_FAILED, "Failed to"
+ " retrieve GF_ID");
goto out;
}
- ret = gf_uuid_parse (text_column, gfdb_query_record->gfid);
+ ret = gf_uuid_parse (text_column, pgfid);
if (ret) {
gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
- LG_MSG_PARSE_FAILED, "Failed parsing "
+ LG_MSG_PARSE_FAILED, "Failed to parse "
"GF_ID");
goto out;
}
- /*Retrive Link Buffer - column index 1*/
+ /* Get Base name */
text_column = (char *)sqlite3_column_text
- (prep_stmt, 1);
- /* Get link string. Do shallow copy here
- * query_callback function should do a
- * deep copy and then do operations on this field*/
- gfdb_query_record->_link_info_str = text_column;
- gfdb_query_record->link_info_size = strlen
- (text_column);
-
- /* Call the call back function provided*/
- ret = query_callback (gfdb_query_record,
- _query_cbk_args);
+ (prep_stmt, 2);
+ if (!text_column) {
+ gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
+ LG_MSG_GET_ID_FAILED, "Failed to"
+ " retrieve GF_ID");
+ goto out;
+ }
+ base_name = text_column;
+
+
+ /* Add link info to the list */
+ ret = gfdb_add_link_to_query_record (query_record,
+ pgfid, base_name);
if (ret) {
gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
- LG_MSG_QUERY_CALL_BACK_FAILED,
- "Query Call back failed!");
+ LG_MSG_GET_ID_FAILED, "Failed to"
+ " add link info to query record");
goto out;
}
+ is_first_record = _gf_false;
+
}
}
if (ret != SQLITE_DONE) {
gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
- LG_MSG_GET_RECORD_FAILED, "Failed retriving records "
+ LG_MSG_GET_RECORD_FAILED, "Failed to retrieve records "
"from db : %s", sqlite3_errmsg (db_conn));
ret = -1;
goto out;
}
+
+ if (!is_query_empty) {
+ /*
+ * Call the call_back function for the last record from the
+ * Database
+ * */
+ ret = query_callback (query_record, _query_cbk_args);
+ if (ret) {
+ gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0,
+ LG_MSG_QUERY_CALL_BACK_FAILED,
+ "Query call back failed");
+ goto out;
+ }
+ }
+
ret = 0;
out:
- gfdb_query_record_fini (&gfdb_query_record);
+ gfdb_query_record_free (query_record);
+ query_record = NULL;
return ret;
}
@@ -1204,7 +1325,7 @@ gf_sql_clear_counters (gf_sql_connection_t *sql_conn)
&sql_strerror);
if (ret != SQLITE_OK) {
gf_msg (GFDB_STR_SQLITE3, GF_LOG_ERROR, 0, LG_MSG_EXEC_FAILED,
- "Failed executing: %s : %s",
+ "Failed to execute: %s : %s",
query_str, sql_strerror);
sqlite3_free (sql_strerror);
ret = -1;