Veil
veil_variables.c
Go to the documentation of this file.
1 /**
2  * @file veil_variables.c
3  * \code
4  * Author: Marc Munro
5  * Copyright (c) 2005 - 2011 Marc Munro
6  * License: BSD
7  * \endcode
8  * @brief
9  * Functions for dealing with Veil variables.
10  *
11  * Variables may be either session or shared, and are used to retain
12  * state between function calls. Shared variables are available to all
13  * suitably privileged sessions within a database. Session variables
14  * hold values that are private to a single session.
15  *
16  */
17 
18 #include "postgres.h"
19 #include "veil_datatypes.h"
20 #include "utils/hsearch.h"
21 #include "storage/shmem.h"
22 
23 #include "veil_funcs.h"
24 
25 /**
26  * Baselines the number of session variables that can be created in each
27  * context.
28  */
29 #define SESSION_HASH_ELEMS 32
30 
31 /**
32  * This identifies the hash table for all session variables. The shared
33  * variable hash tables are managed in veil_shmem.c.
34  */
35 
36 static HTAB *session_hash = NULL;
37 
38 
39 /**
40  * Create, or attach to, a hash for session variables.
41  *
42  */
43 static HTAB *
45 {
46  HASHCTL hashctl;
47 
48  /* TODO: Think about creating a specific memory context for this. */
49 
50  hashctl.keysize = HASH_KEYLEN;
51  hashctl.entrysize = sizeof(VarEntry);
52 
53  return hash_create("VEIL_SESSION",
54  SESSION_HASH_ELEMS, &hashctl, HASH_ELEM);
55 }
56 
57 /**
58  * Define a new, or attach to an existing, shared variable. Raise an
59  * ERROR if the variable already exists as a session variable or if we
60  * cannot create the variable due to resource limitations (out of
61  * memory, or out of space in the shared hash).
62  *
63  * @param name The name of the variable.
64  *
65  * @return Pointer to the shared variable. If the variable is newly
66  * created by this call then it will be unitialised (ie it will have a
67  * NULL obj reference).
68  */
69 VarEntry *
71 {
72  VarEntry *var;
73  HTAB *shared_hash = vl_get_shared_hash();
74  bool found;
75 
76  if (!session_hash) {
78  }
79 
80  var = (VarEntry *) hash_search(session_hash, (void *) name,
81  HASH_FIND, &found);
82  if (found) {
83  ereport(ERROR,
84  (errcode(ERRCODE_INTERNAL_ERROR),
85  errmsg("attempt to redefine session variable %s", name),
86  errdetail("You are trying to create shared variable %s "
87  "but it already exists as a session variable.",
88  name)));
89  }
90 
91  var = (VarEntry *) hash_search(shared_hash, (void *) name,
92  HASH_ENTER, &found);
93 
94  if (!var) {
95  ereport(ERROR,
96  (errcode(ERRCODE_INTERNAL_ERROR),
97  errmsg("Out of memory for shared variables")));
98  }
99 
100  if (!found) {
101  /* Shared variable did not already exist so we must initialise
102  * it. */
103 
104  var->obj = NULL;
105  var->shared = true;
106  }
107 
108  return var;
109 }
110 
111 /**
112  * Lookup a variable by name, creating it as as a session variable if it
113  * does not already exist.
114  *
115  * @param name The name of the variable
116  *
117  * @return Pointer to the shared or session variable. If the variable
118  * is newly created by this call then it will be unitialised (ie it will
119  * have a NULL obj reference).
120  */
121 VarEntry *
123 {
124  VarEntry *var;
125  HTAB *shared_hash = vl_get_shared_hash();
126  bool found;
127 
128  if (!session_hash) {
130  }
131 
132  var = (VarEntry *)hash_search(session_hash, (void *) name,
133  HASH_FIND, &found);
134  if (!var) {
135  /* See whether this is a shared variable. */
136  var = (VarEntry *)hash_search(shared_hash, (void *) name,
137  HASH_FIND, NULL);
138  }
139 
140 
141  if (!var) {
142  /* Create new session variable */
143  var = (VarEntry *) hash_search(session_hash, (void *) name,
144  HASH_ENTER, &found);
145  if (!var) {
146  ereport(ERROR,
147  (errcode(ERRCODE_INTERNAL_ERROR),
148  errmsg("Out of memory for shared variables")));
149  }
150  var->obj = NULL;
151  var->shared = false;
152  }
153  return var;
154 }
155 
156 /**
157  * Return the next variable from a scan of the hash of variables. Note
158  * that this function is not re-entrant.
159  *
160  * @param prev The last variable retrieved by a scan, or NULL if
161  * starting a new scan.
162  *
163  * @return The next variable encountered in the scan. NULL if we have
164  * finished.
165  */
168 {
169  static bool doing_shared;
170  static HTAB *hash;
171  static HASH_SEQ_STATUS status;
172  static veil_variable_t result;
173  VarEntry *var;
174 
175  if (!session_hash) {
177  }
178 
179  if (!prev) {
180  doing_shared = true;
181  /* Initialise a scan of the shared hash. */
182  hash = vl_get_shared_hash();
183 
184  hash_seq_init(&status, hash);
185  }
186 
187  var = hash_seq_search(&status);
188 
189  if (!var) {
190  /* No more entries from that hash. */
191  if (doing_shared) {
192  /* Switch to, and get var from, the session hash. */
193  doing_shared = false;
194  hash = session_hash;
195  hash_seq_init(&status, hash);
196  var = hash_seq_search(&status);
197  }
198  }
199 
200  if (var) {
201  /* Yay, we have an entry. */
202  result.name = var->key;
203  result.shared = var->shared;
204  if (var->obj) {
205  result.type = vl_ObjTypeName(var->obj->type);
206  }
207  else {
208  result.type = vl_ObjTypeName(OBJ_UNDEFINED);;
209  }
210  return &result;
211  }
212  else {
213  /* Thats all. There are no more entries */
214  return NULL;
215  }
216 }
217 
218 /**
219  * Reset all Int4 entries in an ::Int4Array (to zero).
220  *
221  * @param array The array to be reset.
222  */
223 void
225 {
226  int elems = 1 + array->arraymax - array->arrayzero;
227  int i;
228  for (i = 0; i < elems; i++) {
229  array->array[i] = 0;
230  }
231 }
232 
233 /**
234  * Return a newly initialised (zeroed) ::Int4Array. It may already
235  * exist in which case it will be re-used if possible. It may
236  * be created in either session or shared memory depending on the value
237  * of shared.
238  *
239  * @param current Pointer to an existing Int4Array if one exists.
240  * @param shared Whether to create the variable in shared or session
241  * memory.
242  * @param min Index of the first entry in the array.
243  * @param max Index of the last entry in the array.
244  */
245 Int4Array *
246 vl_NewInt4Array(Int4Array *current, bool shared,
247  int32 min, int32 max)
248 {
249  Int4Array *result = NULL;
250  int elems = 1 + max - min;
251 
252  if (current) {
253  int cur_elems = 1 + current->arraymax - current->arrayzero;
254  if (elems <= cur_elems) {
255  vl_ClearInt4Array(current);
256  result = current;
257  }
258  else {
259  if (!shared) {
260  /* Note that we can't free shared memory - no api to do
261  * so. */
262  pfree(current);
263  }
264  }
265  }
266  if (!result) {
267  if (shared) {
268  result = vl_shmalloc(sizeof(Int4Array) + (sizeof(int32) * elems));
269  }
270  else {
271  result = vl_malloc(sizeof(Int4Array) + (sizeof(int32) * elems));
272  }
273  }
274  result->type = OBJ_INT4_ARRAY;
275  result->arrayzero = min;
276  result->arraymax = max;
277 
278  return result;
279 }
280 
281 /**
282  * Set an entry within an ::Int4Array. If idx is outside of the
283  * acceptable range, raise an error.
284  *
285  * @param array The ::Int4Array within which the entry is to be set.
286  * @param idx The index of the entry to be set.
287  * @param value The value to which the entry will be set.
288  */
289 void
290 vl_Int4ArraySet(Int4Array *array, int32 idx, int32 value)
291 {
292  if ((idx < array->arrayzero) ||
293  (idx > array->arraymax))
294  {
295  ereport(ERROR,
296  (errcode(ERRCODE_INTERNAL_ERROR),
297  errmsg("Int4ArraySet range error"),
298  errdetail("Index (%d) not in range %d..%d. ", idx,
299  array->arrayzero, array->arraymax)));
300  }
301  array->array[idx - array->arrayzero] = value;
302 }
303 
304 /**
305  * Get an entry from an ::Int4Array. If idx is outside of the
306  * acceptable range, raise an error.
307  *
308  * @param array The ::Int4Array within from the entry is to be read.
309  * @param idx The index of the entry to be retrieved.
310 
311  * @return The value of the entry
312  */
313 int32
314 vl_Int4ArrayGet(Int4Array *array, int32 idx)
315 {
316  if ((idx < array->arrayzero) ||
317  (idx > array->arraymax))
318  {
319  ereport(ERROR,
320  (errcode(ERRCODE_INTERNAL_ERROR),
321  errmsg("Int4ArrayGet range error"),
322  errdetail("Index (%d) not in range %d..%d. ", idx,
323  array->arrayzero, array->arraymax)));
324  }
325  return array->array[idx - array->arrayzero];
326 }
327 
#define SESSION_HASH_ELEMS
Baselines the number of session variables that can be created in each context.
Subtype of Object for storing arrays of integers.
HTAB * vl_get_shared_hash(void)
Return the shared hash for the current context.
Definition: veil_shmem.c:552
Describes a veil shared or session variable.
bool shared
Whether this is a shared variable (as opposed to a session variable)
char * name
The name of the variable.
Int4Array * vl_NewInt4Array(Int4Array *current, bool shared, int32 min, int32 max)
Return a newly initialised (zeroed) Int4Array.
void vl_ClearInt4Array(Int4Array *array)
Reset all Int4 entries in an Int4Array (to zero).
ObjType type
This must have the value OBJ_INT4_ARRAY.
static HTAB * create_session_hash()
Create, or attach to, a hash for session variables.
#define HASH_KEYLEN
The key length for veil hash types.
int32 arrayzero
The index of array element zero: the index of the lowest numbered bitmap in the array.
Provide definitions for all non-local C-callable Veil functions.
bool shared
Whether this is a shared variable.
VarEntry * vl_lookup_shared_variable(char *name)
Define a new, or attach to an existing, shared variable.
char * type
The type of the variable (eg "Bitmap")
A Veil variable.
static HTAB * session_hash
This identifies the hash table for all session variables.
int32 vl_Int4ArrayGet(Int4Array *array, int32 idx)
Get an entry from an Int4Array.
void * vl_shmalloc(size_t size)
Dynamically allocate a piece of shared memory from the current context.
Definition: veil_shmem.c:414
void * vl_malloc(size_t size)
Dynamically allocate memory using palloc in TopMemoryContext.
Definition: veil_utils.c:28
ObjType type
Identifies the type of the object.
int32 arraymax
The index of the lowest numbered bitmap in the array.
Object * obj
Pointer to the contents of the variable.
VarEntry * vl_lookup_variable(char *name)
Lookup a variable by name, creating it as as a session variable if it does not already exist...
veil_variable_t * vl_next_variable(veil_variable_t *prev)
Return the next variable from a scan of the hash of variables.
int32 array[0]
Element zero of the array of integers.
struct VarEntry VarEntry
A Veil variable.
void vl_Int4ArraySet(Int4Array *array, int32 idx, int32 value)
Set an entry within an Int4Array.
char key[60]
String containing variable name.
char * vl_ObjTypeName(ObjType obj)
Return a static string describing an ObjType object.
Definition: veil_utils.c:45
Define all Veil public datatypes.