veil_serialise.c

Go to the documentation of this file.
00001 /**
00002  * @file   veil_serialise.c
00003  * \code
00004  *     Author:       Marc Munro
00005  *     Copyright (c) 2009 - 2010 Marc Munro
00006  *     License:      BSD
00007  * $Id: veil_serialise.c,v 1.3 2008/11/18 18:45:18 bloodnok Exp $
00008  * \endcode
00009  * @brief  
00010  * Functions serialising and de-serialising session variables.   The
00011  * purpose of this is to allow the contents of session variables to be
00012  * saved for later re-use.  They may be saved in files, temporary tables
00013  * or using some smart cache such as memcached (thru the pgmemcache
00014  * add-in).
00015  * 
00016  */
00017 
00018 //TODO: Provide a patch to postgres to make b64_encode and
00019 //      b64_decode extern functions and to elimiate the 
00020 //      redundant copies from pgcrypto
00021 
00022 #include "postgres.h"
00023 #include "veil_version.h"
00024 #include "veil_funcs.h"
00025 #include "veil_datatypes.h"
00026 
00027 
00028 #define INT4VAR_HDR       'V'
00029 #define RANGE_HDR         'R'
00030 #define BITMAP_HDR        'B'
00031 #define BITMAP_ARRAY_HDR  'A'
00032 #define BITMAP_HASH_HDR   'H'
00033 #define INT4_ARRAY_HDR    'I'
00034 #define BITMAP_HASH_MORE  '>'
00035 #define BITMAP_HASH_DONE  '.'
00036 
00037 
00038 // Length of 64-bit integer in base64;
00039 #define HDRLEN                 8   // HDR field plus int32 for length of item
00040 #define INT32SIZE_B64          7
00041 #define BOOLSIZE               1
00042 
00043 
00044 /* BEGIN SECTION OF CODE COPIED FROM pgcrypto.c */
00045 
00046 static const char _base64[] =
00047 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00048 
00049 static const int8 b64lookup[128] = {
00050     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00051     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00052     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
00053     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
00054     -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
00055     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
00056     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
00057     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
00058 };
00059 
00060 static unsigned
00061 b64_encode(const char *src, unsigned len, char *dst)
00062 {
00063     char       *p,
00064                *lend = dst + 76;
00065     const char *s,
00066                *end = src + len;
00067     int         pos = 2;
00068     uint32      buf = 0;
00069 
00070     s = src;
00071     p = dst;
00072 
00073     while (s < end)
00074     {
00075         buf |= (unsigned char) *s << (pos << 3);
00076         pos--;
00077         s++;
00078 
00079         /* write it out */
00080         if (pos < 0)
00081         {
00082             *p++ = _base64[(buf >> 18) & 0x3f];
00083             *p++ = _base64[(buf >> 12) & 0x3f];
00084             *p++ = _base64[(buf >> 6) & 0x3f];
00085             *p++ = _base64[buf & 0x3f];
00086 
00087             pos = 2;
00088             buf = 0;
00089         }
00090         if (p >= lend)
00091         {
00092             *p++ = '\n';
00093             lend = p + 76;
00094         }
00095     }
00096     if (pos != 2)
00097     {
00098         *p++ = _base64[(buf >> 18) & 0x3f];
00099         *p++ = _base64[(buf >> 12) & 0x3f];
00100         *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
00101         *p++ = '=';
00102     }
00103 
00104     return p - dst;
00105 }
00106 
00107 static unsigned
00108 b64_decode(const char *src, unsigned len, char *dst)
00109 {
00110     const char *srcend = src + len,
00111                *s = src;
00112     char       *p = dst;
00113     char        c;
00114     int         b = 0;
00115     uint32      buf = 0;
00116     int         pos = 0,
00117                 end = 0;
00118 
00119     while (s < srcend)
00120     {
00121         c = *s++;
00122 
00123         if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
00124             continue;
00125 
00126         if (c == '=')
00127         {
00128             /* end sequence */
00129             if (!end)
00130             {
00131                 if (pos == 2)
00132                     end = 1;
00133                 else if (pos == 3)
00134                     end = 2;
00135                 else
00136                     ereport(ERROR,
00137                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00138                              errmsg("unexpected \"=\"")));
00139             }
00140             b = 0;
00141         }
00142         else
00143         {
00144             b = -1;
00145             if (c > 0 && c < 127)
00146                 b = b64lookup[(unsigned char) c];
00147             if (b < 0)
00148                 ereport(ERROR,
00149                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00150                          errmsg("invalid symbol")));
00151         }
00152         /* add it to buffer */
00153         buf = (buf << 6) + b;
00154         pos++;
00155         if (pos == 4)
00156         {
00157             *p++ = (buf >> 16) & 255;
00158             if (end == 0 || end > 1)
00159                 *p++ = (buf >> 8) & 255;
00160             if (end == 0 || end > 2)
00161                 *p++ = buf & 255;
00162             buf = 0;
00163             pos = 0;
00164         }
00165     }
00166 
00167     if (pos != 0)
00168         ereport(ERROR,
00169                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00170                  errmsg("invalid end sequence")));
00171 
00172     return p - dst;
00173 }
00174 
00175 /* END SECTION OF CODE COPIED FROM pgcrypto.c */
00176 
00177 
00178 /** 
00179  * Return the length of a base64 encoded stream for a binary stream of
00180  * ::bytes length.
00181  * 
00182  * @param bytes The length of the input binary stream in bytes
00183  * @return The length of the base64 character stream required to
00184  * represent the input stream.
00185  */
00186 static int
00187 streamlen(int bytes)
00188 {
00189     return (4 * ((bytes + 2) / 3));
00190 }
00191 
00192 /** 
00193  * Return the length of the header part of a serialised data stream for
00194  * the given named variable.  Note that the header contains the name and
00195  * a base64 encode length indicator for the name.
00196  * 
00197  * @param name The variable name to be recorded in the header
00198  * @return The length of the base64 character stream required to
00199  * hold the serialised header for the named variable.
00200  */
00201 static int
00202 hdrlen(char *name)
00203 {
00204     return HDRLEN + INT32SIZE_B64 + strlen(name);
00205 }
00206 
00207 
00208 /** 
00209  * Serialise an int4 value as a base64 stream (truncated to save a
00210  * byte) into *p_stream.
00211  *
00212  * @param p_stream Pointer into stream currently being written.  This
00213  * must be large enought to take the contents to be written.  This
00214  * pointer is updated to point to the next free slot in the stream after
00215  * writing the int4 value, and is null terminated at that position.
00216  * @param value The value to be written to the stream.
00217  */
00218 static void
00219 serialise_int4(char **p_stream, int4 value)
00220 {
00221     int len = b64_encode((char *) &value, sizeof(int32), *p_stream);
00222     //elog(NOTICE, "Serialising %d\n", value);
00223     (*p_stream) += (len - 1);  // X: dumb optimisation saves a byte
00224     (**p_stream) = '\0';
00225 }
00226 
00227 
00228 /** 
00229  * De-serialise an int4 value from a base64 character stream.
00230  *
00231  * @param p_stream Pointer into the stream currently being read.
00232  * must be large enought to take the contents to be written.  This
00233  * pointer is updated to point to the next free slot in the stream after
00234  * reading the int4 value.
00235  * @return the int4 value read from the stream
00236  */
00237 static int4
00238 deserialise_int4(char **p_stream)
00239 {
00240     int4 value;
00241     char *endpos = (*p_stream) + INT32SIZE_B64;
00242     char endchar = *endpos;
00243     *endpos = '=';  // deal with dumb optimisation (X) above
00244     b64_decode(*p_stream, INT32SIZE_B64 + 1, (char *) &value);
00245     *endpos = endchar;
00246     //elog(NOTICE, "De-serialising %d from %s\n", value, *p_stream);
00247     (*p_stream) += INT32SIZE_B64;
00248     return value;
00249 }
00250 
00251 /** 
00252  * Serialise a binary stream as a base64 stream into *p_stream.
00253  *
00254  * @param p_stream Pointer into stream currently being written.  This
00255  * pointer is updated to point to the next free slot in the stream after
00256  * writing the contents of instream and is null terminated at that
00257  * position.
00258  * @param bytes The number of bytes to be written.
00259  * @param instream The binary stream to be written.
00260  */
00261 static void
00262 serialise_stream(char **p_stream, int4 bytes, char *instream)
00263 {
00264     int len = b64_encode(instream, bytes, *p_stream);
00265     (*p_stream)[len] = '\0';
00266     //elog(NOTICE, "Serialising %d bytes into %s\n", bytes, *p_stream);
00267     (*p_stream) += len;
00268 }
00269 
00270 /** 
00271  * De-serialise a binary stream.
00272  *
00273  * @param p_stream Pointer into the stream currently being read.
00274  * pointer is updated to point to the next free slot in the stream after
00275  * reading the stream.
00276  * @param bytes The number of bytes to be read
00277  * @param outstream Pointer into the pre-allocated memory are into which
00278  * the binary from p_stream is to be written.
00279  */
00280 static void
00281 deserialise_stream(char **p_stream, int4 bytes, char *outstream)
00282 {
00283     int4 len = streamlen(bytes);
00284     //elog(NOTICE, "De-serialising %d bytes from %s\n", bytes, *p_stream);
00285     b64_decode(*p_stream, len, outstream);
00286     (*p_stream) += len;
00287     //elog(NOTICE, "Stream is now: %s\n", *p_stream);
00288 }
00289 
00290 
00291 /** 
00292  * Serialise a boolean value into *p_stream.
00293  *
00294  * @param p_stream Pointer into stream currently being written.  This
00295  * pointer is updated to point to the next free slot in the stream after
00296  * writing the contents of value and is null terminated at that
00297  * position.  A true value is written as 'T', and false as 'F'.
00298  * @param value The boolean value to be written.
00299  */
00300 static void
00301 serialise_bool(char **p_stream, bool value)
00302 {
00303     (**p_stream) = value? 'T': 'F';
00304     (*p_stream)++;
00305     (**p_stream) = '\0';
00306 }
00307 
00308 /** 
00309  * De-serialise a boolean value.
00310  *
00311  * @param p_stream Pointer into the stream currently being read.
00312  * pointer is updated to point to the next free slot in the stream after
00313  * reading the stream.
00314  * @return True or false depending on the contents of p_stream.
00315  */
00316 static bool
00317 deserialise_bool(char **p_stream)
00318 {
00319     bool result = (**p_stream) == 'T';
00320     (*p_stream)++;
00321 
00322     return result;
00323 }
00324 
00325 /** 
00326  * Serialise a character value into *p_stream.
00327  *
00328  * @param p_stream Pointer into stream currently being written.  This
00329  * pointer is updated to point to the next free slot in the stream after
00330  * writing the contents of value and is null terminated at that
00331  * position.  The character is written as a single byte character.
00332  * @param value The character value to be written.
00333  */
00334 static void
00335 serialise_char(char **p_stream, char value)
00336 {
00337     (**p_stream) = value;
00338     (*p_stream)++;
00339     (**p_stream) = '\0';
00340 }
00341 
00342 /** 
00343  * De-serialise a character value.
00344  *
00345  * @param p_stream Pointer into the stream currently being read.
00346  * pointer is updated to point to the next free slot in the stream after
00347  * reading the stream.
00348  * @return The value of the character read from p_stream.
00349  */
00350 static char
00351 deserialise_char (char **p_stream)
00352 {
00353     char result = **p_stream;
00354     (*p_stream)++;
00355 
00356     return result;
00357 }
00358 
00359 /** 
00360  * Serialise a string (containing a name) into *p_stream.
00361  *
00362  * @param p_stream Pointer into stream currently being written.  This
00363  * pointer is updated to point to the next free slot in the stream after
00364  * writing the contents of value and is null terminated at that
00365  * position.  The character is written as a single byte character.
00366  * @param name The string to be written.
00367  */
00368 static void
00369 serialise_name(char **p_stream, char *name)
00370 {
00371     static char *blank_name = "";
00372     char *safe_name;
00373     if (name) {
00374         safe_name = name;
00375     }
00376     else {
00377         safe_name = blank_name;
00378     }
00379         
00380     serialise_int4(p_stream, strlen(safe_name));
00381     strcpy((*p_stream), safe_name);
00382     (*p_stream) += strlen(safe_name);
00383     (**p_stream) = '\0';
00384 }
00385 
00386 /** 
00387  * De-serialise a string returning a dynamically allocated string.
00388  *
00389  * @param p_stream Pointer into the stream currently being read.
00390  * pointer is updated to point to the next free slot in the stream after
00391  * reading the stream.
00392  * @return Dynamically allocated copy of string read from *p_stream
00393  */
00394 static char *
00395 deserialise_name(char **p_stream)
00396 {
00397     int32 name_len = deserialise_int4(p_stream);
00398     char *result = palloc((name_len + 1) * sizeof(char));
00399     strncpy(result, *p_stream, name_len);
00400     result[name_len] = '\0';
00401     //elog(NOTICE, "De-serialising name %s from %s\n", result, *p_stream);
00402     (*p_stream) += name_len;
00403     return result;
00404 }
00405 
00406 /** 
00407  * Serialise a veil integer variable into a dynamically allocated string.
00408  *
00409  * @param var Pointer to the variable to be serialised
00410  * @param name The name of the variable
00411  * @return Dynamically allocated string containing the serialised
00412  * variable
00413  */
00414 static char *
00415 serialise_int4var(Int4Var *var, char *name)
00416 {
00417     int stream_len = hdrlen(name) + BOOLSIZE + INT32SIZE_B64 + 1;
00418     char *stream = palloc(stream_len * sizeof(char));
00419     char *streamstart = stream;
00420     
00421     serialise_char(&stream, INT4VAR_HDR);
00422     serialise_name(&stream, name);
00423     serialise_bool(&stream, var->isnull);
00424     serialise_int4(&stream, var->value);
00425     return streamstart;
00426 }
00427 
00428 /** 
00429  * De-serialise a veil integer variable.
00430  *
00431  * @param **p_stream Pointer into the stream currently being read.
00432  * pointer is updated to point to the next free slot in the stream after
00433  * reading the stream
00434  * @return Pointer to the variable created or updated from the stream.
00435  */
00436 static VarEntry *
00437 deserialise_int4var(char **p_stream)
00438 {
00439     char *name = deserialise_name(p_stream);
00440     VarEntry *var = vl_lookup_variable(name);
00441     Int4Var *i4v = (Int4Var *) var->obj;
00442 
00443     if (i4v) {
00444         if (i4v->type != OBJ_INT4) {
00445             vl_type_mismatch(name, OBJ_INT4, i4v->type);
00446         }
00447     }
00448     else {
00449         var->obj = (Object *) vl_NewInt4(var->shared);
00450         i4v = (Int4Var *) var->obj;
00451     }
00452     i4v->isnull = deserialise_bool(p_stream);
00453     i4v->value = deserialise_int4(p_stream);
00454     return var;
00455 }
00456 
00457 /** 
00458  * Serialise a veil integer array variable into a dynamically allocated
00459  * string.
00460  *
00461  * @param array Pointer to the variable to be serialised
00462  * @param name The name of the variable
00463  * @return Dynamically allocated string containing the serialised
00464  * variable
00465  */
00466 static char *
00467 serialise_int4array(Int4Array *array, char *name)
00468 {
00469     int elems = 1 + array->arraymax - array->arrayzero;
00470     int stream_len = hdrlen(name) + (2 * INT32SIZE_B64) +
00471         streamlen(elems * sizeof(int32)) + 1;
00472     char *stream = palloc(stream_len * sizeof(char));
00473     char *streamstart = stream;
00474 
00475     serialise_char(&stream, INT4_ARRAY_HDR);
00476     serialise_name(&stream, name);
00477     serialise_int4(&stream, array->arrayzero);
00478     serialise_int4(&stream, array->arraymax);
00479     serialise_stream(&stream, elems * sizeof(int32), 
00480                      (char *) &(array->array[0]));
00481 
00482     return streamstart;
00483 }
00484 
00485 /** 
00486  * De-serialise a veil integer array variable.
00487  *
00488  * @param **p_stream Pointer into the stream currently being read.
00489  * pointer is updated to point to the next free slot in the stream after
00490  * reading the stream
00491  * @return Pointer to the variable created or updated from the stream.
00492  */
00493 static VarEntry *
00494 deserialise_int4array(char **p_stream)
00495 {
00496     char *name = deserialise_name(p_stream);
00497     int4 arrayzero;
00498     int4 arraymax;
00499     int4 elems;
00500     VarEntry *var = vl_lookup_variable(name);
00501     Int4Array *array = (Int4Array *) var->obj;
00502 
00503     //elog(NOTICE, "Stream is %s\n", *p_stream);
00504     arrayzero = deserialise_int4(p_stream);
00505     arraymax = deserialise_int4(p_stream);
00506     elems = 1 + arraymax - arrayzero;
00507 
00508     if (array) {
00509         if (array->type != OBJ_INT4_ARRAY) {
00510             vl_type_mismatch(name, OBJ_INT4_ARRAY, array->type);
00511         }
00512     }
00513     array = vl_NewInt4Array(array, var->shared, arrayzero, arraymax);
00514     var->obj = (Object *) array;
00515 
00516     deserialise_stream(p_stream, elems * sizeof(int4), 
00517                        (char *) &(array->array[0]));
00518     return var;
00519 }
00520 
00521 /** 
00522  * Serialise a veil range variable into a dynamically allocated
00523  * string.
00524  *
00525  * @param range Pointer to the variable to be serialised
00526  * @param name The name of the variable
00527  * @return Dynamically allocated string containing the serialised
00528  * variable
00529  */
00530 static char *
00531 serialise_range(Range *range, char *name)
00532 {
00533     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 1;
00534     char *stream = palloc(stream_len * sizeof(char));
00535     char *streamstart = stream;
00536 
00537     serialise_char(&stream, RANGE_HDR);
00538     serialise_name(&stream, name);
00539     serialise_int4(&stream, range->min);
00540     serialise_int4(&stream, range->max);
00541     return streamstart;
00542 }
00543 
00544 /** 
00545  * De-serialise a veil range variable.
00546  *
00547  * @param **p_stream Pointer into the stream currently being read.
00548  * pointer is updated to point to the next free slot in the stream after
00549  * reading the stream
00550  * @return Pointer to the variable created or updated from the stream.
00551  */
00552 static VarEntry *
00553 deserialise_range(char **p_stream)
00554 {
00555     char *name = deserialise_name(p_stream);
00556     VarEntry *var = vl_lookup_variable(name);
00557     Range *range = (Range *) var->obj;
00558 
00559     if (range) {
00560         if (range->type != OBJ_RANGE) {
00561             vl_type_mismatch(name, OBJ_RANGE, range->type);
00562         }
00563     }
00564     else {
00565         var->obj = (Object *) vl_NewRange(var->shared);
00566         range = (Range *) var->obj;
00567     }
00568 
00569     range->min = deserialise_int4(p_stream);
00570     range->max = deserialise_int4(p_stream);
00571     return var;
00572 }
00573 
00574 /** 
00575  * Serialise a single bitmap from a veil bitmap array or bitmap hash.
00576  *
00577  * @param p_stream Pointer into the stream currently being read.
00578  * pointer is updated to point to the next free slot in the stream after
00579  * writing the stream.
00580  * @param bitmap The bitmap to be serialised.
00581  */
00582 static void
00583 serialise_one_bitmap(char **p_stream, Bitmap *bitmap)
00584 {
00585     int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
00586     serialise_int4(p_stream, bitmap->bitzero);
00587     serialise_int4(p_stream, bitmap->bitmax);
00588     serialise_stream(p_stream, elems * sizeof(int32), 
00589                      (char *) &(bitmap->bitset));
00590 }
00591 
00592 /** 
00593  * Serialise a veil bitmap variable into a dynamically allocated
00594  * string.
00595  *
00596  * @param bitmap Pointer to the variable to be serialised
00597  * @param name The name of the variable
00598  * @return Dynamically allocated string containing the serialised
00599  * variable
00600  */
00601 static char *
00602 serialise_bitmap(Bitmap *bitmap, char *name)
00603 {
00604     int elems = ARRAYELEMS(bitmap->bitzero, bitmap->bitmax);
00605     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 
00606                      streamlen(sizeof(int32) * elems) + 1;
00607     char *stream = palloc(stream_len * sizeof(char));
00608     char *streamstart = stream;
00609 
00610     serialise_char(&stream, BITMAP_HDR);
00611     serialise_name(&stream, name);
00612     serialise_one_bitmap(&stream, bitmap);
00613     return streamstart;
00614 }
00615 
00616 /** 
00617  * De-serialise a single bitmap into a veil bitmap array or bitmap hash.
00618  *
00619  * @param p_bitmap Pointer to bitmap pointer.  This may be updated to
00620  * contain a dynamically allocated bitmap if none is already present.
00621  * @param name, the name of the variable, for error reporting purposes.
00622  * @param shared Whether the bitmap is part of a shared rather than
00623  * session variable.
00624  * @param **p_stream Pointer into the stream currently being read.
00625  * pointer is updated to point to the next free slot in the stream after
00626  * reading the stream.
00627  */
00628 static void
00629 deserialise_one_bitmap(Bitmap **p_bitmap, char *name, 
00630                        bool shared, char **p_stream)
00631 {
00632     Bitmap *bitmap = *p_bitmap;
00633     int4 bitzero;
00634     int4 bitmax;
00635     int4 elems;
00636 
00637     bitzero = deserialise_int4(p_stream);
00638     bitmax = deserialise_int4(p_stream);
00639     elems = ARRAYELEMS(bitzero, bitmax);
00640 
00641     if (bitmap) {
00642         if (bitmap->type != OBJ_BITMAP) {
00643             vl_type_mismatch(name, OBJ_BITMAP, bitmap->type);
00644         }
00645     }
00646     // Check size and re-allocate memory if needed
00647     vl_NewBitmap(p_bitmap, shared, bitzero, bitmax);
00648     bitmap = *p_bitmap;
00649 
00650     deserialise_stream(p_stream, elems * sizeof(bitmap->bitset[0]), 
00651                        (char *) &(bitmap->bitset[0]));
00652 
00653 }
00654 
00655 /** 
00656  * De-serialise a veil bitmap variable.
00657  *
00658  * @param **p_stream Pointer into the stream currently being read.
00659  * pointer is updated to point to the next free slot in the stream after
00660  * reading the stream
00661  * @return Pointer to the variable created or updated from the stream.
00662  */
00663 static VarEntry *
00664 deserialise_bitmap(char **p_stream)
00665 {
00666     char *name = deserialise_name(p_stream);
00667     VarEntry *var = vl_lookup_variable(name);
00668     Bitmap *bitmap = (Bitmap *) var->obj;
00669 
00670     deserialise_one_bitmap(&bitmap, name, var->shared, p_stream);
00671     var->obj = (Object *) bitmap;
00672     return var;
00673 }
00674 
00675 /** 
00676  * Serialise a veil bitmap array variable into a dynamically allocated
00677  * string.
00678  *
00679  * @param bmarray Pointer to the variable to be serialised
00680  * @param name The name of the variable
00681  * @return Dynamically allocated string containing the serialised
00682  * variable
00683  */
00684 static char *
00685 serialise_bitmap_array(BitmapArray *bmarray, char *name)
00686 {
00687     int bitset_elems = ARRAYELEMS(bmarray->bitzero, bmarray->bitmax);
00688     int array_elems = 1 + bmarray->arraymax - bmarray->arrayzero;
00689     int bitmap_len = (INT32SIZE_B64 * 2) + 
00690                      streamlen(sizeof(int32) * bitset_elems);
00691     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 4) + 
00692                      (bitmap_len * array_elems) + 1;
00693     int idx;
00694     char *stream = palloc(stream_len * sizeof(char));
00695     char *streamstart = stream;
00696 
00697     serialise_char(&stream, BITMAP_ARRAY_HDR);
00698     serialise_name(&stream, name);
00699     serialise_int4(&stream, bmarray->bitzero);
00700     serialise_int4(&stream, bmarray->bitmax);
00701     serialise_int4(&stream, bmarray->arrayzero);
00702     serialise_int4(&stream, bmarray->arraymax);
00703     for (idx = 0; idx < array_elems; idx++) {
00704         serialise_one_bitmap(&stream, bmarray->bitmap[idx]);
00705         //elog(NOTICE, "Serialised next bitmap into %s\n", streamstart);
00706     }
00707     return streamstart;
00708 }
00709 
00710 /** 
00711  * De-serialise a veil bitmap array variable.
00712  *
00713  * @param **p_stream Pointer into the stream currently being read.
00714  * pointer is updated to point to the next free slot in the stream after
00715  * reading the stream
00716  * @return Pointer to the variable created or updated from the stream.
00717  */
00718 static VarEntry *
00719 deserialise_bitmap_array(char **p_stream)
00720 {
00721     char *name = deserialise_name(p_stream);
00722     int4 bitzero;
00723     int4 bitmax;
00724     int4 arrayzero;
00725     int4 arraymax;
00726     int4 array_elems;
00727     int4 idx;
00728     VarEntry *var = vl_lookup_variable(name);
00729     BitmapArray *bmarray = (BitmapArray *) var->obj;
00730 
00731     bitzero = deserialise_int4(p_stream);
00732     bitmax = deserialise_int4(p_stream);
00733     arrayzero = deserialise_int4(p_stream);
00734     arraymax = deserialise_int4(p_stream);
00735 
00736     if (bmarray) {
00737         if (bmarray->type != OBJ_BITMAP_ARRAY) {
00738             vl_type_mismatch(name, OBJ_BITMAP_ARRAY, bmarray->type);
00739         }
00740     }
00741     // Check size and re-allocate memory if needed
00742     vl_NewBitmapArray(&bmarray, var->shared, arrayzero, 
00743                       arraymax, bitzero, bitmax);
00744     var->obj = (Object *) bmarray;
00745 
00746     array_elems = 1 + arraymax - arrayzero;
00747     for (idx = 0; idx < array_elems; idx++) {
00748         //elog(NOTICE, "Deserialising next bitmap from %s\n", *p_stream);
00749         deserialise_one_bitmap(&(bmarray->bitmap[idx]), "", 
00750                                var->shared, p_stream);
00751         
00752     }
00753     return var;
00754 }
00755 
00756 
00757 /** 
00758  * Calculate the size needed for a base64 stream to contain all of the
00759  * bitmaps in a bitmap hash including their keys.
00760  *
00761  * @param bmhash Pointer to the variable to be serialised
00762  * @param bitset_size The size, in bytes, of each bitset in the bitmap
00763  * hash.
00764  * @return Number of bytes required to contain all of the bitmaps and
00765  * keys in the bitmap_hash
00766  */
00767 static int
00768 sizeof_bitmaps_in_hash(BitmapHash *bmhash, int bitset_size)
00769 {
00770     VarEntry *var = NULL;
00771     int size = 1;  // Allow for final end of stream indicator
00772     while (var = vl_NextHashEntry(bmhash->hash, var)) {
00773         // 1 byte below for record/end flag to precede each bitmap in
00774         // the hash
00775         //elog(NOTICE, "COUNTING");
00776         size += 1 + bitset_size + hdrlen(var->key); 
00777     }
00778     return size;
00779 }
00780 
00781 
00782 /** 
00783  * Serialise a veil bitmap hash variable into a dynamically allocated
00784  * string.
00785  *
00786  * @param bmhash Pointer to the variable to be serialised
00787  * @param name The name of the variable
00788  * @return Dynamically allocated string containing the serialised
00789  * variable
00790  */
00791 static char *
00792 serialise_bitmap_hash(BitmapHash *bmhash, char *name)
00793 {
00794     int bitset_elems = ARRAYELEMS(bmhash->bitzero, bmhash->bitmax);
00795     int bitset_size = (INT32SIZE_B64 * 2) + 
00796                       streamlen(sizeof(int32) * bitset_elems);
00797     int all_bitmaps_size = sizeof_bitmaps_in_hash(bmhash, bitset_size);
00798     int stream_len = hdrlen(name) + (INT32SIZE_B64 * 2) + 
00799                      all_bitmaps_size + 1;
00800     char *stream = palloc(stream_len * sizeof(char));
00801     char *streamstart = stream;
00802     VarEntry *var = NULL;
00803 
00804     serialise_char(&stream, BITMAP_HASH_HDR);
00805     serialise_name(&stream, name);
00806     serialise_int4(&stream, bmhash->bitzero);
00807     serialise_int4(&stream, bmhash->bitmax);
00808     //elog(NOTICE, "ABOUT TO SERIALISE THE BITMAPS...");
00809     while (var = vl_NextHashEntry(bmhash->hash, var)) {
00810         serialise_char(&stream, BITMAP_HASH_MORE);
00811         serialise_name(&stream, var->key);
00812         serialise_one_bitmap(&stream, (Bitmap *) var->obj);
00813         //elog(NOTICE, "Serialised next bitmap into %s\n", streamstart);
00814     }
00815     serialise_char(&stream, BITMAP_HASH_DONE);
00816 
00817     return streamstart;
00818 }
00819 
00820 /** 
00821  * De-serialise a veil bitmap hash variable.
00822  *
00823  * @param **p_stream Pointer into the stream currently being read.
00824  * pointer is updated to point to the next free slot in the stream after
00825  * reading the stream
00826  * @return Pointer to the variable created or updated from the stream.
00827  */
00828 static VarEntry *
00829 deserialise_bitmap_hash(char **p_stream)
00830 {
00831     char *name = deserialise_name(p_stream);
00832     char *hashkey;
00833     int4 bitzero;
00834     int4 bitmax;
00835     int4 idx;
00836     VarEntry *var = vl_lookup_variable(name);
00837     BitmapHash *bmhash = (BitmapHash *) var->obj;
00838     Bitmap *tmp_bitmap = NULL;
00839     Bitmap *bitmap;
00840 
00841     bitzero = deserialise_int4(p_stream);
00842     bitmax = deserialise_int4(p_stream);
00843 
00844     if (bmhash) {
00845         if (bmhash->type != OBJ_BITMAP_HASH) {
00846             vl_type_mismatch(name, OBJ_BITMAP_HASH, bmhash->type);
00847         }
00848     }
00849     // Check size and re-allocate memory if needed
00850     vl_NewBitmapHash(&bmhash, name, bitzero, bitmax);
00851     var->obj = (Object *) bmhash;
00852 
00853     while (deserialise_char(p_stream) == BITMAP_HASH_MORE) {
00854         hashkey = deserialise_name(p_stream);
00855         deserialise_one_bitmap(&tmp_bitmap, "", var->shared, p_stream);
00856         // tmp_bitmap now contains a (dynamically allocated) bitmap
00857         // Now we want to copy that into the bmhash.  We don't worry
00858         // about memory leaks here since this is allocated only once
00859         // per call of this function, and the memory context will
00860         // eventually be freed anyway.
00861         bitmap = vl_AddBitmapToHash(bmhash, hashkey);
00862         vl_BitmapUnion(bitmap, tmp_bitmap);
00863     }
00864     return var;
00865 }
00866 
00867 /** 
00868  * Serialise a veil variable
00869  *
00870  * @param name  The name of the variable to be serialised.
00871  * @return Dynamically allocated string containing the serialised value.
00872  */
00873 extern char *
00874 vl_serialise_var(char *name)
00875 {
00876     VarEntry *var;
00877     char *result = NULL;
00878 
00879     var = vl_lookup_variable(name);
00880     if (var && var->obj) {
00881         switch (var->obj->type) {
00882             case OBJ_INT4:
00883                 result = serialise_int4var((Int4Var *)var->obj, name);
00884                 break;
00885             case OBJ_INT4_ARRAY:
00886                 result = serialise_int4array((Int4Array *)var->obj, name);
00887                 break;
00888             case OBJ_RANGE:
00889                 result = serialise_range((Range *)var->obj, name);
00890                 break;
00891             case OBJ_BITMAP:
00892                 result = serialise_bitmap((Bitmap *)var->obj, name);
00893                 break;
00894             case OBJ_BITMAP_ARRAY:
00895                 result = serialise_bitmap_array((BitmapArray *)var->obj, name);
00896                 break;
00897             case OBJ_BITMAP_HASH:
00898                 result = serialise_bitmap_hash((BitmapHash *)var->obj, name);
00899                 break;
00900             default:
00901                 ereport(ERROR,
00902                         (errcode(ERRCODE_INTERNAL_ERROR),
00903                          errmsg("Unsupported type for variable serialisation"),
00904                          errdetail("Cannot serialise objects of type %d.", 
00905                                    (int4) var->obj->type)));
00906                 
00907         }
00908     }
00909     return result;
00910 }
00911 
00912 /** 
00913  * De-serialise the next veil variable from *p_stream
00914  *
00915  * @param **p_stream Pointer into the stream currently being read.
00916  * pointer is updated to point to the next free slot in the stream after
00917  * reading the stream
00918  * @return The deserialised variable.
00919  */
00920 extern VarEntry *
00921 vl_deserialise_next(char **p_stream)
00922 {
00923     VarEntry *var;
00924     if ((**p_stream) != '\0') {
00925         char type = deserialise_char(p_stream);
00926         switch (type){
00927             case INT4VAR_HDR: var = deserialise_int4var(p_stream);
00928                 break;
00929             case INT4_ARRAY_HDR: var = deserialise_int4array(p_stream);
00930                 break;
00931             case RANGE_HDR: var = deserialise_range(p_stream);
00932                 break;
00933             case BITMAP_HDR: var = deserialise_bitmap(p_stream);
00934                 break;
00935             case BITMAP_ARRAY_HDR: var = deserialise_bitmap_array(p_stream);
00936                 break;
00937             case BITMAP_HASH_HDR: var = deserialise_bitmap_hash(p_stream);
00938                 break;
00939             default:
00940                 ereport(ERROR,
00941                     (errcode(ERRCODE_INTERNAL_ERROR),
00942                      errmsg("Unsupported type for variable deserialisation"),
00943                      errdetail("Cannot deserialise objects of type %c.", 
00944                                type)));
00945                 
00946         }
00947     }
00948     return var;
00949 }
00950 
00951 /** 
00952  * De-serialise a base64 string containing, possibly many, derialised
00953  * veil variables.
00954  *
00955  * @param **p_stream Pointer into the stream currently being read.
00956  * @return A count of the number of variables that have been de-serialised.
00957  */
00958 extern int4
00959 vl_deserialise(char **p_stream)
00960 {
00961     int count = 0;
00962     while ((**p_stream) != '\0') {
00963         (void) vl_deserialise_next(p_stream);
00964         count++;
00965     }
00966     return count;
00967 }

Generated on Fri Mar 12 08:38:37 2010 for Veil by  doxygen 1.5.6