Browse Source

lib/srdb1: Added support for database row and table locking to SRDB1

- Requires support within the database module
Peter Dunkley 13 years ago
parent
commit
6c39a678a5
5 changed files with 148 additions and 12 deletions
  1. 2 1
      lib/srdb1/db.c
  2. 12 1
      lib/srdb1/db.h
  3. 39 0
      lib/srdb1/db_locking.h
  4. 68 10
      lib/srdb1/db_query.c
  5. 27 0
      lib/srdb1/db_query.h

+ 2 - 1
lib/srdb1/db.c

@@ -243,11 +243,12 @@ int db_bind_mod(const str* mod, db_func_t* mydbf)
 		dbf.insert_delayed = (db_insert_delayed_f)find_mod_export(tmp,
 			"db_insert_delayed", 2, 0);
 		dbf.start_transaction = (db_start_transaction_f)find_mod_export(tmp,
-			"db_start_transaction", 1, 0);
+			"db_start_transaction", 2, 0);
 		dbf.end_transaction = (db_end_transaction_f)find_mod_export(tmp,
 			"db_end_transaction", 1, 0);
 		dbf.abort_transaction = (db_abort_transaction_f)find_mod_export(tmp,
 			"db_abort_transaction", 1, 0);
+		dbf.query_lock = (db_query_f)find_mod_export(tmp, "db_query_lock", 2, 0);
 	}
 	if(db_check_api(&dbf, tmp)!=0)
 		goto error;

+ 12 - 1
lib/srdb1/db.h

@@ -51,6 +51,7 @@
 #include "db_con.h"
 #include "db_row.h"
 #include "db_pooling.h"
+#include "db_locking.h"
 
 /**
  * \brief Specify table name that will be used for subsequent operations.
@@ -342,7 +343,7 @@ typedef int (*db_affected_rows_f) (const db1_con_t* _h);
  * \param _h structure representing database connection
  * \return 0 if everything is OK, otherwise returns < 0
  */
-typedef int (*db_start_transaction_f) (db1_con_t* _h);
+typedef int (*db_start_transaction_f) (db1_con_t* _h, db_locking_t _l);
 
 /**
  * \brief End a transaction. 
@@ -391,6 +392,7 @@ typedef struct db_func {
 	db_start_transaction_f start_transaction; /* Start a single transaction consisting of multiple queries */
 	db_end_transaction_f end_transaction; /* End a transaction */
 	db_abort_transaction_f abort_transaction; /* Abort a transaction */
+	db_query_f        query_lock;    /* query a table and lock rows for update */
 } db_func_t;
 
 
@@ -534,6 +536,15 @@ int db_fetch_query(db_func_t *dbf, int frows,
 		const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
 		const db_key_t _o, db1_res_t** _r);
 
+/**
+ * \brief wrapper around db query_lock to handle fetch capability
+ * \return -1 error; 0 ok with no fetch capability; 1 ok with fetch capability
+ */
+int db_fetch_query_lock(db_func_t *dbf, int frows,
+		db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+		const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
+		const db_key_t _o, db1_res_t** _r);
+
 /**
  * \brief wrapper around db fetch to handle fetch capability
  * \return -1 error; 0 ok with no fetch capability; 1 ok with fetch capability

+ 39 - 0
lib/srdb1/db_locking.h

@@ -0,0 +1,39 @@
+/*
+ * $Id$
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * \file lib/srdb1/db_locking.h
+ * \ingroup db1
+ * \brief Defines Locking states
+ *
+ */
+
+#ifndef DB1_LOCKING_H
+#define DB1_LOCKING_H
+
+
+typedef enum {
+	DB_LOCKING_NONE,
+	DB_LOCKING_WRITE,
+	DB_LOCKING_FULL
+} db_locking_t;
+
+
+#endif /* DB1_LOCKING_H */

+ 68 - 10
lib/srdb1/db_query.c

@@ -66,11 +66,11 @@ static inline int db_do_submit_query(const db1_con_t* _h, const str *_query,
 	return ret;
 }
 
-int db_do_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+static int db_do_query_internal(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
 	const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
 	const db_key_t _o, db1_res_t** _r, int (*val2str) (const db1_con_t*,
 	const db_val_t*, char*, int* _len), int (*submit_query)(const db1_con_t*,
-	const str*), int (*store_result)(const db1_con_t* _h, db1_res_t** _r))
+	const str*), int (*store_result)(const db1_con_t* _h, db1_res_t** _r), int _l)
 {
 	int off, ret;
 
@@ -111,6 +111,11 @@ int db_do_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
 		if (ret < 0 || ret >= (sql_buffer_size - off)) goto error;
 		off += ret;
 	}
