[open-ils-commits] r18686 - trunk/Open-ILS/src/c-apps (miker)
svn at svn.open-ils.org
svn at svn.open-ils.org
Wed Nov 10 14:53:42 EST 2010
Author: miker
Date: 2010-11-10 14:53:37 -0500 (Wed, 10 Nov 2010)
New Revision: 18686
Modified:
trunk/Open-ILS/src/c-apps/oils_sql.c
Log:
Improved permission checking speed for PCRUD mode.
When there are more than some number of rows (5, by default) we use usr_has_perm_at_all to get the list of locations and cache them. This cache is flushed per-session.
Modified: trunk/Open-ILS/src/c-apps/oils_sql.c
===================================================================
--- trunk/Open-ILS/src/c-apps/oils_sql.c 2010-11-10 17:54:34 UTC (rev 18685)
+++ trunk/Open-ILS/src/c-apps/oils_sql.c 2010-11-10 19:53:37 UTC (rev 18686)
@@ -100,8 +100,12 @@
char* SELECT ( osrfMethodContext*, jsonObject*, const jsonObject*, const jsonObject*,
const jsonObject*, const jsonObject*, const jsonObject*, const jsonObject*, int );
+static osrfStringArray* getPermLocationCache( osrfMethodContext*, const char* );
+static void setPermLocationCache( osrfMethodContext*, const char*, osrfStringArray* );
+
void userDataFree( void* );
static void sessionDataFree( char*, void* );
+static void pcacheFree( char*, void* );
static int obj_is_true( const jsonObject* obj );
static const char* json_type( int code );
static const char* get_primitive( osrfHash* field );
@@ -115,7 +119,7 @@
static void clear_query_stack( void );
static const jsonObject* verifyUserPCRUD( osrfMethodContext* );
-static int verifyObjectPCRUD( osrfMethodContext*, const jsonObject* );
+static int verifyObjectPCRUD( osrfMethodContext*, const jsonObject*, const int );
static const char* org_tree_root( osrfMethodContext* ctx );
static jsonObject* single_hash( const char* key, const char* value );
@@ -135,6 +139,7 @@
static int max_flesh_depth = 100;
+static int perm_at_threshold = 5;
static int enforce_pcrud = 0; // Boolean
static char* modulename = NULL;
@@ -505,13 +510,18 @@
that it will free whatever else needs freeing.
*/
static void sessionDataFree( char* key, void* item ) {
- if( !strcmp( key, "xact_id" )
- || !strcmp( key, "authkey" ) ) {
+ if( !strcmp( key, "xact_id" ) || !strcmp( key, "authkey" ) )
free( item );
- } else if( !strcmp( key, "user_login" ) )
+ else if( !strcmp( key, "user_login" ) )
jsonObjectFree( (jsonObject*) item );
+ else if( !strcmp( key, "pcache" ) )
+ osrfHashFree( (osrfHash*) item );
}
+static void pcacheFree( char* key, void* item ) {
+ osrfStringArrayFree( (osrfStringArray*) item );
+}
+
/**
@brief Save a transaction id.
@param ctx Pointer to the method context.
@@ -563,6 +573,59 @@
/*@}*/
/**
+ @brief Stash the location for a particular perm in the sessionData cache
+ @param ctx Pointer to the method context.
+ @param perm Name of the permission we're looking at
+ @param array StringArray of perm location ids
+*/
+static void setPermLocationCache( osrfMethodContext* ctx, const char* perm, osrfStringArray* locations ) {
+ if( ctx && ctx->session ) {
+ osrfAppSession* session = ctx->session;
+
+ osrfHash* cache = session->userData;
+
+ // If the session doesn't already have a hash, create one. Make sure
+ // that the application session frees the hash when it terminates.
+ if( NULL == cache ) {
+ session->userData = cache = osrfNewHash();
+ osrfHashSetCallback( cache, &sessionDataFree );
+ ctx->session->userDataFree = &userDataFree;
+ }
+
+ osrfHash* pcache = osrfHashGet(cache, "pcache");
+
+ if( NULL == pcache ) {
+ pcache = osrfNewHash();
+ osrfHashSetCallback( pcache, &pcacheFree );
+ osrfHashSet( cache, pcache, "pcache" );
+ }
+
+ if( perm && locations )
+ osrfHashSet( pcache, locations, strdup(perm) );
+ }
+}
+
+/**
+ @brief Grab stashed location for a particular perm in the sessionData cache
+ @param ctx Pointer to the method context.
+ @param perm Name of the permission we're looking at
+*/
+static osrfStringArray* getPermLocationCache( osrfMethodContext* ctx, const char* perm ) {
+ if( ctx && ctx->session ) {
+ osrfAppSession* session = ctx->session;
+ osrfHash* cache = session->userData;
+ if( cache ) {
+ osrfHash* pcache = osrfHashGet(cache, "pcache");
+ if( pcache ) {
+ return osrfHashGet( pcache, perm );
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
@brief Save the user's login in the userData for the current application session.
@param ctx Pointer to the method context.
@param user_login Pointer to the user login object to be cached (we cache the original,
@@ -1136,7 +1199,7 @@
jsonObject* cur = 0;
unsigned long res_idx = 0;
while((cur = jsonObjectGetIndex( obj, res_idx++ ) )) {
- if( enforce_pcrud && !verifyObjectPCRUD( ctx, cur ))
+ if( enforce_pcrud && !verifyObjectPCRUD( ctx, cur, obj->size ))
continue;
osrfAppRespond( ctx, cur );
}
@@ -1228,7 +1291,7 @@
jsonObject* cur;
unsigned long res_idx = 0;
while((cur = jsonObjectGetIndex( obj, res_idx++ ) )) {
- if( enforce_pcrud && !verifyObjectPCRUD( ctx, cur ))
+ if( enforce_pcrud && !verifyObjectPCRUD( ctx, cur, obj->size ))
continue; // Suppress due to lack of permission
else
osrfAppRespond( ctx,
@@ -1277,7 +1340,7 @@
}
if( enforce_pcrud )
- return verifyObjectPCRUD( ctx, param );
+ return verifyObjectPCRUD( ctx, param, 1 );
else
return 1;
}
@@ -1349,7 +1412,7 @@
The @a obj parameter points to a JSON_HASH of column values, keyed on column name.
*/
-static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj ) {
+static int verifyObjectPCRUD ( osrfMethodContext* ctx, const jsonObject* obj, const int rs_size ) {
dbhandle = writehandle;
@@ -1714,10 +1777,55 @@
// In other words permissions are additive.
int i = 0;
while( (perm = osrfStringArrayGetString(permission, i++)) ) {
+ dbi_result result;
+
+ osrfStringArray* pcache = NULL;
+ if (rs_size > perm_at_threshold) { // grab and cache locations of user perms
+ pcache = getPermLocationCache(ctx, perm);
+
+ if (!pcache) {
+ pcache = osrfNewStringArray(0);
+
+ result = dbi_conn_queryf(
+ writehandle,
+ "SELECT permission.usr_has_perm_at_all(%d, '%s') AS at;",
+ userid,
+ perm
+ );
+
+ if( result ) {
+ osrfLogDebug(
+ OSRF_LOG_MARK,
+ "Received a result for permission [%s] for user %d",
+ perm,
+ userid
+ );
+
+ if( dbi_result_first_row( result )) {
+ do {
+ jsonObject* return_val = oilsMakeJSONFromResult( result );
+ osrfStringArrayAdd( pcache, jsonObjectGetString( jsonObjectGetKeyConst( return_val, "at" ) ) );
+ jsonObjectFree( return_val );
+ } while( dbi_result_next_row( result ));
+
+ setPermLocationCache(ctx, perm, pcache);
+ }
+
+ dbi_result_free( result );
+ }
+ }
+ }
+
int j = 0;
while( (context_org = osrfStringArrayGetString( context_org_array, j++ )) ) {
- dbi_result result;
+ if (rs_size > perm_at_threshold) {
+ if (osrfStringArrayContains( pcache, context_org )) {
+ OK = 1;
+ break;
+ }
+ }
+
if( pkey_value ) {
osrfLogDebug(
OSRF_LOG_MARK,
@@ -1788,6 +1896,8 @@
}
}
+ if (rs_size > perm_at_threshold) break;
+
osrfLogDebug( OSRF_LOG_MARK,
"Checking non-object permission [%s] for user %d at org %d",
perm, userid, atoi(context_org) );
@@ -1828,6 +1938,7 @@
}
}
+
if( OK )
break;
}
@@ -2237,7 +2348,7 @@
jsonObjectFree( list );
if( enforce_pcrud ) {
- if(!verifyObjectPCRUD( ctx, obj )) {
+ if(!verifyObjectPCRUD( ctx, obj, 1 )) {
jsonObjectFree( obj );
growing_buffer* msg = buffer_init( 128 );
@@ -5975,7 +6086,7 @@
id = oilsFMGetString( jsonObjectGetIndex(ctx->params, _obj_pos), pkey );
} else {
- if( enforce_pcrud && !verifyObjectPCRUD( ctx, NULL )) {
+ if( enforce_pcrud && !verifyObjectPCRUD( ctx, NULL, 1 )) {
osrfAppRespondComplete( ctx, NULL );
return -1;
}
More information about the open-ils-commits
mailing list