veil_variables.c

Go to the documentation of this file.
00001 /**
00002  * @file   veil_variables.c
00003  * \code
00004  *     Author:       Marc Munro
00005  *     Copyright (c) 2005 - 2011 Marc Munro
00006  *     License:      BSD
00007  * \endcode
00008  * @brief  
00009  * Functions for dealing with Veil variables.
00010  *
00011  * Variables may be either session or shared, and are used to retain
00012  * state between function calls.  Shared variables are available to all
00013  * suitably privileged sessions within a database.  Session variables
00014  * hold values that are private to a single session.
00015  * 
00016  */
00017 
00018 #include "postgres.h"
00019 #include "veil_datatypes.h"
00020 #include "utils/hsearch.h"
00021 #include "storage/shmem.h"
00022 
00023 #include "veil_funcs.h"
00024 
00025 /**
00026  * Baselines the number of session variables that can be created in each
00027  * context.
00028  */
00029 #define SESSION_HASH_ELEMS    32
00030 
00031 /**
00032  * This identifies the hash table for all session variables.  The shared
00033  * variable hash tables are managed in veil_shmem.c.
00034  */
00035 
00036 static HTAB *session_hash = NULL;
00037 
00038 
00039 /** 
00040  * Create, or attach to, a hash for session variables.
00041  * 
00042  */
00043 static HTAB *
00044 create_session_hash()
00045 {
00046     HASHCTL hashctl;
00047 
00048     /* TODO: Think about creating a specific memory context for this. */
00049 
00050     hashctl.keysize = HASH_KEYLEN;
00051     hashctl.entrysize = sizeof(VarEntry);
00052 
00053     return hash_create("VEIL_SESSION", 
00054                        SESSION_HASH_ELEMS, &hashctl, HASH_ELEM);
00055 }
00056 
00057 /** 
00058  * Define a new, or attach to an existing, shared variable.  Raise an
00059  * ERROR if the variable already exists as a session variable or if we
00060  * cannot create the variable due to resource limitations (out of
00061  * memory, or out of space in the shared hash).
00062  * 
00063  * @param name The name of the variable.
00064  * 
00065  * @return Pointer to the shared variable.  If the variable is newly
00066  * created by this call then it will be unitialised (ie it will have a
00067  * NULL obj reference).
00068  */
00069 VarEntry *
00070 vl_lookup_shared_variable(char *name)
00071 {
00072     VarEntry *var;
00073     HTAB     *shared_hash = vl_get_shared_hash();
00074     bool      found;
00075 
00076     if (!session_hash) {
00077         session_hash = create_session_hash();
00078     }
00079 
00080     var = (VarEntry *) hash_search(session_hash, (void *) name,
00081                                    HASH_FIND, &found);
00082     if (found) {
00083         ereport(ERROR,
00084                 (errcode(ERRCODE_INTERNAL_ERROR),
00085                  errmsg("attempt to redefine session variable %s", name),
00086                  errdetail("You are trying to create shared variable %s "
00087                            "but it already exists as a session variable.",
00088                            name)));
00089     }
00090 
00091     var = (VarEntry *) hash_search(shared_hash, (void *) name,
00092                                    HASH_ENTER, &found);
00093 
00094     if (!var) {
00095         ereport(ERROR,
00096                 (errcode(ERRCODE_INTERNAL_ERROR),
00097                  errmsg("Out of memory for shared variables")));
00098     }
00099 
00100     if (!found) {
00101         /* Shared variable did not already exist so we must initialise
00102          * it. */
00103 
00104         var->obj = NULL;
00105         var->shared = true;
00106     }
00107 
00108     return var;
00109 }
00110 
00111 /** 
00112  * Lookup a variable by name, creating it as as a session variable if it
00113  * does not already exist.
00114  * 
00115  * @param name The name of the variable
00116  * 
00117  * @return Pointer to the shared or session variable.  If the variable
00118  * is newly created by this call then it will be unitialised (ie it will
00119  * have a NULL obj reference).
00120  */
00121 VarEntry *
00122 vl_lookup_variable(char *name)
00123 {
00124     VarEntry *var;
00125     HTAB     *shared_hash = vl_get_shared_hash();
00126     bool found;
00127 
00128     if (!session_hash) {
00129         session_hash = create_session_hash();
00130     }
00131 
00132     var = (VarEntry *)hash_search(session_hash, (void *) name,
00133                                   HASH_FIND, &found);
00134     if (!var) {
00135         /* See whether this is a shared variable. */
00136         var = (VarEntry *)hash_search(shared_hash, (void *) name,
00137                                       HASH_FIND, NULL);
00138     }
00139 
00140 
00141     if (!var) {
00142         /* Create new session variable */
00143         var = (VarEntry *) hash_search(session_hash, (void *) name,
00144                                        HASH_ENTER, &found);
00145         if (!var) {
00146             ereport(ERROR,
00147                     (errcode(ERRCODE_INTERNAL_ERROR),
00148                      errmsg("Out of memory for shared variables")));
00149         }
00150         var->obj = NULL;
00151         var->shared = false;
00152     }
00153     return var;
00154 }
00155 
00156 /** 
00157  * Return the next variable from a scan of the hash of variables.  Note
00158  * that this function is not re-entrant.
00159  * 
00160  * @param prev The last variable retrieved by a scan, or NULL if
00161  * starting a new scan.
00162  * 
00163  * @return The next variable encountered in the scan.  NULL if we have
00164  * finished.
00165  */
00166 veil_variable_t *
00167 vl_next_variable(veil_variable_t *prev)
00168 {
00169     static bool doing_shared;
00170     static HTAB *hash;
00171     static HASH_SEQ_STATUS status;
00172     static veil_variable_t result;
00173     VarEntry *var;
00174 
00175     if (!session_hash) {
00176         session_hash = create_session_hash();
00177     }
00178 
00179     if (!prev) {
00180         doing_shared = true;
00181         /* Initialise a scan of the shared hash. */
00182         hash = vl_get_shared_hash();
00183 
00184         hash_seq_init(&status, hash);
00185     }
00186 
00187     var = hash_seq_search(&status);
00188 
00189     if (!var) {
00190         /* No more entries from that hash. */
00191         if (doing_shared) {
00192             /* Switch to, and get var from, the session hash. */
00193             doing_shared = false;
00194             hash = session_hash;
00195             hash_seq_init(&status, hash);
00196             var = hash_seq_search(&status);
00197         }
00198     }
00199 
00200     if (var) {
00201         /* Yay, we have an entry. */
00202         result.name = var->key;
00203         result.shared = var->shared;
00204         if (var->obj) {
00205             result.type = vl_ObjTypeName(var->obj->type);
00206         }
00207         else {
00208             result.type = vl_ObjTypeName(OBJ_UNDEFINED);;
00209         }
00210         return &result;
00211     }
00212     else {
00213         /* Thats all.  There are no more entries */
00214         return NULL;
00215     }
00216 }
00217 
00218 /** 
00219  * Reset all Int4 entries in an ::Int4Array (to zero).
00220  * 
00221  * @param array The array to be reset.
00222  */
00223 void
00224 vl_ClearInt4Array(Int4Array *array)
00225 {
00226     int elems = 1 + array->arraymax - array->arrayzero;
00227     int i;
00228     for (i = 0; i < elems; i++) {
00229         array->array[i] = 0;
00230     }
00231 }
00232 
00233 /** 
00234  * Return a newly initialised (zeroed) ::Int4Array.  It may already
00235  * exist in which case it will be re-used if possible.  It may
00236  * be created in either session or shared memory depending on the value
00237  * of shared.
00238  * 
00239  * @param current Pointer to an existing Int4Array if one exists.
00240  * @param shared Whether to create the variable in shared or session
00241  * memory.
00242  * @param min Index of the first entry in the array.
00243  * @param max Index of the last entry in the array.
00244  */
00245 Int4Array *
00246 vl_NewInt4Array(Int4Array *current, bool shared,
00247                 int32 min, int32 max)
00248 {
00249     Int4Array *result = NULL;
00250     int        elems = 1 + max - min;
00251 
00252     if (current) {
00253         int cur_elems = 1 + current->arraymax - current->arrayzero;
00254         if (elems <= cur_elems) {
00255             vl_ClearInt4Array(current);
00256             result = current;
00257         }
00258         else {
00259             if (!shared) {
00260                 /* Note that we can't free shared memory - no api to do
00261                  * so. */
00262                 pfree(current);
00263             }
00264         }
00265     }
00266     if (!result) {
00267         if (shared) {
00268             result = vl_shmalloc(sizeof(Int4Array) + (sizeof(int32) * elems));
00269         }
00270         else {
00271             result = vl_malloc(sizeof(Int4Array) + (sizeof(int32) * elems));
00272         }
00273     }
00274     result->type = OBJ_INT4_ARRAY;
00275     result->arrayzero = min;
00276     result->arraymax = max;
00277 
00278     return result;
00279 }
00280 
00281 /** 
00282  * Set an entry within an ::Int4Array.  If idx is outside of the
00283  * acceptable range, raise an error.
00284  * 
00285  * @param array The ::Int4Array within which the entry is to be set. 
00286  * @param idx The index of the entry to be set.
00287  * @param value The value to which the entry will be set.
00288  */
00289 void
00290 vl_Int4ArraySet(Int4Array *array, int32 idx, int32 value)
00291 {
00292     if ((idx < array->arrayzero) ||
00293         (idx > array->arraymax))
00294     {
00295         ereport(ERROR,
00296                 (errcode(ERRCODE_INTERNAL_ERROR),
00297                  errmsg("Int4ArraySet range error"),
00298                  errdetail("Index (%d) not in range %d..%d.  ", idx,
00299                            array->arrayzero, array->arraymax)));
00300     }
00301     array->array[idx - array->arrayzero] = value;
00302 }
00303 
00304 /** 
00305  * Get an entry from an ::Int4Array.  If idx is outside of the
00306  * acceptable range, raise an error.
00307  * 
00308  * @param array The ::Int4Array within from the entry is to be read. 
00309  * @param idx The index of the entry to be retrieved.
00310 
00311  * @return The value of the entry
00312  */
00313 int32
00314 vl_Int4ArrayGet(Int4Array *array, int32 idx)
00315 {
00316     if ((idx < array->arrayzero) ||
00317         (idx > array->arraymax))
00318     {
00319         ereport(ERROR,
00320                 (errcode(ERRCODE_INTERNAL_ERROR),
00321                  errmsg("Int4ArrayGet range error"),
00322                  errdetail("Index (%d) not in range %d..%d.  ", idx,
00323                            array->arrayzero, array->arraymax)));
00324     }
00325     return array->array[idx - array->arrayzero];
00326 }
00327  

Generated on Mon Sep 12 15:26:45 2011 for Veil by  doxygen 1.5.6