db.c: implemented incremental migration
diff mbox

Message ID 1459421505-25727-1-git-send-email-axilirator@gmail.com
State New
Headers show

Commit Message

Vadim Yanitskiy March 31, 2016, 10:51 a.m. UTC
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
diff 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