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