db.c: implemented incremental migration

Submitted by axilirator@gmail.com on March 31, 2016, 10:51 a.m.

Details

Message ID 1459421505-25727-1-git-send-email-axilirator@gmail.com
State New
Series "db.c: implemented incremental migration"
Headers show

Commit Message

axilirator@gmail.com March 31, 2016, 10:51 a.m.
In the past normal migration was possible only if the actual
schema version differed from the version used in DB by 1. For
example, if DB uses an old version 3 and you need to use it
with the code written for version 5, the check_db_revision()
will convert it to 4 and DB will still use incompatible schema
version during Osmo-NITB running time. After next run it will
be converted to version 5.

This patch replaces a set of 'else-if' checks by a 'switch'
without 'break' statements between 'case' labels (waterfall).
It makes you able to migrate from current version to the
latest despite any difference between them.

Also fixed the sms_from_result_v3() to avoid large depth of
function calls, because they can be changed in the future
and lose compatibility with old table schemas.

Also fixed db_test and now it is successful.

Signed-off-by: Vadim Yanitskiy <axilirator@gmail.com>
---
 openbsc/src/libmsc/db.c      | 65 ++++++++++++++++++++++++++++----------------
 openbsc/tests/db/db_test.c   |  1 +
 openbsc/tests/db/db_test.err |  3 ++
 3 files changed, 45 insertions(+), 24 deletions(-)

Patch hide | download patch | download mbox

diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 04aee79..ad5afca 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -225,23 +225,27 @@  static struct gsm_sms *sms_from_result_v3(dbi_result result)
 {
 	struct gsm_sms *sms = sms_alloc();
 	long long unsigned int sender_id;
-	struct gsm_subscriber *sender;
-	const char *text, *daddr;
+	const char *text, *daddr, *extension;
 	const unsigned char *user_data;
-	char buf[32];
+	dbi_result sender_result;
 
 	if (!sms)
 		return NULL;
 
-	sms->id = dbi_result_get_ulonglong(result, "id");
-
 	sender_id = dbi_result_get_ulonglong(result, "sender_id");
-	snprintf(buf, sizeof(buf), "%llu", sender_id);
-	sender = db_get_subscriber(GSM_SUBSCRIBER_ID, buf);
-	OSMO_ASSERT(sender);
-	strncpy(sms->src.addr, sender->extension, sizeof(sms->src.addr)-1);
-	subscr_direct_free(sender);
-	sender = NULL;
+	sms->id   = dbi_result_get_ulonglong(result, "id");
+
+	sender_result = dbi_conn_queryf(conn,
+		"SELECT * FROM Subscriber "
+		"WHERE id = %llu", sender_id);
+
+	if (sender_result) {
+		if (dbi_result_next_row(sender_result)) {
+			extension = dbi_result_get_string(sender_result, "extension");
+			strncpy(sms->src.addr, extension, sizeof(sms->src.addr) - 1);
+		}
+		dbi_result_free(sender_result);
+	}
 
 	sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req");
 	sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req");
@@ -477,16 +481,20 @@  static int check_db_revision(void)
 {
 	dbi_result result;
 	const char *rev_s;
+	int db_rev = 0;
 
+	/* Make a query */
 	result = dbi_conn_query(conn,
-				"SELECT value FROM Meta WHERE key='revision'");
+				"SELECT value FROM Meta "
+				"WHERE key = 'revision'");
 	if (!result)
 		return -EINVAL;
-
 	if (!dbi_result_next_row(result)) {
 		dbi_result_free(result);
 		return -EINVAL;
 	}
+
+	/* Fetch the DB schema revision */
 	rev_s = dbi_result_get_string(result, "value");
 	if (!rev_s) {
 		dbi_result_free(result);
@@ -494,28 +502,37 @@  static int check_db_revision(void)
 	}
 
 	if (!strcmp(rev_s, SCHEMA_REVISION)) {
-		/* everything is fine */
-	} else if (!strcmp(rev_s, "2")) {
+		/* Everything is fine */
+		dbi_result_free(result);
+		return 0;
+	}
+
+	db_rev = atoi(rev_s);
+	dbi_result_free(result);
+
+	/* Incremental migration waterfall */
+	switch (db_rev) {
+	case 2:
 		if (update_db_revision_2())
 			goto error;
-	} else if (!strcmp(rev_s, "3")) {
+	case 3:
 		if (update_db_revision_3())
 			goto error;
-	} else if (!strcmp(rev_s, "4")) {
+	case 4:
 		if (update_db_revision_4())
-			goto error;	
-	} else {
-		LOGP(DDB, LOGL_FATAL, "Invalid database schema revision '%s'.\n", rev_s);
-		dbi_result_free(result);
+			goto error;
+
+		/* The end of waterfall */
+		break;
+	default:
+		LOGP(DDB, LOGL_FATAL, "Invalid database schema revision '%d'.\n", db_rev);
 		return -EINVAL;
 	}
 
-	dbi_result_free(result);
 	return 0;
 
 error:
-	LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%s'.\n", rev_s);
-	dbi_result_free(result);
+	LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%d'.\n", db_rev);
 	return -EINVAL;
 }
 
diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c
index a02d1f8..2fdd830 100644
--- a/openbsc/tests/db/db_test.c
+++ b/openbsc/tests/db/db_test.c
@@ -187,6 +187,7 @@  int main()
 
 	char *alice_imsi = "3243245432345";
 	alice = db_create_subscriber(alice_imsi);
+	db_subscriber_alloc_tmsi(alice);
 	db_sync_subscriber(alice);
 	alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi);
 	COMPARE(alice, alice_db);
diff --git a/openbsc/tests/db/db_test.err b/openbsc/tests/db/db_test.err
index fa9a54c..d8a3e7f 100644
--- a/openbsc/tests/db/db_test.err
+++ b/openbsc/tests/db/db_test.err
@@ -1,2 +1,5 @@ 
 Going to migrate from revision 3
+Migration complete.
+Going to migrate from revision 4
+Migration complete.
 
\ No newline at end of file