[PATCH 4/4] sms: Add code to migrate the database to the new schema

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

Alexander Chemeris alexander.chemeris at gmail.com
Sat Mar 8 13:58:46 UTC 2014


Hi Holger,

Thank you for improving robustness of the code. I looked through it and it
looks good to me.

Please let me know when you merge to the master so I could rebase the SMS
validity decoding code on top of it and submit it for review.


On Sat, Mar 8, 2014 at 1:54 PM, Holger Hans Peter Freyther <
holger at freyther.de> wrote:

> From: Holger Hans Peter Freyther <holger at moiji-mobile.com>
>
> This is mostly based on Alexander's migration code. The code
> adds transaction handling and some sanity checks and cleanups
> to the code. We made the decision to fork the sms_from_result
> method and freeze it to that version. This way sms_from_result
> can move forward without having to deal with legacy.
> ---
>  openbsc/src/libbsc/gsm_subscriber_base.c |   6 +
>  openbsc/src/libmsc/db.c                  | 209
> ++++++++++++++++++++++++++++---
>  2 files changed, 199 insertions(+), 16 deletions(-)
>
> diff --git a/openbsc/src/libbsc/gsm_subscriber_base.c
> b/openbsc/src/libbsc/gsm_subscriber_base.c
> index 5755687..5e00443 100644
> --- a/openbsc/src/libbsc/gsm_subscriber_base.c
> +++ b/openbsc/src/libbsc/gsm_subscriber_base.c
> @@ -72,6 +72,12 @@ static void subscr_free(struct gsm_subscriber *subscr)
>         talloc_free(subscr);
>  }
>
> +void subscr_direct_free(struct gsm_subscriber *subscr)
> +{
> +       OSMO_ASSERT(subscr->use_count == 1);
> +       subscr_free(subscr);
> +}
> +
>  struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
>  {
>         subscr->use_count++;
> diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
> index 2351485..3b92691 100644
> --- a/openbsc/src/libmsc/db.c
> +++ b/openbsc/src/libmsc/db.c
> @@ -38,23 +38,42 @@
>  #include <osmocom/core/statistics.h>
>  #include <osmocom/core/rate_ctr.h>
>
> +/* Semi-Private-Interface (SPI) for the subscriber code */
> +void subscr_direct_free(struct gsm_subscriber *subscr);
> +
>  static char *db_basename = NULL;
>  static char *db_dirname = NULL;
>  static dbi_conn conn;
>
> -#define SCHEMA_REVISION "3"
> +#define SCHEMA_REVISION "4"
> +
> +enum {
> +       SCHEMA_META,
> +       INSERT_META,
> +       SCHEMA_SUBSCRIBER,
> +       SCHEMA_AUTH,
> +       SCHEMA_EQUIPMENT,
> +       SCHEMA_EQUIPMENT_WATCH,
> +       SCHEMA_SMS,
> +       SCHEMA_VLR,
> +       SCHEMA_APDU,
> +       SCHEMA_COUNTERS,
> +       SCHEMA_RATE,
> +       SCHEMA_AUTHKEY,
> +       SCHEMA_AUTHLAST,
> +};
>
> -static char *create_stmts[] = {
> -       "CREATE TABLE IF NOT EXISTS Meta ("
> +static const char *create_stmts[] = {
> +       [SCHEMA_META] = "CREATE TABLE IF NOT EXISTS Meta ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "key TEXT UNIQUE NOT NULL, "
>                 "value TEXT NOT NULL"
>                 ")",
> -       "INSERT OR IGNORE INTO Meta "
> +       [INSERT_META] = "INSERT OR IGNORE INTO Meta "
>                 "(key, value) "
>                 "VALUES "
>                 "('revision', " SCHEMA_REVISION ")",
> -       "CREATE TABLE IF NOT EXISTS Subscriber ("
> +       [SCHEMA_SUBSCRIBER] = "CREATE TABLE IF NOT EXISTS Subscriber ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "created TIMESTAMP NOT NULL, "
>                 "updated TIMESTAMP NOT NULL, "
> @@ -66,13 +85,13 @@ static char *create_stmts[] = {
>                 "lac INTEGER NOT NULL DEFAULT 0, "
>                 "expire_lu TIMESTAMP DEFAULT NULL"
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS AuthToken ("
> +       [SCHEMA_AUTH] = "CREATE TABLE IF NOT EXISTS AuthToken ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "subscriber_id INTEGER UNIQUE NOT NULL, "
>                 "created TIMESTAMP NOT NULL, "
>                 "token TEXT UNIQUE NOT NULL"
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS Equipment ("
> +       [SCHEMA_EQUIPMENT] = "CREATE TABLE IF NOT EXISTS Equipment ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "created TIMESTAMP NOT NULL, "
>                 "updated TIMESTAMP NOT NULL, "
> @@ -82,7 +101,7 @@ static char *create_stmts[] = {
>                 "classmark3 BLOB, "
>                 "imei NUMERIC UNIQUE NOT NULL"
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS EquipmentWatch ("
> +       [SCHEMA_EQUIPMENT_WATCH] = "CREATE TABLE IF NOT EXISTS
> EquipmentWatch ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "created TIMESTAMP NOT NULL, "
>                 "updated TIMESTAMP NOT NULL, "
> @@ -90,7 +109,7 @@ static char *create_stmts[] = {
>                 "equipment_id NUMERIC NOT NULL, "
>                 "UNIQUE (subscriber_id, equipment_id) "
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS SMS ("
> +       [SCHEMA_SMS] = "CREATE TABLE IF NOT EXISTS SMS ("
>                 /* metadata, not part of sms */
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "created TIMESTAMP NOT NULL, "
> @@ -114,39 +133,39 @@ static char *create_stmts[] = {
>                 "header BLOB, "         /* UD Header */
>                 "text TEXT "            /* decoded UD after UDH */
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS VLR ("
> +       [SCHEMA_VLR] = "CREATE TABLE IF NOT EXISTS VLR ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "created TIMESTAMP NOT NULL, "
>                 "updated TIMESTAMP NOT NULL, "
>                 "subscriber_id NUMERIC UNIQUE NOT NULL, "
>                 "last_bts NUMERIC NOT NULL "
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS ApduBlobs ("
> +       [SCHEMA_APDU] = "CREATE TABLE IF NOT EXISTS ApduBlobs ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "created TIMESTAMP NOT NULL, "
>                 "apdu_id_flags INTEGER NOT NULL, "
>                 "subscriber_id INTEGER NOT NULL, "
>                 "apdu BLOB "
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS Counters ("
> +       [SCHEMA_COUNTERS] = "CREATE TABLE IF NOT EXISTS Counters ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "timestamp TIMESTAMP NOT NULL, "
>                 "value INTEGER NOT NULL, "
>                 "name TEXT NOT NULL "
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS RateCounters ("
> +       [SCHEMA_RATE] = "CREATE TABLE IF NOT EXISTS RateCounters ("
>                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
>                 "timestamp TIMESTAMP NOT NULL, "
>                 "value INTEGER NOT NULL, "
>                 "name TEXT NOT NULL, "
>                 "idx INTEGER NOT NULL "
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS AuthKeys ("
> +       [SCHEMA_AUTHKEY] = "CREATE TABLE IF NOT EXISTS AuthKeys ("
>                 "subscriber_id INTEGER PRIMARY KEY, "
>                 "algorithm_id INTEGER NOT NULL, "
>                 "a3a8_ki BLOB "
>                 ")",
> -       "CREATE TABLE IF NOT EXISTS AuthLastTuples ("
> +       [SCHEMA_AUTHLAST] = "CREATE TABLE IF NOT EXISTS AuthLastTuples ("
>                 "subscriber_id INTEGER PRIMARY KEY, "
>                 "issued TIMESTAMP NOT NULL, "
>                 "use_count INTEGER NOT NULL DEFAULT 0, "
> @@ -185,12 +204,164 @@ static int update_db_revision_2(void)
>                                 "WHERE key = 'revision'");
>         if (!result) {
>                 LOGP(DDB, LOGL_ERROR,
> -                    "Failed set new revision (upgrade vom rev 2).\n");
> +                    "Failed to update DB schema revision  (upgrade from
> rev 2).\n");
> +               return -EINVAL;
> +       }
> +       dbi_result_free(result);
> +
> +       return 0;
> +}
> +
> +/**
> + * Copied from the normal sms_from_result_v3 to avoid having
> + * to make sure that the real routine will remain backward
> + * compatible.
> + */
> +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 unsigned char *user_data;
> +       char buf[32];
> +
> +       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->reply_path_req = dbi_result_get_uint(result,
> "reply_path_req");
> +       sms->status_rep_req = dbi_result_get_uint(result,
> "status_rep_req");
> +       sms->ud_hdr_ind = dbi_result_get_uint(result, "ud_hdr_ind");
> +       sms->protocol_id = dbi_result_get_uint(result, "protocol_id");
> +       sms->data_coding_scheme = dbi_result_get_uint(result,
> +                                                 "data_coding_scheme");
> +
> +       daddr = dbi_result_get_string(result, "dest_addr");
> +       if (daddr) {
> +               strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
> +               sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
> +       }
> +
> +       sms->user_data_len = dbi_result_get_field_length(result,
> "user_data");
> +       user_data = dbi_result_get_binary(result, "user_data");
> +       if (sms->user_data_len > sizeof(sms->user_data))
> +               sms->user_data_len = (uint8_t) sizeof(sms->user_data);
> +       memcpy(sms->user_data, user_data, sms->user_data_len);
> +
> +       text = dbi_result_get_string(result, "text");
> +       if (text) {
> +               strncpy(sms->text, text, sizeof(sms->text));
> +               sms->text[sizeof(sms->text)-1] = '\0';
> +       }
> +       return sms;
> +}
> +
> +static int update_db_revision_3(void)
> +{
> +       dbi_result result;
> +       struct gsm_sms *sms;
> +
> +       result = dbi_conn_query(conn, "BEGIN EXCLUSIVE TRANSACTION");
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                       "Failed to begin transaction (upgrade from rev
> 3)\n");
>                 return -EINVAL;
>         }
>         dbi_result_free(result);
>
> +       /* Rename old SMS table to be able create a new one */
> +       result = dbi_conn_query(conn, "ALTER TABLE SMS RENAME TO SMS_3");
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                    "Failed to rename the old SMS table (upgrade from rev
> 3).\n");
> +               goto rollback;
> +       }
> +       dbi_result_free(result);
> +
> +       /* Create new SMS table with all the bells and whistles! */
> +       result = dbi_conn_query(conn, create_stmts[SCHEMA_SMS]);
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                    "Failed to create a new SMS table (upgrade from rev
> 3).\n");
> +               goto rollback;
> +       }
> +       dbi_result_free(result);
> +
> +       /* Cycle through old messages and convert them to the new format */
> +       result = dbi_conn_queryf(conn, "SELECT * FROM SMS_3");
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                    "Failed fetch messages from the old SMS table
> (upgrade from rev 3).\n");
> +               goto rollback;
> +       }
> +       while (dbi_result_next_row(result)) {
> +               sms = sms_from_result_v3(result);
> +               if (db_sms_store(sms) != 0) {
> +                       LOGP(DDB, LOGL_ERROR, "Failed to store message to
> the new SMS table(upgrade from rev 3).\n");
> +                       sms_free(sms);
> +                       dbi_result_free(result);
> +                       goto rollback;
> +               }
> +               sms_free(sms);
> +       }
> +       dbi_result_free(result);
> +
> +       /* Remove the temporary table */
> +       result = dbi_conn_query(conn, "DROP TABLE SMS_3");
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                    "Failed to drop the old SMS table (upgrade from rev
> 3).\n");
> +               goto rollback;
> +       }
> +       dbi_result_free(result);
> +
> +       /* We're done. Bump DB Meta revision to 4 */
> +       result = dbi_conn_query(conn,
> +                               "UPDATE Meta "
> +                               "SET value = '4' "
> +                               "WHERE key = 'revision'");
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                    "Failed to update DB schema revision (upgrade from
> rev 3).\n");
> +               goto rollback;
> +       }
> +       dbi_result_free(result);
> +
> +       result = dbi_conn_query(conn, "COMMIT TRANSACTION");
> +       if (!result) {
> +               LOGP(DDB, LOGL_ERROR,
> +                       "Failed to commit the transaction (upgrade from
> rev 3)\n");
> +               return -EINVAL;
> +       }
> +
> +       /* Shrink DB file size by actually wiping out SMS_3 table data */
> +       result = dbi_conn_query(conn, "VACUUM");
> +       if (!result)
> +               LOGP(DDB, LOGL_ERROR,
> +                       "VACUUM failed. Ignoring it (upgrade from rev
> 3).\n");
> +       else
> +               dbi_result_free(result);
> +
>         return 0;
> +
> +rollback:
> +       result = dbi_conn_query(conn, "ROLLBACK TRANSACTION");
> +       if (!result)
> +               LOGP(DDB, LOGL_ERROR,
> +                       "Rollback failed (upgrade from rev 3).\n");
> +       else
> +               dbi_result_free(result);
> +       return -EINVAL;
>  }
>
>  static int check_db_revision(void)
> @@ -218,6 +389,12 @@ static int check_db_revision(void)
>                         dbi_result_free(result);
>                         return -EINVAL;
>                 }
> +       } else if (!strcmp(rev_s, "3")) {
> +               if (update_db_revision_3()) {
> +                       LOGP(DDB, LOGL_FATAL, "Failed to update database
> from schema revision '%s'.\n", rev_s);
> +                       dbi_result_free(result);
> +                       return -EINVAL;
> +               }
>         } else if (!strcmp(rev_s, SCHEMA_REVISION)) {
>                 /* everything is fine */
>         } else {
> --
> 1.9.0
>
>
>


-- 
Regards,
Alexander Chemeris.
CEO, Fairwaves, Inc. / ООО УмРадио
https://fairwaves.co
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/openbsc/attachments/20140308/a9106da4/attachment.htm>


More information about the OpenBSC mailing list