+	if (_l) {
+		ret = snprintf(sql_buf + off, sql_buffer_size - off, " for update");
+		if (ret < 0 || ret >= (sql_buffer_size - off)) goto error;
+		off += ret;
+	}
 	/*
 	 * Null-terminate the string for the postgres driver. Its query function
 	 * don't support a length parameter, so they need this for the correct
@@ -142,6 +147,26 @@ error:
 	return -1;
 }
 
+int db_do_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+	const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
+	const db_key_t _o, db1_res_t** _r, int (*val2str) (const db1_con_t*,
+	const db_val_t*, char*, int* _len), int (*submit_query)(const db1_con_t*,
+	const str*), int (*store_result)(const db1_con_t* _h, db1_res_t** _r))
+{
+	return db_do_query_internal(_h, _k, _op, _v, _c, _n, _nc, _o, _r, val2str,
+					submit_query, store_result, 0);
+}
+
+int db_do_query_lock(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+	const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
+	const db_key_t _o, db1_res_t** _r, int (*val2str) (const db1_con_t*,
+	const db_val_t*, char*, int* _len), int (*submit_query)(const db1_con_t*,
+	const str*), int (*store_result)(const db1_con_t* _h, db1_res_t** _r))
+{
+	return db_do_query_internal(_h, _k, _op, _v, _c, _n, _nc, _o, _r, val2str,
+					submit_query, store_result, 1);
+}
+
 
 int db_do_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r,
 	int (*submit_query)(const db1_con_t* _h, const str* _c),
@@ -382,23 +407,24 @@ int db_query_init(void)
     return 0;
 }
 
-/**
- * wrapper around db query to handle fetch capability
- * return: -1 error; 0 ok with no fetch capability; 1 ok with fetch capability
- */
-int db_fetch_query(db_func_t *dbf, int frows,
+static int db_fetch_query_internal(db_func_t *dbf, int frows,
 		db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
 		const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
-		const db_key_t _o, db1_res_t** _r)
+		const db_key_t _o, db1_res_t** _r, db_query_f _query)
 {
 
 	int ret;
 
+	if (!_query) {
+		LM_ERR("bad query function pointer\n");
+		goto error;
+	}
+
 	ret = 0;
 	*_r = NULL;
 
 	if (DB_CAPABILITY(*dbf, DB_CAP_FETCH)) {
-		if(dbf->query(_h, _k, _op, _v, _c, _n, _nc, _o, 0) < 0)
+		if(_query(_h, _k, _op, _v, _c, _n, _nc, _o, 0) < 0)
 		{
 			LM_ERR("unable to query db for fetch\n");
 			goto error;
@@ -410,7 +436,7 @@ int db_fetch_query(db_func_t *dbf, int frows,
 		}
 		ret = 1;
 	} else {
-		if(dbf->query(_h, _k, _op, _v, _c, _n, _nc, _o, _r) < 0)
+		if(_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r) < 0)
 		{
 			LM_ERR("unable to do full db querry\n");
 			goto error;
@@ -428,6 +454,38 @@ error:
 	return -1;
 }
 
+/**
+ * wrapper around db query to handle fetch capability
+ * return: -1 error; 0 ok with no fetch capability; 1 ok with fetch capability
+ */
+int db_fetch_query(db_func_t *dbf, int frows,
+		db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+		const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
+		const db_key_t _o, db1_res_t** _r)
+{
+	return db_fetch_query_internal(dbf, frows, _h, _k, _op, _v, _c, _n,
+					_nc, _o, _r, dbf->query);
+}
+
+/**
+ * wrapper around db query_lock to handle fetch capability
+ * return: -1 error; 0 ok with no fetch capability; 1 ok with fetch capability
+ */
+int db_fetch_query_lock(db_func_t *dbf, int frows,
+		db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+		const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
+		const db_key_t _o, db1_res_t** _r)
+{
+	if (!dbf->query_lock)
+	{
+		LM_ERR("query_lock not supported by this database module\n");
+		return -1;
+	}
+
+	return db_fetch_query_internal(dbf, frows, _h, _k, _op, _v, _c, _n,
+					_nc, _o, _r, dbf->query_lock);
+}
+
 /**
  * wrapper around db fetch to handle fetch capability
  * return: -1 error; 0 ok with no fetch capability; 1 ok with fetch capability

+ 27 - 0
lib/srdb1/db_query.h

@@ -72,6 +72,33 @@ int db_do_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
 	const db_val_t*, char*, int*), int (*submit_query)(const db1_con_t* _h,
 	const str* _c), int (*store_result)(const db1_con_t* _h, db1_res_t** _r));
 
+/**
+ * \brief Helper function for db queries with update lock
+ *
+ * This method evaluates the actual arguments for the database query and
+ * setups the string that is used for the query in the db module.
+ * Then its submit the query and stores the result if necessary. It uses for
+ * its work the implementation in the concrete database module.
+ *
+ * \param _h structure representing database connection
+ * \param _k key names, if not present the whole table will be returned
+ * \param _op operators
+ * \param _v values of the keys that must match
+ * \param _c column names that should be returned
+ * \param _n number of key/value pairs that are compared, if zero then no comparison is done
+ * \param _nc number of colums that should be returned
+ * \param _o order by the specificied column, optional
+ * \param _r the result that is returned, set to NULL if you want to use fetch_result later
+ * \param (*val2str) function pointer to the db specific val conversion function
+ * \param (*submit_query) function pointer to the db specific query submit function
+ * \param (*store_result) function pointer to the db specific store result function
+ * \return zero on success, negative on errors
+ */
+int db_do_query_lock(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
+	const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
+	const db_key_t _o, db1_res_t** _r, int (*val2str) (const db1_con_t*,
+	const db_val_t*, char*, int*), int (*submit_query)(const db1_con_t* _h,
+	const str* _c), int (*store_result)(const db1_con_t* _h, db1_res_t** _r));
 
 /**
  * \brief Helper function for raw db queries