github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/database/vedis/vedis.c (about)

     1  /*
     2   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
     3   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
     4   * Version 1.2.6
     5   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
     6   * please contact Symisc Systems via:
     7   *       legal@symisc.net
     8   *       licensing@symisc.net
     9   *       contact@symisc.net
    10   * or visit:
    11   *      http://vedis.symisc.net/
    12   */
    13  /*
    14   * Copyright (C) 2013 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine <chm@symisc.net>].
    15   * All rights reserved.
    16   *
    17   * Redistribution and use in source and binary forms, with or without
    18   * modification, are permitted provided that the following conditions
    19   * are met:
    20   * 1. Redistributions of source code must retain the above copyright
    21   *    notice, this list of conditions and the following disclaimer.
    22   * 2. Redistributions in binary form must reproduce the above copyright
    23   *    notice, this list of conditions and the following disclaimer in the
    24   *    documentation and/or other materials provided with the distribution.
    25   * 3. Redistributions in any form must be accompanied by information on
    26   *    how to obtain complete source code for the Vedis engine and any 
    27   *    accompanying software that uses the Vedis engine software.
    28   *    The source code must either be included in the distribution
    29   *    or be available for no more than the cost of distribution plus
    30   *    a nominal fee, and must be freely redistributable under reasonable
    31   *    conditions. For an executable file, complete source code means
    32   *    the source code for all modules it contains.It does not include
    33   *    source code for modules or files that typically accompany the major
    34   *    components of the operating system on which the executable file runs.
    35   *
    36   * THIS SOFTWARE IS PROVIDED BY SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS
    37   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    38   * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
    39   * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SYMISC SYSTEMS
    40   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    41   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    42   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    43   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    44   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    45   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
    46   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    47   */
    48  /*
    49   * $SymiscID: vedis.c v1.2.6 Unix|Win32/64 2013-09-15 23:42:22 stable <chm@symisc.net> $ 
    50   */
    51  /* This file is an amalgamation of many separate C source files from vedis version 1.2.6
    52   * By combining all the individual C code files into this single large file, the entire code
    53   * can be compiled as a single translation unit. This allows many compilers to do optimization's
    54   * that would not be possible if the files were compiled separately. Performance improvements
    55   * are commonly seen when vedis is compiled as a single translation unit.
    56   *
    57   * This file is all you need to compile vedis. To use vedis in other programs, you need
    58   * this file and the "vedis.h" header file that defines the programming interface to the 
    59   * vedis engine.(If you do not have the "vedis.h" header file at hand, you will find
    60   * a copy embedded within the text of this file.Search for "Header file: <vedis.h>" to find
    61   * the start of the embedded vedis.h header file.) Additional code files may be needed if
    62   * you want a wrapper to interface vedis with your choice of programming language.
    63   * To get the official documentation, please visit http://vedis.symisc.net/
    64   */
    65   /*
    66    * Make the sure the following directive is defined in the amalgamation build.
    67    */
    68   #ifndef VEDIS_AMALGAMATION
    69   #define VEDIS_AMALGAMATION
    70   #endif /* VEDIS_AMALGAMATION */
    71  /*
    72   * Embedded header file for vedis: <vedis.h>
    73   */
    74  /*
    75   * ----------------------------------------------------------
    76   * File: vedis.h
    77   * MD5: 935b32c31005cfdaa53305ce2d582dbf
    78   * ----------------------------------------------------------
    79   */
    80  /* This file was automatically generated.  Do not edit (Except for compile time directives)! */ 
    81  #ifndef  _VEDIS_H_
    82  #define  _VEDIS_H_
    83  /*
    84   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
    85   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
    86   * Version 1.2.6
    87   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
    88   * please contact Symisc Systems via:
    89   *       legal@symisc.net
    90   *       licensing@symisc.net
    91   *       contact@symisc.net
    92   * or visit:
    93   *      http://vedis.symisc.net/
    94   */
    95  /*
    96   * Copyright (C) 2013 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine <chm@symisc.net>].
    97   * All rights reserved.
    98   *
    99   * Redistribution and use in source and binary forms, with or without
   100   * modification, are permitted provided that the following conditions
   101   * are met:
   102   * 1. Redistributions of source code must retain the above copyright
   103   *    notice, this list of conditions and the following disclaimer.
   104   * 2. Redistributions in binary form must reproduce the above copyright
   105   *    notice, this list of conditions and the following disclaimer in the
   106   *    documentation and/or other materials provided with the distribution.
   107   * 3. Redistributions in any form must be accompanied by information on
   108   *    how to obtain complete source code for the Vedis engine and any 
   109   *    accompanying software that uses the Vedis engine software.
   110   *    The source code must either be included in the distribution
   111   *    or be available for no more than the cost of distribution plus
   112   *    a nominal fee, and must be freely redistributable under reasonable
   113   *    conditions. For an executable file, complete source code means
   114   *    the source code for all modules it contains.It does not include
   115   *    source code for modules or files that typically accompany the major
   116   *    components of the operating system on which the executable file runs.
   117   *
   118   * THIS SOFTWARE IS PROVIDED BY SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS
   119   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   120   * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
   121   * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SYMISC SYSTEMS
   122   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   123   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   124   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   125   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   126   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   127   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   128   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   129   */
   130  /* Make sure we can call this stuff from C++ */
   131  #ifdef __cplusplus
   132  extern "C" { 
   133  #endif
   134   /* $SymiscID: vedis.h v1.2 Unix 2013-09-16 00:38 stable <chm@symisc.net> $ */
   135  #include <stdarg.h> /* needed for the definition of va_list */
   136  /*
   137   * Compile time engine version, signature, identification in the symisc source tree
   138   * and copyright notice.
   139   * Each macro have an equivalent C interface associated with it that provide the same
   140   * information but are associated with the library instead of the header file.
   141   * Refer to [vedis_lib_version()], [vedis_lib_signature()], [vedis_lib_ident()] and
   142   * [vedis_lib_copyright()] for more information.
   143   */
   144  /*
   145   * The VEDIS_VERSION C preprocessor macroevaluates to a string literal
   146   * that is the vedis version in the format "X.Y.Z" where X is the major
   147   * version number and Y is the minor version number and Z is the release
   148   * number.
   149   */
   150  #define VEDIS_VERSION "1.2.6"
   151  /*
   152   * The VEDIS_VERSION_NUMBER C preprocessor macro resolves to an integer
   153   * with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same
   154   * numbers used in [VEDIS_VERSION].
   155   */
   156  #define VEDIS_VERSION_NUMBER 1002006
   157  /*
   158   * The VEDIS_SIG C preprocessor macro evaluates to a string
   159   * literal which is the public signature of the vedis engine.
   160   */
   161  #define VEDIS_SIG "vedis/1.2.6"
   162  /*
   163   * Vedis identification in the Symisc source tree:
   164   * Each particular check-in of a particular software released
   165   * by symisc systems have an unique identifier associated with it.
   166   * This macro hold the one associated with vedis.
   167   */
   168  #define VEDIS_IDENT "vedis:e361b2f3d4a71ac17e9f2ac1876232a13467dea1"
   169  /*
   170   * Copyright notice.
   171   * If you have any questions about the licensing situation, please
   172   * visit http://vedis.symisc.net/licensing.html
   173   * or contact Symisc Systems via:
   174   *   legal@symisc.net
   175   *   licensing@symisc.net
   176   *   contact@symisc.net
   177   */
   178  #define VEDIS_COPYRIGHT "Copyright (C) Symisc Systems, S.U.A.R.L [Mrad Chems Eddine <chm@symisc.net>] 2013, http://vedis.symisc.net/"
   179  /* Forward declaration to public objects */
   180  typedef struct vedis_io_methods vedis_io_methods;
   181  typedef struct vedis_kv_methods vedis_kv_methods;
   182  typedef struct vedis_kv_engine vedis_kv_engine;
   183  typedef struct vedis_context vedis_context;
   184  typedef struct vedis_value vedis_value;
   185  typedef struct vedis_vfs vedis_vfs;
   186  typedef struct vedis vedis;
   187  /*
   188   * ------------------------------
   189   * Compile time directives
   190   * ------------------------------
   191   * For most purposes, Vedis can be built just fine using the default compilation options.
   192   * However, if required, the compile-time options documented below can be used to omit Vedis
   193   * features (resulting in a smaller compiled library size) or to change the default values
   194   * of some parameters.
   195   * Every effort has been made to ensure that the various combinations of compilation options
   196   * work harmoniously and produce a working library.
   197   *
   198   * VEDIS_ENABLE_THREADS
   199   *  This option controls whether or not code is included in Vedis to enable it to operate
   200   *  safely in a multithreaded environment. The default is not. All mutexing code is omitted
   201   *  and it is unsafe to use Vedis in a multithreaded program. When compiled with the
   202   *  VEDIS_ENABLE_THREADS directive enabled, Vedis can be used in a multithreaded program
   203   *  and it is safe to share the same virtual machine and engine handle between two or more threads.
   204   *  The value of VEDIS_ENABLE_THREADS can be determined at run-time using the vedis_lib_is_threadsafe()
   205   *  interface.
   206   *  When Vedis has been compiled with threading support then the threading mode can be altered
   207   * at run-time using the vedis_lib_config() interface together with one of these verbs:
   208   *    VEDIS_LIB_CONFIG_THREAD_LEVEL_SINGLE
   209   *    VEDIS_LIB_CONFIG_THREAD_LEVEL_MULTI
   210   *  Platforms others than Windows and UNIX systems must install their own mutex subsystem via 
   211   *  vedis_lib_config() with a configuration verb set to VEDIS_LIB_CONFIG_USER_MUTEX.
   212   *  Otherwise the library is not threadsafe.
   213   *  Note that you must link Vedis with the POSIX threads library under UNIX systems (i.e: -lpthread).
   214   *
   215   */
   216  /* Symisc public definitions */
   217  #if !defined(SYMISC_STANDARD_DEFS)
   218  #define SYMISC_STANDARD_DEFS
   219  #if defined (_WIN32) || defined (WIN32) || defined(__MINGW32__) || defined (_MSC_VER) || defined (_WIN32_WCE)
   220  /* Windows Systems */
   221  #if !defined(__WINNT__)
   222  #define __WINNT__
   223  #endif 
   224  /*
   225   * Determine if we are dealing with WindowsCE - which has a much
   226   * reduced API.
   227   */
   228  #if defined(_WIN32_WCE)
   229  #ifndef __WIN_CE__
   230  #define __WIN_CE__
   231  #endif /* __WIN_CE__ */
   232  #endif /* _WIN32_WCE */
   233  #else
   234  /*
   235   * By default we will assume that we are compiling on a UNIX systems.
   236   * Otherwise the OS_OTHER directive must be defined.
   237   */
   238  #if !defined(OS_OTHER)
   239  #if !defined(__UNIXES__)
   240  #define __UNIXES__
   241  #endif /* __UNIXES__ */
   242  #else
   243  #endif /* OS_OTHER */
   244  #endif /* __WINNT__/__UNIXES__ */
   245  #if defined(_MSC_VER) || defined(__BORLANDC__)
   246  typedef signed __int64     sxi64; /* 64 bits(8 bytes) signed int64 */
   247  typedef unsigned __int64   sxu64; /* 64 bits(8 bytes) unsigned int64 */
   248  #else
   249  typedef signed long long int   sxi64; /* 64 bits(8 bytes) signed int64 */
   250  typedef unsigned long long int sxu64; /* 64 bits(8 bytes) unsigned int64 */
   251  #endif /* _MSC_VER */
   252  /* Signature of the consumer routine */
   253  typedef int (*ProcConsumer)(const void *, unsigned int, void *);
   254  /* Forward reference */
   255  typedef struct SyMutexMethods SyMutexMethods;
   256  typedef struct SyMemMethods SyMemMethods;
   257  typedef struct SyString SyString;
   258  typedef struct syiovec syiovec;
   259  typedef struct SyMutex SyMutex;
   260  typedef struct Sytm Sytm;
   261  /* Scatter and gather array. */
   262  struct syiovec
   263  {
   264  #if defined (__WINNT__)
   265  	/* Same fields type and offset as WSABUF structure defined one winsock2 header */
   266  	unsigned long nLen;
   267  	char *pBase;
   268  #else
   269  	void *pBase;
   270  	unsigned long nLen;
   271  #endif
   272  };
   273  struct SyString
   274  {
   275  	const char *zString;  /* Raw string (may not be null terminated) */
   276  	unsigned int nByte;   /* Raw string length */
   277  };
   278  /* Time structure. */
   279  struct Sytm
   280  {
   281    int tm_sec;     /* seconds (0 - 60) */
   282    int tm_min;     /* minutes (0 - 59) */
   283    int tm_hour;    /* hours (0 - 23) */
   284    int tm_mday;    /* day of month (1 - 31) */
   285    int tm_mon;     /* month of year (0 - 11) */
   286    int tm_year;    /* year + 1900 */
   287    int tm_wday;    /* day of week (Sunday = 0) */
   288    int tm_yday;    /* day of year (0 - 365) */
   289    int tm_isdst;   /* is summer time in effect? */
   290    char *tm_zone;  /* abbreviation of timezone name */
   291    long tm_gmtoff; /* offset from UTC in seconds */
   292  };
   293  /* Convert a tm structure (struct tm *) found in <time.h> to a Sytm structure */
   294  #define STRUCT_TM_TO_SYTM(pTM, pSYTM) \
   295  	(pSYTM)->tm_hour = (pTM)->tm_hour;\
   296  	(pSYTM)->tm_min	 = (pTM)->tm_min;\
   297  	(pSYTM)->tm_sec	 = (pTM)->tm_sec;\
   298  	(pSYTM)->tm_mon	 = (pTM)->tm_mon;\
   299  	(pSYTM)->tm_mday = (pTM)->tm_mday;\
   300  	(pSYTM)->tm_year = (pTM)->tm_year + 1900;\
   301  	(pSYTM)->tm_yday = (pTM)->tm_yday;\
   302  	(pSYTM)->tm_wday = (pTM)->tm_wday;\
   303  	(pSYTM)->tm_isdst = (pTM)->tm_isdst;\
   304  	(pSYTM)->tm_gmtoff = 0;\
   305  	(pSYTM)->tm_zone = 0;
   306  
   307  /* Convert a SYSTEMTIME structure (LPSYSTEMTIME: Windows Systems only ) to a Sytm structure */
   308  #define SYSTEMTIME_TO_SYTM(pSYSTIME, pSYTM) \
   309  	 (pSYTM)->tm_hour = (pSYSTIME)->wHour;\
   310  	 (pSYTM)->tm_min  = (pSYSTIME)->wMinute;\
   311  	 (pSYTM)->tm_sec  = (pSYSTIME)->wSecond;\
   312  	 (pSYTM)->tm_mon  = (pSYSTIME)->wMonth - 1;\
   313  	 (pSYTM)->tm_mday = (pSYSTIME)->wDay;\
   314  	 (pSYTM)->tm_year = (pSYSTIME)->wYear;\
   315  	 (pSYTM)->tm_yday = 0;\
   316  	 (pSYTM)->tm_wday = (pSYSTIME)->wDayOfWeek;\
   317  	 (pSYTM)->tm_gmtoff = 0;\
   318  	 (pSYTM)->tm_isdst = -1;\
   319  	 (pSYTM)->tm_zone = 0;
   320  
   321  /* Dynamic memory allocation methods. */
   322  struct SyMemMethods 
   323  {
   324  	void * (*xAlloc)(unsigned int);          /* [Required:] Allocate a memory chunk */
   325  	void * (*xRealloc)(void *, unsigned int); /* [Required:] Re-allocate a memory chunk */
   326  	void   (*xFree)(void *);                 /* [Required:] Release a memory chunk */
   327  	unsigned int  (*xChunkSize)(void *);     /* [Optional:] Return chunk size */
   328  	int    (*xInit)(void *);                 /* [Optional:] Initialization callback */
   329  	void   (*xRelease)(void *);              /* [Optional:] Release callback */
   330  	void  *pUserData;                        /* [Optional:] First argument to xInit() and xRelease() */
   331  };
   332  /* Out of memory callback signature. */
   333  typedef int (*ProcMemError)(void *);
   334  /* Mutex methods. */
   335  struct SyMutexMethods 
   336  {
   337  	int (*xGlobalInit)(void);		/* [Optional:] Global mutex initialization */
   338  	void  (*xGlobalRelease)(void);	/* [Optional:] Global Release callback () */
   339  	SyMutex * (*xNew)(int);	        /* [Required:] Request a new mutex */
   340  	void  (*xRelease)(SyMutex *);	/* [Optional:] Release a mutex  */
   341  	void  (*xEnter)(SyMutex *);	    /* [Required:] Enter mutex */
   342  	int (*xTryEnter)(SyMutex *);    /* [Optional:] Try to enter a mutex */
   343  	void  (*xLeave)(SyMutex *);	    /* [Required:] Leave a locked mutex */
   344  };
   345  #if defined (_MSC_VER) || defined (__MINGW32__) ||  defined (__GNUC__) && defined (__declspec)
   346  #define SX_APIIMPORT	__declspec(dllimport)
   347  #define SX_APIEXPORT	__declspec(dllexport)
   348  #else
   349  #define	SX_APIIMPORT
   350  #define	SX_APIEXPORT
   351  #endif
   352  /* Standard return values from Symisc public interfaces */
   353  #define SXRET_OK       0      /* Not an error */	
   354  #define SXERR_MEM      (-1)   /* Out of memory */
   355  #define SXERR_IO       (-2)   /* IO error */
   356  #define SXERR_EMPTY    (-3)   /* Empty field */
   357  #define SXERR_LOCKED   (-4)   /* Locked operation */
   358  #define SXERR_ORANGE   (-5)   /* Out of range value */
   359  #define SXERR_NOTFOUND (-6)   /* Item not found */
   360  #define SXERR_LIMIT    (-7)   /* Limit reached */
   361  #define SXERR_MORE     (-8)   /* Need more input */
   362  #define SXERR_INVALID  (-9)   /* Invalid parameter */
   363  #define SXERR_ABORT    (-10)  /* User callback request an operation abort */
   364  #define SXERR_EXISTS   (-11)  /* Item exists */
   365  #define SXERR_SYNTAX   (-12)  /* Syntax error */
   366  #define SXERR_UNKNOWN  (-13)  /* Unknown error */
   367  #define SXERR_BUSY     (-14)  /* Busy operation */
   368  #define SXERR_OVERFLOW (-15)  /* Stack or buffer overflow */
   369  #define SXERR_WILLBLOCK (-16) /* Operation will block */
   370  #define SXERR_NOTIMPLEMENTED  (-17) /* Operation not implemented */
   371  #define SXERR_EOF      (-18) /* End of input */
   372  #define SXERR_PERM     (-19) /* Permission error */
   373  #define SXERR_NOOP     (-20) /* No-op */	
   374  #define SXERR_FORMAT   (-21) /* Invalid format */
   375  #define SXERR_NEXT     (-22) /* Not an error */
   376  #define SXERR_OS       (-23) /* System call return an error */
   377  #define SXERR_CORRUPT  (-24) /* Corrupted pointer */
   378  #define SXERR_CONTINUE (-25) /* Not an error: Operation in progress */
   379  #define SXERR_NOMATCH  (-26) /* No match */
   380  #define SXERR_RESET    (-27) /* Operation reset */
   381  #define SXERR_DONE     (-28) /* Not an error */
   382  #define SXERR_SHORT    (-29) /* Buffer too short */
   383  #define SXERR_PATH     (-30) /* Path error */
   384  #define SXERR_TIMEOUT  (-31) /* Timeout */
   385  #define SXERR_BIG      (-32) /* Too big for processing */
   386  #define SXERR_RETRY    (-33) /* Retry your call */
   387  #define SXERR_IGNORE   (-63) /* Ignore */
   388  #endif /* SYMISC_PUBLIC_DEFS */
   389  /* 
   390   * Marker for exported interfaces. 
   391   */
   392  #define VEDIS_APIEXPORT SX_APIEXPORT
   393  /* Standard Vedis return values */
   394  #define VEDIS_OK      SXRET_OK      /* Successful result */
   395  /* Beginning of error codes */
   396  #define VEDIS_NOMEM    SXERR_MEM     /* Out of memory */
   397  #define VEDIS_ABORT    SXERR_ABORT   /* Another thread have released this instance */
   398  #define VEDIS_IOERR    SXERR_IO      /* IO error */
   399  #define VEDIS_CORRUPT  SXERR_CORRUPT /* Corrupt pointer */
   400  #define VEDIS_LOCKED   SXERR_LOCKED  /* Forbidden Operation */ 
   401  #define VEDIS_BUSY	 SXERR_BUSY    /* The database file is locked */
   402  #define VEDIS_DONE	 SXERR_DONE    /* Operation done */
   403  #define VEDIS_PERM     SXERR_PERM    /* Permission error */
   404  #define VEDIS_NOTIMPLEMENTED SXERR_NOTIMPLEMENTED /* Method not implemented by the underlying Key/Value storage engine */
   405  #define VEDIS_NOTFOUND SXERR_NOTFOUND /* No such record */
   406  #define VEDIS_NOOP     SXERR_NOOP     /* No such method */
   407  #define VEDIS_INVALID  SXERR_INVALID  /* Invalid parameter */
   408  #define VEDIS_EOF      SXERR_EOF      /* End Of Input */
   409  #define VEDIS_UNKNOWN  SXERR_UNKNOWN  /* Unknown configuration option */
   410  #define VEDIS_LIMIT    SXERR_LIMIT    /* Database limit reached */
   411  #define VEDIS_EXISTS   SXERR_EXISTS   /* Record exists */
   412  #define VEDIS_EMPTY    SXERR_EMPTY    /* Empty record */
   413  #define VEDIS_FULL        (-73)       /* Full database (unlikely) */
   414  #define VEDIS_CANTOPEN    (-74)       /* Unable to open the database file */
   415  #define VEDIS_READ_ONLY   (-75)       /* Read only Key/Value storage engine */
   416  #define VEDIS_LOCKERR     (-76)       /* Locking protocol error */
   417  /* end-of-error-codes */
   418  /*
   419   * If compiling for a processor that lacks floating point
   420   * support, substitute integer for floating-point.
   421   */
   422  #ifdef VEDIS_OMIT_FLOATING_POINT
   423  typedef sxi64 vedis_real;
   424  #else
   425  typedef double vedis_real;
   426  #endif
   427  typedef sxi64 vedis_int64;
   428  /*
   429   * Vedis Configuration Commands.
   430   *
   431   * The following set of constants are the available configuration verbs that can
   432   * be used by the host-application to configure a Vedis datastore handle.
   433   * These constants must be passed as the second argument to [vedis_config()].
   434   *
   435   * Each options require a variable number of arguments.
   436   * The [vedis_config()] interface will return VEDIS_OK on success, any other
   437   * return value indicates failure.
   438   * For a full discussion on the configuration verbs and their expected 
   439   * parameters, please refer to this page:
   440   *      http://vedis.symisc.net/c_api/vedis_config.html
   441   */
   442  #define VEDIS_CONFIG_ERR_LOG             1  /* TWO ARGUMENTS: const char **pzBuf, int *pLen */
   443  #define VEDIS_CONFIG_MAX_PAGE_CACHE      2  /* ONE ARGUMENT: int nMaxPage */
   444  #define VEDIS_CONFIG_KV_ENGINE           4  /* ONE ARGUMENT: const char *zKvName */
   445  #define VEDIS_CONFIG_DISABLE_AUTO_COMMIT 5  /* NO ARGUMENTS */
   446  #define VEDIS_CONFIG_GET_KV_NAME         6  /* ONE ARGUMENT: const char **pzPtr */
   447  #define VEDIS_CONFIG_DUP_EXEC_VALUE      7  /* ONE ARGUMENT: vedis_value **ppOut */
   448  #define VEDIS_CONFIG_RELEASE_DUP_VALUE   8  /* ONE ARGUMENT: vedis_value *pIn */
   449  #define VEDIS_CONFIG_OUTPUT_CONSUMER     9  /* TWO ARGUMENTS: int (*xConsumer)(vedis_value *pOut,void *pUserdata), void *pUserdata */
   450  /*
   451   * Storage engine configuration commands.
   452   *
   453   * The following set of constants are the available configuration verbs that can
   454   * be used by the host-application to configure the underlying storage engine (i.e Hash, B+tree, R+tree).
   455   * These constants must be passed as the first argument to [vedis_kv_config()].
   456   * Each options require a variable number of arguments.
   457   * The [vedis_kv_config()] interface will return VEDIS_OK on success, any other return
   458   * value indicates failure.
   459   * For a full discussion on the configuration verbs and their expected parameters, please
   460   * refer to this page:
   461   *      http://vedis.symisc.net/c_api/vedis_kv_config.html
   462   */
   463  #define VEDIS_KV_CONFIG_HASH_FUNC  1 /* ONE ARGUMENT: unsigned int (*xHash)(const void *,unsigned int) */
   464  #define VEDIS_KV_CONFIG_CMP_FUNC   2 /* ONE ARGUMENT: int (*xCmp)(const void *,const void *,unsigned int) */
   465  /*
   466   * Global Library Configuration Commands.
   467   *
   468   * The following set of constants are the available configuration verbs that can
   469   * be used by the host-application to configure the whole library.
   470   * These constants must be passed as the first argument to [vedis_lib_config()].
   471   *
   472   * Each options require a variable number of arguments.
   473   * The [vedis_lib_config()] interface will return VEDIS_OK on success, any other return
   474   * value indicates failure.
   475   * Notes:
   476   * The default configuration is recommended for most applications and so the call to
   477   * [vedis_lib_config()] is usually not necessary. It is provided to support rare 
   478   * applications with unusual needs. 
   479   * The [vedis_lib_config()] interface is not threadsafe. The application must insure that
   480   * no other [vedis_*()] interfaces are invoked by other threads while [vedis_lib_config()]
   481   * is running. Furthermore, [vedis_lib_config()] may only be invoked prior to library
   482   * initialization using [vedis_lib_init()] or [vedis_init()] or after shutdown
   483   * by [vedis_lib_shutdown()]. If [vedis_lib_config()] is called after [vedis_lib_init()]
   484   * or [vedis_init()] and before [vedis_lib_shutdown()] then it will return VEDIS_LOCKED.
   485   * For a full discussion on the configuration verbs and their expected parameters, please
   486   * refer to this page:
   487   *      http://vedis.symisc.net/c_api/vedis_lib.html
   488   */
   489  #define VEDIS_LIB_CONFIG_USER_MALLOC            1 /* ONE ARGUMENT: const SyMemMethods *pMemMethods */ 
   490  #define VEDIS_LIB_CONFIG_MEM_ERR_CALLBACK       2 /* TWO ARGUMENTS: int (*xMemError)(void *), void *pUserData */
   491  #define VEDIS_LIB_CONFIG_USER_MUTEX             3 /* ONE ARGUMENT: const SyMutexMethods *pMutexMethods */ 
   492  #define VEDIS_LIB_CONFIG_THREAD_LEVEL_SINGLE    4 /* NO ARGUMENTS */ 
   493  #define VEDIS_LIB_CONFIG_THREAD_LEVEL_MULTI     5 /* NO ARGUMENTS */ 
   494  #define VEDIS_LIB_CONFIG_VFS                    6 /* ONE ARGUMENT: const vedis_vfs *pVfs */
   495  #define VEDIS_LIB_CONFIG_STORAGE_ENGINE         7 /* ONE ARGUMENT: vedis_kv_methods *pStorage */
   496  #define VEDIS_LIB_CONFIG_PAGE_SIZE              8 /* ONE ARGUMENT: int iPageSize */
   497  /*
   498   * Synchronization Type Flags
   499   *
   500   * When Vedis invokes the xSync() method of an [vedis_io_methods] object it uses
   501   * a combination of these integer values as the second argument.
   502   *
   503   * When the VEDIS_SYNC_DATAONLY flag is used, it means that the sync operation only
   504   * needs to flush data to mass storage.  Inode information need not be flushed.
   505   * If the lower four bits of the flag equal VEDIS_SYNC_NORMAL, that means to use normal
   506   * fsync() semantics. If the lower four bits equal VEDIS_SYNC_FULL, that means to use
   507   * Mac OS X style fullsync instead of fsync().
   508   */
   509  #define VEDIS_SYNC_NORMAL        0x00002
   510  #define VEDIS_SYNC_FULL          0x00003
   511  #define VEDIS_SYNC_DATAONLY      0x00010
   512  /*
   513   * File Locking Levels
   514   *
   515   * Vedis uses one of these integer values as the second
   516   * argument to calls it makes to the xLock() and xUnlock() methods
   517   * of an [vedis_io_methods] object.
   518   */
   519  #define VEDIS_LOCK_NONE          0
   520  #define VEDIS_LOCK_SHARED        1
   521  #define VEDIS_LOCK_RESERVED      2
   522  #define VEDIS_LOCK_PENDING       3
   523  #define VEDIS_LOCK_EXCLUSIVE     4
   524  /*
   525   * CAPIREF: OS Interface: Open File Handle
   526   *
   527   * An [vedis_file] object represents an open file in the [vedis_vfs] OS interface
   528   * layer.
   529   * Individual OS interface implementations will want to subclass this object by appending
   530   * additional fields for their own use. The pMethods entry is a pointer to an
   531   * [vedis_io_methods] object that defines methods for performing
   532   * I/O operations on the open file.
   533  */
   534  typedef struct vedis_file vedis_file;
   535  struct vedis_file {
   536    const vedis_io_methods *pMethods;  /* Methods for an open file. MUST BE FIRST */
   537  };
   538  /*
   539   * CAPIREF: OS Interface: File Methods Object
   540   *
   541   * Every file opened by the [vedis_vfs] xOpen method populates an
   542   * [vedis_file] object (or, more commonly, a subclass of the
   543   * [vedis_file] object) with a pointer to an instance of this object.
   544   * This object defines the methods used to perform various operations
   545   * against the open file represented by the [vedis_file] object.
   546   *
   547   * If the xOpen method sets the vedis_file.pMethods element 
   548   * to a non-NULL pointer, then the vedis_io_methods.xClose method
   549   * may be invoked even if the xOpen reported that it failed.  The
   550   * only way to prevent a call to xClose following a failed xOpen
   551   * is for the xOpen to set the vedis_file.pMethods element to NULL.
   552   *
   553   * The flags argument to xSync may be one of [VEDIS_SYNC_NORMAL] or
   554   * [VEDIS_SYNC_FULL]. The first choice is the normal fsync().
   555   * The second choice is a Mac OS X style fullsync. The [VEDIS_SYNC_DATAONLY]
   556   * flag may be ORed in to indicate that only the data of the file
   557   * and not its inode needs to be synced.
   558   *
   559   * The integer values to xLock() and xUnlock() are one of
   560   *
   561   * VEDIS_LOCK_NONE
   562   * VEDIS_LOCK_SHARED
   563   * VEDIS_LOCK_RESERVED
   564   * VEDIS_LOCK_PENDING
   565   * VEDIS_LOCK_EXCLUSIVE
   566   * 
   567   * xLock() increases the lock. xUnlock() decreases the lock.
   568   * The xCheckReservedLock() method checks whether any database connection,
   569   * either in this process or in some other process, is holding a RESERVED,
   570   * PENDING, or EXCLUSIVE lock on the file. It returns true if such a lock exists
   571   * and false otherwise.
   572   * 
   573   * The xSectorSize() method returns the sector size of the device that underlies
   574   * the file. The sector size is the minimum write that can be performed without
   575   * disturbing other bytes in the file.
   576   */
   577  struct vedis_io_methods {
   578    int iVersion;                 /* Structure version number (currently 1) */
   579    int (*xClose)(vedis_file*);
   580    int (*xRead)(vedis_file*, void*, vedis_int64 iAmt, vedis_int64 iOfst);
   581    int (*xWrite)(vedis_file*, const void*, vedis_int64 iAmt, vedis_int64 iOfst);
   582    int (*xTruncate)(vedis_file*, vedis_int64 size);
   583    int (*xSync)(vedis_file*, int flags);
   584    int (*xFileSize)(vedis_file*, vedis_int64 *pSize);
   585    int (*xLock)(vedis_file*, int);
   586    int (*xUnlock)(vedis_file*, int);
   587    int (*xCheckReservedLock)(vedis_file*, int *pResOut);
   588    int (*xSectorSize)(vedis_file*);
   589  };
   590  /*
   591   * CAPIREF: OS Interface Object
   592   *
   593   * An instance of the vedis_vfs object defines the interface between
   594   * the Vedis core and the underlying operating system.  The "vfs"
   595   * in the name of the object stands for "Virtual File System".
   596   *
   597   * Only a single vfs can be registered within the Vedis core.
   598   * Vfs registration is done using the [vedis_lib_config()] interface
   599   * with a configuration verb set to VEDIS_LIB_CONFIG_VFS.
   600   * Note that Windows and UNIX (Linux, FreeBSD, Solaris, Mac OS X, etc.) users
   601   * does not have to worry about registering and installing a vfs since Vedis
   602   * come with a built-in vfs for these platforms that implements most the methods
   603   * defined below.
   604   *
   605   * Clients running on exotic systems (ie: Other than Windows and UNIX systems)
   606   * must register their own vfs in order to be able to use the Vedis library.
   607   *
   608   * The value of the iVersion field is initially 1 but may be larger in
   609   * future versions of Vedis. 
   610   *
   611   * The szOsFile field is the size of the subclassed [vedis_file] structure
   612   * used by this VFS. mxPathname is the maximum length of a pathname in this VFS.
   613   * 
   614   * At least szOsFile bytes of memory are allocated by Vedis to hold the [vedis_file]
   615   * structure passed as the third argument to xOpen. The xOpen method does not have to
   616   * allocate the structure; it should just fill it in. Note that the xOpen method must
   617   * set the vedis_file.pMethods to either a valid [vedis_io_methods] object or to NULL.
   618   * xOpen must do this even if the open fails. Vedis expects that the vedis_file.pMethods
   619   * element will be valid after xOpen returns regardless of the success or failure of the
   620   * xOpen call.
   621   */
   622  struct vedis_vfs {
   623    const char *zName;       /* Name of this virtual file system [i.e: Windows, UNIX, etc.] */
   624    int iVersion;            /* Structure version number (currently 1) */
   625    int szOsFile;            /* Size of subclassed vedis_file */
   626    int mxPathname;          /* Maximum file pathname length */
   627    int (*xOpen)(vedis_vfs*, const char *zName, vedis_file*,unsigned int flags);
   628    int (*xDelete)(vedis_vfs*, const char *zName, int syncDir);
   629    int (*xAccess)(vedis_vfs*, const char *zName, int flags, int *pResOut);
   630    int (*xFullPathname)(vedis_vfs*, const char *zName,int buf_len,char *zBuf);
   631    int (*xTmpDir)(vedis_vfs*,char *zBuf,int buf_len);
   632    int (*xSleep)(vedis_vfs*, int microseconds);
   633    int (*xCurrentTime)(vedis_vfs*,Sytm *pOut);
   634    int (*xGetLastError)(vedis_vfs*, int, char *);
   635    int (*xMmap)(const char *, void **, vedis_int64 *);  
   636    void (*xUnmap)(void *,vedis_int64);
   637  };
   638  /*
   639   * Flags for the xAccess VFS method
   640   *
   641   * These integer constants can be used as the third parameter to
   642   * the xAccess method of an [vedis_vfs] object.  They determine
   643   * what kind of permissions the xAccess method is looking for.
   644   * With VEDIS_ACCESS_EXISTS, the xAccess method
   645   * simply checks whether the file exists.
   646   * With VEDIS_ACCESS_READWRITE, the xAccess method
   647   * checks whether the named directory is both readable and writable
   648   * (in other words, if files can be added, removed, and renamed within
   649   * the directory).
   650   * The VEDIS_ACCESS_READWRITE constant is currently used only by the
   651   * [temp_store_directory pragma], though this could change in a future
   652   * release of Vedis.
   653   * With VEDIS_ACCESS_READ, the xAccess method
   654   * checks whether the file is readable.  The VEDIS_ACCESS_READ constant is
   655   * currently unused, though it might be used in a future release of
   656   * Vedis.
   657   */
   658  #define VEDIS_ACCESS_EXISTS    0
   659  #define VEDIS_ACCESS_READWRITE 1   
   660  #define VEDIS_ACCESS_READ      2 
   661  /*
   662   * The type used to represent a page number.  The first page in a file
   663   * is called page 1.  0 is used to represent "not a page".
   664   * A page number is an unsigned 64-bit integer.
   665   */
   666  typedef sxu64 pgno;
   667  /*
   668   * A database disk page is represented by an instance
   669   * of the follwoing structure.
   670   */
   671  typedef struct vedis_page vedis_page;
   672  struct vedis_page
   673  {
   674    unsigned char *zData;       /* Content of this page */
   675    void *pUserData;            /* Extra content */
   676    pgno pgno;                  /* Page number for this page */
   677  };
   678  /*
   679   * Vedis handle to the underlying Key/Value Storage Engine (See below).
   680   */
   681  typedef void * vedis_kv_handle;
   682  /*
   683   * Vedis pager IO methods.
   684   *
   685   * An instance of the following structure define the exported methods of the Vedis pager
   686   * to the underlying Key/Value storage engine.
   687   */
   688  typedef struct vedis_kv_io vedis_kv_io;
   689  struct vedis_kv_io
   690  {
   691  	vedis_kv_handle  pHandle;     /* Vedis handle passed as the first parameter to the
   692  									 * method defined below.
   693  									 */
   694  	vedis_kv_methods *pMethods;   /* Underlying storage engine */
   695  	/* Pager methods */
   696  	int (*xGet)(vedis_kv_handle,pgno,vedis_page **);
   697  	int (*xLookup)(vedis_kv_handle,pgno,vedis_page **);
   698  	int (*xNew)(vedis_kv_handle,vedis_page **);
   699  	int (*xWrite)(vedis_page *);
   700  	int (*xDontWrite)(vedis_page *);
   701  	int (*xDontJournal)(vedis_page *);
   702  	int (*xDontMkHot)(vedis_page *);
   703  	int (*xPageRef)(vedis_page *);
   704  	int (*xPageUnref)(vedis_page *);
   705  	int (*xPageSize)(vedis_kv_handle);
   706  	int (*xReadOnly)(vedis_kv_handle);
   707  	unsigned char * (*xTmpPage)(vedis_kv_handle);
   708  	void (*xSetUnpin)(vedis_kv_handle,void (*xPageUnpin)(void *)); 
   709  	void (*xSetReload)(vedis_kv_handle,void (*xPageReload)(void *));
   710  	void (*xErr)(vedis_kv_handle,const char *);
   711  };
   712  /*
   713   * Key/Value Cursor Object.
   714   *
   715   * An instance of a subclass of the following object defines a cursor
   716   * used to scan through a key-value storage engine.
   717   */
   718  typedef struct vedis_kv_cursor vedis_kv_cursor;
   719  struct vedis_kv_cursor
   720  {
   721    vedis_kv_engine *pStore; /* Must be first */
   722    /* Subclasses will typically add additional fields */
   723  };
   724  /*
   725   * Possible seek positions.
   726   */
   727  #define VEDIS_CURSOR_MATCH_EXACT  1
   728  #define VEDIS_CURSOR_MATCH_LE     2
   729  #define VEDIS_CURSOR_MATCH_GE     3
   730  /*
   731   * Key/Value Storage Engine.
   732   *
   733   * A Key-Value storage engine is defined by an instance of the following
   734   * object.
   735   * Vedis works with run-time interchangeable storage engines (i.e. Hash, B+Tree, R+Tree, LSM, etc.).
   736   * The storage engine works with key/value pairs where both the key
   737   * and the value are byte arrays of arbitrary length and with no restrictions on content.
   738   * Vedis come with two built-in KV storage engine: A Virtual Linear Hash (VLH) storage
   739   * engine is used for persistent on-disk databases with O(1) lookup time and an in-memory
   740   * hash-table or Red-black tree storage engine is used for in-memory databases.
   741   * Future versions of Vedis might add other built-in storage engines (i.e. LSM). 
   742   * Registration of a Key/Value storage engine at run-time is done via [vedis_lib_config()]
   743   * with a configuration verb set to VEDIS_LIB_CONFIG_STORAGE_ENGINE.
   744   */
   745  struct vedis_kv_engine
   746  {
   747    const vedis_kv_io *pIo; /* IO methods: MUST be first */
   748     /* Subclasses will typically add additional fields */
   749  };
   750  /*
   751   * Key/Value Storage Engine Virtual Method Table.
   752   *
   753   * Key/Value storage engine methods is defined by an instance of the following
   754   * object.
   755   * Registration of a Key/Value storage engine at run-time is done via [vedis_lib_config()]
   756   * with a configuration verb set to VEDIS_LIB_CONFIG_STORAGE_ENGINE.
   757   */
   758  struct vedis_kv_methods
   759  {
   760    const char *zName; /* Storage engine name [i.e. Hash, B+tree, LSM, R-tree, Mem, etc.]*/
   761    int szKv;          /* 'vedis_kv_engine' subclass size */
   762    int szCursor;      /* 'vedis_kv_cursor' subclass size */
   763    int iVersion;      /* Structure version, currently 1 */
   764    /* Storage engine methods */
   765    int (*xInit)(vedis_kv_engine *,int iPageSize);
   766    void (*xRelease)(vedis_kv_engine *);
   767    int (*xConfig)(vedis_kv_engine *,int op,va_list ap);
   768    int (*xOpen)(vedis_kv_engine *,pgno);
   769    int (*xReplace)(
   770  	  vedis_kv_engine *,
   771  	  const void *pKey,int nKeyLen,
   772  	  const void *pData,vedis_int64 nDataLen
   773  	  ); 
   774      int (*xAppend)(
   775  	  vedis_kv_engine *,
   776  	  const void *pKey,int nKeyLen,
   777  	  const void *pData,vedis_int64 nDataLen
   778  	  );
   779    void (*xCursorInit)(vedis_kv_cursor *);
   780    int (*xSeek)(vedis_kv_cursor *,const void *pKey,int nByte,int iPos); /* Mandatory */
   781    int (*xFirst)(vedis_kv_cursor *);
   782    int (*xLast)(vedis_kv_cursor *);
   783    int (*xValid)(vedis_kv_cursor *);
   784    int (*xNext)(vedis_kv_cursor *);
   785    int (*xPrev)(vedis_kv_cursor *);
   786    int (*xDelete)(vedis_kv_cursor *);
   787    int (*xKeyLength)(vedis_kv_cursor *,int *);
   788    int (*xKey)(vedis_kv_cursor *,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
   789    int (*xDataLength)(vedis_kv_cursor *,vedis_int64 *);
   790    int (*xData)(vedis_kv_cursor *,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
   791    void (*xReset)(vedis_kv_cursor *);
   792    void (*xCursorRelease)(vedis_kv_cursor *);
   793  };
   794  /*
   795   * Vedis journal file suffix.
   796   */
   797  #ifndef VEDIS_JOURNAL_FILE_SUFFIX
   798  #define VEDIS_JOURNAL_FILE_SUFFIX "_vedis_journal"
   799  #endif
   800  /*
   801   * Call Context - Error Message Serverity Level.
   802   *
   803   * The following constans are the allowed severity level that can
   804   * passed as the second argument to the [vedis_context_throw_error()] or
   805   * [vedis_context_throw_error_format()] interfaces.
   806   * Refer to the official documentation for additional information.
   807   */
   808  #define VEDIS_CTX_ERR       1 /* Call context error such as unexpected number of arguments, invalid types and so on. */
   809  #define VEDIS_CTX_WARNING   2 /* Call context Warning */
   810  #define VEDIS_CTX_NOTICE    3 /* Call context Notice */
   811  /* 
   812   * C-API-REF: Please refer to the official documentation for interfaces
   813   * purpose and expected parameters. 
   814   */
   815  /* Vedis Datastore Handle */
   816  VEDIS_APIEXPORT int vedis_open(vedis **ppStore,const char *zStorage);
   817  VEDIS_APIEXPORT int vedis_config(vedis *pStore,int iOp,...);
   818  VEDIS_APIEXPORT int vedis_close(vedis *pStore);
   819  
   820  /* Command Execution Interfaces */
   821  VEDIS_APIEXPORT int vedis_exec(vedis *pStore,const char *zCmd,int nLen);
   822  VEDIS_APIEXPORT int vedis_exec_fmt(vedis *pStore,const char *zFmt,...);
   823  VEDIS_APIEXPORT int vedis_exec_result(vedis *pStore,vedis_value **ppOut);
   824  
   825  /* Foreign Command Registar */
   826  VEDIS_APIEXPORT int vedis_register_command(vedis *pStore,const char *zName,int (*xCmd)(vedis_context *,int,vedis_value **),void *pUserdata);
   827  VEDIS_APIEXPORT int vedis_delete_command(vedis *pStore,const char *zName);
   828  
   829  /* Raw Data Store/Fetch (http://vedis.org) */
   830  VEDIS_APIEXPORT int vedis_kv_store(vedis *pStore,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen);
   831  VEDIS_APIEXPORT int vedis_kv_append(vedis *pStore,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen);
   832  VEDIS_APIEXPORT int vedis_kv_store_fmt(vedis *pStore,const void *pKey,int nKeyLen,const char *zFormat,...);
   833  VEDIS_APIEXPORT int vedis_kv_append_fmt(vedis *pStore,const void *pKey,int nKeyLen,const char *zFormat,...);
   834  VEDIS_APIEXPORT int vedis_kv_fetch(vedis *pStore,const void *pKey,int nKeyLen,void *pBuf,vedis_int64 /* in|out */*pBufLen);
   835  VEDIS_APIEXPORT int vedis_kv_fetch_callback(vedis *pStore,const void *pKey,
   836  	                    int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
   837  VEDIS_APIEXPORT int vedis_kv_config(vedis *pStore,int iOp,...);
   838  VEDIS_APIEXPORT int vedis_kv_delete(vedis *pStore,const void *pKey,int nKeyLen);
   839  
   840  /* Manual Transaction Manager */
   841  VEDIS_APIEXPORT int vedis_begin(vedis *pStore);
   842  VEDIS_APIEXPORT int vedis_commit(vedis *pStore);
   843  VEDIS_APIEXPORT int vedis_rollback(vedis *pStore);
   844  
   845  /* Utility interfaces */
   846  VEDIS_APIEXPORT int vedis_util_random_string(vedis *pStore,char *zBuf,unsigned int buf_size);
   847  VEDIS_APIEXPORT unsigned int vedis_util_random_num(vedis *pStore);
   848  
   849  /* Call Context Key/Value Store Interfaces */
   850  VEDIS_APIEXPORT int vedis_context_kv_store(vedis_context *pCtx,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen);
   851  VEDIS_APIEXPORT int vedis_context_kv_append(vedis_context *pCtx,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen);
   852  VEDIS_APIEXPORT int vedis_context_kv_store_fmt(vedis_context *pCtx,const void *pKey,int nKeyLen,const char *zFormat,...);
   853  VEDIS_APIEXPORT int vedis_context_kv_append_fmt(vedis_context *pCtx,const void *pKey,int nKeyLen,const char *zFormat,...);
   854  VEDIS_APIEXPORT int vedis_context_kv_fetch(vedis_context *pCtx,const void *pKey,int nKeyLen,void *pBuf,vedis_int64 /* in|out */*pBufLen);
   855  VEDIS_APIEXPORT int vedis_context_kv_fetch_callback(vedis_context *pCtx,const void *pKey,
   856  	                    int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
   857  VEDIS_APIEXPORT int vedis_context_kv_delete(vedis_context *pCtx,const void *pKey,int nKeyLen);
   858  
   859  /* Command Execution Context Interfaces */
   860  VEDIS_APIEXPORT int vedis_context_throw_error(vedis_context *pCtx, int iErr, const char *zErr);
   861  VEDIS_APIEXPORT int vedis_context_throw_error_format(vedis_context *pCtx, int iErr, const char *zFormat, ...);
   862  VEDIS_APIEXPORT unsigned int vedis_context_random_num(vedis_context *pCtx);
   863  VEDIS_APIEXPORT int vedis_context_random_string(vedis_context *pCtx, char *zBuf, int nBuflen);
   864  VEDIS_APIEXPORT void * vedis_context_user_data(vedis_context *pCtx);
   865  VEDIS_APIEXPORT int    vedis_context_push_aux_data(vedis_context *pCtx, void *pUserData);
   866  VEDIS_APIEXPORT void * vedis_context_peek_aux_data(vedis_context *pCtx);
   867  VEDIS_APIEXPORT void * vedis_context_pop_aux_data(vedis_context *pCtx);
   868  
   869  /* Setting The Return Value Of A Vedis Command */
   870  VEDIS_APIEXPORT int vedis_result_int(vedis_context *pCtx, int iValue);
   871  VEDIS_APIEXPORT int vedis_result_int64(vedis_context *pCtx, vedis_int64 iValue);
   872  VEDIS_APIEXPORT int vedis_result_bool(vedis_context *pCtx, int iBool);
   873  VEDIS_APIEXPORT int vedis_result_double(vedis_context *pCtx, double Value);
   874  VEDIS_APIEXPORT int vedis_result_null(vedis_context *pCtx);
   875  VEDIS_APIEXPORT int vedis_result_string(vedis_context *pCtx, const char *zString, int nLen);
   876  VEDIS_APIEXPORT int vedis_result_string_format(vedis_context *pCtx, const char *zFormat, ...);
   877  VEDIS_APIEXPORT int vedis_result_value(vedis_context *pCtx, vedis_value *pValue);
   878  
   879  /* Extracting Vedis Commands Parameter/Return Values */
   880  VEDIS_APIEXPORT int vedis_value_to_int(vedis_value *pValue);
   881  VEDIS_APIEXPORT int vedis_value_to_bool(vedis_value *pValue);
   882  VEDIS_APIEXPORT vedis_int64 vedis_value_to_int64(vedis_value *pValue);
   883  VEDIS_APIEXPORT double vedis_value_to_double(vedis_value *pValue);
   884  VEDIS_APIEXPORT const char * vedis_value_to_string(vedis_value *pValue, int *pLen);
   885  
   886  /* Dynamically Typed Value Object Query Interfaces */
   887  VEDIS_APIEXPORT int vedis_value_is_int(vedis_value *pVal);
   888  VEDIS_APIEXPORT int vedis_value_is_float(vedis_value *pVal);
   889  VEDIS_APIEXPORT int vedis_value_is_bool(vedis_value *pVal);
   890  VEDIS_APIEXPORT int vedis_value_is_string(vedis_value *pVal);
   891  VEDIS_APIEXPORT int vedis_value_is_null(vedis_value *pVal);
   892  VEDIS_APIEXPORT int vedis_value_is_numeric(vedis_value *pVal);
   893  VEDIS_APIEXPORT int vedis_value_is_scalar(vedis_value *pVal);
   894  VEDIS_APIEXPORT int vedis_value_is_array(vedis_value *pVal);
   895  
   896  /* Populating dynamically Typed Objects  */
   897  VEDIS_APIEXPORT int vedis_value_int(vedis_value *pVal, int iValue);
   898  VEDIS_APIEXPORT int vedis_value_int64(vedis_value *pVal, vedis_int64 iValue);
   899  VEDIS_APIEXPORT int vedis_value_bool(vedis_value *pVal, int iBool);
   900  VEDIS_APIEXPORT int vedis_value_null(vedis_value *pVal);
   901  VEDIS_APIEXPORT int vedis_value_double(vedis_value *pVal, double Value);
   902  VEDIS_APIEXPORT int vedis_value_string(vedis_value *pVal, const char *zString, int nLen);
   903  VEDIS_APIEXPORT int vedis_value_string_format(vedis_value *pVal, const char *zFormat, ...);
   904  VEDIS_APIEXPORT int vedis_value_reset_string_cursor(vedis_value *pVal);
   905  VEDIS_APIEXPORT int vedis_value_release(vedis_value *pVal);
   906  
   907  /* On-demand Object Value Allocation */
   908  VEDIS_APIEXPORT vedis_value * vedis_context_new_scalar(vedis_context *pCtx);
   909  VEDIS_APIEXPORT vedis_value * vedis_context_new_array(vedis_context *pCtx);
   910  VEDIS_APIEXPORT void vedis_context_release_value(vedis_context *pCtx, vedis_value *pValue);
   911  
   912  /* Working with Vedis Arrays */
   913  VEDIS_APIEXPORT vedis_value * vedis_array_fetch(vedis_value *pArray,unsigned int index);
   914  VEDIS_APIEXPORT int vedis_array_walk(vedis_value *pArray, int (*xWalk)(vedis_value *, void *), void *pUserData);
   915  VEDIS_APIEXPORT int vedis_array_insert(vedis_value *pArray,vedis_value *pValue);
   916  VEDIS_APIEXPORT unsigned int vedis_array_count(vedis_value *pArray);
   917  VEDIS_APIEXPORT int vedis_array_reset(vedis_value *pArray);
   918  VEDIS_APIEXPORT vedis_value * vedis_array_next_elem(vedis_value *pArray);
   919  
   920  /* Global Library Management Interfaces */
   921  VEDIS_APIEXPORT int vedis_lib_init(void);
   922  VEDIS_APIEXPORT int vedis_lib_config(int nConfigOp, ...);
   923  VEDIS_APIEXPORT int vedis_lib_shutdown(void);
   924  VEDIS_APIEXPORT int vedis_lib_is_threadsafe(void);
   925  VEDIS_APIEXPORT const char * vedis_lib_version(void);
   926  VEDIS_APIEXPORT const char * vedis_lib_signature(void);
   927  VEDIS_APIEXPORT const char * vedis_lib_ident(void);
   928  VEDIS_APIEXPORT const char * vedis_lib_copyright(void);
   929  
   930  #ifdef __cplusplus
   931  }
   932  #endif /* __cplusplus */
   933  #endif /* _VEDIS_H_ */
   934  /*
   935   * ----------------------------------------------------------
   936   * File: vedisInt.h
   937   * MD5: 9cc0cabef3741742fc403ac1a3dc0e0a
   938   * ----------------------------------------------------------
   939   */
   940  /*
   941   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
   942   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
   943   * Version 1.2.6
   944   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
   945   * please contact Symisc Systems via:
   946   *       legal@symisc.net
   947   *       licensing@symisc.net
   948   *       contact@symisc.net
   949   * or visit:
   950   *      http://vedis.symisc.net/
   951   */
   952   /* $SymiscID: vedisInt.h v2.1 FreeBSD 2013-09-15 01:49 devel <chm@symisc.net> $ */
   953  #ifndef __VEDISINT_H__
   954  #define __VEDISINT_H__
   955  /* Internal interface definitions for Vedis. */
   956  #ifdef VEDIS_AMALGAMATION
   957  #ifndef VEDIS_PRIVATE
   958  /* Marker for routines not intended for external use */
   959  #define VEDIS_PRIVATE static
   960  #endif /* VEDIS_PRIVATE */
   961  #else
   962  #define VEDIS_PRIVATE
   963  #include "vedis.h"
   964  #endif 
   965  #ifndef VEDIS_PI
   966  /* Value of PI */
   967  #define VEDIS_PI 3.1415926535898
   968  #endif
   969  /*
   970   * Constants for the largest and smallest possible 64-bit signed integers.
   971   * These macros are designed to work correctly on both 32-bit and 64-bit
   972   * compilers.
   973   */
   974  #ifndef LARGEST_INT64
   975  #define LARGEST_INT64  (0xffffffff|(((sxi64)0x7fffffff)<<32))
   976  #endif
   977  #ifndef SMALLEST_INT64
   978  #define SMALLEST_INT64 (((sxi64)-1) - LARGEST_INT64)
   979  #endif
   980  
   981  /* Symisc Standard types */
   982  #if !defined(SYMISC_STD_TYPES)
   983  #define SYMISC_STD_TYPES
   984  #ifdef __WINNT__
   985  /* Disable nuisance warnings on Borland compilers */
   986  #if defined(__BORLANDC__)
   987  #pragma warn -rch /* unreachable code */
   988  #pragma warn -ccc /* Condition is always true or false */
   989  #pragma warn -aus /* Assigned value is never used */
   990  #pragma warn -csu /* Comparing signed and unsigned */
   991  #pragma warn -spa /* Suspicious pointer arithmetic */
   992  #endif
   993  #endif
   994  typedef signed char        sxi8; /* signed char */
   995  typedef unsigned char      sxu8; /* unsigned char */
   996  typedef signed short int   sxi16; /* 16 bits(2 bytes) signed integer */
   997  typedef unsigned short int sxu16; /* 16 bits(2 bytes) unsigned integer */
   998  typedef int                sxi32; /* 32 bits(4 bytes) integer */
   999  typedef unsigned int       sxu32; /* 32 bits(4 bytes) unsigned integer */
  1000  typedef long               sxptr;
  1001  typedef unsigned long      sxuptr;
  1002  typedef long               sxlong;
  1003  typedef unsigned long      sxulong;
  1004  typedef sxi32              sxofft;
  1005  typedef sxi64              sxofft64;
  1006  typedef long double	       sxlongreal;
  1007  typedef double             sxreal;
  1008  #define SXI8_HIGH       0x7F
  1009  #define SXU8_HIGH       0xFF
  1010  #define SXI16_HIGH      0x7FFF
  1011  #define SXU16_HIGH      0xFFFF
  1012  #define SXI32_HIGH      0x7FFFFFFF
  1013  #define SXU32_HIGH      0xFFFFFFFF
  1014  #define SXI64_HIGH      0x7FFFFFFFFFFFFFFF
  1015  #define SXU64_HIGH      0xFFFFFFFFFFFFFFFF 
  1016  #if !defined(TRUE)
  1017  #define TRUE 1
  1018  #endif
  1019  #if !defined(FALSE)
  1020  #define FALSE 0
  1021  #endif
  1022  /*
  1023   * The following macros are used to cast pointers to integers and
  1024   * integers to pointers.
  1025   */
  1026  #if defined(__PTRDIFF_TYPE__)  
  1027  # define SX_INT_TO_PTR(X)  ((void*)(__PTRDIFF_TYPE__)(X))
  1028  # define SX_PTR_TO_INT(X)  ((int)(__PTRDIFF_TYPE__)(X))
  1029  #elif !defined(__GNUC__)    
  1030  # define SX_INT_TO_PTR(X)  ((void*)&((char*)0)[X])
  1031  # define SX_PTR_TO_INT(X)  ((int)(((char*)X)-(char*)0))
  1032  #else                       
  1033  # define SX_INT_TO_PTR(X)  ((void*)(X))
  1034  # define SX_PTR_TO_INT(X)  ((int)(X))
  1035  #endif
  1036  #define SXMIN(a, b)  ((a < b) ? (a) : (b))
  1037  #define SXMAX(a, b)  ((a < b) ? (b) : (a))
  1038  #endif /* SYMISC_STD_TYPES */
  1039  /* Symisc Run-time API private definitions */
  1040  #if !defined(SYMISC_PRIVATE_DEFS)
  1041  #define SYMISC_PRIVATE_DEFS
  1042  
  1043  typedef sxi32 (*ProcRawStrCmp)(const SyString *, const SyString *);
  1044  #define SyStringData(RAW)	((RAW)->zString)
  1045  #define SyStringLength(RAW)	((RAW)->nByte)
  1046  #define SyStringInitFromBuf(RAW, ZBUF, NLEN){\
  1047  	(RAW)->zString 	= (const char *)ZBUF;\
  1048  	(RAW)->nByte	= (sxu32)(NLEN);\
  1049  }
  1050  #define SyStringUpdatePtr(RAW, NBYTES){\
  1051  	if( NBYTES > (RAW)->nByte ){\
  1052  		(RAW)->nByte = 0;\
  1053  	}else{\
  1054  		(RAW)->zString += NBYTES;\
  1055  		(RAW)->nByte -= NBYTES;\
  1056  	}\
  1057  }
  1058  #define SyStringDupPtr(RAW1, RAW2)\
  1059  	(RAW1)->zString = (RAW2)->zString;\
  1060  	(RAW1)->nByte = (RAW2)->nByte;
  1061  
  1062  #define SyStringTrimLeadingChar(RAW, CHAR)\
  1063  	while((RAW)->nByte > 0 && (RAW)->zString[0] == CHAR ){\
  1064  			(RAW)->zString++;\
  1065  			(RAW)->nByte--;\
  1066  	}
  1067  #define SyStringTrimTrailingChar(RAW, CHAR)\
  1068  	while((RAW)->nByte > 0 && (RAW)->zString[(RAW)->nByte - 1] == CHAR){\
  1069  		(RAW)->nByte--;\
  1070  	}
  1071  #define SyStringCmp(RAW1, RAW2, xCMP)\
  1072  	(((RAW1)->nByte == (RAW2)->nByte) ? xCMP((RAW1)->zString, (RAW2)->zString, (RAW2)->nByte) : (sxi32)((RAW1)->nByte - (RAW2)->nByte))
  1073  
  1074  #define SyStringCmp2(RAW1, RAW2, xCMP)\
  1075  	(((RAW1)->nByte >= (RAW2)->nByte) ? xCMP((RAW1)->zString, (RAW2)->zString, (RAW2)->nByte) : (sxi32)((RAW2)->nByte - (RAW1)->nByte))
  1076  
  1077  #define SyStringCharCmp(RAW, CHAR) \
  1078  	(((RAW)->nByte == sizeof(char)) ? ((RAW)->zString[0] == CHAR ? 0 : CHAR - (RAW)->zString[0]) : ((RAW)->zString[0] == CHAR ? 0 : (RAW)->nByte - sizeof(char)))
  1079  
  1080  #define SX_ADDR(PTR)    ((sxptr)PTR)
  1081  #define SX_ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
  1082  #define SXUNUSED(P)	(P = 0)
  1083  #define	SX_EMPTY(PTR)   (PTR == 0)
  1084  #define SX_EMPTY_STR(STR) (STR == 0 || STR[0] == 0 )
  1085  typedef struct SyMemBackend SyMemBackend;
  1086  typedef struct SyBlob SyBlob;
  1087  typedef struct SySet SySet;
  1088  /* Standard function signatures */
  1089  typedef sxi32 (*ProcCmp)(const void *, const void *, sxu32);
  1090  typedef sxi32 (*ProcPatternMatch)(const char *, sxu32, const char *, sxu32, sxu32 *);
  1091  typedef sxi32 (*ProcSearch)(const void *, sxu32, const void *, sxu32, ProcCmp, sxu32 *);
  1092  typedef sxu32 (*ProcHash)(const void *, sxu32);
  1093  typedef sxi32 (*ProcHashSum)(const void *, sxu32, unsigned char *, sxu32);
  1094  typedef sxi32 (*ProcSort)(void *, sxu32, sxu32, ProcCmp);
  1095  #define MACRO_LIST_PUSH(Head, Item)\
  1096  	Item->pNext = Head;\
  1097  	Head = Item; 
  1098  #define MACRO_LD_PUSH(Head, Item)\
  1099  	if( Head == 0 ){\
  1100  		Head = Item;\
  1101  	}else{\
  1102  		Item->pNext = Head;\
  1103  		Head->pPrev = Item;\
  1104  		Head = Item;\
  1105  	}
  1106  #define MACRO_LD_REMOVE(Head, Item)\
  1107  	if( Head == Item ){\
  1108  		Head = Head->pNext;\
  1109  	}\
  1110  	if( Item->pPrev ){ Item->pPrev->pNext = Item->pNext;}\
  1111  	if( Item->pNext ){ Item->pNext->pPrev = Item->pPrev;}
  1112  /*
  1113   * A generic dynamic set.
  1114   */
  1115  struct SySet
  1116  {
  1117  	SyMemBackend *pAllocator; /* Memory backend */
  1118  	void *pBase;              /* Base pointer */	
  1119  	sxu32 nUsed;              /* Total number of used slots  */
  1120  	sxu32 nSize;              /* Total number of available slots */
  1121  	sxu32 eSize;              /* Size of a single slot */
  1122  	sxu32 nCursor;	          /* Loop cursor */	
  1123  	void *pUserData;          /* User private data associated with this container */
  1124  };
  1125  #define SySetBasePtr(S)           ((S)->pBase)
  1126  #define SySetBasePtrJump(S, OFFT)  (&((char *)(S)->pBase)[OFFT*(S)->eSize])
  1127  #define SySetUsed(S)              ((S)->nUsed)
  1128  #define SySetSize(S)              ((S)->nSize)
  1129  #define SySetElemSize(S)          ((S)->eSize) 
  1130  #define SySetCursor(S)            ((S)->nCursor)
  1131  #define SySetGetAllocator(S)      ((S)->pAllocator)
  1132  #define SySetSetUserData(S, DATA)  ((S)->pUserData = DATA)
  1133  #define SySetGetUserData(S)       ((S)->pUserData)
  1134  /*
  1135   * A variable length containers for generic data.
  1136   */
  1137  struct SyBlob
  1138  {
  1139  	SyMemBackend *pAllocator; /* Memory backend */
  1140  	void   *pBlob;	          /* Base pointer */
  1141  	sxu32  nByte;	          /* Total number of used bytes */
  1142  	sxu32  mByte;	          /* Total number of available bytes */
  1143  	sxu32  nFlags;	          /* Blob internal flags, see below */
  1144  };
  1145  #define SXBLOB_LOCKED	0x01	/* Blob is locked [i.e: Cannot auto grow] */
  1146  #define SXBLOB_STATIC	0x02	/* Not allocated from heap   */
  1147  #define SXBLOB_RDONLY   0x04    /* Read-Only data */
  1148  
  1149  #define SyBlobFreeSpace(BLOB)	 ((BLOB)->mByte - (BLOB)->nByte)
  1150  #define SyBlobLength(BLOB)	     ((BLOB)->nByte)
  1151  #define SyBlobData(BLOB)	     ((BLOB)->pBlob)
  1152  #define SyBlobCurData(BLOB)	     ((void*)(&((char*)(BLOB)->pBlob)[(BLOB)->nByte]))
  1153  #define SyBlobDataAt(BLOB, OFFT)	 ((void *)(&((char *)(BLOB)->pBlob)[OFFT]))
  1154  #define SyBlobGetAllocator(BLOB) ((BLOB)->pAllocator)
  1155  
  1156  #define SXMEM_POOL_INCR			3
  1157  #define SXMEM_POOL_NBUCKETS		12
  1158  #define SXMEM_BACKEND_MAGIC	0xBAC3E67D
  1159  #define SXMEM_BACKEND_CORRUPT(BACKEND)	(BACKEND == 0 || BACKEND->nMagic != SXMEM_BACKEND_MAGIC)
  1160  
  1161  #define SXMEM_BACKEND_RETRY	3
  1162  /* A memory backend subsystem is defined by an instance of the following structures */
  1163  typedef union SyMemHeader SyMemHeader;
  1164  typedef struct SyMemBlock SyMemBlock;
  1165  struct SyMemBlock
  1166  {
  1167  	SyMemBlock *pNext, *pPrev; /* Chain of allocated memory blocks */
  1168  #ifdef UNTRUST
  1169  	sxu32 nGuard;             /* magic number associated with each valid block, so we
  1170  							   * can detect misuse.
  1171  							   */
  1172  #endif
  1173  };
  1174  /*
  1175   * Header associated with each valid memory pool block.
  1176   */
  1177  union SyMemHeader
  1178  {
  1179  	SyMemHeader *pNext; /* Next chunk of size 1 << (nBucket + SXMEM_POOL_INCR) in the list */
  1180  	sxu32 nBucket;      /* Bucket index in aPool[] */
  1181  };
  1182  struct SyMemBackend
  1183  {
  1184  	const SyMutexMethods *pMutexMethods; /* Mutex methods */
  1185  	const SyMemMethods *pMethods;  /* Memory allocation methods */
  1186  	SyMemBlock *pBlocks;           /* List of valid memory blocks */
  1187  	sxu32 nBlock;                  /* Total number of memory blocks allocated so far */
  1188  	ProcMemError xMemError;        /* Out-of memory callback */
  1189  	void *pUserData;               /* First arg to xMemError() */
  1190  	SyMutex *pMutex;               /* Per instance mutex */
  1191  	sxu32 nMagic;                  /* Sanity check against misuse */
  1192  	SyMemHeader *apPool[SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR]; /* Pool of memory chunks */
  1193  };
  1194  /* Mutex types */
  1195  #define SXMUTEX_TYPE_FAST	1
  1196  #define SXMUTEX_TYPE_RECURSIVE	2
  1197  #define SXMUTEX_TYPE_STATIC_1	3
  1198  #define SXMUTEX_TYPE_STATIC_2	4
  1199  #define SXMUTEX_TYPE_STATIC_3	5
  1200  #define SXMUTEX_TYPE_STATIC_4	6
  1201  #define SXMUTEX_TYPE_STATIC_5	7
  1202  #define SXMUTEX_TYPE_STATIC_6	8
  1203  
  1204  #define SyMutexGlobalInit(METHOD){\
  1205  	if( (METHOD)->xGlobalInit ){\
  1206  	(METHOD)->xGlobalInit();\
  1207  	}\
  1208  }
  1209  #define SyMutexGlobalRelease(METHOD){\
  1210  	if( (METHOD)->xGlobalRelease ){\
  1211  	(METHOD)->xGlobalRelease();\
  1212  	}\
  1213  }
  1214  #define SyMutexNew(METHOD, TYPE)			(METHOD)->xNew(TYPE)
  1215  #define SyMutexRelease(METHOD, MUTEX){\
  1216  	if( MUTEX && (METHOD)->xRelease ){\
  1217  		(METHOD)->xRelease(MUTEX);\
  1218  	}\
  1219  }
  1220  #define SyMutexEnter(METHOD, MUTEX){\
  1221  	if( MUTEX ){\
  1222  	(METHOD)->xEnter(MUTEX);\
  1223  	}\
  1224  }
  1225  #define SyMutexTryEnter(METHOD, MUTEX){\
  1226  	if( MUTEX && (METHOD)->xTryEnter ){\
  1227  	(METHOD)->xTryEnter(MUTEX);\
  1228  	}\
  1229  }
  1230  #define SyMutexLeave(METHOD, MUTEX){\
  1231  	if( MUTEX ){\
  1232  	(METHOD)->xLeave(MUTEX);\
  1233  	}\
  1234  }
  1235  /* Comparison, byte swap, byte copy macros */
  1236  #define SX_MACRO_FAST_CMP(X1, X2, SIZE, RC){\
  1237  	register unsigned char *r1 = (unsigned char *)X1;\
  1238  	register unsigned char *r2 = (unsigned char *)X2;\
  1239  	register sxu32 LEN = SIZE;\
  1240  	for(;;){\
  1241  	  if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
  1242  	  if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
  1243  	  if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
  1244  	  if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\
  1245  	}\
  1246  	RC = !LEN ? 0 : r1[0] - r2[0];\
  1247  }
  1248  #define	SX_MACRO_FAST_MEMCPY(SRC, DST, SIZ){\
  1249  	register unsigned char *xSrc = (unsigned char *)SRC;\
  1250  	register unsigned char *xDst = (unsigned char *)DST;\
  1251  	register sxu32 xLen = SIZ;\
  1252  	for(;;){\
  1253  	    if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
  1254  		if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
  1255  		if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
  1256  		if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\
  1257  	}\
  1258  }
  1259  #define SX_MACRO_BYTE_SWAP(X, Y, Z){\
  1260  	register unsigned char *s = (unsigned char *)X;\
  1261  	register unsigned char *d = (unsigned char *)Y;\
  1262  	sxu32	ZLong = Z;  \
  1263  	sxi32 c; \
  1264  	for(;;){\
  1265  	  if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
  1266  	  if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
  1267  	  if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
  1268  	  if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\
  1269  	}\
  1270  }
  1271  #define SX_MSEC_PER_SEC	(1000)			/* Millisec per seconds */
  1272  #define SX_USEC_PER_SEC	(1000000)		/* Microsec per seconds */
  1273  #define SX_NSEC_PER_SEC	(1000000000)	/* Nanosec per seconds */
  1274  #endif /* SYMISC_PRIVATE_DEFS */
  1275  /* Symisc Run-time API auxiliary definitions */
  1276  #if !defined(SYMISC_PRIVATE_AUX_DEFS)
  1277  #define SYMISC_PRIVATE_AUX_DEFS
  1278  
  1279  typedef struct SyHashEntry_Pr SyHashEntry_Pr;
  1280  typedef struct SyHashEntry SyHashEntry;
  1281  typedef struct SyHash SyHash;
  1282  /*
  1283   * Each public hashtable entry is represented by an instance
  1284   * of the following structure.
  1285   */
  1286  struct SyHashEntry
  1287  {
  1288  	const void *pKey; /* Hash key */
  1289  	sxu32 nKeyLen;    /* Key length */
  1290  	void *pUserData;  /* User private data */
  1291  };
  1292  #define SyHashEntryGetUserData(ENTRY) ((ENTRY)->pUserData)
  1293  #define SyHashEntryGetKey(ENTRY)      ((ENTRY)->pKey)
  1294  /* Each active hashtable is identified by an instance of the following structure */
  1295  struct SyHash
  1296  {
  1297  	SyMemBackend *pAllocator;         /* Memory backend */
  1298  	ProcHash xHash;                   /* Hash function */
  1299  	ProcCmp xCmp;                     /* Comparison function */
  1300  	SyHashEntry_Pr *pList, *pCurrent;  /* Linked list of hash entries user for linear traversal */
  1301  	sxu32 nEntry;                     /* Total number of entries */
  1302  	SyHashEntry_Pr **apBucket;        /* Hash buckets */
  1303  	sxu32 nBucketSize;                /* Current bucket size */
  1304  };
  1305  #define SXHASH_BUCKET_SIZE 16 /* Initial bucket size: must be a power of two */
  1306  #define SXHASH_FILL_FACTOR 3
  1307  /* Hash access macro */
  1308  #define SyHashFunc(HASH)		((HASH)->xHash)
  1309  #define SyHashCmpFunc(HASH)		((HASH)->xCmp)
  1310  #define SyHashTotalEntry(HASH)	((HASH)->nEntry)
  1311  #define SyHashGetPool(HASH)		((HASH)->pAllocator)
  1312  /*
  1313   * An instance of the following structure define a single context
  1314   * for an Pseudo Random Number Generator.
  1315   *
  1316   * Nothing in this file or anywhere else in the library does any kind of
  1317   * encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
  1318   * number generator) not as an encryption device.
  1319   * This implementation is taken from the SQLite3 source tree.
  1320   */
  1321  typedef struct SyPRNGCtx SyPRNGCtx;
  1322  struct SyPRNGCtx
  1323  {
  1324      sxu8 i, j;				/* State variables */
  1325      unsigned char s[256];   /* State variables */
  1326  	sxu16 nMagic;			/* Sanity check */
  1327   };
  1328  typedef sxi32 (*ProcRandomSeed)(void *, unsigned int, void *);
  1329  /* High resolution timer.*/
  1330  typedef struct sytime sytime;
  1331  struct sytime
  1332  {
  1333  	long tm_sec;	/* seconds */
  1334  	long tm_usec;	/* microseconds */
  1335  };
  1336  /* Forward declaration */
  1337  typedef struct SyStream SyStream;
  1338  typedef struct SyToken  SyToken;
  1339  typedef struct SyLex    SyLex;
  1340  /*
  1341   * Tokenizer callback signature.
  1342   */
  1343  typedef sxi32 (*ProcTokenizer)(SyStream *, SyToken *, void *, void *);
  1344  /*
  1345   * Each token in the input is represented by an instance
  1346   * of the following structure.
  1347   */
  1348  struct SyToken
  1349  {
  1350  	SyString sData;  /* Token text and length */
  1351  	sxu32 nType;     /* Token type */
  1352  	sxu32 nLine;     /* Token line number */
  1353  	void *pUserData; /* User private data associated with this token */
  1354  };
  1355  /*
  1356   * During tokenization, information about the state of the input
  1357   * stream is held in an instance of the following structure.
  1358   */
  1359  struct SyStream
  1360  {
  1361  	const unsigned char *zInput; /* Complete text of the input */
  1362  	const unsigned char *zText; /* Current input we are processing */	
  1363  	const unsigned char *zEnd; /* End of input marker */
  1364  	sxu32  nLine; /* Total number of processed lines */
  1365  	sxu32  nIgn; /* Total number of ignored tokens */
  1366  	SySet *pSet; /* Token containers */
  1367  };
  1368  /*
  1369   * Each lexer is represented by an instance of the following structure.
  1370   */
  1371  struct SyLex
  1372  {
  1373  	SyStream sStream;         /* Input stream */
  1374  	ProcTokenizer xTokenizer; /* Tokenizer callback */
  1375  	void * pUserData;         /* Third argument to xTokenizer() */
  1376  	SySet *pTokenSet;         /* Token set */
  1377  };
  1378  #define SyLexTotalToken(LEX)    SySetTotalEntry(&(LEX)->aTokenSet)
  1379  #define SyLexTotalLines(LEX)    ((LEX)->sStream.nLine)
  1380  #define SyLexTotalIgnored(LEX)  ((LEX)->sStream.nIgn)
  1381  #define XLEX_IN_LEN(STREAM)     (sxu32)(STREAM->zEnd - STREAM->zText)
  1382  #endif /* SYMISC_PRIVATE_AUX_DEFS */
  1383  /*
  1384  ** Notes on UTF-8 (According to SQLite3 authors):
  1385  **
  1386  **   Byte-0    Byte-1    Byte-2    Byte-3    Value
  1387  **  0xxxxxxx                                 00000000 00000000 0xxxxxxx
  1388  **  110yyyyy  10xxxxxx                       00000000 00000yyy yyxxxxxx
  1389  **  1110zzzz  10yyyyyy  10xxxxxx             00000000 zzzzyyyy yyxxxxxx
  1390  **  11110uuu  10uuzzzz  10yyyyyy  10xxxxxx   000uuuuu zzzzyyyy yyxxxxxx
  1391  **
  1392  */
  1393  /*
  1394  ** Assuming zIn points to the first byte of a UTF-8 character, 
  1395  ** advance zIn to point to the first byte of the next UTF-8 character.
  1396  */
  1397  #define SX_JMP_UTF8(zIn, zEnd)\
  1398  	while(zIn < zEnd && (((unsigned char)zIn[0] & 0xc0) == 0x80) ){ zIn++; }
  1399  #define SX_WRITE_UTF8(zOut, c) {                       \
  1400    if( c<0x00080 ){                                     \
  1401      *zOut++ = (sxu8)(c&0xFF);                          \
  1402    }else if( c<0x00800 ){                               \
  1403      *zOut++ = 0xC0 + (sxu8)((c>>6)&0x1F);              \
  1404      *zOut++ = 0x80 + (sxu8)(c & 0x3F);                 \
  1405    }else if( c<0x10000 ){                               \
  1406      *zOut++ = 0xE0 + (sxu8)((c>>12)&0x0F);             \
  1407      *zOut++ = 0x80 + (sxu8)((c>>6) & 0x3F);            \
  1408      *zOut++ = 0x80 + (sxu8)(c & 0x3F);                 \
  1409    }else{                                               \
  1410      *zOut++ = 0xF0 + (sxu8)((c>>18) & 0x07);           \
  1411      *zOut++ = 0x80 + (sxu8)((c>>12) & 0x3F);           \
  1412      *zOut++ = 0x80 + (sxu8)((c>>6) & 0x3F);            \
  1413      *zOut++ = 0x80 + (sxu8)(c & 0x3F);                 \
  1414    }                                                    \
  1415  }
  1416  /* Rely on the standard ctype */
  1417  #include <ctype.h>
  1418  #define SyToUpper(c) toupper(c) 
  1419  #define SyToLower(c) tolower(c) 
  1420  #define SyisUpper(c) isupper(c)
  1421  #define SyisLower(c) islower(c)
  1422  #define SyisSpace(c) isspace(c)
  1423  #define SyisBlank(c) isspace(c)
  1424  #define SyisAlpha(c) isalpha(c)
  1425  #define SyisDigit(c) isdigit(c)
  1426  #define SyisHex(c)	 isxdigit(c)
  1427  #define SyisPrint(c) isprint(c)
  1428  #define SyisPunct(c) ispunct(c)
  1429  #define SyisSpec(c)	 iscntrl(c)
  1430  #define SyisCtrl(c)	 iscntrl(c)
  1431  #define SyisAscii(c) isascii(c)
  1432  #define SyisAlphaNum(c) isalnum(c)
  1433  #define SyisGraph(c)     isgraph(c)
  1434  #define SyDigToHex(c)    "0123456789ABCDEF"[c & 0x0F] 		
  1435  #define SyDigToInt(c)     ((c < 0xc0 && SyisDigit(c))? (c - '0') : 0 )
  1436  #define SyCharToUpper(c)  ((c < 0xc0 && SyisLower(c))? SyToUpper(c) : c)
  1437  #define SyCharToLower(c)  ((c < 0xc0 && SyisUpper(c))? SyToLower(c) : c)
  1438  /* Remove white space/NUL byte from a raw string */
  1439  #define SyStringLeftTrim(RAW)\
  1440  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && SyisSpace((RAW)->zString[0])){\
  1441  		(RAW)->nByte--;\
  1442  		(RAW)->zString++;\
  1443  	}
  1444  #define SyStringLeftTrimSafe(RAW)\
  1445  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && ((RAW)->zString[0] == 0 || SyisSpace((RAW)->zString[0]))){\
  1446  		(RAW)->nByte--;\
  1447  		(RAW)->zString++;\
  1448  	}
  1449  #define SyStringRightTrim(RAW)\
  1450  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0  && SyisSpace((RAW)->zString[(RAW)->nByte - 1])){\
  1451  		(RAW)->nByte--;\
  1452  	}
  1453  #define SyStringRightTrimSafe(RAW)\
  1454  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0  && \
  1455  	(( RAW)->zString[(RAW)->nByte - 1] == 0 || SyisSpace((RAW)->zString[(RAW)->nByte - 1]))){\
  1456  		(RAW)->nByte--;\
  1457  	}
  1458  
  1459  #define SyStringFullTrim(RAW)\
  1460  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0  && SyisSpace((RAW)->zString[0])){\
  1461  		(RAW)->nByte--;\
  1462  		(RAW)->zString++;\
  1463  	}\
  1464  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0  && SyisSpace((RAW)->zString[(RAW)->nByte - 1])){\
  1465  		(RAW)->nByte--;\
  1466  	}
  1467  #define SyStringFullTrimSafe(RAW)\
  1468  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0  && \
  1469            ( (RAW)->zString[0] == 0 || SyisSpace((RAW)->zString[0]))){\
  1470  		(RAW)->nByte--;\
  1471  		(RAW)->zString++;\
  1472  	}\
  1473  	while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0  && \
  1474                     ( (RAW)->zString[(RAW)->nByte - 1] == 0 || SyisSpace((RAW)->zString[(RAW)->nByte - 1]))){\
  1475  		(RAW)->nByte--;\
  1476  	}
  1477  
  1478  #ifndef VEDIS_DISABLE_HASH_FUNC
  1479  /* MD5 context */
  1480  typedef struct MD5Context MD5Context;
  1481  struct MD5Context {
  1482   sxu32 buf[4];
  1483   sxu32 bits[2];
  1484   unsigned char in[64];
  1485  };
  1486  /* SHA1 context */
  1487  typedef struct SHA1Context SHA1Context;
  1488  struct SHA1Context {
  1489    unsigned int state[5];
  1490    unsigned int count[2];
  1491    unsigned char buffer[64];
  1492  };
  1493  #endif /* VEDIS_DISABLE_HASH_FUNC */
  1494  /*
  1495  ** The following values may be passed as the second argument to
  1496  ** UnqliteOsLock(). The various locks exhibit the following semantics:
  1497  **
  1498  ** SHARED:    Any number of processes may hold a SHARED lock simultaneously.
  1499  ** RESERVED:  A single process may hold a RESERVED lock on a file at
  1500  **            any time. Other processes may hold and obtain new SHARED locks.
  1501  ** PENDING:   A single process may hold a PENDING lock on a file at
  1502  **            any one time. Existing SHARED locks may persist, but no new
  1503  **            SHARED locks may be obtained by other processes.
  1504  ** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
  1505  **
  1506  ** PENDING_LOCK may not be passed directly to UnqliteOsLock(). Instead, a
  1507  ** process that requests an EXCLUSIVE lock may actually obtain a PENDING
  1508  ** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
  1509  ** UnqliteOsLock().
  1510  */
  1511  #define NO_LOCK         0
  1512  #define SHARED_LOCK     1
  1513  #define RESERVED_LOCK   2
  1514  #define PENDING_LOCK    3
  1515  #define EXCLUSIVE_LOCK  4
  1516  /*
  1517   * Vedis Locking Strategy (Same as SQLite3)
  1518   *
  1519   * The following #defines specify the range of bytes used for locking.
  1520   * SHARED_SIZE is the number of bytes available in the pool from which
  1521   * a random byte is selected for a shared lock.  The pool of bytes for
  1522   * shared locks begins at SHARED_FIRST. 
  1523   *
  1524   * The same locking strategy and byte ranges are used for Unix and Windows.
  1525   * This leaves open the possiblity of having clients on winNT, and
  1526   * unix all talking to the same shared file and all locking correctly.
  1527   * To do so would require that samba (or whatever
  1528   * tool is being used for file sharing) implements locks correctly between
  1529   * windows and unix.  I'm guessing that isn't likely to happen, but by
  1530   * using the same locking range we are at least open to the possibility.
  1531   *
  1532   * Locking in windows is mandatory.  For this reason, we cannot store
  1533   * actual data in the bytes used for locking.  The pager never allocates
  1534   * the pages involved in locking therefore.  SHARED_SIZE is selected so
  1535   * that all locks will fit on a single page even at the minimum page size.
  1536   * PENDING_BYTE defines the beginning of the locks.  By default PENDING_BYTE
  1537   * is set high so that we don't have to allocate an unused page except
  1538   * for very large databases.  But one should test the page skipping logic 
  1539   * by setting PENDING_BYTE low and running the entire regression suite.
  1540   *
  1541   * Changing the value of PENDING_BYTE results in a subtly incompatible
  1542   * file format.  Depending on how it is changed, you might not notice
  1543   * the incompatibility right away, even running a full regression test.
  1544   * The default location of PENDING_BYTE is the first byte past the
  1545   * 1GB boundary.
  1546   */
  1547  #define PENDING_BYTE     (0x40000000)
  1548  #define RESERVED_BYTE    (PENDING_BYTE+1)
  1549  #define SHARED_FIRST     (PENDING_BYTE+2)
  1550  #define SHARED_SIZE      510
  1551  /*
  1552   * The default size of a disk sector in bytes.
  1553   */
  1554  #ifndef VEDIS_DEFAULT_SECTOR_SIZE
  1555  #define VEDIS_DEFAULT_SECTOR_SIZE 512
  1556  #endif
  1557  /* Forward declaration */
  1558  typedef struct vedis_hashmap_node vedis_hashmap_node;
  1559  typedef struct vedis_hashmap vedis_hashmap;
  1560  /* Forward declaration */
  1561  typedef struct vedis_table_entry vedis_table_entry;
  1562  typedef struct vedis_table vedis_table;
  1563  typedef struct Bitvec Bitvec;
  1564  /*
  1565   * Each open database file is managed by a separate instance
  1566   * of the "Pager" structure.
  1567   */
  1568  typedef struct Pager Pager;
  1569  /*
  1570   * Memory Objects.
  1571   * Internally, the Vedis engine manipulates nearly all vedis values
  1572   * [i.e: string, int, float, bool, null] as vedis_values structures.
  1573   * Each vedis_values struct may cache multiple representations (string, integer etc.)
  1574   * of the same value.
  1575   */
  1576  struct vedis_value
  1577  {
  1578  	union{
  1579  		vedis_real rVal;      /* Real value */
  1580  		sxi64 iVal;       /* Integer value */
  1581  		void *pOther;     /* Other values (Hashmap etc.) */
  1582  	}x;
  1583  	sxi32 iFlags;       /* Control flags (see below) */
  1584  	SyBlob sBlob;       /* Blob values (Warning: Must be last field in this structure) */
  1585  };
  1586  /* Allowed value types.
  1587   */
  1588  #define MEMOBJ_STRING    0x001  /* Memory value is a UTF-8/Binary stream */
  1589  #define MEMOBJ_INT       0x002  /* Memory value is an integer */
  1590  #define MEMOBJ_REAL      0x004  /* Memory value is a real number */
  1591  #define MEMOBJ_BOOL      0x008  /* Memory value is a boolean */
  1592  #define MEMOBJ_NULL      0x020  /* Memory value is NULL */
  1593  #define MEMOBJ_HASHMAP   0x040  /* Memory value is a hashmap  */
  1594  /* Mask of all known types */
  1595  #define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP) 
  1596  /*
  1597   * The following macro clear the current vedis_value type and replace
  1598   * it with the given one.
  1599   */
  1600  #define MemObjSetType(OBJ, TYPE) ((OBJ)->iFlags = ((OBJ)->iFlags&~MEMOBJ_ALL)|TYPE)
  1601  #define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL)
  1602  /* vedis cast method signature */
  1603  typedef sxi32 (*ProcMemObjCast)(vedis_value *);
  1604  /*
  1605   * Auxiliary data associated with each foreign command is stored
  1606   * in a stack of the following structure.
  1607   * Note that automatic tracked chunks are also stored in an instance
  1608   * of this structure.
  1609   */
  1610  typedef struct vedis_aux_data vedis_aux_data;
  1611  struct vedis_aux_data
  1612  {
  1613  	void *pAuxData; /* Aux data */
  1614  };
  1615  /*
  1616   * Each registered vedis command is represented by an instance of the following
  1617   * structure.
  1618   */
  1619  typedef int (*ProcVedisCmd)(vedis_context *,int,vedis_value **);
  1620  typedef struct vedis_cmd vedis_cmd;
  1621  struct vedis_cmd
  1622  {
  1623  	SyString sName;       /* Command name */
  1624  	sxu32 nHash;          /* Hash of the command name */
  1625  	ProcVedisCmd xCmd;    /* Command implementation */
  1626  	SySet aAux;           /* Stack of auxiliary data */
  1627  	void *pUserData;      /* Command private data */
  1628  	vedis_cmd *pNext,*pPrev; /* Pointer to other commands in the chaine */
  1629  	vedis_cmd *pNextCol,*pPrevCol; /* Collision chain */
  1630  };
  1631  /*
  1632   * The 'context' argument for an installable commands. A pointer to an
  1633   * instance of this structure is the first argument to the routines used
  1634   * implement the vedis commands.
  1635   */
  1636  struct vedis_context
  1637  {
  1638  	vedis *pVedis;       /* Vedis handle */
  1639  	vedis_cmd *pCmd;     /* Executed vedis command */
  1640  	SyBlob sWorker;      /* Working buffer */
  1641  	vedis_value *pRet;   /* Return value is stored here. */
  1642  	SySet sVar;          /* Container of dynamically allocated vedis_values
  1643  						  * [i.e: Garbage collection purposes.]
  1644  						  */
  1645  };
  1646  /*
  1647   * Command output consumer callback.
  1648   */
  1649  typedef int (*ProcCmdConsumer)(vedis_value *,void *);
  1650  /*
  1651   * Each datastore connection is an instance of the following structure.
  1652   */
  1653  struct vedis
  1654  {
  1655  	SyMemBackend sMem;               /* Memory allocator subsystem */
  1656  	SyBlob sErr;                     /* Error log */
  1657  	Pager *pPager;                   /* Storage backend */
  1658  	vedis_kv_cursor *pCursor;        /* General purpose database cursor */
  1659  	vedis_cmd **apCmd;               /* Table of vedis command */
  1660  	sxu32 nSize;                     /* Table size */
  1661  	sxu32 nCmd;                      /* Total number of installed vedis commands */
  1662  	vedis_cmd *pList;                /* List of vedis command */
  1663  	vedis_table **apTable;           /* Loaded vedis tables */
  1664  	sxu32 nTableSize;                /* apTable[] size */
  1665  	sxu32 nTable;                    /* apTable[] length */
  1666  	vedis_table *pTableList;         /* List of vedis tables loaded in memory */
  1667  #if defined(VEDIS_ENABLE_THREADS)
  1668  	const SyMutexMethods *pMethods;  /* Mutex methods */
  1669  	SyMutex *pMutex;                 /* Per-handle mutex */
  1670  #endif
  1671  	ProcCmdConsumer xResultConsumer; /* Result consumer callback */
  1672  	void *pUserData;                 /* Last argument to xResultConsumer() */
  1673  	vedis_value sResult;             /* Execution result of the last executed command */
  1674  	sxi32 iFlags;                    /* Control flags (See below)  */
  1675  	vedis *pNext,*pPrev;             /* List of active handles */
  1676  	sxu32 nMagic;                    /* Sanity check against misuse */
  1677  };
  1678  #define VEDIS_FL_DISABLE_AUTO_COMMIT   0x001 /* Disable auto-commit on close */
  1679  /*
  1680   * Vedis Token
  1681   * The following set of constants are the tokens recognized
  1682   * by the lexer when processing input.
  1683   * Important: Token values MUST BE A POWER OF TWO.
  1684   */
  1685  #define VEDIS_TK_INTEGER   0x0000001  /* Integer */
  1686  #define VEDIS_TK_REAL      0x0000002  /* Real number */
  1687  #define VEDIS_TK_NUM       (VEDIS_TK_INTEGER|VEDIS_TK_REAL) /* Numeric token, either integer or real */
  1688  #define VEDIS_TK_STREAM    0x0000004 /* UTF-8/Binary stream */
  1689  #define VEDIS_TK_SEMI      0x0000008 /* ';' semi-colon */
  1690  /* 
  1691   * Database signature to identify a valid database image.
  1692   */
  1693  #define VEDIS_DB_SIG "SymiscVedis"
  1694  /*
  1695   * Database magic number (4 bytes).
  1696   */
  1697  #define VEDIS_DB_MAGIC   0xCA1DB634
  1698  /*
  1699   * Maximum page size in bytes.
  1700   */
  1701  #ifdef VEDIS_MAX_PAGE_SIZE
  1702  # undef VEDIS_MAX_PAGE_SIZE
  1703  #endif
  1704  #define VEDIS_MAX_PAGE_SIZE 65536 /* 65K */
  1705  /*
  1706   * Minimum page size in bytes.
  1707   */
  1708  #ifdef VEDIS_MIN_PAGE_SIZE
  1709  # undef VEDIS_MIN_PAGE_SIZE
  1710  #endif
  1711  #define VEDIS_MIN_PAGE_SIZE 512
  1712  /*
  1713   * The default size of a database page.
  1714   */
  1715  #ifndef VEDIS_DEFAULT_PAGE_SIZE
  1716  # undef VEDIS_DEFAULT_PAGE_SIZE
  1717  #endif
  1718  # define VEDIS_DEFAULT_PAGE_SIZE 4096 /* 4K */
  1719  /*
  1720   * These bit values are intended for use in the 3rd parameter to the [vedis_open()] interface
  1721   * and in the 4th parameter to the xOpen method of the [vedis_vfs] object.
  1722   */
  1723  #define VEDIS_OPEN_READONLY         0x00000001  /* Read only mode. Ok for [vedis_open] */
  1724  #define VEDIS_OPEN_READWRITE        0x00000002  /* Ok for [vedis_open] */
  1725  #define VEDIS_OPEN_CREATE           0x00000004  /* Ok for [vedis_open] */
  1726  #define VEDIS_OPEN_EXCLUSIVE        0x00000008  /* VFS only */
  1727  #define VEDIS_OPEN_TEMP_DB          0x00000010  /* VFS only */
  1728  #define VEDIS_OPEN_NOMUTEX          0x00000020  /* Ok for [vedis_open] */
  1729  #define VEDIS_OPEN_OMIT_JOURNALING  0x00000040  /* Omit journaling for this database. Ok for [vedis_open] */
  1730  #define VEDIS_OPEN_IN_MEMORY        0x00000080  /* An in memory database. Ok for [vedis_open]*/
  1731  #define VEDIS_OPEN_MMAP             0x00000100  /* Obtain a memory view of the whole file. Ok for [vedis_open] */
  1732  /*
  1733   * Each vedis table (i.e.: Hash, Set, List, etc.) is identified by an instance
  1734   * of the following structure.
  1735   */
  1736  struct vedis_table_entry
  1737  {
  1738  	vedis_table *pTable; /* Table that own this entry */
  1739  	sxi32 iType;           /* Node type */
  1740  	union{
  1741  		sxi64 iKey;        /* Int key */
  1742  		SyBlob sKey;       /* Blob key */
  1743  	}xKey;
  1744  	sxi32 iFlags;          /* Control flags */
  1745  	sxu32 nHash;           /* Key hash value */
  1746  	SyBlob sData;          /* Data */
  1747  	sxu32 nId;             /* Unique ID associated with this entry */
  1748  	vedis_table_entry *pNext,*pPrev; 
  1749  	vedis_table_entry *pNextCollide,*pPrevCollide;
  1750  };
  1751  /* Allowed node types */
  1752  #define VEDIS_TABLE_ENTRY_INT_NODE    1  /* Node with an int [i.e: 64-bit integer] key */
  1753  #define VEDIS_TABLE_ENTRY_BLOB_NODE  2  /* Node with a string/BLOB key */
  1754  /*
  1755   * Supported Vedis Data Structures.
  1756   */
  1757  #define VEDIS_TABLE_HASH 1
  1758  #define VEDIS_TABLE_SET  2
  1759  #define VEDIS_TABLE_LIST 3
  1760  /* hashmap.c */
  1761  VEDIS_PRIVATE sxu32 vedisHashmapCount(vedis_hashmap *pMap);
  1762  VEDIS_PRIVATE sxi32 vedisHashmapWalk(
  1763  	vedis_hashmap *pMap, /* Target hashmap */
  1764  	int (*xWalk)(vedis_value *, void *), /* Walker callback */
  1765  	void *pUserData /* Last argument to xWalk() */
  1766  	);
  1767  VEDIS_PRIVATE void vedisHashmapResetLoopCursor(vedis_hashmap *pMap);
  1768  VEDIS_PRIVATE vedis_value * vedisHashmapGetNextEntry(vedis_hashmap *pMap);
  1769  VEDIS_PRIVATE vedis_hashmap * vedisNewHashmap(
  1770  	vedis *pStore,             /* Engine that trigger the hashmap creation */
  1771  	sxu32 (*xIntHash)(sxi64), /* Hash function for int keys.NULL otherwise*/
  1772  	sxu32 (*xBlobHash)(const void *, sxu32) /* Hash function for BLOB keys.NULL otherwise */
  1773  	);
  1774  VEDIS_PRIVATE void vedisHashmapRef(vedis_hashmap *pMap);
  1775  VEDIS_PRIVATE void vedisHashmapUnref(vedis_hashmap *pMap);
  1776  VEDIS_PRIVATE vedis * vedisHashmapGetEngine(vedis_hashmap *pMap);
  1777  VEDIS_PRIVATE sxi32 vedisHashmapLookup(
  1778  	vedis_hashmap *pMap,        /* Target hashmap */
  1779  	vedis_value *pKey,          /* Lookup key */
  1780  	vedis_value **ppOut /* OUT: Target node on success */
  1781  	);
  1782  VEDIS_PRIVATE sxi32 vedisHashmapInsert(
  1783  	vedis_hashmap *pMap, /* Target hashmap */
  1784  	vedis_value *pKey,   /* Lookup key */
  1785  	vedis_value *pVal    /* Node value.NULL otherwise */
  1786  	);
  1787  /* zSet.c */
  1788  VEDIS_PRIVATE void vedisTableReset(vedis_table *pTable);
  1789  VEDIS_PRIVATE int VedisRemoveTableEntry(vedis_table *pTable,vedis_table_entry *pEntry);
  1790  VEDIS_PRIVATE vedis_table_entry * vedisTableFirstEntry(vedis_table *pTable);
  1791  VEDIS_PRIVATE vedis_table_entry * vedisTableLastEntry(vedis_table *pTable);
  1792  VEDIS_PRIVATE vedis_table_entry * vedisTableNextEntry(vedis_table *pTable);
  1793  VEDIS_PRIVATE sxu32 vedisTableLength(vedis_table *pTable);
  1794  VEDIS_PRIVATE vedis_table * vedisFetchTable(vedis *pDb,vedis_value *pName,int create_new,int iType);
  1795  VEDIS_PRIVATE vedis_table_entry * vedisTableGetRecordByIndex(vedis_table *pTable,sxu32 nIndex);
  1796  VEDIS_PRIVATE vedis_table_entry * vedisTableGetRecord(vedis_table *pTable,vedis_value *pKey);
  1797  VEDIS_PRIVATE int vedisTableInsertRecord(vedis_table *pTable,vedis_value *pKey,vedis_value *pData);
  1798  VEDIS_PRIVATE int vedisTableDeleteRecord(vedis_table *pTable,vedis_value *pKey);
  1799  VEDIS_PRIVATE  vedis_table * vedisTableChain(vedis_table *pEntry);
  1800  VEDIS_PRIVATE  SyString * vedisTableName(vedis_table *pEntry);
  1801  VEDIS_PRIVATE int vedisOnCommit(void *pUserData);
  1802  /* cmd.c */
  1803  VEDIS_PRIVATE int vedisRegisterBuiltinCommands(vedis *pVedis);
  1804  /* json.c */
  1805  VEDIS_PRIVATE int vedisJsonSerialize(vedis_value *pValue,SyBlob *pOut);
  1806  /* obj.c */
  1807  VEDIS_PRIVATE void vedisMemObjInit(vedis *pVedis,vedis_value *pObj);
  1808  VEDIS_PRIVATE sxi32 vedisMemObjInitFromString(vedis *pStore, vedis_value *pObj, const SyString *pVal);
  1809  VEDIS_PRIVATE sxi32 vedisMemObjInitFromInt(vedis *pStore, vedis_value *pObj, sxi64 iVal);
  1810  VEDIS_PRIVATE vedis_value * vedisNewObjectValue(vedis *pVedis,SyToken *pToken);
  1811  VEDIS_PRIVATE vedis_value * vedisNewObjectArrayValue(vedis *pVedis);
  1812  VEDIS_PRIVATE void vedisObjectValueDestroy(vedis *pVedis,vedis_value *pValue);
  1813  VEDIS_PRIVATE SyBlob * vedisObjectValueBlob(vedis_value *pValue);
  1814  VEDIS_PRIVATE sxi32 vedisMemObjRelease(vedis_value *pObj);
  1815  VEDIS_PRIVATE sxi32 vedisMemObjTryInteger(vedis_value *pObj);
  1816  VEDIS_PRIVATE sxi32 vedisMemObjIsNumeric(vedis_value *pObj);
  1817  VEDIS_PRIVATE sxi32 vedisMemObjToInteger(vedis_value *pObj);
  1818  VEDIS_PRIVATE sxi32 vedisMemObjToReal(vedis_value *pObj);
  1819  VEDIS_PRIVATE sxi32 vedisMemObjToBool(vedis_value *pObj);
  1820  VEDIS_PRIVATE sxi32 vedisMemObjToString(vedis_value *pObj);
  1821  VEDIS_PRIVATE sxi32 vedisMemObjToNull(vedis_value *pObj);
  1822  VEDIS_PRIVATE sxi32 vedisMemObjStore(vedis_value *pSrc, vedis_value *pDest);
  1823  /* parse.c */
  1824  VEDIS_PRIVATE int vedisProcessInput(vedis *pVedis,const char *zInput,sxu32 nByte);
  1825  VEDIS_PRIVATE SyBlob * VedisContextResultBuffer(vedis_context *pCtx);
  1826  VEDIS_PRIVATE SyBlob * VedisContextWorkingBuffer(vedis_context *pCtx);
  1827  /* api.c */
  1828  VEDIS_PRIVATE const SyMemBackend * vedisExportMemBackend(void);
  1829  VEDIS_PRIVATE int vedisKvFetchCallback(vedis *pStore,const void *pKey,int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData);
  1830  VEDIS_PRIVATE int vedisKvDelete(vedis *pStore,const void *pKey,int nKeyLen);
  1831  VEDIS_PRIVATE int vedisDataConsumer(
  1832  	const void *pOut,   /* Data to consume */
  1833  	unsigned int nLen,  /* Data length */
  1834  	void *pUserData     /* User private data */
  1835  	);
  1836  VEDIS_PRIVATE vedis_kv_methods * vedisFindKVStore(
  1837  	const char *zName, /* Storage engine name [i.e. Hash, B+tree, LSM, etc.] */
  1838  	sxu32 nByte        /* zName length */
  1839  	);
  1840  VEDIS_PRIVATE int vedisGetPageSize(void);
  1841  VEDIS_PRIVATE int vedisGenError(vedis *pDb,const char *zErr);
  1842  VEDIS_PRIVATE int vedisGenErrorFormat(vedis *pDb,const char *zFmt,...);
  1843  VEDIS_PRIVATE int vedisGenOutofMem(vedis *pDb);
  1844  VEDIS_PRIVATE vedis_cmd * vedisFetchCommand(vedis *pVedis,SyString *pName);
  1845  /* vfs.c [io_win.c, io_unix.c ] */
  1846  VEDIS_PRIVATE const vedis_vfs * vedisExportBuiltinVfs(void);
  1847  /* mem_kv.c */
  1848  VEDIS_PRIVATE const vedis_kv_methods * vedisExportMemKvStorage(void);
  1849  /* lhash_kv.c */
  1850  VEDIS_PRIVATE const vedis_kv_methods * vedisExportDiskKvStorage(void);
  1851  /* os.c */
  1852  VEDIS_PRIVATE int vedisOsRead(vedis_file *id, void *pBuf, vedis_int64 amt, vedis_int64 offset);
  1853  VEDIS_PRIVATE int vedisOsWrite(vedis_file *id, const void *pBuf, vedis_int64 amt, vedis_int64 offset);
  1854  VEDIS_PRIVATE int vedisOsTruncate(vedis_file *id, vedis_int64 size);
  1855  VEDIS_PRIVATE int vedisOsSync(vedis_file *id, int flags);
  1856  VEDIS_PRIVATE int vedisOsFileSize(vedis_file *id, vedis_int64 *pSize);
  1857  VEDIS_PRIVATE int vedisOsLock(vedis_file *id, int lockType);
  1858  VEDIS_PRIVATE int vedisOsUnlock(vedis_file *id, int lockType);
  1859  VEDIS_PRIVATE int vedisOsCheckReservedLock(vedis_file *id, int *pResOut);
  1860  VEDIS_PRIVATE int vedisOsSectorSize(vedis_file *id);
  1861  VEDIS_PRIVATE int vedisOsOpen(
  1862    vedis_vfs *pVfs,
  1863    SyMemBackend *pAlloc,
  1864    const char *zPath, 
  1865    vedis_file **ppOut, 
  1866    unsigned int flags
  1867  );
  1868  VEDIS_PRIVATE int vedisOsCloseFree(SyMemBackend *pAlloc,vedis_file *pId);
  1869  VEDIS_PRIVATE int vedisOsDelete(vedis_vfs *pVfs, const char *zPath, int dirSync);
  1870  VEDIS_PRIVATE int vedisOsAccess(vedis_vfs *pVfs,const char *zPath,int flags,int *pResOut);
  1871  /* bitmap.c */
  1872  VEDIS_PRIVATE Bitvec *vedisBitvecCreate(SyMemBackend *pAlloc,pgno iSize);
  1873  VEDIS_PRIVATE int vedisBitvecTest(Bitvec *p,pgno i);
  1874  VEDIS_PRIVATE int vedisBitvecSet(Bitvec *p,pgno i);
  1875  VEDIS_PRIVATE void vedisBitvecDestroy(Bitvec *p);
  1876  /* pager.c */
  1877  VEDIS_PRIVATE int vedisInitCursor(vedis *pDb,vedis_kv_cursor **ppOut);
  1878  VEDIS_PRIVATE int vedisReleaseCursor(vedis *pDb,vedis_kv_cursor *pCur);
  1879  VEDIS_PRIVATE int vedisPagerisMemStore(vedis *pStore);
  1880  VEDIS_PRIVATE int vedisPagerSetCachesize(Pager *pPager,int mxPage);
  1881  VEDIS_PRIVATE int vedisPagerSetCommitCallback(Pager *pPager,int (*xCommit)(void *),void *pUserdata);
  1882  VEDIS_PRIVATE int vedisPagerClose(Pager *pPager);
  1883  VEDIS_PRIVATE int vedisPagerOpen(
  1884    vedis_vfs *pVfs,       /* The virtual file system to use */
  1885    vedis *pDb,            /* Database handle */
  1886    const char *zFilename,   /* Name of the database file to open */
  1887    unsigned int iFlags      /* flags controlling this file */
  1888    );
  1889  VEDIS_PRIVATE int vedisPagerRegisterKvEngine(Pager *pPager,vedis_kv_methods *pMethods);
  1890  VEDIS_PRIVATE vedis_kv_engine * vedisPagerGetKvEngine(vedis *pDb);
  1891  VEDIS_PRIVATE int vedisPagerBegin(Pager *pPager);
  1892  VEDIS_PRIVATE int vedisPagerCommit(Pager *pPager);
  1893  VEDIS_PRIVATE int vedisPagerRollback(Pager *pPager,int bResetKvEngine);
  1894  VEDIS_PRIVATE void vedisPagerRandomString(Pager *pPager,char *zBuf,sxu32 nLen);
  1895  VEDIS_PRIVATE sxu32 vedisPagerRandomNum(Pager *pPager);
  1896  /* lib.c */
  1897  #ifdef VEDIS_ENABLE_HASH_CMD
  1898  VEDIS_PRIVATE sxi32 SyBinToHexConsumer(const void *pIn, sxu32 nLen, ProcConsumer xConsumer, void *pConsumerData);
  1899  VEDIS_PRIVATE sxu32 SyCrc32(const void *pSrc, sxu32 nLen);
  1900  VEDIS_PRIVATE void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len);
  1901  VEDIS_PRIVATE void MD5Final(unsigned char digest[16], MD5Context *ctx);
  1902  VEDIS_PRIVATE sxi32 MD5Init(MD5Context *pCtx);
  1903  VEDIS_PRIVATE sxi32 SyMD5Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[16]);
  1904  VEDIS_PRIVATE void SHA1Init(SHA1Context *context);
  1905  VEDIS_PRIVATE void SHA1Update(SHA1Context *context, const unsigned char *data, unsigned int len);
  1906  VEDIS_PRIVATE void SHA1Final(SHA1Context *context, unsigned char digest[20]);
  1907  VEDIS_PRIVATE sxi32 SySha1Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[20]);
  1908  #endif /* VEDIS_ENABLE_HASH_CMD */
  1909  VEDIS_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx, void *pBuf, sxu32 nLen);
  1910  VEDIS_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx, ProcRandomSeed xSeed, void *pUserData);
  1911  #ifdef __UNIXES__
  1912  VEDIS_PRIVATE sxu32 SyBufferFormat(char *zBuf, sxu32 nLen, const char *zFormat, ...);
  1913  #endif /* __UNIXES__ */
  1914  VEDIS_PRIVATE sxu32 SyBlobFormatAp(SyBlob *pBlob, const char *zFormat, va_list ap);
  1915  VEDIS_PRIVATE sxu32 SyBlobFormat(SyBlob *pBlob, const char *zFormat, ...);
  1916  VEDIS_PRIVATE sxi32 SyLexRelease(SyLex *pLex);
  1917  VEDIS_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex, const char *zInput, sxu32 nLen, void *pCtxData, ProcSort xSort, ProcCmp xCmp);
  1918  VEDIS_PRIVATE sxi32 SyLexInit(SyLex *pLex, SySet *pSet, ProcTokenizer xTokenizer, void *pUserData);
  1919  VEDIS_PRIVATE sxi32 SyBase64Decode(const char *zB64, sxu32 nLen, ProcConsumer xConsumer, void *pUserData);
  1920  VEDIS_PRIVATE sxi32 SyBase64Encode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData);
  1921  VEDIS_PRIVATE sxu32 SyBinHash(const void *pSrc, sxu32 nLen);
  1922  VEDIS_PRIVATE sxi32 SyStrToReal(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest);
  1923  VEDIS_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest);
  1924  VEDIS_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest);
  1925  VEDIS_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest);
  1926  VEDIS_PRIVATE sxi32 SyHexToint(sxi32 c);
  1927  VEDIS_PRIVATE sxi32 SyStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest);
  1928  VEDIS_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc, sxu32 nLen, sxu8 *pReal, const char **pzTail);
  1929  VEDIS_PRIVATE void *SySetPop(SySet *pSet);
  1930  VEDIS_PRIVATE void *SySetPeek(SySet *pSet);
  1931  VEDIS_PRIVATE sxi32 SySetRelease(SySet *pSet);
  1932  VEDIS_PRIVATE sxi32 SySetReset(SySet *pSet);
  1933  VEDIS_PRIVATE sxi32 SySetPut(SySet *pSet, const void *pItem);
  1934  VEDIS_PRIVATE sxi32 SySetInit(SySet *pSet, SyMemBackend *pAllocator, sxu32 ElemSize);
  1935  VEDIS_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob);
  1936  VEDIS_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob);
  1937  VEDIS_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc, SyBlob *pDest);
  1938  VEDIS_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob);
  1939  VEDIS_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob, const void *pData, sxu32 nSize);
  1940  VEDIS_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob, SyMemBackend *pAllocator);
  1941  VEDIS_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob, void *pBuffer, sxu32 nSize);
  1942  VEDIS_PRIVATE void *SyMemBackendDup(SyMemBackend *pBackend, const void *pSrc, sxu32 nSize);
  1943  VEDIS_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend);
  1944  VEDIS_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend, const SyMemMethods *pMethods, ProcMemError xMemErr, void *pUserData);
  1945  VEDIS_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend, ProcMemError xMemErr, void *pUserData);
  1946  VEDIS_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,const SyMemBackend *pParent);
  1947  #if 0
  1948  /* Not used in the current release of the VEDIS engine */
  1949  VEDIS_PRIVATE void *SyMemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte);
  1950  #endif
  1951  VEDIS_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend, void *pChunk);
  1952  VEDIS_PRIVATE void *SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte);
  1953  VEDIS_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend, void *pChunk);
  1954  VEDIS_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte);
  1955  VEDIS_PRIVATE void *SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte);
  1956  VEDIS_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen);
  1957  VEDIS_PRIVATE sxi32 SyMemcmp(const void *pB1, const void *pB2, sxu32 nSize);
  1958  VEDIS_PRIVATE void SyZero(void *pSrc, sxu32 nSize);
  1959  VEDIS_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight, sxu32 SLen);
  1960  VEDIS_PRIVATE sxu32 Systrcpy(char *zDest, sxu32 nDestLen, const char *zSrc, sxu32 nLen);
  1961  #if defined(__APPLE__)
  1962  VEDIS_PRIVATE sxi32 SyStrncmp(const char *zLeft, const char *zRight, sxu32 nLen);
  1963  #endif
  1964  VEDIS_PRIVATE sxu32 SyStrlen(const char *zSrc);
  1965  #if defined(VEDIS_ENABLE_THREADS)
  1966  VEDIS_PRIVATE const SyMutexMethods *SyMutexExportMethods(void);
  1967  VEDIS_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend, const SyMutexMethods *pMethods);
  1968  VEDIS_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend);
  1969  #endif
  1970  VEDIS_PRIVATE void SyBigEndianPack32(unsigned char *buf,sxu32 nb);
  1971  VEDIS_PRIVATE void SyBigEndianUnpack32(const unsigned char *buf,sxu32 *uNB);
  1972  VEDIS_PRIVATE void SyBigEndianPack16(unsigned char *buf,sxu16 nb);
  1973  VEDIS_PRIVATE void SyBigEndianUnpack16(const unsigned char *buf,sxu16 *uNB);
  1974  VEDIS_PRIVATE void SyBigEndianPack64(unsigned char *buf,sxu64 n64);
  1975  VEDIS_PRIVATE void SyBigEndianUnpack64(const unsigned char *buf,sxu64 *n64);
  1976  #if 0
  1977  VEDIS_PRIVATE sxi32 SyBlobAppendBig64(SyBlob *pBlob,sxu64 n64);
  1978  #endif
  1979  VEDIS_PRIVATE sxi32 SyBlobAppendBig32(SyBlob *pBlob,sxu32 n32);
  1980  VEDIS_PRIVATE sxi32 SyBlobAppendBig16(SyBlob *pBlob,sxu16 n16);
  1981  VEDIS_PRIVATE void SyTimeFormatToDos(Sytm *pFmt,sxu32 *pOut);
  1982  VEDIS_PRIVATE void SyDosTimeFormat(sxu32 nDosDate, Sytm *pOut);
  1983  #endif /* _VEDISINT_H_ */
  1984  /*
  1985   * ----------------------------------------------------------
  1986   * File: zset.c
  1987   * MD5: 88b2fa4158316f4d34b59a22d03468d5
  1988   * ----------------------------------------------------------
  1989   */
  1990  /*
  1991   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
  1992   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
  1993   * Version 1.2.6
  1994   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  1995   * please contact Symisc Systems via:
  1996   *       legal@symisc.net
  1997   *       licensing@symisc.net
  1998   *       contact@symisc.net
  1999   * or visit:
  2000   *      http://vedis.symisc.net/
  2001   */
  2002  /* $SymiscID: obj.c v1.6 Linux 2013-07-10 03:52 stable <chm@symisc.net> $ */
  2003  #ifndef VEDIS_AMALGAMATION
  2004  #include "vedisInt.h"
  2005  #endif
  2006  /* Hash, Set, List in a single data structure which support persistance for the set
  2007   * of the HSET, HGET, ZSET, etc. command family.
  2008   * This was taken from the PH7 engine source tree, another project developed by
  2009   * Symisc Systems,S.U.A.R.L. Visit http://ph7.symisc.net/ for additional
  2010   * information.
  2011   */
  2012  struct vedis_table
  2013  {
  2014  	vedis *pStore;  /* Store that own this instance */
  2015  	SyString sName; /* Table name */
  2016  	vedis_table_entry **apBucket;  /* Hash bucket */
  2017  	vedis_table_entry *pFirst;     /* First inserted entry */
  2018  	vedis_table_entry *pLast;      /* Last inserted entry */
  2019  	vedis_table_entry *pCur;       /* Current entry */
  2020  	sxu32 nEntry;                  /* Total entries */
  2021  	sxu32 nSize;                   /* apBucket[] length */
  2022  	sxu32 (*xIntHash)(sxi64);      /* Hash function for int_keys */
  2023  	sxu32 (*xBlobHash)(const void *, sxu32); /* Hash function for blob_keys */
  2024  	sxi32 iFlags;                 /* vedisTable control flags */
  2025  	sxi64 iNextIdx;               /* Next available automatically assigned index */
  2026  	sxi32 iTableType;          /* Table type [i.e. Hash, Set, ...] */
  2027  	sxu32 nLastID;             /* Last assigned ID */
  2028  	vedis_table *pNext,*pPrev; /* Link to other tables */
  2029  	vedis_table *pNextCol,*pPrevCol; /* Collision chain */
  2030  };
  2031  /* Table control flags */
  2032  #define VEDIS_TABLE_DISK_LOAD 0x001 /* Decoding table entries from diks */
  2033  /*
  2034   * Default hash function for int [i.e; 64-bit integer] keys.
  2035   */
  2036  static sxu32 VedisTableIntHash(sxi64 iKey)
  2037  {
  2038  	return (sxu32)(iKey ^ (iKey << 8) ^ (iKey >> 8));
  2039  }
  2040  /*
  2041   * Default hash function for string/BLOB keys.
  2042   */
  2043  static sxu32 VedisTableBinHash(const void *pSrc, sxu32 nLen)
  2044  {
  2045  	register unsigned char *zIn = (unsigned char *)pSrc;
  2046  	unsigned char *zEnd;
  2047  	sxu32 nH = 5381;
  2048  	zEnd = &zIn[nLen];
  2049  	for(;;){
  2050  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
  2051  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
  2052  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
  2053  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
  2054  	}	
  2055  	return nH;
  2056  }
  2057  /*
  2058   * Allocate a new hashmap node with a 64-bit integer key.
  2059   * If something goes wrong [i.e: out of memory], this function return NULL.
  2060   * Otherwise a fresh [vedis_table_entry] instance is returned.
  2061   */
  2062  static vedis_table_entry * vedisTableNewIntNode(vedis_table *pTable, sxi64 iKey, sxu32 nHash,vedis_value *pValue)
  2063  {
  2064  	vedis_table_entry *pNode;
  2065  	/* Allocate a new node */
  2066  	pNode = (vedis_table_entry *)SyMemBackendPoolAlloc(&pTable->pStore->sMem, sizeof(vedis_table_entry));
  2067  	if( pNode == 0 ){
  2068  		return 0;
  2069  	}
  2070  	/* Zero the stucture */
  2071  	SyZero(pNode, sizeof(vedis_table_entry));
  2072  	/* Fill in the structure */
  2073  	pNode->pTable  = &(*pTable);
  2074  	pNode->iType = VEDIS_TABLE_ENTRY_INT_NODE;
  2075  	pNode->nHash = nHash;
  2076  	pNode->xKey.iKey = iKey;
  2077  	SyBlobInit(&pNode->sData,&pTable->pStore->sMem);
  2078  	/* Duplicate the value */
  2079  	if( pValue ){
  2080  		const char *zData;
  2081  		int nByte;
  2082  		zData = vedis_value_to_string(pValue,&nByte);
  2083  		if( nByte > 0 ){
  2084  			SyBlobAppend(&pNode->sData,zData,(sxu32)nByte);
  2085  		}
  2086  	}
  2087  	return pNode;
  2088  }
  2089  /*
  2090   * Allocate a new hashmap node with a BLOB key.
  2091   * If something goes wrong [i.e: out of memory], this function return NULL.
  2092   * Otherwise a fresh [vedis_table_entry] instance is returned.
  2093   */
  2094  static vedis_table_entry * vedisTableNewBlobNode(vedis_table *pTable, const void *pKey, sxu32 nKeyLen, sxu32 nHash,vedis_value *pValue)
  2095  {
  2096  	vedis_table_entry *pNode;
  2097  	/* Allocate a new node */
  2098  	pNode = (vedis_table_entry *)SyMemBackendPoolAlloc(&pTable->pStore->sMem, sizeof(vedis_table_entry));
  2099  	if( pNode == 0 ){
  2100  		return 0;
  2101  	}
  2102  	/* Zero the stucture */
  2103  	SyZero(pNode, sizeof(vedis_table_entry));
  2104  	/* Fill in the structure */
  2105  	pNode->pTable  = &(*pTable);
  2106  	pNode->iType = VEDIS_TABLE_ENTRY_BLOB_NODE;
  2107  	pNode->nHash = nHash;
  2108  	SyBlobInit(&pNode->xKey.sKey, &pTable->pStore->sMem);
  2109  	SyBlobAppend(&pNode->xKey.sKey, pKey, nKeyLen);
  2110  	SyBlobInit(&pNode->sData,&pTable->pStore->sMem);
  2111  	/* Duplicate the value */
  2112  	if( pValue ){
  2113  		const char *zData;
  2114  		int nByte;
  2115  		zData = vedis_value_to_string(pValue,&nByte);
  2116  		if( nByte > 0 ){
  2117  			SyBlobAppend(&pNode->sData,zData,(sxu32)nByte);
  2118  		}
  2119  	}
  2120  	return pNode;
  2121  }
  2122  /* Forward declaration */
  2123  static int vedisTableEntrySerialize(vedis_table *pTable,vedis_table_entry *pEntry);
  2124  /*
  2125   * link a hashmap node to the given bucket index (last argument to this function).
  2126   */
  2127  static int vedisTableNodeLink(vedis_table *pTable, vedis_table_entry *pNode, sxu32 nBucketIdx)
  2128  {
  2129  	int rc = VEDIS_OK;
  2130  	/* Link */
  2131  	if( pTable->apBucket[nBucketIdx] != 0 ){
  2132  		pNode->pNextCollide = pTable->apBucket[nBucketIdx];
  2133  		pTable->apBucket[nBucketIdx]->pPrevCollide = pNode;
  2134  	}
  2135  	pTable->apBucket[nBucketIdx] = pNode;
  2136  	/* Link to the map list */
  2137  	if( pTable->pFirst == 0 ){
  2138  		pTable->pFirst = pTable->pLast = pNode;
  2139  		/* Point to the first inserted node */
  2140  		pTable->pCur = pNode;
  2141  	}else{
  2142  		MACRO_LD_PUSH(pTable->pLast, pNode);
  2143  	}
  2144  	pNode->nId = pTable->nLastID++;
  2145  	++pTable->nEntry;
  2146  	if( !vedisPagerisMemStore(pTable->pStore) && !(pTable->iFlags & VEDIS_TABLE_DISK_LOAD)){
  2147  		rc = vedisTableEntrySerialize(pTable,pNode);
  2148  	}
  2149  	return rc;
  2150  }
  2151  /*
  2152   * Unlink a node from the hashmap.
  2153   * If the node count reaches zero then release the whole hash-bucket.
  2154   */
  2155  static void vedisTableUnlinkNode(vedis_table_entry *pNode)
  2156  {
  2157  	vedis_table *pTable = pNode->pTable;	
  2158  	/* Unlink from the corresponding bucket */
  2159  	if( pNode->pPrevCollide == 0 ){
  2160  		pTable->apBucket[pNode->nHash & (pTable->nSize - 1)] = pNode->pNextCollide;
  2161  	}else{
  2162  		pNode->pPrevCollide->pNextCollide = pNode->pNextCollide;
  2163  	}
  2164  	if( pNode->pNextCollide ){
  2165  		pNode->pNextCollide->pPrevCollide = pNode->pPrevCollide;
  2166  	}
  2167  	if( pTable->pFirst == pNode ){
  2168  		pTable->pFirst = pNode->pPrev;
  2169  	}
  2170  	if( pTable->pCur == pNode ){
  2171  		/* Advance the node cursor */
  2172  		pTable->pCur = pTable->pCur->pPrev; /* Reverse link */
  2173  	}
  2174  	/* Unlink from the map list */
  2175  	MACRO_LD_REMOVE(pTable->pLast, pNode);
  2176  	/* Release the value */
  2177  	if( pNode->iType == VEDIS_TABLE_ENTRY_BLOB_NODE ){
  2178  		SyBlobRelease(&pNode->xKey.sKey);
  2179  	}
  2180  	SyBlobRelease(&pNode->sData);
  2181  	SyMemBackendPoolFree(&pTable->pStore->sMem, pNode);
  2182  	pTable->nEntry--;
  2183  	if( pTable->nEntry < 1 ){
  2184  		/* Free the hash-bucket */
  2185  		SyMemBackendFree(&pTable->pStore->sMem, pTable->apBucket);
  2186  		pTable->apBucket = 0;
  2187  		pTable->nSize = 0;
  2188  		pTable->pFirst = pTable->pLast = pTable->pCur = 0;
  2189  	}
  2190  }
  2191  #define VEDIS_TABLE_FILL_FACTOR 3
  2192  /*
  2193   * Grow the hash-table and rehash all entries.
  2194   */
  2195  static sxi32 vedisTableGrowBucket(vedis_table *pTable)
  2196  {
  2197  	if( pTable->nEntry >= pTable->nSize * VEDIS_TABLE_FILL_FACTOR ){
  2198  		vedis_table_entry **apOld = pTable->apBucket;
  2199  		vedis_table_entry *pEntry, **apNew;
  2200  		sxu32 nNew = pTable->nSize << 1;
  2201  		sxu32 nBucket;
  2202  		sxu32 n;
  2203  		if( nNew < 1 ){
  2204  			nNew = 16;
  2205  		}
  2206  		/* Allocate a new bucket */
  2207  		apNew = (vedis_table_entry **)SyMemBackendAlloc(&pTable->pStore->sMem, nNew * sizeof(vedis_table_entry *));
  2208  		if( apNew == 0 ){
  2209  			if( pTable->nSize < 1 ){
  2210  				return SXERR_MEM; /* Fatal */
  2211  			}
  2212  			/* Not so fatal here, simply a performance hit */
  2213  			return SXRET_OK;
  2214  		}
  2215  		/* Zero the table */
  2216  		SyZero((void *)apNew, nNew * sizeof(vedis_table_entry *));
  2217  		/* Reflect the change */
  2218  		pTable->apBucket = apNew;
  2219  		pTable->nSize = nNew;
  2220  		if( apOld == 0 ){
  2221  			/* First allocated table [i.e: no entry], return immediately */
  2222  			return SXRET_OK;
  2223  		}
  2224  		/* Rehash old entries */
  2225  		pEntry = pTable->pFirst;
  2226  		n = 0;
  2227  		for( ;; ){
  2228  			if( n >= pTable->nEntry ){
  2229  				break;
  2230  			}
  2231  			/* Clear the old collision link */
  2232  			pEntry->pNextCollide = pEntry->pPrevCollide = 0;
  2233  			/* Link to the new bucket */
  2234  			nBucket = pEntry->nHash & (nNew - 1);
  2235  			if( pTable->apBucket[nBucket] != 0 ){
  2236  				pEntry->pNextCollide = pTable->apBucket[nBucket];
  2237  				pTable->apBucket[nBucket]->pPrevCollide = pEntry;
  2238  			}
  2239  			pTable->apBucket[nBucket] = pEntry;
  2240  			/* Point to the next entry */
  2241  			pEntry = pEntry->pPrev; /* Reverse link */
  2242  			n++;
  2243  		}
  2244  		/* Free the old table */
  2245  		SyMemBackendFree(&pTable->pStore->sMem, (void *)apOld);
  2246  	}
  2247  	return SXRET_OK;
  2248  }
  2249  /*
  2250   * Insert a 64-bit integer key and it's associated value (if any) in the given
  2251   * hashmap.
  2252   */
  2253  static sxi32 vedisTableInsertIntKey(vedis_table *pTable,sxi64 iKey,vedis_value *pValue)
  2254  {
  2255  	vedis_table_entry *pNode;
  2256  	sxu32 nHash;
  2257  	sxi32 rc;
  2258  	/* Hash the key */
  2259  	nHash = pTable->xIntHash(iKey);
  2260  	/* Allocate a new int node */
  2261  	pNode = vedisTableNewIntNode(&(*pTable), iKey, nHash, pValue);
  2262  	if( pNode == 0 ){
  2263  		return SXERR_MEM;
  2264  	}
  2265  	/* Make sure the bucket is big enough to hold the new entry */
  2266  	rc = vedisTableGrowBucket(&(*pTable));
  2267  	if( rc == VEDIS_OK ){
  2268  		/* Perform the insertion */
  2269  		rc = vedisTableNodeLink(&(*pTable), pNode, nHash & (pTable->nSize - 1));
  2270  	}
  2271  	if( rc != SXRET_OK ){
  2272  		SyMemBackendPoolFree(&pTable->pStore->sMem, pNode);
  2273  		return rc;
  2274  	}
  2275  	return VEDIS_OK;
  2276  }
  2277  /*
  2278   * Insert a BLOB key and it's associated value (if any) in the given
  2279   * hashmap.
  2280   */
  2281  static sxi32 vedisTableInsertBlobKey(vedis_table *pTable,const void *pKey,sxu32 nKeyLen,vedis_value *pValue)
  2282  {
  2283  	vedis_table_entry *pNode;
  2284  	sxu32 nHash;
  2285  	sxi32 rc;
  2286  	/* Hash the key */
  2287  	nHash = pTable->xBlobHash(pKey, nKeyLen);
  2288  	/* Allocate a new blob node */
  2289  	pNode = vedisTableNewBlobNode(&(*pTable), pKey, nKeyLen, nHash,pValue);
  2290  	if( pNode == 0 ){
  2291  		return SXERR_MEM;
  2292  	}
  2293  	/* Make sure the bucket is big enough to hold the new entry */
  2294  	rc = vedisTableGrowBucket(&(*pTable));
  2295  	if( rc == VEDIS_OK ){
  2296  		/* Perform the insertion */
  2297  		rc = vedisTableNodeLink(&(*pTable), pNode, nHash & (pTable->nSize - 1));
  2298  	}
  2299  	if( rc != SXRET_OK ){
  2300  		SyMemBackendPoolFree(&pTable->pStore->sMem, pNode);
  2301  		return rc;
  2302  	}
  2303  	/* All done */
  2304  	return VEDIS_OK;
  2305  }
  2306  /*
  2307   * Check if a given 64-bit integer key exists in the given hashmap.
  2308   * Write a pointer to the target node on success. Otherwise
  2309   * SXERR_NOTFOUND is returned on failure.
  2310   */
  2311  static sxi32 vedisTableLookupIntKey(
  2312  	vedis_table *pMap,         /* Target hashmap */
  2313  	sxi64 iKey,                /* lookup key */
  2314  	vedis_table_entry **ppNode  /* OUT: target node on success */
  2315  	)
  2316  {
  2317  	vedis_table_entry *pNode;
  2318  	sxu32 nHash;
  2319  	if( pMap->nEntry < 1 ){
  2320  		/* Don't bother hashing, there is no entry anyway */
  2321  		return SXERR_NOTFOUND;
  2322  	}
  2323  	/* Hash the key first */
  2324  	nHash = pMap->xIntHash(iKey);
  2325  	/* Point to the appropriate bucket */
  2326  	pNode = pMap->apBucket[nHash & (pMap->nSize - 1)];
  2327  	/* Perform the lookup */
  2328  	for(;;){
  2329  		if( pNode == 0 ){
  2330  			break;
  2331  		}
  2332  		if( pNode->iType == VEDIS_TABLE_ENTRY_INT_NODE
  2333  			&& pNode->nHash == nHash
  2334  			&& pNode->xKey.iKey == iKey ){
  2335  				/* Node found */
  2336  				if( ppNode ){
  2337  					*ppNode = pNode;
  2338  				}
  2339  				return SXRET_OK;
  2340  		}
  2341  		/* Follow the collision link */
  2342  		pNode = pNode->pNextCollide;
  2343  	}
  2344  	/* No such entry */
  2345  	return SXERR_NOTFOUND;
  2346  }
  2347  /*
  2348   * Check if a given BLOB key exists in the given hashmap.
  2349   * Write a pointer to the target node on success. Otherwise
  2350   * SXERR_NOTFOUND is returned on failure.
  2351   */
  2352  static sxi32 vedisTableLookupBlobKey(
  2353  	vedis_table *pMap,          /* Target hashmap */
  2354  	const void *pKey,           /* Lookup key */
  2355  	sxu32 nKeyLen,              /* Key length in bytes */
  2356  	vedis_table_entry **ppNode   /* OUT: target node on success */
  2357  	)
  2358  {
  2359  	vedis_table_entry *pNode;
  2360  	sxu32 nHash;
  2361  	if( pMap->nEntry < 1 ){
  2362  		/* Don't bother hashing, there is no entry anyway */
  2363  		return SXERR_NOTFOUND;
  2364  	}
  2365  	/* Hash the key first */
  2366  	nHash = pMap->xBlobHash(pKey, nKeyLen);
  2367  	/* Point to the appropriate bucket */
  2368  	pNode = pMap->apBucket[nHash & (pMap->nSize - 1)];
  2369  	/* Perform the lookup */
  2370  	for(;;){
  2371  		if( pNode == 0 ){
  2372  			break;
  2373  		}
  2374  		if( pNode->iType == VEDIS_TABLE_ENTRY_BLOB_NODE 
  2375  			&& pNode->nHash == nHash
  2376  			&& SyBlobLength(&pNode->xKey.sKey) == nKeyLen 
  2377  			&& SyMemcmp(SyBlobData(&pNode->xKey.sKey), pKey, nKeyLen) == 0 ){
  2378  				/* Node found */
  2379  				if( ppNode ){
  2380  					*ppNode = pNode;
  2381  				}
  2382  				return SXRET_OK;
  2383  		}
  2384  		/* Follow the collision link */
  2385  		pNode = pNode->pNextCollide;
  2386  	}
  2387  	/* No such entry */
  2388  	return SXERR_NOTFOUND;
  2389  }
  2390  /*
  2391   * Check if a given key exists in the given hashmap.
  2392   * Write a pointer to the target node on success.
  2393   * Otherwise SXERR_NOTFOUND is returned on failure.
  2394   */
  2395  static sxi32 vedisTableLookup(
  2396  	vedis_table *pMap,          /* Target hashmap */
  2397  	vedis_value *pKey,            /* Lookup key */
  2398  	vedis_table_entry **ppNode   /* OUT: target node on success */
  2399  	)
  2400  {
  2401  	vedis_table_entry *pNode = 0; /* cc -O6 warning */
  2402  	sxi32 rc;
  2403  	if( pKey->iFlags & (MEMOBJ_STRING|MEMOBJ_HASHMAP|MEMOBJ_REAL) ){
  2404  		if( (pKey->iFlags & MEMOBJ_STRING) == 0 ){
  2405  			/* Force a string cast */
  2406  			vedisMemObjToString(&(*pKey));
  2407  		}
  2408  		if( SyBlobLength(&pKey->sBlob) > 0 ){
  2409  			/* Perform a blob lookup */
  2410  			rc = vedisTableLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &pNode);
  2411  			goto result;
  2412  		}
  2413  	}
  2414  	/* Perform an int lookup */
  2415  	if((pKey->iFlags & MEMOBJ_INT) == 0 ){
  2416  		/* Force an integer cast */
  2417  		vedisMemObjToInteger(pKey);
  2418  	}
  2419  	/* Perform an int lookup */
  2420  	rc = vedisTableLookupIntKey(&(*pMap), pKey->x.iVal, &pNode);
  2421  result:
  2422  	if( rc == SXRET_OK ){
  2423  		/* Node found */
  2424  		if( ppNode ){
  2425  			*ppNode = pNode;
  2426  		}
  2427  		return SXRET_OK;
  2428  	}
  2429  	/* No such entry */
  2430  	return SXERR_NOTFOUND;
  2431  }
  2432  /*
  2433   * Insert a given key and it's associated value (if any) in the given
  2434   * hashmap.
  2435   * If a node with the given key already exists in the database
  2436   * then this function overwrite the old value.
  2437   */
  2438  static sxi32 vedisTableInsert(
  2439  	vedis_table *pMap, /* Target hashmap */
  2440  	vedis_value *pKey,   /* Lookup key  */
  2441  	vedis_value *pVal    /* Node value */
  2442  	)
  2443  {
  2444  	vedis_table_entry *pNode = 0;
  2445  	sxi32 rc = SXRET_OK;
  2446  	
  2447  	if( pKey && (pKey->iFlags & (MEMOBJ_STRING|MEMOBJ_HASHMAP)) ){
  2448  		if( (pKey->iFlags & MEMOBJ_STRING) == 0 ){
  2449  			/* Force a string cast */
  2450  			vedisMemObjToString(&(*pKey));
  2451  		}
  2452  		if( SyBlobLength(&pKey->sBlob) < 1  ){
  2453  			/* Automatic index assign */
  2454  			pKey = 0;
  2455  			goto IntKey;
  2456  		}
  2457  		if( SXRET_OK == vedisTableLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), 
  2458  			SyBlobLength(&pKey->sBlob), &pNode) ){
  2459  				/* Overwrite the old value */
  2460  				SyBlobReset(&pNode->sData);
  2461  				if( pVal ){
  2462  					const char *zVal;
  2463  					int nByte;
  2464  					/* Get a string representation */
  2465  					zVal = vedis_value_to_string(pVal,&nByte);
  2466  					if( nByte > 0 ){
  2467  						SyBlobAppend(&pNode->sData,zVal,(sxu32)nByte);
  2468  					}
  2469  				}
  2470  				if( !vedisPagerisMemStore(pMap->pStore) ){
  2471  					rc = vedisTableEntrySerialize(pMap,pNode);
  2472  				}
  2473  				return rc;
  2474  		}else{
  2475  			/* Perform a blob-key insertion */
  2476  			rc = vedisTableInsertBlobKey(&(*pMap),SyBlobData(&pKey->sBlob),SyBlobLength(&pKey->sBlob),&(*pVal));
  2477  			if( rc != VEDIS_OK ){
  2478  				return rc;
  2479  			}
  2480  		}
  2481  		return rc;
  2482  	}
  2483  IntKey:
  2484  	if( pKey ){
  2485  		if((pKey->iFlags & MEMOBJ_INT) == 0 ){
  2486  			/* Force an integer cast */
  2487  			vedisMemObjToInteger(pKey);
  2488  		}
  2489  		if( SXRET_OK == vedisTableLookupIntKey(&(*pMap), pKey->x.iVal, &pNode) ){
  2490  			/* Overwrite the old value */
  2491  			SyBlobReset(&pNode->sData);
  2492  				if( pVal ){
  2493  					const char *zVal;
  2494  					int nByte;
  2495  					/* Get a string representation */
  2496  					zVal = vedis_value_to_string(pVal,&nByte);
  2497  					if( nByte > 0 ){
  2498  						SyBlobAppend(&pNode->sData,zVal,(sxu32)nByte);
  2499  					}
  2500  				}
  2501  				rc = VEDIS_OK;
  2502  				if( !vedisPagerisMemStore(pMap->pStore) ){
  2503  					rc = vedisTableEntrySerialize(pMap,pNode);
  2504  				}
  2505  				return rc;
  2506  		}
  2507  		/* Perform a 64-bit-int-key insertion */
  2508  		rc = vedisTableInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal));
  2509  		if( rc == SXRET_OK ){
  2510  			if( pKey->x.iVal >= pMap->iNextIdx ){
  2511  				/* Increment the automatic index */ 
  2512  				pMap->iNextIdx = pKey->x.iVal + 1;
  2513  				/* Make sure the automatic index is not reserved */
  2514  				while( SXRET_OK == vedisTableLookupIntKey(&(*pMap), pMap->iNextIdx, 0) ){
  2515  					pMap->iNextIdx++;
  2516  				}
  2517  			}
  2518  		}
  2519  	}else{
  2520  		/* Assign an automatic index */
  2521  		rc = vedisTableInsertIntKey(&(*pMap),pMap->iNextIdx,&(*pVal));
  2522  		if( rc == SXRET_OK ){
  2523  			++pMap->iNextIdx;
  2524  		}
  2525  	}
  2526  	/* Insertion result */
  2527  	return rc;
  2528  }
  2529  /*
  2530   * Exported interfaces used by the built-in Vedis commands.
  2531   */
  2532  /*
  2533   * Remove the given entry from the target table.
  2534   */
  2535  VEDIS_PRIVATE int VedisRemoveTableEntry(vedis_table *pTable,vedis_table_entry *pEntry)
  2536  {
  2537  	int rc = VEDIS_OK;
  2538  	if( !vedisPagerisMemStore(pTable->pStore) ){
  2539  		SyBlob sWorker;
  2540  		/* Remove the entry from disk */
  2541  		SyBlobInit(&sWorker,&pTable->pStore->sMem);
  2542  		/* Build the key */
  2543  		SyBlobFormat(&sWorker,"vt%z%d%u",&pTable->sName,pTable->iTableType,pEntry->nId);
  2544  		/* Perform the deletion */
  2545  		rc = vedisKvDelete(pTable->pStore,SyBlobData(&sWorker),(int)SyBlobLength(&sWorker));
  2546  		/* Cleanup */
  2547  		SyBlobRelease(&sWorker);
  2548  	}
  2549  	vedisTableUnlinkNode(pEntry);
  2550  	return rc;
  2551  }
  2552  /*
  2553   * Fetch a record from the given table.
  2554   */
  2555  VEDIS_PRIVATE vedis_table_entry * vedisTableGetRecord(vedis_table *pTable,vedis_value *pKey)
  2556  {
  2557  	vedis_table_entry *pEntry;
  2558  	int rc;
  2559  	/* Fetch */
  2560  	rc = vedisTableLookup(pTable,pKey,&pEntry);
  2561  	return rc == VEDIS_OK ? pEntry : 0 /* No such entry */;
  2562  }
  2563  /*
  2564   * Only lists.
  2565   */
  2566  VEDIS_PRIVATE vedis_table_entry * vedisTableGetRecordByIndex(vedis_table *pTable,sxu32 nIndex)
  2567  {
  2568  	vedis_table_entry *pEntry = 0; /* cc warning */
  2569  	vedis_value sKey;
  2570  	int rc;
  2571  	vedisMemObjInitFromInt(pTable->pStore,&sKey,(sxi64)nIndex);
  2572  	/* Fetch */
  2573  	rc = vedisTableLookup(pTable,&sKey,&pEntry);
  2574  	vedisMemObjRelease(&sKey);
  2575  	return rc == VEDIS_OK ? pEntry : 0 /* No such entry */;
  2576  }
  2577  /*
  2578   * Delete a record from the given table.
  2579   */
  2580  VEDIS_PRIVATE int vedisTableDeleteRecord(vedis_table *pTable,vedis_value *pKey)
  2581  {
  2582  	vedis_table_entry *pEntry;
  2583  	int rc;
  2584  	/* Fetch */
  2585  	rc = vedisTableLookup(pTable,pKey,&pEntry);
  2586  	if( rc != VEDIS_OK ){
  2587  		return rc;
  2588  	}
  2589  	/* Perform the deletion */
  2590  	rc = VedisRemoveTableEntry(pTable,pEntry);
  2591  	return rc;
  2592  }
  2593  /*
  2594   * Insert a record into the given table.
  2595   */
  2596  VEDIS_PRIVATE int vedisTableInsertRecord(vedis_table *pTable,vedis_value *pKey,vedis_value *pData)
  2597  {
  2598  	int rc;
  2599  	rc = vedisTableInsert(pTable,pKey,pData);
  2600  	return rc;
  2601  }
  2602  /*
  2603   * Return the total entries in a given table.
  2604   */
  2605  VEDIS_PRIVATE sxu32 vedisTableLength(vedis_table *pTable)
  2606  {
  2607  	return pTable->nEntry;
  2608  }
  2609  /*
  2610   * Point to the first entry in a given table.
  2611   */
  2612  VEDIS_PRIVATE void vedisTableReset(vedis_table *pTable)
  2613  {
  2614  	/* Reset the loop cursor */
  2615  	pTable->pCur = pTable->pFirst;
  2616  }
  2617  /*
  2618   * Return the entry pointed by the cursor in a given table.
  2619   */
  2620  VEDIS_PRIVATE vedis_table_entry * vedisTableNextEntry(vedis_table *pTable)
  2621  {
  2622  	vedis_table_entry *pCur = pTable->pCur;
  2623  	if( pCur == 0 ){
  2624  		/* End of the list, return null */
  2625  		return 0;
  2626  	}
  2627  	/* Advance the node cursor */
  2628  	pTable->pCur = pCur->pPrev; /* Reverse link */
  2629  	/* Current Entry */
  2630  	return pCur;
  2631  }
  2632  /*
  2633   * Return the last entry in a given table.
  2634   */
  2635  VEDIS_PRIVATE vedis_table_entry * vedisTableLastEntry(vedis_table *pTable)
  2636  {
  2637  	return pTable->nEntry > 0 ? pTable->pLast : 0 /* Empty list*/;
  2638  }
  2639  /*
  2640   * Return the first entry in a given table.
  2641   */
  2642  VEDIS_PRIVATE vedis_table_entry * vedisTableFirstEntry(vedis_table *pTable)
  2643  {
  2644  	return pTable->nEntry > 0 ? pTable->pFirst : 0 /* Empty list*/;
  2645  }
  2646  /*
  2647   * Install a freshly created table.
  2648   */
  2649  static void vedisInstallTable(vedis *pStore,vedis_table *pTable,sxu32 nHash)
  2650  {
  2651  	sxu32 nBucket = nHash & (pStore->nTableSize - 1);
  2652  	/* Install in the corresponding bucket */
  2653  	pTable->pNextCol = pStore->apTable[nBucket];
  2654  	if( pStore->apTable[nBucket] ){
  2655  		pStore->apTable[nBucket]->pPrevCol = pTable;
  2656  	}
  2657  	pStore->apTable[nBucket] = pTable;
  2658  	/* Link the table */
  2659  	MACRO_LD_PUSH(pStore->pTableList,pTable);
  2660  	pStore->nTable++;
  2661  	if( (pStore->nTable >= pStore->nTableSize * 4) && pStore->nTable < 100000 ){
  2662  		/* Grow the hashtable */
  2663  		sxu32 nNewSize = pStore->nTableSize << 1;
  2664  		vedis_table *pEntry,**apNew;
  2665  		sxu32 n;
  2666  		apNew = (vedis_table **)SyMemBackendAlloc(&pStore->sMem, nNewSize * sizeof(vedis_table *));
  2667  		if( apNew ){
  2668  			sxu32 iBucket;
  2669  			/* Zero the new table */
  2670  			SyZero((void *)apNew, nNewSize * sizeof(vedis_table *));
  2671  			/* Rehash all entries */
  2672  			n = 0;
  2673  			pEntry = pStore->pTableList;
  2674  			for(;;){
  2675  				/* Loop one */
  2676  				if( n >= pStore->nTable ){
  2677  					break;
  2678  				}
  2679  				pEntry->pNextCol = pEntry->pPrevCol = 0;
  2680  				/* Install in the new bucket */
  2681  				iBucket = SyBinHash(SyStringData(&pEntry->sName),SyStringLength(&pEntry->sName)) & (nNewSize - 1);
  2682  				pEntry->pNextCol = apNew[iBucket];
  2683  				if( apNew[iBucket] ){
  2684  					apNew[iBucket]->pPrevCol = pEntry;
  2685  				}
  2686  				apNew[iBucket] = pEntry;
  2687  				/* Point to the next entry */
  2688  				pEntry = pEntry->pNext;
  2689  				n++;
  2690  			}
  2691  			/* Release the old table and reflect the change */
  2692  			SyMemBackendFree(&pStore->sMem,(void *)pStore->apTable);
  2693  			pStore->apTable = apNew;
  2694  			pStore->nTableSize  = nNewSize;
  2695  		}
  2696  	}
  2697  }
  2698  /*
  2699   * Allocate a new table.
  2700   */
  2701  static vedis_table * vedisNewTable(vedis *pStore,SyString *pName,int iType,sxu32 nHash)
  2702  {
  2703  	vedis_table *pTable;
  2704  	char *zPtr;
  2705  	/* Allocate a new instance */
  2706  	pTable = (vedis_table *)SyMemBackendAlloc(&pStore->sMem,sizeof(vedis_table)+pName->nByte);
  2707  	if( pTable == 0 ){
  2708  		return 0;
  2709  	}
  2710  	/* Zero the structure */
  2711  	SyZero(pTable,sizeof(vedis_table));
  2712  	/* Fill-in */
  2713  	pTable->iTableType = iType;
  2714  	pTable->pStore = pStore;
  2715  	pTable->xIntHash  = VedisTableIntHash;
  2716  	pTable->xBlobHash = VedisTableBinHash; 
  2717  	zPtr = (char *)&pTable[1];
  2718  	SyMemcpy(pName->zString,zPtr,pName->nByte);
  2719  	SyStringInitFromBuf(&pTable->sName,zPtr,pName->nByte);
  2720  	/* Install the table */
  2721  	vedisInstallTable(pStore,pTable,nHash);
  2722  	return pTable;
  2723  }
  2724  #define VEDIS_TABLE_MAGIC        0xCA10 /* Table magic number */
  2725  #define VEDIS_TABLE_ENTRY_MAGIC  0xEF32 /* Table entry magic number */
  2726  /*
  2727   * Serialize a vedis table to disk.
  2728   */
  2729  static int vedisTableSerialize(vedis_table *pTable)
  2730  {
  2731  	vedis *pStore = pTable->pStore;
  2732  	vedis_kv_methods *pMethods;
  2733  	vedis_kv_engine *pEngine;
  2734  	SyBlob sWorker;
  2735  	sxu32 nOfft;
  2736  	int rc;
  2737  	
  2738  	/* Start the serialization process */
  2739  	pEngine = vedisPagerGetKvEngine(pStore);
  2740  	pMethods = pEngine->pIo->pMethods;
  2741  	if( pMethods->xReplace ==  0 ){
  2742  		vedisGenErrorFormat(pStore,
  2743  			"Cannot serialize table '%z' due to a read-only KV storage engine '%s'",
  2744  			&pTable->sName,pMethods->zName
  2745  			);
  2746  		return VEDIS_READ_ONLY;
  2747  	}
  2748  	SyBlobInit(&sWorker,&pStore->sMem);
  2749  	/* Write the table header */
  2750  	SyBlobFormat(&sWorker,"vt%d%z",pTable->iTableType,&pTable->sName);
  2751  	nOfft = SyBlobLength(&sWorker);
  2752  	/* table header */
  2753  	SyBlobAppendBig16(&sWorker,VEDIS_TABLE_MAGIC); /* Magic number */
  2754  	SyBlobAppendBig32(&sWorker,pTable->nLastID);   /* Last assigned ID */
  2755  	SyBlobAppendBig32(&sWorker,pTable->nEntry);    /* Total number of records  */
  2756  	/* Write the header */
  2757  	rc = pMethods->xReplace(pEngine,SyBlobData(&sWorker),(int)nOfft,SyBlobDataAt(&sWorker,nOfft),SyBlobLength(&sWorker)-nOfft);
  2758  	if( rc != VEDIS_OK ){
  2759  		return rc;
  2760  	}
  2761  	/* All done, clean up and return */
  2762  	SyBlobRelease(&sWorker);
  2763  	return VEDIS_OK;
  2764  }
  2765  /*
  2766   * Serialize a vedis table entry to Disk
  2767   */
  2768  static int vedisTableEntrySerialize(vedis_table *pTable,vedis_table_entry *pEntry)
  2769  {
  2770  	vedis *pStore = pTable->pStore;
  2771  	vedis_kv_methods *pMethods;
  2772  	vedis_kv_engine *pEngine;
  2773  	SyBlob sWorker;
  2774  	sxu32 nByte = 0;
  2775  	sxu32 nOfft;
  2776  	
  2777  	/* Start the serialization process */
  2778  	pEngine = vedisPagerGetKvEngine(pStore);
  2779  	pMethods = pEngine->pIo->pMethods;
  2780  	if( pMethods->xReplace ==  0 ){
  2781  		vedisGenErrorFormat(pStore,
  2782  			"Cannot serialize table '%z' entry due to a read-only KV storage engine '%s'",
  2783  			&pTable->sName,pMethods->zName
  2784  			);
  2785  		return VEDIS_READ_ONLY;
  2786  	}
  2787  	SyBlobInit(&sWorker,&pStore->sMem);
  2788  	/* Prepare the key */
  2789  	SyBlobFormat(&sWorker,"vt%z%d%u",&pTable->sName,pTable->iTableType,pEntry->nId);
  2790  	nOfft = SyBlobLength(&sWorker);
  2791  	/* Prepare the payload */
  2792  	SyBlobAppendBig16(&sWorker,VEDIS_TABLE_ENTRY_MAGIC); /* Magic */
  2793  	SyBlobAppendBig32(&sWorker,pEntry->nId); /* Unique ID */
  2794  	SyBlobAppend(&sWorker,(const void *)&pEntry->iType,sizeof(char)); /* Key type */
  2795  	if( pEntry->iType == VEDIS_TABLE_ENTRY_BLOB_NODE ){
  2796  		nByte = SyBlobLength(&pEntry->xKey.sKey);
  2797  	}
  2798  	SyBlobAppendBig32(&sWorker,nByte);
  2799  	SyBlobAppendBig32(&sWorker,SyBlobLength(&pEntry->sData)); /* Data length */
  2800  	if( pEntry->iType == VEDIS_TABLE_ENTRY_BLOB_NODE ){
  2801  		SyBlobDup(&pEntry->xKey.sKey,&sWorker);
  2802  	}
  2803  	SyBlobDup(&pEntry->sData,&sWorker);
  2804  	/* Perform the write process */
  2805  	pMethods->xReplace(pEngine,SyBlobData(&sWorker),(int)nOfft,SyBlobDataAt(&sWorker,nOfft),SyBlobLength(&sWorker) - nOfft);	
  2806  	/* All done, clean up and return */
  2807  	SyBlobRelease(&sWorker);
  2808  	return VEDIS_OK;
  2809  }
  2810  /*
  2811   * On commit callback.
  2812   */
  2813  VEDIS_PRIVATE int vedisOnCommit(void *pUserData)
  2814  {
  2815  	vedis *pStore = (vedis *)pUserData;
  2816  	vedis_table *pTable;
  2817  	sxu32 n;
  2818  	int rc;
  2819  	/* Make sure we are dealing with an on-disk data store */
  2820  	if( vedisPagerisMemStore(pStore) ){
  2821  		return VEDIS_OK;
  2822  	}
  2823  	pTable = pStore->pTableList;
  2824  	for( n = 0 ; n < pStore->nTable ; ++n ){
  2825  		/* Serialize this table */
  2826  		rc = vedisTableSerialize(pTable);
  2827  		if( rc != VEDIS_OK ){
  2828  			return rc;
  2829  		}
  2830  		/* Point to the next entry */
  2831  		pTable = pTable->pNext;
  2832  	}
  2833  	return VEDIS_OK;
  2834  }
  2835  /*
  2836   * Unserialize an on-disk table.
  2837   */
  2838  static vedis_table * vedisTableUnserialize(
  2839  	vedis *pStore,SyString *pName,int iType,sxu32 nHash,
  2840  	const unsigned char *zBuf,sxu32 nByte,
  2841  	sxu32 *pEntry,sxu32 *pLastID
  2842  	)
  2843  {
  2844  	vedis_table *pNew;
  2845  	sxu16 iMagic;
  2846  	/* Sanity check */
  2847  	if( nByte != 2 /* Magic */ + 4 /* Last unique ID */ + 4 /* Total records */ ){
  2848  		/* Corrupt */
  2849  		return 0;
  2850  	}
  2851  	SyBigEndianUnpack16(zBuf,&iMagic);
  2852  	if( iMagic != VEDIS_TABLE_MAGIC ){
  2853  		return 0;
  2854  	}
  2855  	zBuf += 2; /* Magic */
  2856  	SyBigEndianUnpack32(zBuf,pLastID); /* Last Unique ID */
  2857  	zBuf += 4;
  2858  	SyBigEndianUnpack32(zBuf,pEntry); /* Total number of records */
  2859  	zBuf += 4;
  2860  	/* Allocate a new table */
  2861  	pNew = vedisNewTable(pStore,pName,iType,nHash);
  2862  	return pNew;
  2863  }
  2864  /*
  2865   * Unserialize a table entry.
  2866   */
  2867  static int vedisUnserializeEntry(vedis_table *pTable,const unsigned char *zPtr,sxu32 nByte)
  2868  {
  2869  	const unsigned char *zBuf = zPtr;
  2870  	vedis_value sKey,sData;
  2871  	sxu32 nData,nKey;
  2872  	SyString sEntry;
  2873  	sxu16 iMagic;
  2874  	sxu32 nId;
  2875  	int iType;
  2876  	
  2877  	if( nByte < 2 /* Magic */ + 4 /* Unique ID */+ 1 /* type */ + 4 /* key length */ + 4 /* data length */ ){
  2878  		return VEDIS_CORRUPT;
  2879  	}
  2880  	SyBigEndianUnpack16(zBuf,&iMagic); /* Magic */
  2881  	if( iMagic != VEDIS_TABLE_ENTRY_MAGIC ){
  2882  		return VEDIS_CORRUPT;
  2883  	}
  2884  	zBuf += 2; /* Magic */
  2885  	SyBigEndianUnpack32(zBuf,&nId);
  2886  	zBuf += 4; /* Unique ID */
  2887  	iType = (int)zBuf[0];
  2888  	if( iType != VEDIS_TABLE_ENTRY_BLOB_NODE && iType != VEDIS_TABLE_ENTRY_INT_NODE ){
  2889  		return VEDIS_CORRUPT;
  2890  	}
  2891  	zBuf++;
  2892  	SyBigEndianUnpack32(zBuf,&nKey); /* Key */
  2893  	zBuf += 4;
  2894  	SyBigEndianUnpack32(zBuf,&nData); /* Data */
  2895  	zBuf += 4;
  2896  	/* Sanity check */
  2897  	if(  (sxu32)(&zPtr[nByte] - zBuf) != nKey + nData ){
  2898  		return VEDIS_CORRUPT;
  2899  	}
  2900  	SyStringInitFromBuf(&sEntry,zBuf,nKey);
  2901  	vedisMemObjInitFromString(pTable->pStore,&sKey,&sEntry);
  2902  	zBuf += nKey;
  2903  	SyStringInitFromBuf(&sEntry,zBuf,nData);
  2904  	vedisMemObjInitFromString(pTable->pStore,&sData,&sEntry);
  2905  	/* Perform the insertion */
  2906  	if( VEDIS_OK == vedisTableInsert(pTable,nKey > 0 ? &sKey : 0,nData > 0 ? &sData : 0) ){
  2907  		/* Set the real ID */
  2908  		pTable->pLast->nId = nId;
  2909  		if( pTable->nLastID > 0 ){
  2910  			pTable->nLastID--;
  2911  		}
  2912  	}
  2913  	/* Clean up and return */
  2914  	vedisMemObjRelease(&sKey);
  2915  	vedisMemObjRelease(&sData);
  2916  	return VEDIS_OK;
  2917  }
  2918  /*
  2919   * Fetch a table from disk and load its entries.
  2920   */
  2921  static vedis_table * vedisTableLoadFromDisk(vedis *pStore,SyString *pName,int iType,sxu32 nHash)
  2922  {
  2923  	vedis_table *pTable;
  2924  	SyBlob sWorker;
  2925  	sxu32 nLastID;
  2926  	sxu32 nEntry;
  2927  	sxu32 nByte;
  2928  	sxu32 nOfft;
  2929  	sxu32 nId;
  2930  	sxu32 n;
  2931  	int rc;
  2932  	/* Make sure we are dealing with an on-disk data store */
  2933  	if( vedisPagerisMemStore(pStore) ){
  2934  		return 0;
  2935  	}
  2936  	/* Go fetch */
  2937  	SyBlobInit(&sWorker,&pStore->sMem);
  2938  	SyBlobFormat(&sWorker,"vt%d%z",iType,pName);
  2939  	nOfft = SyBlobLength(&sWorker);
  2940  	rc = vedisKvFetchCallback(pStore,SyBlobData(&sWorker),(int)nOfft,vedisDataConsumer,&sWorker);
  2941  	if( rc != VEDIS_OK ){
  2942  		goto fail;
  2943  	}
  2944  	nByte = SyBlobLength(&sWorker) - nOfft;
  2945  	/* Unserialize the table */
  2946  	nEntry = 0;
  2947  	pTable = vedisTableUnserialize(pStore,pName,iType,nHash,(const unsigned char *)SyBlobDataAt(&sWorker,nOfft),nByte,&nEntry,&nLastID);
  2948  	if( pTable == 0 ){
  2949  		/* No such table */
  2950  		goto fail;
  2951  	}
  2952  	pTable->iFlags |= VEDIS_TABLE_DISK_LOAD;
  2953  	pTable->nLastID = nLastID;
  2954  	/* Unserialize table entries */
  2955  	n = nId = 0;
  2956  	for( ;; ){
  2957  		if( n >= nEntry ){
  2958  			break;
  2959  		}
  2960  		SyBlobReset(&sWorker);
  2961  		/* Read the entry */
  2962  		SyBlobFormat(&sWorker,"vt%z%d%u",&pTable->sName,pTable->iTableType,nId++);
  2963  		nOfft = SyBlobLength(&sWorker);
  2964  		rc = vedisKvFetchCallback(pStore,SyBlobData(&sWorker),nOfft,vedisDataConsumer,&sWorker);
  2965  		if( rc == VEDIS_OK ){
  2966  			/* Decode the entry */
  2967  			vedisUnserializeEntry(pTable,(const unsigned char *)SyBlobDataAt(&sWorker,nOfft),SyBlobLength(&sWorker) - nOfft);
  2968  			n++;
  2969  		}else if( rc != VEDIS_NOTFOUND ){
  2970  			break;
  2971  		}
  2972  	}
  2973  	SyBlobRelease(&sWorker);
  2974  	/* Remove stale flags */
  2975  	pTable->iFlags &= ~VEDIS_TABLE_DISK_LOAD;
  2976  	/* All done */
  2977  	return pTable;
  2978  fail:
  2979  	SyBlobRelease(&sWorker);
  2980  	/* No such table */
  2981  	return 0;
  2982  }
  2983  /*
  2984   * Fetch a table and load its entries.
  2985   */
  2986  VEDIS_PRIVATE vedis_table * vedisFetchTable(vedis *pDb,vedis_value *pName,int create_new,int iType)
  2987  {
  2988  	vedis_table *pTable;
  2989  	const char *zName;
  2990  	SyString sName;
  2991  	sxu32 nHash;
  2992  	int nByte;
  2993  	/* Extract table name */
  2994  	zName = vedis_value_to_string(pName,&nByte);
  2995  	if( nByte < 1 ){
  2996  		/* Invalid table name */
  2997  		vedisGenError(pDb,"Invalid table name");
  2998  		return 0;
  2999  	}
  3000  	SyStringInitFromBuf(&sName,zName,nByte);
  3001  	/* Fetch table */
  3002  	nHash = SyBinHash(sName.zString,sName.nByte);
  3003  	pTable = pDb->apTable[nHash & (pDb->nTableSize - 1)];
  3004  	for(;;){
  3005  		if( pTable == 0 ){
  3006  			break;
  3007  		}
  3008  		if( pTable->iTableType == iType && SyStringCmp(&sName,&pTable->sName,SyMemcmp) == 0 ){
  3009  			/* Table found */
  3010  			return pTable;
  3011  		}
  3012  		/* Point to the next entry */
  3013  		pTable = pTable->pNext;
  3014  	}
  3015  	/* Try to load from disk */
  3016  	pTable = vedisTableLoadFromDisk(pDb,&sName,iType,nHash);
  3017  	if( pTable ){
  3018  		return pTable;
  3019  	}
  3020  	if( !create_new ){
  3021  		/* No such table */
  3022  		return 0;
  3023  	}
  3024  	/* fall through, create a new table */
  3025  	pTable = vedisNewTable(pDb,&sName,iType,nHash);
  3026  	if( !pTable ){
  3027  		vedisGenOutofMem(pDb);
  3028  		return 0;
  3029  	}
  3030  	return pTable;
  3031  }
  3032  /*
  3033   * Return the name of the given table.
  3034   */
  3035  VEDIS_PRIVATE  SyString * vedisTableName(vedis_table *pEntry)
  3036  {
  3037  	return &pEntry->sName;
  3038  }
  3039  /*
  3040   * Return the next table on the chain.
  3041   */
  3042  VEDIS_PRIVATE  vedis_table * vedisTableChain(vedis_table *pEntry)
  3043  {
  3044  	return pEntry->pNext;
  3045  }
  3046  /*
  3047   * ----------------------------------------------------------
  3048   * File: parse.c
  3049   * MD5: 90f0b67cbdc5dc75d39c2ce4f9ba3edd
  3050   * ----------------------------------------------------------
  3051   */
  3052  /*
  3053   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
  3054   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
  3055   * Version 1.2.6
  3056   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  3057   * please contact Symisc Systems via:
  3058   *       legal@symisc.net
  3059   *       licensing@symisc.net
  3060   *       contact@symisc.net
  3061   * or visit:
  3062   *      http://vedis.symisc.net/
  3063   */
  3064  /* $SymiscID: parse.c v1.3 Win7 2013-07-08 05:42 stable <chm@symisc.net> $ */
  3065  #ifndef VEDIS_AMALGAMATION
  3066  #include "vedisInt.h"
  3067  #endif
  3068  /* Vedis command Lexer & parser */
  3069  /*
  3070   * Tokenize a raw input.
  3071   * Get a single low-level token from the input file. Update the stream pointer so that
  3072   * it points to the first character beyond the extracted token.
  3073   */
  3074  static sxi32 vedisTokenizeInput(SyStream *pStream,SyToken *pToken,void *pUserData,void *pCtxData)
  3075  {
  3076  	const unsigned char *zIn;
  3077  	SyString *pStr;
  3078  	sxi32 c;
  3079  	/* Ignore leading white spaces */
  3080  	while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisSpace(pStream->zText[0]) ){
  3081  		/* Advance the stream cursor */
  3082  		if( pStream->zText[0] == '\n' ){
  3083  			/* Update line counter */
  3084  			pStream->nLine++;
  3085  		}
  3086  		pStream->zText++;
  3087  	}
  3088  	if( pStream->zText >= pStream->zEnd ){
  3089  		/* End of input reached */
  3090  		return SXERR_EOF;
  3091  	}
  3092  	/* Record token starting position and line */
  3093  	pToken->nLine = pStream->nLine;
  3094  	pToken->pUserData = 0;
  3095  	pStr = &pToken->sData;
  3096  	SyStringInitFromBuf(pStr, pStream->zText, 0);
  3097  	if( pStream->zText[0] == ';' ){
  3098  		pStream->zText++;
  3099  		/* A stream of semi-colons */
  3100  		while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && pStream->zText[0] == ';' ){
  3101  			pStream->zText++;
  3102  		}
  3103  		/* Mark the token */
  3104  		pToken->nType = VEDIS_TK_SEMI;
  3105  		/* Record token length */
  3106  		pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString);
  3107  	}else if( SyisDigit(pStream->zText[0]) ){
  3108  		pStream->zText++;
  3109  		/* Decimal digit stream */
  3110  		while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){
  3111  			pStream->zText++;
  3112  		}
  3113  		/* Mark the token as integer until we encounter a real number */
  3114  		pToken->nType = VEDIS_TK_INTEGER;
  3115  		if( pStream->zText < pStream->zEnd ){
  3116  			c = pStream->zText[0];
  3117  			if( c == '.' ){
  3118  				/* Real number */
  3119  				pStream->zText++;
  3120  				while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){
  3121  					pStream->zText++;
  3122  				}
  3123  				if( pStream->zText < pStream->zEnd ){
  3124  					c = pStream->zText[0];
  3125  					if( c=='e' || c=='E' ){
  3126  						pStream->zText++;
  3127  						if( pStream->zText < pStream->zEnd ){
  3128  							c = pStream->zText[0];
  3129  							if( (c =='+' || c=='-') && &pStream->zText[1] < pStream->zEnd  &&
  3130  								pStream->zText[1] < 0xc0 && SyisDigit(pStream->zText[1]) ){
  3131  									pStream->zText++;
  3132  							}
  3133  							while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){
  3134  								pStream->zText++;
  3135  							}
  3136  						}
  3137  					}
  3138  				}
  3139  				pToken->nType = VEDIS_TK_REAL;
  3140  			}else if( c=='e' || c=='E' ){
  3141  				SXUNUSED(pUserData); /* Prevent compiler warning */
  3142  				SXUNUSED(pCtxData);
  3143  				pStream->zText++;
  3144  				if( pStream->zText < pStream->zEnd ){
  3145  					c = pStream->zText[0];
  3146  					if( (c =='+' || c=='-') && &pStream->zText[1] < pStream->zEnd  &&
  3147  						pStream->zText[1] < 0xc0 && SyisDigit(pStream->zText[1]) ){
  3148  							pStream->zText++;
  3149  					}
  3150  					while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){
  3151  						pStream->zText++;
  3152  					}
  3153  				}
  3154  				pToken->nType = VEDIS_TK_REAL;
  3155  			}else if( c == 'x' || c == 'X' ){
  3156  				/* Hex digit stream */
  3157  				pStream->zText++;
  3158  				while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisHex(pStream->zText[0]) ){
  3159  					pStream->zText++;
  3160  				}
  3161  			}else if(c  == 'b' || c == 'B' ){
  3162  				/* Binary digit stream */
  3163  				pStream->zText++;
  3164  				while( pStream->zText < pStream->zEnd && (pStream->zText[0] == '0' || pStream->zText[0] == '1') ){
  3165  					pStream->zText++;
  3166  				}
  3167  			}
  3168  		}
  3169  		/* Record token length */
  3170  		pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString);
  3171  	}else if( pStream->zText[0] == '"' || pStream->zText[0] == '\'' ){
  3172  		/* Quoted string */
  3173  		c = pStream->zText[0];
  3174  		pStream->zText++;
  3175  		pStr->zString++;
  3176  		while( pStream->zText < pStream->zEnd ){
  3177  			if( pStream->zText[0] == c  ){
  3178  				if( pStream->zText[-1] != '\\' ){
  3179  					break;
  3180  				}
  3181  			}
  3182  			if( pStream->zText[0] == '\n' ){
  3183  				pStream->nLine++;
  3184  			}
  3185  			pStream->zText++;
  3186  		}
  3187  		/* Record token length and type */
  3188  		pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString);
  3189  		pToken->nType = VEDIS_TK_STREAM;
  3190  		/* Jump the trailing quote */
  3191  		pStream->zText++;
  3192  	}else{
  3193  		/* The following code fragment is taken verbatim from the xPP source tree.
  3194  		 * xPP is a modern embeddable macro processor with advanced features useful for
  3195  		 * application seeking for a production quality, ready to use macro processor.
  3196  		 * xPP is a widely used library developed and maintened by Symisc Systems.
  3197  		 * You can reach the xPP home page by following this link:
  3198  		 * http://symisc.net/
  3199  		 */
  3200  		/* Isolate UTF-8 or alphanumeric stream */
  3201  		if( pStream->zText[0] < 0xc0 ){
  3202  			pStream->zText++;
  3203  		}
  3204  		for(;;){
  3205  			zIn = pStream->zText;
  3206  			if( zIn[0] >= 0xc0 ){
  3207  				zIn++;
  3208  				/* UTF-8 stream */
  3209  				while( zIn < pStream->zEnd && ((zIn[0] & 0xc0) == 0x80) ){
  3210  					zIn++;
  3211  				}
  3212  			}
  3213  			/* Delimit the stream */
  3214  			while( zIn < pStream->zEnd && zIn[0] < 0xc0 && zIn[0] != ';' && !SyisSpace(zIn[0]) ){
  3215  				zIn++;
  3216  			}
  3217  			if( zIn == pStream->zText ){
  3218  				/* End of the stream */
  3219  				break;
  3220  			}
  3221  			/* Synchronize pointers */
  3222  			pStream->zText = zIn;
  3223  		}
  3224  		/* Record token length */
  3225  		pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString);
  3226  		/* A simple identifier */
  3227  		pToken->nType = VEDIS_TK_STREAM;
  3228  	}
  3229  	/* Tell the upper-layer to save the extracted token for later processing */
  3230  	return SXRET_OK;
  3231  }
  3232  /*
  3233   * Tokenize a raw input. 
  3234   */
  3235  static sxi32 vedisTokenize(const char *zInput,sxu32 nLen,SySet *pOut)
  3236  {
  3237  	SyLex sLexer;
  3238  	sxi32 rc;
  3239  	/* Initialize the lexer */
  3240  	rc = SyLexInit(&sLexer, &(*pOut),vedisTokenizeInput,0);
  3241  	if( rc != SXRET_OK ){
  3242  		return rc;
  3243  	}
  3244  	/* Tokenize input */
  3245  	rc = SyLexTokenizeInput(&sLexer, zInput, nLen, 0, 0, 0);
  3246  	/* Release the lexer */
  3247  	SyLexRelease(&sLexer);
  3248  	/* Tokenization result */
  3249  	return rc;
  3250  }
  3251  /*
  3252   * Vedis parser state is recorded in an instance of the following structure.
  3253   */
  3254  typedef struct vedis_gen_state vedis_gen_state;
  3255  struct vedis_gen_state
  3256  {
  3257  	SyToken *pIn;  /* Token stream */
  3258  	SyToken *pEnd; /* End of the token stream */
  3259  	vedis *pVedis;    /* Vedis handle  */
  3260  };
  3261  static int vedisInitContext(vedis_context *pCtx,vedis *pVedis,vedis_cmd *pCmd)
  3262  {
  3263  	pCtx->pVedis = pVedis;
  3264  	pCtx->pCmd = pCmd;
  3265  	SyBlobInit(&pCtx->sWorker,&pVedis->sMem);
  3266  	SySetInit(&pCtx->sVar, &pVedis->sMem, sizeof(vedis_value *));
  3267  	pCtx->pRet = &pVedis->sResult;
  3268  	/* Invalidate any prior representation */
  3269  	vedisMemObjRelease(pCtx->pRet);
  3270  	return VEDIS_OK;
  3271  }
  3272  VEDIS_PRIVATE SyBlob * VedisContextResultBuffer(vedis_context *pCtx)
  3273  {
  3274  	return &pCtx->pRet->sBlob;
  3275  }
  3276  VEDIS_PRIVATE SyBlob * VedisContextWorkingBuffer(vedis_context *pCtx)
  3277  {
  3278  	return &pCtx->sWorker;
  3279  }
  3280  static void vedisReleaseContext(vedis_context *pCtx)
  3281  {
  3282  	sxu32 n;
  3283  	if( SySetUsed(&pCtx->sVar) > 0 ){
  3284  		/* Context alloacated values */
  3285  		vedis_value **apObj = (vedis_value **)SySetBasePtr(&pCtx->sVar);
  3286  		for( n = 0 ; n < SySetUsed(&pCtx->sVar) ; ++n ){
  3287  			if( apObj[n] == 0 ){
  3288  				/* Already released */
  3289  				continue;
  3290  			}
  3291  			vedisMemObjRelease(apObj[n]);
  3292  			SyMemBackendPoolFree(&pCtx->pVedis->sMem, apObj[n]);
  3293  		}
  3294  		SySetRelease(&pCtx->sVar);
  3295  	}
  3296  	SyBlobRelease(&pCtx->sWorker);
  3297  }
  3298  static void vedisObjContainerDestroy(SySet *aValues,vedis *pVedis)
  3299  {
  3300  	vedis_value **apValues = (vedis_value **)SySetBasePtr(aValues);
  3301  	sxu32 n;
  3302  	for( n = 0 ; n < SySetUsed(aValues) ; ++n ){
  3303  		vedis_value *pValue = apValues[n];
  3304  		/* Destroy the object */
  3305  		vedisObjectValueDestroy(pVedis,pValue);
  3306  	}
  3307  	SySetRelease(aValues);
  3308  }
  3309  static int vedisExec(vedis_gen_state *pGen)
  3310  {
  3311  	vedis_value *pValue;
  3312  	vedis_context sCtx;
  3313  	vedis_cmd *pCmd;
  3314  	vedis *pStore;
  3315  	SySet sValue;
  3316  	int rc;
  3317  	/* Get the target command */
  3318  	if( !(pGen->pIn->nType & VEDIS_TK_STREAM) ){
  3319  		vedisGenError(pGen->pVedis,"Invalid Vedis command");
  3320  		return SXERR_INVALID;
  3321  	}
  3322  	pStore = pGen->pVedis;
  3323  	/* Extract it */
  3324  	pCmd = vedisFetchCommand(pStore,&pGen->pIn->sData);
  3325  	if( pCmd == 0 ){
  3326  		vedisGenErrorFormat(pStore,"Unknown Vedis command: '%z'",&pGen->pIn->sData);
  3327  		return SXERR_UNKNOWN;
  3328  	}
  3329  	pGen->pIn++;
  3330  	/* Collect command arguments */
  3331  	SySetInit(&sValue,&pStore->sMem,sizeof(vedis_value *));
  3332  	while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType != VEDIS_TK_SEMI /*';'*/) ){
  3333  		pValue = vedisNewObjectValue(pStore,pGen->pIn);
  3334  		if( pValue ){
  3335  			SySetPut(&sValue,(const void *)&pValue);
  3336  		}
  3337  		/* Point to the next token */
  3338  		pGen->pIn++;
  3339  	}
  3340  	/* Init the call context */
  3341  	vedisInitContext(&sCtx,pStore,pCmd);
  3342  	/* Invoke the command */
  3343  	rc = pCmd->xCmd(&sCtx,(int)SySetUsed(&sValue),(vedis_value **)SySetBasePtr(&sValue));
  3344  	if( rc == VEDIS_ABORT ){
  3345  		vedisGenErrorFormat(pGen->pVedis,"Vedis command '%z' request an operation abort",&pCmd->sName);
  3346  	}else{
  3347  		rc = VEDIS_OK;
  3348  	}
  3349  	/* Invoke any output consumer callback */
  3350  	if( pStore->xResultConsumer && rc == VEDIS_OK ){
  3351  		rc = pStore->xResultConsumer(sCtx.pRet,pStore->pUserData);
  3352  		if( rc != VEDIS_ABORT ){
  3353  			rc = VEDIS_OK;
  3354  		}
  3355  	}
  3356  	/* Cleanup */
  3357  	vedisReleaseContext(&sCtx);
  3358  	vedisObjContainerDestroy(&sValue,pGen->pVedis);
  3359  	return rc;
  3360  }
  3361  
  3362  VEDIS_PRIVATE int vedisProcessInput(vedis *pVedis,const char *zInput,sxu32 nByte)
  3363  {
  3364  	SySet sToken;
  3365  	int rc;
  3366  	/* Prepare the tokenizer */
  3367  	SySetInit(&sToken,&pVedis->sMem,sizeof(SyToken));
  3368  	/* Tokenize the input */
  3369  	rc = vedisTokenize(zInput,nByte,&sToken);
  3370  	if( rc != VEDIS_OK ){
  3371  		goto fail;
  3372  	}
  3373  	rc = VEDIS_OK;
  3374  	if( SySetUsed(&sToken) > 0 ){
  3375  		vedis_gen_state sGen;
  3376  		/* Init the parser state */
  3377  		sGen.pIn = (SyToken *)SySetBasePtr(&sToken);
  3378  		sGen.pEnd = &sGen.pIn[SySetUsed(&sToken)];
  3379  		sGen.pVedis = pVedis;
  3380  		/* Process the pipelined commands */
  3381  		for(;;){
  3382  			while( sGen.pIn < sGen.pEnd && sGen.pIn->nType == VEDIS_TK_SEMI ){
  3383  				/* Discard leading and trailing semi-colons */
  3384  				sGen.pIn++;
  3385  			}
  3386  			if( sGen.pIn >= sGen.pEnd ){
  3387  				/* End of the vedis input */
  3388  				break;
  3389  			}
  3390  			/* Execute the command if available */
  3391  			rc = vedisExec(&sGen);
  3392  			if( rc != VEDIS_OK ){
  3393  				break;
  3394  			}
  3395  		}
  3396  	}
  3397  	/* Fall through */
  3398  fail:
  3399  	/* Cleanup */
  3400  	SySetRelease(&sToken);
  3401  	return rc;
  3402  }
  3403  /*
  3404   * ----------------------------------------------------------
  3405   * File: pager.c
  3406   * MD5: b4db2677f77d8b4f49a90287106a7de1
  3407   * ----------------------------------------------------------
  3408   */
  3409  /*
  3410   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
  3411   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
  3412   * Version 1.1.6
  3413   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  3414   * please contact Symisc Systems via:
  3415   *       legal@symisc.net
  3416   *       licensing@symisc.net
  3417   *       contact@symisc.net
  3418   * or visit:
  3419   *      http://vedis.org/licensing.html
  3420   */
  3421   /* $SymiscID: pager.c v1.1 Win7 2012-11-29 03:46 stable <chm@symisc.net> $ */
  3422  #ifndef VEDIS_AMALGAMATION
  3423  #include "vedisInt.h"
  3424  #endif
  3425  /*
  3426  ** This file implements the pager and the transaction manager for UnQLite (Mostly inspired from the SQLite3 Source tree).
  3427  **
  3428  ** The Pager.eState variable stores the current 'state' of a pager. A
  3429  ** pager may be in any one of the seven states shown in the following
  3430  ** state diagram.
  3431  **
  3432  **                            OPEN <------+------+
  3433  **                              |         |      |
  3434  **                              V         |      |
  3435  **               +---------> READER-------+      |
  3436  **               |              |                |
  3437  **               |              V                |
  3438  **               |<-------WRITER_LOCKED--------->| 
  3439  **               |              |                |  
  3440  **               |              V                |
  3441  **               |<------WRITER_CACHEMOD-------->|
  3442  **               |              |                |
  3443  **               |              V                |
  3444  **               |<-------WRITER_DBMOD---------->|
  3445  **               |              |                |
  3446  **               |              V                |
  3447  **               +<------WRITER_FINISHED-------->+
  3448  ** 
  3449  **  OPEN:
  3450  **
  3451  **    The pager starts up in this state. Nothing is guaranteed in this
  3452  **    state - the file may or may not be locked and the database size is
  3453  **    unknown. The database may not be read or written.
  3454  **
  3455  **    * No read or write transaction is active.
  3456  **    * Any lock, or no lock at all, may be held on the database file.
  3457  **    * The dbSize and dbOrigSize variables may not be trusted.
  3458  **
  3459  **  READER:
  3460  **
  3461  **    In this state all the requirements for reading the database in 
  3462  **    rollback mode are met. Unless the pager is (or recently
  3463  **    was) in exclusive-locking mode, a user-level read transaction is 
  3464  **    open. The database size is known in this state.
  3465  ** 
  3466  **    * A read transaction may be active (but a write-transaction cannot).
  3467  **    * A SHARED or greater lock is held on the database file.
  3468  **    * The dbSize variable may be trusted (even if a user-level read 
  3469  **      transaction is not active). The dbOrigSize variables
  3470  **      may not be trusted at this point.
  3471  **    * Even if a read-transaction is not open, it is guaranteed that 
  3472  **      there is no hot-journal in the file-system.
  3473  **
  3474  **  WRITER_LOCKED:
  3475  **
  3476  **    The pager moves to this state from READER when a write-transaction
  3477  **    is first opened on the database. In WRITER_LOCKED state, all locks 
  3478  **    required to start a write-transaction are held, but no actual 
  3479  **    modifications to the cache or database have taken place.
  3480  **
  3481  **    In rollback mode, a RESERVED or (if the transaction was opened with 
  3482  **    EXCLUSIVE flag) EXCLUSIVE lock is obtained on the database file when
  3483  **    moving to this state, but the journal file is not written to or opened 
  3484  **    to in this state. If the transaction is committed or rolled back while 
  3485  **    in WRITER_LOCKED state, all that is required is to unlock the database 
  3486  **    file.
  3487  **
  3488  **    * A write transaction is active.
  3489  **    * If the connection is open in rollback-mode, a RESERVED or greater 
  3490  **      lock is held on the database file.
  3491  **    * The dbSize and dbOrigSize variables are all valid.
  3492  **    * The contents of the pager cache have not been modified.
  3493  **    * The journal file may or may not be open.
  3494  **    * Nothing (not even the first header) has been written to the journal.
  3495  **
  3496  **  WRITER_CACHEMOD:
  3497  **
  3498  **    A pager moves from WRITER_LOCKED state to this state when a page is
  3499  **    first modified by the upper layer. In rollback mode the journal file
  3500  **    is opened (if it is not already open) and a header written to the
  3501  **    start of it. The database file on disk has not been modified.
  3502  **
  3503  **    * A write transaction is active.
  3504  **    * A RESERVED or greater lock is held on the database file.
  3505  **    * The journal file is open and the first header has been written 
  3506  **      to it, but the header has not been synced to disk.
  3507  **    * The contents of the page cache have been modified.
  3508  **
  3509  **  WRITER_DBMOD:
  3510  **
  3511  **    The pager transitions from WRITER_CACHEMOD into WRITER_DBMOD state
  3512  **    when it modifies the contents of the database file.
  3513  **
  3514  **    * A write transaction is active.
  3515  **    * An EXCLUSIVE or greater lock is held on the database file.
  3516  **    * The journal file is open and the first header has been written 
  3517  **      and synced to disk.
  3518  **    * The contents of the page cache have been modified (and possibly
  3519  **      written to disk).
  3520  **
  3521  **  WRITER_FINISHED:
  3522  **
  3523  **    A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD
  3524  **    state after the entire transaction has been successfully written into the
  3525  **    database file. In this state the transaction may be committed simply
  3526  **    by finalizing the journal file. Once in WRITER_FINISHED state, it is 
  3527  **    not possible to modify the database further. At this point, the upper 
  3528  **    layer must either commit or rollback the transaction.
  3529  **
  3530  **    * A write transaction is active.
  3531  **    * An EXCLUSIVE or greater lock is held on the database file.
  3532  **    * All writing and syncing of journal and database data has finished.
  3533  **      If no error occured, all that remains is to finalize the journal to
  3534  **      commit the transaction. If an error did occur, the caller will need
  3535  **      to rollback the transaction. 
  3536  **  
  3537  **
  3538  */
  3539  #define PAGER_OPEN                  0
  3540  #define PAGER_READER                1
  3541  #define PAGER_WRITER_LOCKED         2
  3542  #define PAGER_WRITER_CACHEMOD       3
  3543  #define PAGER_WRITER_DBMOD          4
  3544  #define PAGER_WRITER_FINISHED       5
  3545  /*
  3546  ** Journal files begin with the following magic string.  The data
  3547  ** was obtained from /dev/random.  It is used only as a sanity check.
  3548  **
  3549  ** NOTE: These values must be different from the one used by SQLite3
  3550  ** to avoid journal file collision.
  3551  **
  3552  */
  3553  static const unsigned char aJournalMagic[] = {
  3554    0xc1, 0xd2, 0xfa, 0x77, 0x2b, 0x18, 0x27, 0x2a,
  3555  };
  3556  /*
  3557  ** The journal header size for this pager. This is usually the same 
  3558  ** size as a single disk sector. See also setSectorSize().
  3559  */
  3560  #define JOURNAL_HDR_SZ(pPager) (pPager->iSectorSize)
  3561  /*
  3562   * Database page handle.
  3563   * Each raw disk page is represented in memory by an instance
  3564   * of the following structure.
  3565   */
  3566  typedef struct Page Page;
  3567  struct Page {
  3568    /* Must correspond to vedis_page */
  3569    unsigned char *zData;           /* Content of this page */
  3570    void *pUserData;                /* Extra content */
  3571    pgno pgno;                      /* Page number for this page */
  3572    /**********************************************************************
  3573    ** Elements above are public.  All that follows is private to pcache.c
  3574    ** and should not be accessed by other modules.
  3575    */
  3576    Pager *pPager;                 /* The pager this page is part of */
  3577    int flags;                     /* Page flags defined below */
  3578    int nRef;                      /* Number of users of this page */
  3579    Page *pNext, *pPrev;    /* A list of all pages */
  3580    Page *pDirtyNext;             /* Next element in list of dirty pages */
  3581    Page *pDirtyPrev;             /* Previous element in list of dirty pages */
  3582    Page *pNextCollide,*pPrevCollide; /* Collission chain */
  3583    Page *pNextHot,*pPrevHot;    /* Hot dirty pages chain */
  3584  };
  3585  /* Bit values for Page.flags */
  3586  #define PAGE_DIRTY             0x002  /* Page has changed */
  3587  #define PAGE_NEED_SYNC         0x004  /* fsync the rollback journal before
  3588                                         ** writing this page to the database */
  3589  #define PAGE_DONT_WRITE        0x008  /* Dont write page content to disk */
  3590  #define PAGE_NEED_READ         0x010  /* Content is unread */
  3591  #define PAGE_IN_JOURNAL        0x020  /* Page written to the journal */
  3592  #define PAGE_HOT_DIRTY         0x040  /* Hot dirty page */
  3593  #define PAGE_DONT_MAKE_HOT     0x080  /* Dont make this page Hot. In other words,
  3594  									   * do not link it to the hot dirty list.
  3595  									   */
  3596  /*
  3597   * Each active database pager is represented by an instance of
  3598   * the following structure.
  3599   */
  3600  struct Pager
  3601  {
  3602    SyMemBackend *pAllocator;      /* Memory backend */
  3603    vedis *pDb;                  /* DB handle that own this instance */
  3604    vedis_kv_engine *pEngine;    /* Underlying KV storage engine */
  3605    char *zFilename;               /* Name of the database file */
  3606    char *zJournal;                /* Name of the journal file */
  3607    vedis_vfs *pVfs;             /* Underlying virtual file system */
  3608    vedis_file *pfd,*pjfd;       /* File descriptors for database and journal */
  3609    pgno dbSize;                   /* Number of pages in the file */
  3610    pgno dbOrigSize;               /* dbSize before the current change */
  3611    sxi64 dbByteSize;              /* Database size in bytes */
  3612    void *pMmap;                   /* Read-only Memory view (mmap) of the whole file if requested (VEDIS_OPEN_MMAP). */
  3613    sxu32 nRec;                    /* Number of pages written to the journal */
  3614    SyPRNGCtx sPrng;               /* PRNG Context */
  3615    sxu32 cksumInit;               /* Quasi-random value added to every checksum */
  3616    sxu32 iOpenFlags;              /* Flag passed to vedis_open() after processing */
  3617    sxi64 iJournalOfft;            /* Journal offset we are reading from */
  3618    int (*xBusyHandler)(void *);   /* Busy handler */
  3619    void *pBusyHandlerArg;         /* First arg to xBusyHandler() */
  3620    void (*xPageUnpin)(void *);    /* Page Unpin callback */
  3621    void (*xPageReload)(void *);   /* Page Reload callback */
  3622    int (*xCommit)(void *);        /* On commit user callback */
  3623    void *pCommitData;             /* First arg to xCommit() */
  3624    Bitvec *pVec;                  /* Bitmap */
  3625    Page *pHeader;                 /* Page one of the database (Unqlite header) */
  3626    Sytm tmCreate;                 /* Database creation time */
  3627    SyString sKv;                  /* Underlying Key/Value storage engine name */
  3628    int iState;                    /* Pager state */
  3629    int iLock;                     /* Lock state */
  3630    sxi32 iFlags;                  /* Control flags (see below) */
  3631    int is_mem;                    /* True for an in-memory database */
  3632    int is_rdonly;                 /* True for a read-only database */
  3633    int no_jrnl;                   /* TRUE to omit journaling */
  3634    int iPageSize;                 /* Page size in bytes (default 4K) */
  3635    int iSectorSize;               /* Size of a single sector on disk */
  3636    unsigned char *zTmpPage;       /* Temporary page */
  3637    Page *pFirstDirty;             /* First dirty pages */
  3638    Page *pDirty;                  /* Transient list of dirty pages */
  3639    Page *pAll;                    /* List of all pages */
  3640    Page *pHotDirty;               /* List of hot dirty pages */
  3641    Page *pFirstHot;               /* First hot dirty page */
  3642    sxu32 nHot;                    /* Total number of hot dirty pages */
  3643    Page **apHash;                 /* Page table */
  3644    sxu32 nSize;                   /* apHash[] size: Must be a power of two  */
  3645    sxu32 nPage;                   /* Total number of page loaded in memory */
  3646    sxu32 nCacheMax;               /* Maximum page to cache*/
  3647  };
  3648  /* Control flags */
  3649  #define PAGER_CTRL_COMMIT_ERR   0x001 /* Commit error */
  3650  #define PAGER_CTRL_DIRTY_COMMIT 0x002 /* Dirty commit has been applied */ 
  3651  /*
  3652  ** Read a 32-bit integer from the given file descriptor. 
  3653  ** All values are stored on disk as big-endian.
  3654  */
  3655  static int ReadInt32(vedis_file *pFd,sxu32 *pOut,sxi64 iOfft)
  3656  {
  3657  	unsigned char zBuf[4];
  3658  	int rc;
  3659  	rc = vedisOsRead(pFd,zBuf,sizeof(zBuf),iOfft);
  3660  	if( rc != VEDIS_OK ){
  3661  		return rc;
  3662  	}
  3663  	SyBigEndianUnpack32(zBuf,pOut);
  3664  	return VEDIS_OK;
  3665  }
  3666  /*
  3667  ** Read a 64-bit integer from the given file descriptor. 
  3668  ** All values are stored on disk as big-endian.
  3669  */
  3670  static int ReadInt64(vedis_file *pFd,sxu64 *pOut,sxi64 iOfft)
  3671  {
  3672  	unsigned char zBuf[8];
  3673  	int rc;
  3674  	rc = vedisOsRead(pFd,zBuf,sizeof(zBuf),iOfft);
  3675  	if( rc != VEDIS_OK ){
  3676  		return rc;
  3677  	}
  3678  	SyBigEndianUnpack64(zBuf,pOut);
  3679  	return VEDIS_OK;
  3680  }
  3681  /*
  3682  ** Write a 32-bit integer into the given file descriptor.
  3683  */
  3684  static int WriteInt32(vedis_file *pFd,sxu32 iNum,sxi64 iOfft)
  3685  {
  3686  	unsigned char zBuf[4];
  3687  	int rc;
  3688  	SyBigEndianPack32(zBuf,iNum);
  3689  	rc = vedisOsWrite(pFd,zBuf,sizeof(zBuf),iOfft);
  3690  	return rc;
  3691  }
  3692  /*
  3693  ** Write a 64-bit integer into the given file descriptor.
  3694  */
  3695  static int WriteInt64(vedis_file *pFd,sxu64 iNum,sxi64 iOfft)
  3696  {
  3697  	unsigned char zBuf[8];
  3698  	int rc;
  3699  	SyBigEndianPack64(zBuf,iNum);
  3700  	rc = vedisOsWrite(pFd,zBuf,sizeof(zBuf),iOfft);
  3701  	return rc;
  3702  }
  3703  /*
  3704  ** The maximum allowed sector size. 64KiB. If the xSectorsize() method 
  3705  ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
  3706  ** This could conceivably cause corruption following a power failure on
  3707  ** such a system. This is currently an undocumented limit.
  3708  */
  3709  #define MAX_SECTOR_SIZE 0x10000
  3710  /*
  3711  ** Get the size of a single sector on disk.
  3712  ** The sector size will be used used  to determine the size
  3713  ** and alignment of journal header and within created journal files.
  3714  **
  3715  ** The default sector size is set to 512.
  3716  */
  3717  static int GetSectorSize(vedis_file *pFd)
  3718  {
  3719  	int iSectorSize = VEDIS_DEFAULT_SECTOR_SIZE;
  3720  	if( pFd ){
  3721  		iSectorSize = vedisOsSectorSize(pFd);
  3722  		if( iSectorSize < 32 ){
  3723  			iSectorSize = 512;
  3724  		}
  3725  		if( iSectorSize > MAX_SECTOR_SIZE ){
  3726  			iSectorSize = MAX_SECTOR_SIZE;
  3727  		}
  3728  	}
  3729  	return iSectorSize;
  3730  }
  3731  /* Hash function for page number  */
  3732  #define PAGE_HASH(PNUM) (PNUM)
  3733  /*
  3734   * Fetch a page from the cache.
  3735   */
  3736  static Page * pager_fetch_page(Pager *pPager,pgno page_num)
  3737  {
  3738  	Page *pEntry;
  3739  	if( pPager->nPage < 1 ){
  3740  		/* Don't bother hashing */
  3741  		return 0;
  3742  	}
  3743  	/* Perform the lookup */
  3744  	pEntry = pPager->apHash[PAGE_HASH(page_num) & (pPager->nSize - 1)];
  3745  	for(;;){
  3746  		if( pEntry == 0 ){
  3747  			break;
  3748  		}
  3749  		if( pEntry->pgno == page_num ){
  3750  			return pEntry;
  3751  		}
  3752  		/* Point to the next entry in the colission chain */
  3753  		pEntry = pEntry->pNextCollide;
  3754  	}
  3755  	/* No such page */
  3756  	return 0;
  3757  }
  3758  /*
  3759   * Allocate and initialize a new page.
  3760   */
  3761  static Page * pager_alloc_page(Pager *pPager,pgno num_page)
  3762  {
  3763  	Page *pNew;
  3764  	
  3765  	pNew = (Page *)SyMemBackendPoolAlloc(pPager->pAllocator,sizeof(Page)+pPager->iPageSize);
  3766  	if( pNew == 0 ){
  3767  		return 0;
  3768  	}
  3769  	/* Zero the structure */
  3770  	SyZero(pNew,sizeof(Page)+pPager->iPageSize);
  3771  	/* Page data */
  3772  	pNew->zData = (unsigned char *)&pNew[1];
  3773  	/* Fill in the structure */
  3774  	pNew->pPager = pPager;
  3775  	pNew->nRef = 1;
  3776  	pNew->pgno = num_page;
  3777  	return pNew;
  3778  }
  3779  /*
  3780   * Increment the reference count of a given page.
  3781   */
  3782  static void page_ref(Page *pPage)
  3783  {
  3784  	pPage->nRef++;
  3785  }
  3786  /*
  3787   * Release an in-memory page after its reference count reach zero.
  3788   */
  3789  static int pager_release_page(Pager *pPager,Page *pPage)
  3790  {
  3791  	int rc = VEDIS_OK;
  3792  	if( !(pPage->flags & PAGE_DIRTY)){
  3793  		/* Invoke the unpin callback if available */
  3794  		if( pPager->xPageUnpin && pPage->pUserData ){
  3795  			pPager->xPageUnpin(pPage->pUserData);
  3796  		}
  3797  		pPage->pUserData = 0;
  3798  		SyMemBackendPoolFree(pPager->pAllocator,pPage);
  3799  	}else{
  3800  		/* Dirty page, it will be released later when a dirty commit
  3801  		 * or the final commit have been applied.
  3802  		 */
  3803  		rc = VEDIS_LOCKED;
  3804  	}
  3805  	return rc;
  3806  }
  3807  /* Forward declaration */
  3808  static int pager_unlink_page(Pager *pPager,Page *pPage);
  3809  /*
  3810   * Decrement the reference count of a given page.
  3811   */
  3812  static void page_unref(Page *pPage)
  3813  {
  3814  	pPage->nRef--;
  3815  	if( pPage->nRef < 1	){
  3816  		Pager *pPager = pPage->pPager;
  3817  		if( !(pPage->flags & PAGE_DIRTY)  ){
  3818  			pager_unlink_page(pPager,pPage);
  3819  			/* Release the page */
  3820  			pager_release_page(pPager,pPage);
  3821  		}else{
  3822  			if( pPage->flags & PAGE_DONT_MAKE_HOT ){
  3823  				/* Do not add this page to the hot dirty list */
  3824  				return;
  3825  			}
  3826  			if( !(pPage->flags & PAGE_HOT_DIRTY) ){
  3827  				/* Add to the hot dirty list */
  3828  				pPage->pPrevHot = 0;
  3829  				if( pPager->pFirstHot == 0 ){
  3830  					pPager->pFirstHot = pPager->pHotDirty = pPage;
  3831  				}else{
  3832  					pPage->pNextHot = pPager->pHotDirty;
  3833  					if( pPager->pHotDirty ){
  3834  						pPager->pHotDirty->pPrevHot = pPage;
  3835  					}
  3836  					pPager->pHotDirty = pPage;
  3837  				}
  3838  				pPager->nHot++;
  3839  				pPage->flags |= PAGE_HOT_DIRTY;
  3840  			}
  3841  		}
  3842  	}
  3843  }
  3844  /*
  3845   * Link a freshly created page to the list of active page.
  3846   */
  3847  static int pager_link_page(Pager *pPager,Page *pPage)
  3848  {
  3849  	sxu32 nBucket;
  3850  	/* Install in the corresponding bucket */
  3851  	nBucket = PAGE_HASH(pPage->pgno) & (pPager->nSize - 1);
  3852  	pPage->pNextCollide = pPager->apHash[nBucket];
  3853  	if( pPager->apHash[nBucket] ){
  3854  		pPager->apHash[nBucket]->pPrevCollide = pPage;
  3855  	}
  3856  	pPager->apHash[nBucket] = pPage;
  3857  	/* Link to the list of active pages */
  3858  	MACRO_LD_PUSH(pPager->pAll,pPage);
  3859  	pPager->nPage++;
  3860  	if( (pPager->nPage >= pPager->nSize * 4)  && pPager->nPage < 100000 ){
  3861  		/* Grow the hashtable */
  3862  		sxu32 nNewSize = pPager->nSize << 1;
  3863  		Page *pEntry,**apNew;
  3864  		sxu32 n;
  3865  		apNew = (Page **)SyMemBackendAlloc(pPager->pAllocator, nNewSize * sizeof(Page *));
  3866  		if( apNew ){
  3867  			sxu32 iBucket;
  3868  			/* Zero the new table */
  3869  			SyZero((void *)apNew, nNewSize * sizeof(Page *));
  3870  			/* Rehash all entries */
  3871  			n = 0;
  3872  			pEntry = pPager->pAll;
  3873  			for(;;){
  3874  				/* Loop one */
  3875  				if( n >= pPager->nPage ){
  3876  					break;
  3877  				}
  3878  				pEntry->pNextCollide = pEntry->pPrevCollide = 0;
  3879  				/* Install in the new bucket */
  3880  				iBucket = PAGE_HASH(pEntry->pgno) & (nNewSize - 1);
  3881  				pEntry->pNextCollide = apNew[iBucket];
  3882  				if( apNew[iBucket] ){
  3883  					apNew[iBucket]->pPrevCollide = pEntry;
  3884  				}
  3885  				apNew[iBucket] = pEntry;
  3886  				/* Point to the next entry */
  3887  				pEntry = pEntry->pNext;
  3888  				n++;
  3889  			}
  3890  			/* Release the old table and reflect the change */
  3891  			SyMemBackendFree(pPager->pAllocator,(void *)pPager->apHash);
  3892  			pPager->apHash = apNew;
  3893  			pPager->nSize  = nNewSize;
  3894  		}
  3895  	}
  3896  	return VEDIS_OK;
  3897  }
  3898  /*
  3899   * Unlink a page from the list of active pages.
  3900   */
  3901  static int pager_unlink_page(Pager *pPager,Page *pPage)
  3902  {
  3903  	if( pPage->pNextCollide ){
  3904  		pPage->pNextCollide->pPrevCollide = pPage->pPrevCollide;
  3905  	}
  3906  	if( pPage->pPrevCollide ){
  3907  		pPage->pPrevCollide->pNextCollide = pPage->pNextCollide;
  3908  	}else{
  3909  		sxu32 nBucket = PAGE_HASH(pPage->pgno) & (pPager->nSize - 1);
  3910  		pPager->apHash[nBucket] = pPage->pNextCollide;
  3911  	}
  3912  	MACRO_LD_REMOVE(pPager->pAll,pPage);
  3913  	pPager->nPage--;
  3914  	return VEDIS_OK;
  3915  }
  3916  /*
  3917   * Update the content of a cached page.
  3918   */
  3919  static int pager_fill_page(Pager *pPager,pgno iNum,void *pContents)
  3920  {
  3921  	Page *pPage;
  3922  	/* Fetch the page from the catch */
  3923  	pPage = pager_fetch_page(pPager,iNum);
  3924  	if( pPage == 0 ){
  3925  		return SXERR_NOTFOUND;
  3926  	}
  3927  	/* Reflect the change */
  3928  	SyMemcpy(pContents,pPage->zData,pPager->iPageSize);
  3929  
  3930  	return VEDIS_OK;
  3931  }
  3932  /*
  3933   * Read the content of a page from disk.
  3934   */
  3935  static int pager_get_page_contents(Pager *pPager,Page *pPage,int noContent)
  3936  {
  3937  	int rc = VEDIS_OK;
  3938  	if( pPager->is_mem || noContent || pPage->pgno >= pPager->dbSize ){
  3939  		/* Do not bother reading, zero the page contents only */
  3940  		SyZero(pPage->zData,pPager->iPageSize);
  3941  		return VEDIS_OK;
  3942  	}
  3943  	if( (pPager->iOpenFlags & VEDIS_OPEN_MMAP) && (pPager->pMmap /* Paranoid edition */) ){
  3944  		unsigned char *zMap = (unsigned char *)pPager->pMmap;
  3945  		pPage->zData = &zMap[pPage->pgno * pPager->iPageSize];
  3946  	}else{
  3947  		/* Read content */
  3948  		rc = vedisOsRead(pPager->pfd,pPage->zData,pPager->iPageSize,pPage->pgno * pPager->iPageSize);
  3949  	}
  3950  	return rc;
  3951  }
  3952  /*
  3953   * Add a page to the dirty list.
  3954   */
  3955  static void pager_page_to_dirty_list(Pager *pPager,Page *pPage)
  3956  {
  3957  	if( pPage->flags & PAGE_DIRTY ){
  3958  		/* Already set */
  3959  		return;
  3960  	}
  3961  	/* Mark the page as dirty */
  3962  	pPage->flags |= PAGE_DIRTY|PAGE_NEED_SYNC|PAGE_IN_JOURNAL;
  3963  	/* Link to the list */
  3964  	pPage->pDirtyPrev = 0;
  3965  	pPage->pDirtyNext = pPager->pDirty;
  3966  	if( pPager->pDirty ){
  3967  		pPager->pDirty->pDirtyPrev = pPage;
  3968  	}
  3969  	pPager->pDirty = pPage;
  3970  	if( pPager->pFirstDirty == 0 ){
  3971  		pPager->pFirstDirty = pPage;
  3972  	}
  3973  }
  3974  /*
  3975   * Merge sort.
  3976   * The merge sort implementation is based on the one used by
  3977   * the PH7 Embeddable PHP Engine (http://ph7.symisc.net/).
  3978   */
  3979  /*
  3980  ** Inputs:
  3981  **   a:       A sorted, null-terminated linked list.  (May be null).
  3982  **   b:       A sorted, null-terminated linked list.  (May be null).
  3983  **   cmp:     A pointer to the comparison function.
  3984  **
  3985  ** Return Value:
  3986  **   A pointer to the head of a sorted list containing the elements
  3987  **   of both a and b.
  3988  **
  3989  ** Side effects:
  3990  **   The "next", "prev" pointers for elements in the lists a and b are
  3991  **   changed.
  3992  */
  3993  static Page * page_merge_dirty(Page *pA, Page *pB)
  3994  {
  3995  	Page result, *pTail;
  3996      /* Prevent compiler warning */
  3997  	result.pDirtyNext = result.pDirtyPrev = 0;
  3998  	pTail = &result;
  3999  	while( pA && pB ){
  4000  		if( pA->pgno < pB->pgno ){
  4001  			pTail->pDirtyPrev = pA;
  4002  			pA->pDirtyNext = pTail;
  4003  			pTail = pA;
  4004  			pA = pA->pDirtyPrev;
  4005  		}else{
  4006  			pTail->pDirtyPrev = pB;
  4007  			pB->pDirtyNext = pTail;
  4008  			pTail = pB;
  4009  			pB = pB->pDirtyPrev;
  4010  		}
  4011  	}
  4012  	if( pA ){
  4013  		pTail->pDirtyPrev = pA;
  4014  		pA->pDirtyNext = pTail;
  4015  	}else if( pB ){
  4016  		pTail->pDirtyPrev = pB;
  4017  		pB->pDirtyNext = pTail;
  4018  	}else{
  4019  		pTail->pDirtyPrev = pTail->pDirtyNext = 0;
  4020  	}
  4021  	return result.pDirtyPrev;
  4022  }
  4023  /*
  4024  ** Inputs:
  4025  **   Map:       Input hashmap
  4026  **   cmp:       A comparison function.
  4027  **
  4028  ** Return Value:
  4029  **   Sorted hashmap.
  4030  **
  4031  ** Side effects:
  4032  **   The "next" pointers for elements in list are changed.
  4033  */
  4034  #define N_SORT_BUCKET  32
  4035  static Page * pager_get_dirty_pages(Pager *pPager)
  4036  {
  4037  	Page *a[N_SORT_BUCKET], *p, *pIn;
  4038  	sxu32 i;
  4039  	if( pPager->pFirstDirty == 0 ){
  4040  		/* Don't bother sorting, the list is already empty */
  4041  		return 0;
  4042  	}
  4043  	SyZero(a, sizeof(a));
  4044  	/* Point to the first inserted entry */
  4045  	pIn = pPager->pFirstDirty;
  4046  	while( pIn ){
  4047  		p = pIn;
  4048  		pIn = p->pDirtyPrev;
  4049  		p->pDirtyPrev = 0;
  4050  		for(i=0; i<N_SORT_BUCKET-1; i++){
  4051  			if( a[i]==0 ){
  4052  				a[i] = p;
  4053  				break;
  4054  			}else{
  4055  				p = page_merge_dirty(a[i], p);
  4056  				a[i] = 0;
  4057  			}
  4058  		}
  4059  		if( i==N_SORT_BUCKET-1 ){
  4060  			/* To get here, there need to be 2^(N_SORT_BUCKET) elements in he input list.
  4061  			 * But that is impossible.
  4062  			 */
  4063  			a[i] = page_merge_dirty(a[i], p);
  4064  		}
  4065  	}
  4066  	p = a[0];
  4067  	for(i=1; i<N_SORT_BUCKET; i++){
  4068  		p = page_merge_dirty(p,a[i]);
  4069  	}
  4070  	p->pDirtyNext = 0;
  4071  	return p;
  4072  }
  4073  /*
  4074   * See block comment above.
  4075   */
  4076  static Page * page_merge_hot(Page *pA, Page *pB)
  4077  {
  4078  	Page result, *pTail;
  4079      /* Prevent compiler warning */
  4080  	result.pNextHot = result.pPrevHot = 0;
  4081  	pTail = &result;
  4082  	while( pA && pB ){
  4083  		if( pA->pgno < pB->pgno ){
  4084  			pTail->pPrevHot = pA;
  4085  			pA->pNextHot = pTail;
  4086  			pTail = pA;
  4087  			pA = pA->pPrevHot;
  4088  		}else{
  4089  			pTail->pPrevHot = pB;
  4090  			pB->pNextHot = pTail;
  4091  			pTail = pB;
  4092  			pB = pB->pPrevHot;
  4093  		}
  4094  	}
  4095  	if( pA ){
  4096  		pTail->pPrevHot = pA;
  4097  		pA->pNextHot = pTail;
  4098  	}else if( pB ){
  4099  		pTail->pPrevHot = pB;
  4100  		pB->pNextHot = pTail;
  4101  	}else{
  4102  		pTail->pPrevHot = pTail->pNextHot = 0;
  4103  	}
  4104  	return result.pPrevHot;
  4105  }
  4106  /*
  4107  ** Inputs:
  4108  **   Map:       Input hashmap
  4109  **   cmp:       A comparison function.
  4110  **
  4111  ** Return Value:
  4112  **   Sorted hashmap.
  4113  **
  4114  ** Side effects:
  4115  **   The "next" pointers for elements in list are changed.
  4116  */
  4117  #define N_SORT_BUCKET  32
  4118  static Page * pager_get_hot_pages(Pager *pPager)
  4119  {
  4120  	Page *a[N_SORT_BUCKET], *p, *pIn;
  4121  	sxu32 i;
  4122  	if( pPager->pFirstHot == 0 ){
  4123  		/* Don't bother sorting, the list is already empty */
  4124  		return 0;
  4125  	}
  4126  	SyZero(a, sizeof(a));
  4127  	/* Point to the first inserted entry */
  4128  	pIn = pPager->pFirstHot;
  4129  	while( pIn ){
  4130  		p = pIn;
  4131  		pIn = p->pPrevHot;
  4132  		p->pPrevHot = 0;
  4133  		for(i=0; i<N_SORT_BUCKET-1; i++){
  4134  			if( a[i]==0 ){
  4135  				a[i] = p;
  4136  				break;
  4137  			}else{
  4138  				p = page_merge_hot(a[i], p);
  4139  				a[i] = 0;
  4140  			}
  4141  		}
  4142  		if( i==N_SORT_BUCKET-1 ){
  4143  			/* To get here, there need to be 2^(N_SORT_BUCKET) elements in he input list.
  4144  			 * But that is impossible.
  4145  			 */
  4146  			a[i] = page_merge_hot(a[i], p);
  4147  		}
  4148  	}
  4149  	p = a[0];
  4150  	for(i=1; i<N_SORT_BUCKET; i++){
  4151  		p = page_merge_hot(p,a[i]);
  4152  	}
  4153  	p->pNextHot = 0;
  4154  	return p;
  4155  }
  4156  /*
  4157  ** The format for the journal header is as follows:
  4158  ** - 8 bytes: Magic identifying journal format.
  4159  ** - 4 bytes: Number of records in journal.
  4160  ** - 4 bytes: Random number used for page hash.
  4161  ** - 8 bytes: Initial database page count.
  4162  ** - 4 bytes: Sector size used by the process that wrote this journal.
  4163  ** - 4 bytes: Database page size.
  4164  ** 
  4165  ** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.
  4166  */
  4167  /*
  4168  ** Open the journal file and extract its header information.
  4169  **
  4170  ** If the header is read successfully, *pNRec is set to the number of
  4171  ** page records following this header and *pDbSize is set to the size of the
  4172  ** database before the transaction began, in pages. Also, pPager->cksumInit
  4173  ** is set to the value read from the journal header. VEDIS_OK is returned
  4174  ** in this case.
  4175  **
  4176  ** If the journal header file appears to be corrupted, VEDIS_DONE is
  4177  ** returned and *pNRec and *PDbSize are undefined.  If JOURNAL_HDR_SZ bytes
  4178  ** cannot be read from the journal file an error code is returned.
  4179  */
  4180  static int pager_read_journal_header(
  4181    Pager *pPager,               /* Pager object */
  4182    sxu32 *pNRec,                /* OUT: Value read from the nRec field */
  4183    pgno  *pDbSize               /* OUT: Value of original database size field */
  4184  )
  4185  {
  4186  	sxu32 iPageSize,iSectorSize;
  4187  	unsigned char zMagic[8];
  4188  	sxi64 iHdrOfft;
  4189  	sxi64 iSize;
  4190  	int rc;
  4191  	/* Offset to start reading from */
  4192  	iHdrOfft = 0;
  4193  	/* Get the size of the journal */
  4194  	rc = vedisOsFileSize(pPager->pjfd,&iSize);
  4195  	if( rc != VEDIS_OK ){
  4196  		return VEDIS_DONE;
  4197  	}
  4198  	/* If the journal file is too small, return VEDIS_DONE. */
  4199  	if( 32 /* Minimum sector size */> iSize ){
  4200  		return VEDIS_DONE;
  4201  	}
  4202  	/* Make sure we are dealing with a valid journal */
  4203  	rc = vedisOsRead(pPager->pjfd,zMagic,sizeof(zMagic),iHdrOfft);
  4204  	if( rc != VEDIS_OK ){
  4205  		return rc;
  4206  	}
  4207  	if( SyMemcmp(zMagic,aJournalMagic,sizeof(zMagic)) != 0 ){
  4208  		return VEDIS_DONE;
  4209  	}
  4210  	iHdrOfft += sizeof(zMagic);
  4211  	 /* Read the first three 32-bit fields of the journal header: The nRec
  4212        ** field, the checksum-initializer and the database size at the start
  4213        ** of the transaction. Return an error code if anything goes wrong.
  4214        */
  4215  	rc = ReadInt32(pPager->pjfd,pNRec,iHdrOfft);
  4216  	if( rc != VEDIS_OK ){
  4217  		return rc;
  4218  	}
  4219  	iHdrOfft += 4;
  4220  	rc = ReadInt32(pPager->pjfd,&pPager->cksumInit,iHdrOfft);
  4221  	if( rc != VEDIS_OK ){
  4222  		return rc;
  4223  	}
  4224  	iHdrOfft += 4;
  4225  	rc = ReadInt64(pPager->pjfd,pDbSize,iHdrOfft);
  4226  	if( rc != VEDIS_OK ){
  4227  		return rc;
  4228  	}
  4229  	iHdrOfft += 8;
  4230  	/* Read the page-size and sector-size journal header fields. */
  4231  	rc = ReadInt32(pPager->pjfd,&iSectorSize,iHdrOfft);
  4232  	if( rc != VEDIS_OK ){
  4233  		return rc;
  4234  	}
  4235  	iHdrOfft += 4;
  4236  	rc = ReadInt32(pPager->pjfd,&iPageSize,iHdrOfft);
  4237  	if( rc != VEDIS_OK ){
  4238  		return rc;
  4239  	}
  4240  	/* Check that the values read from the page-size and sector-size fields
  4241      ** are within range. To be 'in range', both values need to be a power
  4242      ** of two greater than or equal to 512 or 32, and not greater than their 
  4243      ** respective compile time maximum limits.
  4244      */
  4245      if( iPageSize < VEDIS_MIN_PAGE_SIZE || iSectorSize<32
  4246       || iPageSize > VEDIS_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE
  4247       || ((iPageSize-1)&iPageSize)!=0    || ((iSectorSize-1)&iSectorSize)!=0 
  4248      ){
  4249        /* If the either the page-size or sector-size in the journal-header is 
  4250        ** invalid, then the process that wrote the journal-header must have 
  4251        ** crashed before the header was synced. In this case stop reading 
  4252        ** the journal file here.
  4253        */
  4254        return VEDIS_DONE;
  4255      }
  4256      /* Update the assumed sector-size to match the value used by 
  4257      ** the process that created this journal. If this journal was
  4258      ** created by a process other than this one, then this routine
  4259      ** is being called from within pager_playback(). The local value
  4260      ** of Pager.sectorSize is restored at the end of that routine.
  4261      */
  4262      pPager->iSectorSize = iSectorSize;
  4263  	pPager->iPageSize = iPageSize;
  4264  	/* Ready to rollback */
  4265  	pPager->iJournalOfft = JOURNAL_HDR_SZ(pPager);
  4266  	/* All done */
  4267  	return VEDIS_OK;
  4268  }
  4269  /*
  4270   * Write the journal header in the given memory buffer.
  4271   * The given buffer is big enough to hold the whole header.
  4272   */
  4273  static int pager_write_journal_header(Pager *pPager,unsigned char *zBuf)
  4274  {
  4275  	unsigned char *zPtr = zBuf;
  4276  	/* 8 bytes magic number */
  4277  	SyMemcpy(aJournalMagic,zPtr,sizeof(aJournalMagic));
  4278  	zPtr += sizeof(aJournalMagic);
  4279  	/* 4 bytes: Number of records in journal. */
  4280  	SyBigEndianPack32(zPtr,0);
  4281  	zPtr += 4;
  4282  	/* 4 bytes: Random number used to compute page checksum. */
  4283  	SyBigEndianPack32(zPtr,pPager->cksumInit);
  4284  	zPtr += 4;
  4285  	/* 8 bytes: Initial database page count. */
  4286  	SyBigEndianPack64(zPtr,pPager->dbOrigSize);
  4287  	zPtr += 8;
  4288  	/* 4 bytes: Sector size used by the process that wrote this journal. */
  4289  	SyBigEndianPack32(zPtr,(sxu32)pPager->iSectorSize);
  4290  	zPtr += 4;
  4291  	/* 4 bytes: Database page size. */
  4292  	SyBigEndianPack32(zPtr,(sxu32)pPager->iPageSize);
  4293  	return VEDIS_OK;
  4294  }
  4295  /*
  4296  ** Parameter aData must point to a buffer of pPager->pageSize bytes
  4297  ** of data. Compute and return a checksum based ont the contents of the 
  4298  ** page of data and the current value of pPager->cksumInit.
  4299  **
  4300  ** This is not a real checksum. It is really just the sum of the 
  4301  ** random initial value (pPager->cksumInit) and every 200th byte
  4302  ** of the page data, starting with byte offset (pPager->pageSize%200).
  4303  ** Each byte is interpreted as an 8-bit unsigned integer.
  4304  **
  4305  ** Changing the formula used to compute this checksum results in an
  4306  ** incompatible journal file format.
  4307  **
  4308  ** If journal corruption occurs due to a power failure, the most likely 
  4309  ** scenario is that one end or the other of the record will be changed. 
  4310  ** It is much less likely that the two ends of the journal record will be
  4311  ** correct and the middle be corrupt.  Thus, this "checksum" scheme,
  4312  ** though fast and simple, catches the mostly likely kind of corruption.
  4313  */
  4314  static sxu32 pager_cksum(Pager *pPager,const unsigned char *zData)
  4315  {
  4316    sxu32 cksum = pPager->cksumInit;         /* Checksum value to return */
  4317    int i = pPager->iPageSize-200;          /* Loop counter */
  4318    while( i>0 ){
  4319      cksum += zData[i];
  4320      i -= 200;
  4321    }
  4322    return cksum;
  4323  }
  4324  /*
  4325  ** Read a single page from the journal file opened on file descriptor
  4326  ** jfd. Playback this one page. Update the offset to read from.
  4327  */
  4328  static int pager_play_back_one_page(Pager *pPager,sxi64 *pOfft,unsigned char *zTmp)
  4329  {
  4330  	unsigned char *zData = zTmp;
  4331  	sxi64 iOfft; /* Offset to read from */
  4332  	pgno iNum;   /* Pager number */
  4333  	sxu32 ckSum; /* Sanity check */
  4334  	int rc;
  4335  	/* Offset to start reading from */
  4336  	iOfft = *pOfft;
  4337  	/* Database page number */
  4338  	rc = ReadInt64(pPager->pjfd,&iNum,iOfft);
  4339  	if( rc != VEDIS_OK ){ return rc; }
  4340  	iOfft += 8;
  4341  	/* Page data */
  4342  	rc = vedisOsRead(pPager->pjfd,zData,pPager->iPageSize,iOfft);
  4343  	if( rc != VEDIS_OK ){ return rc; }
  4344  	iOfft += pPager->iPageSize;
  4345  	/* Page cksum */
  4346  	rc = ReadInt32(pPager->pjfd,&ckSum,iOfft);
  4347  	if( rc != VEDIS_OK ){ return rc; }
  4348  	iOfft += 4;
  4349  	/* Synchronize pointers */
  4350  	*pOfft = iOfft;
  4351  	/* Make sure we are dealing with a valid page */
  4352  	if( ckSum != pager_cksum(pPager,zData) ){
  4353  		/* Ignore that page */
  4354  		return SXERR_IGNORE;
  4355  	}
  4356  	if( iNum >= pPager->dbSize ){
  4357  		/* Ignore that page */
  4358  		return VEDIS_OK;
  4359  	}
  4360  	/* playback */
  4361  	rc = vedisOsWrite(pPager->pfd,zData,pPager->iPageSize,iNum * pPager->iPageSize);
  4362  	if( rc == VEDIS_OK ){
  4363  		/* Flush the cache */
  4364  		pager_fill_page(pPager,iNum,zData);
  4365  	}
  4366  	return rc;
  4367  }
  4368  /*
  4369  ** Playback the journal and thus restore the database file to
  4370  ** the state it was in before we started making changes.  
  4371  **
  4372  ** The journal file format is as follows: 
  4373  **
  4374  **  (1)  8 byte prefix.  A copy of aJournalMagic[].
  4375  **  (2)  4 byte big-endian integer which is the number of valid page records
  4376  **       in the journal. 
  4377  **  (3)  4 byte big-endian integer which is the initial value for the 
  4378  **       sanity checksum.
  4379  **  (4)  8 byte integer which is the number of pages to truncate the
  4380  **       database to during a rollback.
  4381  **  (5)  4 byte big-endian integer which is the sector size.  The header
  4382  **       is this many bytes in size.
  4383  **  (6)  4 byte big-endian integer which is the page size.
  4384  **  (7)  zero padding out to the next sector size.
  4385  **  (8)  Zero or more pages instances, each as follows:
  4386  **        +  4 byte page number.
  4387  **        +  pPager->pageSize bytes of data.
  4388  **        +  4 byte checksum
  4389  **
  4390  ** When we speak of the journal header, we mean the first 7 items above.
  4391  ** Each entry in the journal is an instance of the 8th item.
  4392  **
  4393  ** Call the value from the second bullet "nRec".  nRec is the number of
  4394  ** valid page entries in the journal.  In most cases, you can compute the
  4395  ** value of nRec from the size of the journal file.  But if a power
  4396  ** failure occurred while the journal was being written, it could be the
  4397  ** case that the size of the journal file had already been increased but
  4398  ** the extra entries had not yet made it safely to disk.  In such a case,
  4399  ** the value of nRec computed from the file size would be too large.  For
  4400  ** that reason, we always use the nRec value in the header.
  4401  **
  4402  ** If the file opened as the journal file is not a well-formed
  4403  ** journal file then all pages up to the first corrupted page are rolled
  4404  ** back (or no pages if the journal header is corrupted). The journal file
  4405  ** is then deleted and SQLITE_OK returned, just as if no corruption had
  4406  ** been encountered.
  4407  **
  4408  ** If an I/O or malloc() error occurs, the journal-file is not deleted
  4409  ** and an error code is returned.
  4410  **
  4411  */
  4412  static int pager_playback(Pager *pPager)
  4413  {
  4414  	unsigned char *zTmp = 0; /* cc warning */
  4415  	sxu32 n,nRec;
  4416  	sxi64 iOfft;
  4417  	int rc;
  4418  	/* Read the journal header*/
  4419  	rc = pager_read_journal_header(pPager,&nRec,&pPager->dbSize);
  4420  	if( rc != VEDIS_OK ){
  4421  		if( rc == VEDIS_DONE ){
  4422  			goto end_playback;
  4423  		}
  4424  		vedisGenErrorFormat(pPager->pDb,"IO error while reading journal file '%s' header",pPager->zJournal);
  4425  		return rc;
  4426  	}
  4427  	/* Truncate the database back to its original size */
  4428  	rc = vedisOsTruncate(pPager->pfd,pPager->iPageSize * pPager->dbSize);
  4429  	if( rc != VEDIS_OK ){
  4430  		vedisGenError(pPager->pDb,"IO error while truncating database file");
  4431  		return rc;
  4432  	}
  4433  	/* Allocate a temporary page */
  4434  	zTmp = (unsigned char *)SyMemBackendAlloc(pPager->pAllocator,(sxu32)pPager->iPageSize);
  4435  	if( zTmp == 0 ){
  4436  		vedisGenOutofMem(pPager->pDb);
  4437  		return VEDIS_NOMEM;
  4438  	}
  4439  	SyZero((void *)zTmp,(sxu32)pPager->iPageSize);
  4440  	/* Copy original pages out of the journal and back into the 
  4441      ** database file and/or page cache.
  4442      */
  4443  	iOfft = pPager->iJournalOfft;
  4444  	for( n = 0 ; n < nRec ; ++n ){
  4445  		rc = pager_play_back_one_page(pPager,&iOfft,zTmp);
  4446  		if( rc != VEDIS_OK ){
  4447  			if( rc != SXERR_IGNORE ){
  4448  				vedisGenError(pPager->pDb,"Page playback error");
  4449  				goto end_playback;
  4450  			}
  4451  		}
  4452  	}
  4453  end_playback:
  4454  	/* Release the temp page */
  4455  	SyMemBackendFree(pPager->pAllocator,(void *)zTmp);
  4456  	if( rc == VEDIS_OK ){
  4457  		/* Sync the database file */
  4458  		vedisOsSync(pPager->pfd,VEDIS_SYNC_FULL);
  4459  	}
  4460  	if( rc == VEDIS_DONE ){
  4461  		rc = VEDIS_OK;
  4462  	}
  4463  	/* Return to the caller */
  4464  	return rc;
  4465  }
  4466  /*
  4467  ** Unlock the database file to level eLock, which must be either NO_LOCK
  4468  ** or SHARED_LOCK. Regardless of whether or not the call to xUnlock()
  4469  ** succeeds, set the Pager.iLock variable to match the (attempted) new lock.
  4470  **
  4471  ** Except, if Pager.iLock is set to NO_LOCK when this function is
  4472  ** called, do not modify it. See the comment above the #define of 
  4473  ** NO_LOCK for an explanation of this.
  4474  */
  4475  static int pager_unlock_db(Pager *pPager, int eLock)
  4476  {
  4477    int rc = VEDIS_OK;
  4478    if( pPager->iLock != NO_LOCK ){
  4479      rc = vedisOsUnlock(pPager->pfd,eLock);
  4480      pPager->iLock = eLock;
  4481    }
  4482    return rc;
  4483  }
  4484  /*
  4485  ** Lock the database file to level eLock, which must be either SHARED_LOCK,
  4486  ** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
  4487  ** Pager.eLock variable to the new locking state. 
  4488  **
  4489  ** Except, if Pager.eLock is set to NO_LOCK when this function is 
  4490  ** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK. 
  4491  ** See the comment above the #define of NO_LOCK for an explanation 
  4492  ** of this.
  4493  */
  4494  static int pager_lock_db(Pager *pPager, int eLock){
  4495    int rc = VEDIS_OK;
  4496    if( pPager->iLock < eLock || pPager->iLock == NO_LOCK ){
  4497      rc = vedisOsLock(pPager->pfd, eLock);
  4498      if( rc==VEDIS_OK ){
  4499        pPager->iLock = eLock;
  4500      }else{
  4501  		vedisGenError(pPager->pDb,
  4502  			rc == VEDIS_BUSY ? "Another process or thread hold the requested lock" : "Error while requesting database lock"
  4503  			);
  4504  	}
  4505    }
  4506    return rc;
  4507  }
  4508  /*
  4509  ** Try to obtain a lock of type locktype on the database file. If
  4510  ** a similar or greater lock is already held, this function is a no-op
  4511  ** (returning VEDIS_OK immediately).
  4512  **
  4513  ** Otherwise, attempt to obtain the lock using vedisOsLock(). Invoke 
  4514  ** the busy callback if the lock is currently not available. Repeat 
  4515  ** until the busy callback returns false or until the attempt to 
  4516  ** obtain the lock succeeds.
  4517  **
  4518  ** Return VEDIS_OK on success and an error code if we cannot obtain
  4519  ** the lock. If the lock is obtained successfully, set the Pager.state 
  4520  ** variable to locktype before returning.
  4521  */
  4522  static int pager_wait_on_lock(Pager *pPager, int locktype){
  4523    int rc;                              /* Return code */
  4524    do {
  4525      rc = pager_lock_db(pPager,locktype);
  4526    }while( rc==VEDIS_BUSY && pPager->xBusyHandler && pPager->xBusyHandler(pPager->pBusyHandlerArg) );
  4527    return rc;
  4528  }
  4529  /*
  4530  ** This function is called after transitioning from PAGER_OPEN to
  4531  ** PAGER_SHARED state. It tests if there is a hot journal present in
  4532  ** the file-system for the given pager. A hot journal is one that 
  4533  ** needs to be played back. According to this function, a hot-journal
  4534  ** file exists if the following criteria are met:
  4535  **
  4536  **   * The journal file exists in the file system, and
  4537  **   * No process holds a RESERVED or greater lock on the database file, and
  4538  **   * The database file itself is greater than 0 bytes in size, and
  4539  **   * The first byte of the journal file exists and is not 0x00.
  4540  **
  4541  ** If the current size of the database file is 0 but a journal file
  4542  ** exists, that is probably an old journal left over from a prior
  4543  ** database with the same name. In this case the journal file is
  4544  ** just deleted using OsDelete, *pExists is set to 0 and VEDIS_OK
  4545  ** is returned.
  4546  **
  4547  ** If a hot-journal file is found to exist, *pExists is set to 1 and 
  4548  ** VEDIS_OK returned. If no hot-journal file is present, *pExists is
  4549  ** set to 0 and VEDIS_OK returned. If an IO error occurs while trying
  4550  ** to determine whether or not a hot-journal file exists, the IO error
  4551  ** code is returned and the value of *pExists is undefined.
  4552  */
  4553  static int pager_has_hot_journal(Pager *pPager, int *pExists)
  4554  {
  4555    vedis_vfs *pVfs = pPager->pVfs;
  4556    int rc = VEDIS_OK;           /* Return code */
  4557    int exists = 1;               /* True if a journal file is present */
  4558  
  4559    *pExists = 0;
  4560    rc = vedisOsAccess(pVfs, pPager->zJournal, VEDIS_ACCESS_EXISTS, &exists);
  4561    if( rc==VEDIS_OK && exists ){
  4562      int locked = 0;             /* True if some process holds a RESERVED lock */
  4563  
  4564      /* Race condition here:  Another process might have been holding the
  4565      ** the RESERVED lock and have a journal open at the vedisOsAccess() 
  4566      ** call above, but then delete the journal and drop the lock before
  4567      ** we get to the following vedisOsCheckReservedLock() call.  If that
  4568      ** is the case, this routine might think there is a hot journal when
  4569      ** in fact there is none.  This results in a false-positive which will
  4570      ** be dealt with by the playback routine.
  4571      */
  4572      rc = vedisOsCheckReservedLock(pPager->pfd, &locked);
  4573      if( rc==VEDIS_OK && !locked ){
  4574        sxi64 n = 0;                    /* Size of db file in bytes */
  4575   
  4576        /* Check the size of the database file. If it consists of 0 pages,
  4577        ** then delete the journal file. See the header comment above for 
  4578        ** the reasoning here.  Delete the obsolete journal file under
  4579        ** a RESERVED lock to avoid race conditions.
  4580        */
  4581        rc = vedisOsFileSize(pPager->pfd,&n);
  4582        if( rc==VEDIS_OK ){
  4583          if( n < 1 ){
  4584            if( pager_lock_db(pPager, RESERVED_LOCK)==VEDIS_OK ){
  4585              vedisOsDelete(pVfs, pPager->zJournal, 0);
  4586  			pager_unlock_db(pPager, SHARED_LOCK);
  4587            }
  4588          }else{
  4589            /* The journal file exists and no other connection has a reserved
  4590            ** or greater lock on the database file. */
  4591  			*pExists = 1;
  4592          }
  4593        }
  4594      }
  4595    }
  4596    return rc;
  4597  }
  4598  /*
  4599   * Rollback a journal file. (See block-comment above).
  4600   */
  4601  static int pager_journal_rollback(Pager *pPager,int check_hot)
  4602  {
  4603  	int rc;
  4604  	if( check_hot ){
  4605  		int iExists = 0; /* cc warning */
  4606  		/* Check if the journal file exists */
  4607  		rc = pager_has_hot_journal(pPager,&iExists);
  4608  		if( rc != VEDIS_OK  ){
  4609  			/* IO error */
  4610  			return rc;
  4611  		}
  4612  		if( !iExists ){
  4613  			/* Journal file does not exists */
  4614  			return VEDIS_OK;
  4615  		}
  4616  	}
  4617  	if( pPager->is_rdonly ){
  4618  		vedisGenErrorFormat(pPager->pDb,
  4619  			"Cannot rollback journal file '%s' due to a read-only database handle",pPager->zJournal);
  4620  		return VEDIS_READ_ONLY;
  4621  	}
  4622  	/* Get an EXCLUSIVE lock on the database file. At this point it is
  4623        ** important that a RESERVED lock is not obtained on the way to the
  4624        ** EXCLUSIVE lock. If it were, another process might open the
  4625        ** database file, detect the RESERVED lock, and conclude that the
  4626        ** database is safe to read while this process is still rolling the 
  4627        ** hot-journal back.
  4628        ** 
  4629        ** Because the intermediate RESERVED lock is not requested, any
  4630        ** other process attempting to access the database file will get to 
  4631        ** this point in the code and fail to obtain its own EXCLUSIVE lock 
  4632        ** on the database file.
  4633        **
  4634        ** Unless the pager is in locking_mode=exclusive mode, the lock is
  4635        ** downgraded to SHARED_LOCK before this function returns.
  4636        */
  4637  	/* Open the journal file */
  4638  	rc = vedisOsOpen(pPager->pVfs,pPager->pAllocator,pPager->zJournal,&pPager->pjfd,VEDIS_OPEN_READWRITE);
  4639  	if( rc != VEDIS_OK ){
  4640  		vedisGenErrorFormat(pPager->pDb,"IO error while opening journal file: '%s'",pPager->zJournal);
  4641  		goto fail;
  4642  	}
  4643  	rc = pager_lock_db(pPager,EXCLUSIVE_LOCK);
  4644  	if( rc != VEDIS_OK ){
  4645  		vedisGenError(pPager->pDb,"Cannot acquire an exclusive lock on the database while journal rollback");
  4646  		goto fail;
  4647  	}
  4648  	/* Sync the journal file */
  4649  	vedisOsSync(pPager->pjfd,VEDIS_SYNC_NORMAL);
  4650  	/* Finally rollback the database */
  4651  	rc = pager_playback(pPager);
  4652  	/* Switch back to shared lock */
  4653  	pager_unlock_db(pPager,SHARED_LOCK);
  4654  fail:
  4655  	/* Close the journal handle */
  4656  	vedisOsCloseFree(pPager->pAllocator,pPager->pjfd);
  4657  	pPager->pjfd = 0;
  4658  	if( rc == VEDIS_OK ){
  4659  		/* Delete the journal file */
  4660  		vedisOsDelete(pPager->pVfs,pPager->zJournal,TRUE);
  4661  	}
  4662  	return rc;
  4663  }
  4664  /*
  4665   * Write the vedis header (First page). (Big-Endian)
  4666   */
  4667  static int pager_write_db_header(Pager *pPager)
  4668  {
  4669  	unsigned char *zRaw = pPager->pHeader->zData;
  4670  	vedis_kv_engine *pEngine = pPager->pEngine;
  4671  	sxu32 nDos;
  4672  	sxu16 nLen;
  4673  	/* Database signature */
  4674  	SyMemcpy(VEDIS_DB_SIG,zRaw,sizeof(VEDIS_DB_SIG)-1);
  4675  	zRaw += sizeof(VEDIS_DB_SIG)-1;
  4676  	/* Database magic number */
  4677  	SyBigEndianPack32(zRaw,VEDIS_DB_MAGIC);
  4678  	zRaw += 4; /* 4 byte magic number */
  4679  	/* Database creation time */
  4680  	SyZero(&pPager->tmCreate,sizeof(Sytm));
  4681  	if( pPager->pVfs->xCurrentTime ){
  4682  		pPager->pVfs->xCurrentTime(pPager->pVfs,&pPager->tmCreate);
  4683  	}
  4684  	/* DOS time format (4 bytes) */
  4685  	SyTimeFormatToDos(&pPager->tmCreate,&nDos);
  4686  	SyBigEndianPack32(zRaw,nDos);
  4687  	zRaw += 4; /* 4 byte DOS time */
  4688  	/* Sector size */
  4689  	SyBigEndianPack32(zRaw,(sxu32)pPager->iSectorSize);
  4690  	zRaw += 4; /* 4 byte sector size */
  4691  	/* Page size */
  4692  	SyBigEndianPack32(zRaw,(sxu32)pPager->iPageSize);
  4693  	zRaw += 4; /* 4 byte page size */
  4694  	/* Key value storage engine */
  4695  	nLen = (sxu16)SyStrlen(pEngine->pIo->pMethods->zName);
  4696  	SyBigEndianPack16(zRaw,nLen); /* 2 byte storage engine name */
  4697  	zRaw += 2;
  4698  	SyMemcpy((const void *)pEngine->pIo->pMethods->zName,(void *)zRaw,nLen);
  4699  	zRaw += nLen;
  4700  	/* All rest are meta-data available to the host application */
  4701  	return VEDIS_OK;
  4702  }
  4703  /*
  4704   * Read the vedis header (first page). (Big-Endian)
  4705   */
  4706  static int pager_extract_header(Pager *pPager,const unsigned char *zRaw,sxu32 nByte)
  4707  {
  4708  	const unsigned char *zEnd = &zRaw[nByte];
  4709  	sxu32 nDos,iMagic;
  4710  	sxu16 nLen;
  4711  	char *zKv;
  4712  	/* Database signature */
  4713  	if( SyMemcmp(VEDIS_DB_SIG,zRaw,sizeof(VEDIS_DB_SIG)-1) != 0 ){
  4714  		/* Corrupt database */
  4715  		return VEDIS_CORRUPT;
  4716  	}
  4717  	zRaw += sizeof(VEDIS_DB_SIG)-1;
  4718  	/* Database magic number */
  4719  	SyBigEndianUnpack32(zRaw,&iMagic);
  4720  	zRaw += 4; /* 4 byte magic number */
  4721  	if( iMagic != VEDIS_DB_MAGIC ){
  4722  		/* Corrupt database */
  4723  		return VEDIS_CORRUPT;
  4724  	}
  4725  	/* Database creation time */
  4726  	SyBigEndianUnpack32(zRaw,&nDos);
  4727  	zRaw += 4; /* 4 byte DOS time format */
  4728  	SyDosTimeFormat(nDos,&pPager->tmCreate);
  4729  	/* Sector size */
  4730  	SyBigEndianUnpack32(zRaw,(sxu32 *)&pPager->iSectorSize);
  4731  	zRaw += 4; /* 4 byte sector size */
  4732  	/* Page size */
  4733  	SyBigEndianUnpack32(zRaw,(sxu32 *)&pPager->iPageSize);
  4734  	zRaw += 4; /* 4 byte page size */
  4735  	/* Check that the values read from the page-size and sector-size fields
  4736      ** are within range. To be 'in range', both values need to be a power
  4737      ** of two greater than or equal to 512 or 32, and not greater than their 
  4738      ** respective compile time maximum limits.
  4739      */
  4740      if( pPager->iPageSize<VEDIS_MIN_PAGE_SIZE || pPager->iSectorSize<32
  4741       || pPager->iPageSize>VEDIS_MAX_PAGE_SIZE || pPager->iSectorSize>MAX_SECTOR_SIZE
  4742       || ((pPager->iPageSize<-1)&pPager->iPageSize)!=0    || ((pPager->iSectorSize-1)&pPager->iSectorSize)!=0 
  4743      ){
  4744        return VEDIS_CORRUPT;
  4745  	}
  4746  	/* Key value storage engine */
  4747  	SyBigEndianUnpack16(zRaw,&nLen); /* 2 byte storage engine length */
  4748  	zRaw += 2;
  4749  	if( nLen > (sxu16)(zEnd - zRaw) ){
  4750  		nLen = (sxu16)(zEnd - zRaw);
  4751  	}
  4752  	zKv = (char *)SyMemBackendDup(pPager->pAllocator,(const char *)zRaw,nLen);
  4753  	if( zKv == 0 ){
  4754  		return VEDIS_NOMEM;
  4755  	}
  4756  	SyStringInitFromBuf(&pPager->sKv,zKv,nLen);
  4757  	return VEDIS_OK;
  4758  }
  4759  /*
  4760   * Read the database header.
  4761   */
  4762  static int pager_read_db_header(Pager *pPager)
  4763  {
  4764  	unsigned char zRaw[VEDIS_MIN_PAGE_SIZE]; /* Minimum page size */
  4765  	sxi64 n = 0;              /* Size of db file in bytes */
  4766  	int rc;
  4767  	/* Get the file size first */
  4768  	rc = vedisOsFileSize(pPager->pfd,&n);
  4769  	if( rc != VEDIS_OK ){
  4770  		return rc;
  4771  	}
  4772  	pPager->dbByteSize = n;
  4773  	if( n > 0 ){
  4774  		vedis_kv_methods *pMethods;
  4775  		SyString *pKv;
  4776  		pgno nPage;
  4777  		if( n < VEDIS_MIN_PAGE_SIZE ){
  4778  			/* A valid vedis database must be at least 512 bytes long */
  4779  			vedisGenError(pPager->pDb,"Malformed database image");
  4780  			return VEDIS_CORRUPT;
  4781  		}
  4782  		/* Read the database header */
  4783  		rc = vedisOsRead(pPager->pfd,zRaw,sizeof(zRaw),0);
  4784  		if( rc != VEDIS_OK ){
  4785  			vedisGenError(pPager->pDb,"IO error while reading database header");
  4786  			return rc;
  4787  		}
  4788  		/* Extract the header */
  4789  		rc = pager_extract_header(pPager,zRaw,sizeof(zRaw));
  4790  		if( rc != VEDIS_OK ){
  4791  			vedisGenError(pPager->pDb,rc == VEDIS_NOMEM ? "Unqlite is running out of memory" : "Malformed database image");
  4792  			return rc;
  4793  		}
  4794  		/* Update pager state  */
  4795  		nPage = (pgno)(n / pPager->iPageSize);
  4796  		if( nPage==0 && n>0 ){
  4797  			nPage = 1;
  4798  		}
  4799  		pPager->dbSize = nPage;
  4800  		/* Laod the target Key/Value storage engine */
  4801  		pKv = &pPager->sKv;
  4802  		pMethods = vedisFindKVStore(pKv->zString,pKv->nByte);
  4803  		if( pMethods == 0 ){
  4804  			vedisGenErrorFormat(pPager->pDb,"No such Key/Value storage engine '%z'",pKv);
  4805  			return VEDIS_NOTIMPLEMENTED;
  4806  		}
  4807  		/* Install the new KV storage engine */
  4808  		rc = vedisPagerRegisterKvEngine(pPager,pMethods);
  4809  		if( rc != VEDIS_OK ){
  4810  			return rc;
  4811  		}
  4812  	}else{
  4813  		/* Set a default page and sector size */
  4814  		pPager->iSectorSize = GetSectorSize(pPager->pfd);
  4815  		pPager->iPageSize = vedisGetPageSize();
  4816  		SyStringInitFromBuf(&pPager->sKv,pPager->pEngine->pIo->pMethods->zName,SyStrlen(pPager->pEngine->pIo->pMethods->zName));
  4817  		pPager->dbSize = 0;
  4818  	}
  4819  	/* Allocate a temporary page size */
  4820  	pPager->zTmpPage = (unsigned char *)SyMemBackendAlloc(pPager->pAllocator,(sxu32)pPager->iPageSize);
  4821  	if( pPager->zTmpPage == 0 ){
  4822  		vedisGenOutofMem(pPager->pDb);
  4823  		return VEDIS_NOMEM;
  4824  	}
  4825  	SyZero(pPager->zTmpPage,(sxu32)pPager->iPageSize);
  4826  	return VEDIS_OK;
  4827  }
  4828  /*
  4829   * Write the database header.
  4830   */
  4831  static int pager_create_header(Pager *pPager)
  4832  {
  4833  	Page *pHeader;
  4834  	int rc;
  4835  	/* Allocate a new page */
  4836  	pHeader = pager_alloc_page(pPager,0);
  4837  	if( pHeader == 0 ){
  4838  		return VEDIS_NOMEM;
  4839  	}
  4840  	pPager->pHeader = pHeader;
  4841  	/* Link the page */
  4842  	pager_link_page(pPager,pHeader);
  4843  	/* Add to the dirty list */
  4844  	pager_page_to_dirty_list(pPager,pHeader);
  4845  	/* Write the database header */
  4846  	rc = pager_write_db_header(pPager);
  4847  	return rc;
  4848  }
  4849  /*
  4850  ** This function is called to obtain a shared lock on the database file.
  4851  ** It is illegal to call vedisPagerAcquire() until after this function
  4852  ** has been successfully called. If a shared-lock is already held when
  4853  ** this function is called, it is a no-op.
  4854  **
  4855  ** The following operations are also performed by this function.
  4856  **
  4857  **   1) If the pager is currently in PAGER_OPEN state (no lock held
  4858  **      on the database file), then an attempt is made to obtain a
  4859  **      SHARED lock on the database file. Immediately after obtaining
  4860  **      the SHARED lock, the file-system is checked for a hot-journal,
  4861  **      which is played back if present. 
  4862  **
  4863  ** If everything is successful, VEDIS_OK is returned. If an IO error 
  4864  ** occurs while locking the database, checking for a hot-journal file or 
  4865  ** rolling back a journal file, the IO error code is returned.
  4866  */
  4867  static int pager_shared_lock(Pager *pPager)
  4868  {
  4869  	int rc = VEDIS_OK;
  4870  	if( pPager->iState == PAGER_OPEN ){
  4871  		vedis_kv_methods *pMethods;
  4872  		/* Open the target database */
  4873  		rc = vedisOsOpen(pPager->pVfs,pPager->pAllocator,pPager->zFilename,&pPager->pfd,pPager->iOpenFlags);
  4874  		if( rc != VEDIS_OK ){
  4875  			vedisGenErrorFormat(pPager->pDb,
  4876  				"IO error while opening the target database file: %s",pPager->zFilename
  4877  				);
  4878  			return rc;
  4879  		}
  4880  		/* Try to obtain a shared lock */
  4881  		rc = pager_wait_on_lock(pPager,SHARED_LOCK);
  4882  		if( rc == VEDIS_OK ){
  4883  			if( pPager->iLock <= SHARED_LOCK ){
  4884  				/* Rollback any hot journal */
  4885  				rc = pager_journal_rollback(pPager,1);
  4886  				if( rc != VEDIS_OK ){
  4887  					return rc;
  4888  				}
  4889  			}
  4890  			/* Read the database header */
  4891  			rc = pager_read_db_header(pPager);
  4892  			if( rc != VEDIS_OK ){
  4893  				return rc;
  4894  			}
  4895  			if(pPager->dbSize > 0 ){
  4896  				if( pPager->iOpenFlags & VEDIS_OPEN_MMAP ){
  4897  					const vedis_vfs *pVfs = vedisExportBuiltinVfs();
  4898  					/* Obtain a read-only memory view of the whole file */
  4899  					if( pVfs && pVfs->xMmap ){
  4900  						int vr;
  4901  						vr = pVfs->xMmap(pPager->zFilename,&pPager->pMmap,&pPager->dbByteSize);
  4902  						if( vr != VEDIS_OK ){
  4903  							/* Generate a warning */
  4904  							vedisGenError(pPager->pDb,"Cannot obtain a read-only memory view of the target database");
  4905  							pPager->iOpenFlags &= ~VEDIS_OPEN_MMAP;
  4906  						}
  4907  					}else{
  4908  						/* Generate a warning */
  4909  						vedisGenError(pPager->pDb,"Cannot obtain a read-only memory view of the target database");
  4910  						pPager->iOpenFlags &= ~VEDIS_OPEN_MMAP;
  4911  					}
  4912  				}
  4913  			}
  4914  			/* Update the pager state */
  4915  			pPager->iState = PAGER_READER;
  4916  			/* Invoke the xOpen methods if available */
  4917  			pMethods = pPager->pEngine->pIo->pMethods;
  4918  			if( pMethods->xOpen ){
  4919  				rc = pMethods->xOpen(pPager->pEngine,pPager->dbSize);
  4920  				if( rc != VEDIS_OK ){
  4921  					vedisGenErrorFormat(pPager->pDb,
  4922  						"xOpen() method of the underlying KV engine '%z' failed",
  4923  						&pPager->sKv
  4924  						);
  4925  					pager_unlock_db(pPager,NO_LOCK);
  4926  					pPager->iState = PAGER_OPEN;
  4927  					return rc;
  4928  				}
  4929  			}
  4930  		}else if( rc == VEDIS_BUSY ){
  4931  			vedisGenError(pPager->pDb,"Another process or thread have a reserved or exclusive lock on this database");
  4932  		}		
  4933  	}
  4934  	return rc;
  4935  }
  4936  /*
  4937  ** Begin a write-transaction on the specified pager object. If a 
  4938  ** write-transaction has already been opened, this function is a no-op.
  4939  */
  4940  VEDIS_PRIVATE int vedisPagerBegin(Pager *pPager)
  4941  {
  4942  	int rc;
  4943  	/* Obtain a shared lock on the database first */
  4944  	rc = pager_shared_lock(pPager);
  4945  	if( rc != VEDIS_OK ){
  4946  		return rc;
  4947  	}
  4948  	if( pPager->iState >= PAGER_WRITER_LOCKED ){
  4949  		return VEDIS_OK;
  4950  	}
  4951  	if( pPager->is_rdonly ){
  4952  		vedisGenError(pPager->pDb,"Read-only database");
  4953  		/* Read only database */
  4954  		return VEDIS_READ_ONLY;
  4955  	}
  4956  	/* Obtain a reserved lock on the database */
  4957  	rc = pager_wait_on_lock(pPager,RESERVED_LOCK);
  4958  	if( rc == VEDIS_OK ){
  4959  		/* Create the bitvec */
  4960  		pPager->pVec = vedisBitvecCreate(pPager->pAllocator,pPager->dbSize);
  4961  		if( pPager->pVec == 0 ){
  4962  			vedisGenOutofMem(pPager->pDb);
  4963  			rc = VEDIS_NOMEM;
  4964  			goto fail;
  4965  		}
  4966  		/* Change to the WRITER_LOCK state */
  4967  		pPager->iState = PAGER_WRITER_LOCKED;
  4968  		pPager->dbOrigSize = pPager->dbSize;
  4969  		pPager->iJournalOfft = 0;
  4970  		pPager->nRec = 0;
  4971  		if( pPager->dbSize < 1 ){
  4972  			/* Write the  database header */
  4973  			rc = pager_create_header(pPager);
  4974  			if( rc != VEDIS_OK ){
  4975  				goto fail;
  4976  			}
  4977  			pPager->dbSize = 1;
  4978  		}
  4979  	}else if( rc == VEDIS_BUSY ){
  4980  		vedisGenError(pPager->pDb,"Another process or thread have a reserved lock on this database");
  4981  	}
  4982  	return rc;
  4983  fail:
  4984  	/* Downgrade to shared lock */
  4985  	pager_unlock_db(pPager,SHARED_LOCK);
  4986  	return rc;
  4987  }
  4988  /*
  4989  ** This function is called at the start of every write transaction.
  4990  ** There must already be a RESERVED or EXCLUSIVE lock on the database 
  4991  ** file when this routine is called.
  4992  **
  4993  */
  4994  static int vedisOpenJournal(Pager *pPager)
  4995  {
  4996  	unsigned char *zHeader;
  4997  	int rc = VEDIS_OK;
  4998  	if( pPager->is_mem || pPager->no_jrnl ){
  4999  		/* Journaling is omitted for this database */
  5000  		goto finish;
  5001  	}
  5002  	if( pPager->iState >= PAGER_WRITER_CACHEMOD ){
  5003  		/* Already opened */
  5004  		return VEDIS_OK;
  5005  	}
  5006  	/* Delete any previously journal with the same name */
  5007  	vedisOsDelete(pPager->pVfs,pPager->zJournal,1);
  5008  	/* Open the journal file */
  5009  	rc = vedisOsOpen(pPager->pVfs,pPager->pAllocator,pPager->zJournal,
  5010  		&pPager->pjfd,VEDIS_OPEN_CREATE|VEDIS_OPEN_READWRITE);
  5011  	if( rc != VEDIS_OK ){
  5012  		vedisGenErrorFormat(pPager->pDb,"IO error while opening journal file: %s",pPager->zJournal);
  5013  		return rc;
  5014  	}
  5015  	/* Write the journal header */
  5016  	zHeader = (unsigned char *)SyMemBackendAlloc(pPager->pAllocator,(sxu32)pPager->iSectorSize);
  5017  	if( zHeader == 0 ){
  5018  		rc = VEDIS_NOMEM;
  5019  		goto fail;
  5020  	}
  5021  	pager_write_journal_header(pPager,zHeader);
  5022  	/* Perform the disk write */
  5023  	rc = vedisOsWrite(pPager->pjfd,zHeader,pPager->iSectorSize,0);
  5024  	/* Offset to start writing from */
  5025  	pPager->iJournalOfft = pPager->iSectorSize;
  5026  	/* All done, journal will be synced later */
  5027  	SyMemBackendFree(pPager->pAllocator,zHeader);
  5028  finish:
  5029  	if( rc == VEDIS_OK ){
  5030  		pPager->iState = PAGER_WRITER_CACHEMOD;
  5031  		return VEDIS_OK;
  5032  	}
  5033  fail:
  5034  	/* Unlink the journal file if something goes wrong */
  5035  	vedisOsCloseFree(pPager->pAllocator,pPager->pjfd);
  5036  	vedisOsDelete(pPager->pVfs,pPager->zJournal,0);
  5037  	pPager->pjfd = 0;
  5038  	return rc;
  5039  }
  5040  /*
  5041  ** Sync the journal. In other words, make sure all the pages that have
  5042  ** been written to the journal have actually reached the surface of the
  5043  ** disk and can be restored in the event of a hot-journal rollback.
  5044  *
  5045  * This routine try also to obtain an exlusive lock on the database.
  5046  */
  5047  static int vedisFinalizeJournal(Pager *pPager,int *pRetry,int close_jrnl)
  5048  {
  5049  	int rc;
  5050  	*pRetry = 0;
  5051  	/* Grab the exclusive lock first */
  5052  	rc = pager_lock_db(pPager,EXCLUSIVE_LOCK);
  5053  	if( rc != VEDIS_OK ){
  5054  		/* Retry the excusive lock process */
  5055  		*pRetry = 1;
  5056  		rc = VEDIS_OK;
  5057  	}
  5058  	if( pPager->no_jrnl ){
  5059  		/* Journaling is omitted, return immediately */
  5060  		return VEDIS_OK;
  5061  	}
  5062  	/* Write the total number of database records */
  5063  	rc = WriteInt32(pPager->pjfd,pPager->nRec,8 /* sizeof(aJournalRec) */);
  5064  	if( rc != VEDIS_OK ){
  5065  		if( pPager->nRec > 0 ){
  5066  			return rc;
  5067  		}else{
  5068  			/* Not so fatal */
  5069  			rc = VEDIS_OK;
  5070  		}
  5071  	}
  5072  	/* Sync the journal and close it */
  5073  	rc = vedisOsSync(pPager->pjfd,VEDIS_SYNC_NORMAL);
  5074  	if( close_jrnl ){
  5075  		/* close the journal file */
  5076  		if( VEDIS_OK != vedisOsCloseFree(pPager->pAllocator,pPager->pjfd) ){
  5077  			if( rc != VEDIS_OK /* vedisOsSync */ ){
  5078  				return rc;
  5079  			}
  5080  		}
  5081  		pPager->pjfd = 0;
  5082  	}
  5083  	if( (*pRetry) == 1 ){
  5084  		if( pager_lock_db(pPager,EXCLUSIVE_LOCK) == VEDIS_OK ){
  5085  			/* Got exclusive lock */
  5086  			*pRetry = 0;
  5087  		}
  5088  	}
  5089  	return VEDIS_OK;
  5090  }
  5091  /*
  5092   * Mark a single data page as writeable. The page is written into the 
  5093   * main journal as required.
  5094   */
  5095  static int page_write(Pager *pPager,Page *pPage)
  5096  {
  5097  	int rc;
  5098  	if( !pPager->is_mem && !pPager->no_jrnl ){
  5099  		/* Write the page to the transaction journal */
  5100  		if( pPage->pgno < pPager->dbOrigSize && !vedisBitvecTest(pPager->pVec,pPage->pgno) ){
  5101  			sxu32 cksum;
  5102  			if( pPager->nRec == SXU32_HIGH ){
  5103  				/* Journal Limit reached */
  5104  				vedisGenError(pPager->pDb,"Journal record limit reached, commit your changes");
  5105  				return VEDIS_LIMIT;
  5106  			}
  5107  			/* Write the page number */
  5108  			rc = WriteInt64(pPager->pjfd,pPage->pgno,pPager->iJournalOfft);
  5109  			if( rc != VEDIS_OK ){ return rc; }
  5110  			/* Write the raw page */
  5111  			/** CODEC */
  5112  			rc = vedisOsWrite(pPager->pjfd,pPage->zData,pPager->iPageSize,pPager->iJournalOfft + 8);
  5113  			if( rc != VEDIS_OK ){ return rc; }
  5114  			/* Compute the checksum */
  5115  			cksum = pager_cksum(pPager,pPage->zData);
  5116  			rc = WriteInt32(pPager->pjfd,cksum,pPager->iJournalOfft + 8 + pPager->iPageSize);
  5117  			if( rc != VEDIS_OK ){ return rc; }
  5118  			/* Update the journal offset */
  5119  			pPager->iJournalOfft += 8 /* page num */ + pPager->iPageSize + 4 /* cksum */;
  5120  			pPager->nRec++;
  5121  			/* Mark as journalled  */
  5122  			vedisBitvecSet(pPager->pVec,pPage->pgno);
  5123  		}
  5124  	}
  5125  	/* Add the page to the dirty list */
  5126  	pager_page_to_dirty_list(pPager,pPage);
  5127  	/* Update the database size and return. */
  5128  	if( (1 + pPage->pgno) > pPager->dbSize ){
  5129  		pPager->dbSize = 1 + pPage->pgno;
  5130  		if( pPager->dbSize == SXU64_HIGH ){
  5131  			vedisGenError(pPager->pDb,"Database maximum page limit (64-bit) reached");
  5132  			return VEDIS_LIMIT;
  5133  		}
  5134  	}	
  5135  	return VEDIS_OK;
  5136  }
  5137  /*
  5138  ** The argument is the first in a linked list of dirty pages connected
  5139  ** by the PgHdr.pDirty pointer. This function writes each one of the
  5140  ** in-memory pages in the list to the database file. The argument may
  5141  ** be NULL, representing an empty list. In this case this function is
  5142  ** a no-op.
  5143  **
  5144  ** The pager must hold at least a RESERVED lock when this function
  5145  ** is called. Before writing anything to the database file, this lock
  5146  ** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained,
  5147  ** VEDIS_BUSY is returned and no data is written to the database file.
  5148  */
  5149  static int pager_write_dirty_pages(Pager *pPager,Page *pDirty)
  5150  {
  5151  	int rc = VEDIS_OK;
  5152  	Page *pNext;
  5153  	for(;;){
  5154  		if( pDirty == 0 ){
  5155  			break;
  5156  		}
  5157  		/* Point to the next dirty page */
  5158  		pNext = pDirty->pDirtyPrev; /* Not a bug: Reverse link */
  5159  		if( (pDirty->flags & PAGE_DONT_WRITE) == 0 ){
  5160  			rc = vedisOsWrite(pPager->pfd,pDirty->zData,pPager->iPageSize,pDirty->pgno * pPager->iPageSize);
  5161  			if( rc != VEDIS_OK ){
  5162  				/* A rollback should be done */
  5163  				break;
  5164  			}
  5165  		}
  5166  		/* Remove stale flags */
  5167  		pDirty->flags &= ~(PAGE_DIRTY|PAGE_DONT_WRITE|PAGE_NEED_SYNC|PAGE_IN_JOURNAL|PAGE_HOT_DIRTY);
  5168  		if( pDirty->nRef < 1 ){
  5169  			/* Unlink the page now it is unused */
  5170  			pager_unlink_page(pPager,pDirty);
  5171  			/* Release the page */
  5172  			pager_release_page(pPager,pDirty);
  5173  		}
  5174  		/* Point to the next page */
  5175  		pDirty = pNext;
  5176  	}
  5177  	pPager->pDirty = pPager->pFirstDirty = 0;
  5178  	pPager->pHotDirty = pPager->pFirstHot = 0;
  5179  	pPager->nHot = 0;
  5180  	return rc;
  5181  }
  5182  /*
  5183  ** The argument is the first in a linked list of hot dirty pages connected
  5184  ** by the PgHdr.pHotDirty pointer. This function writes each one of the
  5185  ** in-memory pages in the list to the database file. The argument may
  5186  ** be NULL, representing an empty list. In this case this function is
  5187  ** a no-op.
  5188  **
  5189  ** The pager must hold at least a RESERVED lock when this function
  5190  ** is called. Before writing anything to the database file, this lock
  5191  ** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained,
  5192  ** VEDIS_BUSY is returned and no data is written to the database file.
  5193  */
  5194  static int pager_write_hot_dirty_pages(Pager *pPager,Page *pDirty)
  5195  {
  5196  	int rc = VEDIS_OK;
  5197  	Page *pNext;
  5198  	for(;;){
  5199  		if( pDirty == 0 ){
  5200  			break;
  5201  		}
  5202  		/* Point to the next page */
  5203  		pNext = pDirty->pPrevHot; /* Not a bug: Reverse link */
  5204  		if( (pDirty->flags & PAGE_DONT_WRITE) == 0 ){
  5205  			rc = vedisOsWrite(pPager->pfd,pDirty->zData,pPager->iPageSize,pDirty->pgno * pPager->iPageSize);
  5206  			if( rc != VEDIS_OK ){
  5207  				break;
  5208  			}
  5209  		}
  5210  		/* Remove stale flags */
  5211  		pDirty->flags &= ~(PAGE_DIRTY|PAGE_DONT_WRITE|PAGE_NEED_SYNC|PAGE_IN_JOURNAL|PAGE_HOT_DIRTY);
  5212  		/* Unlink from the list of dirty pages */
  5213  		if( pDirty->pDirtyPrev ){
  5214  			pDirty->pDirtyPrev->pDirtyNext = pDirty->pDirtyNext;
  5215  		}else{
  5216  			pPager->pDirty = pDirty->pDirtyNext;
  5217  		}
  5218  		if( pDirty->pDirtyNext ){
  5219  			pDirty->pDirtyNext->pDirtyPrev = pDirty->pDirtyPrev;
  5220  		}else{
  5221  			pPager->pFirstDirty = pDirty->pDirtyPrev;
  5222  		}
  5223  		/* Discard */
  5224  		pager_unlink_page(pPager,pDirty);
  5225  		/* Release the page */
  5226  		pager_release_page(pPager,pDirty);
  5227  		/* Next hot page */
  5228  		pDirty = pNext;
  5229  	}
  5230  	return rc;
  5231  }
  5232  /*
  5233   * Commit a transaction: Phase one.
  5234   */
  5235  static int pager_commit_phase1(Pager *pPager)
  5236  {
  5237  	int get_excl = 0;
  5238  	Page *pDirty;
  5239  	int rc;
  5240  	/* If no database changes have been made, return early. */
  5241  	if( pPager->iState < PAGER_WRITER_CACHEMOD ){
  5242  		return VEDIS_OK;
  5243  	}
  5244  	if( pPager->is_rdonly ){
  5245  		/* Read-Only DB */
  5246  		vedisGenError(pPager->pDb,"Read-Only database");
  5247  		return VEDIS_READ_ONLY;
  5248  	}
  5249  	/* Invoke any user commit callback */
  5250  	if( pPager->xCommit ){
  5251  		rc = pPager->xCommit(pPager->pCommitData);
  5252  		if( rc == VEDIS_ABORT ){
  5253  			vedisGenError(pPager->pDb,"User ommit callback request an operation abort");
  5254  			return VEDIS_ABORT;
  5255  		}
  5256  		/* Fall through */
  5257  		rc = VEDIS_OK;
  5258  	}
  5259  	if( pPager->is_mem ){
  5260  		/* An in-memory database */
  5261  		return VEDIS_OK;
  5262  	}
  5263  	/* Finalize the journal file */
  5264  	rc = vedisFinalizeJournal(pPager,&get_excl,1);
  5265  	if( rc != VEDIS_OK ){
  5266  		return rc;
  5267  	}
  5268  	/* Get the dirty pages */
  5269  	pDirty = pager_get_dirty_pages(pPager);
  5270  	if( get_excl ){
  5271  		/* Wait one last time for the exclusive lock */
  5272  		rc = pager_wait_on_lock(pPager,EXCLUSIVE_LOCK);
  5273  		if( rc != VEDIS_OK ){
  5274  			vedisGenError(pPager->pDb,"Cannot obtain an Exclusive lock on the target database");
  5275  			return rc;
  5276  		}
  5277  	}
  5278  	if( pPager->iFlags & PAGER_CTRL_DIRTY_COMMIT ){
  5279  		/* Synce the database first if a dirty commit have been applied */
  5280  		vedisOsSync(pPager->pfd,VEDIS_SYNC_NORMAL);
  5281  	}
  5282  	/* Write the dirty pages */
  5283  	rc = pager_write_dirty_pages(pPager,pDirty);
  5284  	if( rc != VEDIS_OK ){
  5285  		/* Rollback your DB */
  5286  		pPager->iFlags |= PAGER_CTRL_COMMIT_ERR;
  5287  		pPager->pFirstDirty = pDirty;
  5288  		vedisGenError(pPager->pDb,"IO error while writing dirty pages, rollback your database");
  5289  		return rc;
  5290  	}
  5291  	/* If the file on disk is not the same size as the database image,
  5292       * then use vedisOsTruncate to grow or shrink the file here.
  5293       */
  5294  	if( pPager->dbSize != pPager->dbOrigSize ){
  5295  		vedisOsTruncate(pPager->pfd,pPager->iPageSize * pPager->dbSize);
  5296  	}
  5297  	/* Sync the database file */
  5298  	vedisOsSync(pPager->pfd,VEDIS_SYNC_FULL);
  5299  	/* Remove stale flags */
  5300  	pPager->iJournalOfft = 0;
  5301  	pPager->nRec = 0;
  5302  	return VEDIS_OK;
  5303  }
  5304  /*
  5305   * Commit a transaction: Phase two.
  5306   */
  5307  static int pager_commit_phase2(Pager *pPager)
  5308  {
  5309  	if( !pPager->is_mem ){
  5310  		if( pPager->iState == PAGER_OPEN ){
  5311  			return VEDIS_OK;
  5312  		}
  5313  		if( pPager->iState != PAGER_READER ){
  5314  			if( !pPager->no_jrnl ){
  5315  				/* Finally, unlink the journal file */
  5316  				vedisOsDelete(pPager->pVfs,pPager->zJournal,1);
  5317  			}
  5318  			/* Downgrade to shraed lock */
  5319  			pager_unlock_db(pPager,SHARED_LOCK);
  5320  			pPager->iState = PAGER_READER;
  5321  			if( pPager->pVec ){
  5322  				vedisBitvecDestroy(pPager->pVec);
  5323  				pPager->pVec = 0;
  5324  			}
  5325  		}
  5326  	}
  5327  	return VEDIS_OK;
  5328  }
  5329  /*
  5330   * Perform a dirty commit.
  5331   */
  5332  static int pager_dirty_commit(Pager *pPager)
  5333  {
  5334  	int get_excl = 0;
  5335  	Page *pHot;
  5336  	int rc;
  5337  	/* Finalize the journal file without closing it */
  5338  	rc = vedisFinalizeJournal(pPager,&get_excl,0);
  5339  	if( rc != VEDIS_OK ){
  5340  		/* It's not a fatal error if something goes wrong here since
  5341  		 * its not the final commit.
  5342  		 */
  5343  		return VEDIS_OK;
  5344  	}
  5345  	/* Point to the list of hot pages */
  5346  	pHot = pager_get_hot_pages(pPager);
  5347  	if( pHot == 0 ){
  5348  		return VEDIS_OK;
  5349  	}
  5350  	if( get_excl ){
  5351  		/* Wait one last time for the exclusive lock */
  5352  		rc = pager_wait_on_lock(pPager,EXCLUSIVE_LOCK);
  5353  		if( rc != VEDIS_OK ){
  5354  			/* Not so fatal, will try another time */
  5355  			return VEDIS_OK;
  5356  		}
  5357  	}
  5358  	/* Tell that a dirty commit happen */
  5359  	pPager->iFlags |= PAGER_CTRL_DIRTY_COMMIT;
  5360  	/* Write the hot pages now */
  5361  	rc = pager_write_hot_dirty_pages(pPager,pHot);
  5362  	if( rc != VEDIS_OK ){
  5363  		pPager->iFlags |= PAGER_CTRL_COMMIT_ERR;
  5364  		vedisGenError(pPager->pDb,"IO error while writing hot dirty pages, rollback your database");
  5365  		return rc;
  5366  	}
  5367  	pPager->pFirstHot = pPager->pHotDirty = 0;
  5368  	pPager->nHot = 0;
  5369  	/* No need to sync the database file here, since the journal is already
  5370  	 * open here and this is not the final commit.
  5371  	 */
  5372  	return VEDIS_OK;
  5373  }
  5374  /*
  5375  ** Commit a transaction and sync the database file for the pager pPager.
  5376  **
  5377  ** This routine ensures that:
  5378  **
  5379  **   * the journal is synced,
  5380  **   * all dirty pages are written to the database file, 
  5381  **   * the database file is truncated (if required), and
  5382  **   * the database file synced.
  5383  **   * the journal file is deleted.
  5384  */
  5385  VEDIS_PRIVATE int vedisPagerCommit(Pager *pPager)
  5386  {
  5387  	int rc;
  5388  	/* Commit: Phase One */
  5389  	rc = pager_commit_phase1(pPager);
  5390  	if( rc != VEDIS_OK ){
  5391  		goto fail;
  5392  	}
  5393  	/* Commit: Phase Two */
  5394  	rc = pager_commit_phase2(pPager);
  5395  	if( rc != VEDIS_OK ){
  5396  		goto fail;
  5397  	}
  5398  	/* Remove stale flags */
  5399  	pPager->iFlags &= ~PAGER_CTRL_COMMIT_ERR;
  5400  	/* All done */
  5401  	return VEDIS_OK;
  5402  fail:
  5403  	/* Disable the auto-commit flag */
  5404  	pPager->pDb->iFlags |= VEDIS_FL_DISABLE_AUTO_COMMIT;
  5405  	return rc;
  5406  }
  5407  /*
  5408   * Reset the pager to its initial state. This is caused by
  5409   * a rollback operation.
  5410   */
  5411  static int pager_reset_state(Pager *pPager,int bResetKvEngine)
  5412  {
  5413  	vedis_kv_engine *pEngine = pPager->pEngine;
  5414  	Page *pNext,*pPtr = pPager->pAll;
  5415  	const vedis_kv_io *pIo;
  5416  	int rc;
  5417  	/* Remove stale flags */
  5418  	pPager->iFlags &= ~(PAGER_CTRL_COMMIT_ERR|PAGER_CTRL_DIRTY_COMMIT);
  5419  	pPager->iJournalOfft = 0;
  5420  	pPager->nRec = 0;
  5421  	/* Database original size */
  5422  	pPager->dbSize = pPager->dbOrigSize;
  5423  	/* Discard all in-memory pages */
  5424  	for(;;){
  5425  		if( pPtr == 0 ){
  5426  			break;
  5427  		}
  5428  		pNext = pPtr->pNext; /* Reverse link */
  5429  		/* Remove stale flags */
  5430  		pPtr->flags &= ~(PAGE_DIRTY|PAGE_DONT_WRITE|PAGE_NEED_SYNC|PAGE_IN_JOURNAL|PAGE_HOT_DIRTY);
  5431  		/* Release the page */
  5432  		pager_release_page(pPager,pPtr);
  5433  		/* Point to the next page */
  5434  		pPtr = pNext;
  5435  	}
  5436  	pPager->pAll = 0;
  5437  	pPager->nPage = 0;
  5438  	pPager->pDirty = pPager->pFirstDirty = 0;
  5439  	pPager->pHotDirty = pPager->pFirstHot = 0;
  5440  	pPager->nHot = 0;
  5441  	if( pPager->apHash ){
  5442  		/* Zero the table */
  5443  		SyZero((void *)pPager->apHash,sizeof(Page *) * pPager->nSize);
  5444  	}
  5445  	if( pPager->pVec ){
  5446  		vedisBitvecDestroy(pPager->pVec);
  5447  		pPager->pVec = 0;
  5448  	}
  5449  	/* Switch back to shared lock */
  5450  	pager_unlock_db(pPager,SHARED_LOCK);
  5451  	pPager->iState = PAGER_READER;
  5452  	if( bResetKvEngine ){
  5453  		/* Reset the underlying KV engine */
  5454  		pIo = pEngine->pIo;
  5455  		if( pIo->pMethods->xRelease ){
  5456  			/* Call the release callback */
  5457  			pIo->pMethods->xRelease(pEngine);
  5458  		}
  5459  		/* Zero the structure */
  5460  		SyZero(pEngine,(sxu32)pIo->pMethods->szKv);
  5461  		/* Fill in */
  5462  		pEngine->pIo = pIo;
  5463  		if( pIo->pMethods->xInit ){
  5464  			/* Call the init method */
  5465  			rc = pIo->pMethods->xInit(pEngine,pPager->iPageSize);
  5466  			if( rc != VEDIS_OK ){
  5467  				return rc;
  5468  			}
  5469  		}
  5470  		if( pIo->pMethods->xOpen ){
  5471  			/* Call the xOpen method */
  5472  			rc = pIo->pMethods->xOpen(pEngine,pPager->dbSize);
  5473  			if( rc != VEDIS_OK ){
  5474  				return rc;
  5475  			}
  5476  		}
  5477  	}
  5478  	/* All done */
  5479  	return VEDIS_OK;
  5480  }
  5481  /*
  5482  ** If a write transaction is open, then all changes made within the 
  5483  ** transaction are reverted and the current write-transaction is closed.
  5484  ** The pager falls back to PAGER_READER state if successful.
  5485  **
  5486  ** Otherwise, in rollback mode, this function performs two functions:
  5487  **
  5488  **   1) It rolls back the journal file, restoring all database file and 
  5489  **      in-memory cache pages to the state they were in when the transaction
  5490  **      was opened, and
  5491  **
  5492  **   2) It finalizes the journal file, so that it is not used for hot
  5493  **      rollback at any point in the future (i.e. deletion).
  5494  **
  5495  ** Finalization of the journal file (task 2) is only performed if the 
  5496  ** rollback is successful.
  5497  **
  5498  */
  5499  VEDIS_PRIVATE int vedisPagerRollback(Pager *pPager,int bResetKvEngine)
  5500  {
  5501  	int rc = VEDIS_OK;
  5502  	if( pPager->iState < PAGER_WRITER_LOCKED ){
  5503  		/* A write transaction must be opened */
  5504  		return VEDIS_OK;
  5505  	}
  5506  	if( pPager->is_mem ){
  5507  		/* As of this release 1.1.6: Transactions are not supported for in-memory databases */
  5508  		return VEDIS_OK;
  5509  	}
  5510  	if( pPager->is_rdonly ){
  5511  		/* Read-Only DB */
  5512  		vedisGenError(pPager->pDb,"Read-Only database");
  5513  		return VEDIS_READ_ONLY;
  5514  	}
  5515  	if( pPager->iState >= PAGER_WRITER_CACHEMOD ){
  5516  		if( !pPager->no_jrnl ){
  5517  			/* Close any outstanding joural file */
  5518  			if( pPager->pjfd ){
  5519  				/* Sync the journal file */
  5520  				vedisOsSync(pPager->pjfd,VEDIS_SYNC_NORMAL);
  5521  			}
  5522  			vedisOsCloseFree(pPager->pAllocator,pPager->pjfd);
  5523  			pPager->pjfd = 0;
  5524  			if( pPager->iFlags & (PAGER_CTRL_COMMIT_ERR|PAGER_CTRL_DIRTY_COMMIT) ){
  5525  				/* Perform the rollback */
  5526  				rc = pager_journal_rollback(pPager,0);
  5527  				if( rc != VEDIS_OK ){
  5528  					/* Set the auto-commit flag */
  5529  					pPager->pDb->iFlags |= VEDIS_FL_DISABLE_AUTO_COMMIT;
  5530  					return rc;
  5531  				}
  5532  			}
  5533  		}
  5534  		/* Unlink the journal file */
  5535  		vedisOsDelete(pPager->pVfs,pPager->zJournal,1);
  5536  		/* Reset the pager state */
  5537  		rc = pager_reset_state(pPager,bResetKvEngine);
  5538  		if( rc != VEDIS_OK ){
  5539  			/* Mostly an unlikely scenario */
  5540  			pPager->pDb->iFlags |= VEDIS_FL_DISABLE_AUTO_COMMIT; /* Set the auto-commit flag */
  5541  			vedisGenError(pPager->pDb,"Error while reseting pager to its initial state");
  5542  			return rc;
  5543  		}
  5544  	}else{
  5545  		/* Downgrade to shared lock */
  5546  		pager_unlock_db(pPager,SHARED_LOCK);
  5547  		pPager->iState = PAGER_READER;
  5548  	}
  5549  	return VEDIS_OK;
  5550  }
  5551  /*
  5552   *  Mark a data page as non writeable.
  5553   */
  5554  static int vedisPagerDontWrite(vedis_page *pMyPage)
  5555  {
  5556  	Page *pPage = (Page *)pMyPage;
  5557  	if( pPage->pgno > 0 /* Page 0 is always writeable */ ){
  5558  		pPage->flags |= PAGE_DONT_WRITE;
  5559  	}
  5560  	return VEDIS_OK;
  5561  }
  5562  /*
  5563  ** Mark a data page as writeable. This routine must be called before 
  5564  ** making changes to a page. The caller must check the return value 
  5565  ** of this function and be careful not to change any page data unless 
  5566  ** this routine returns VEDIS_OK.
  5567  */
  5568  static int vedisPageWrite(vedis_page *pMyPage)
  5569  {
  5570  	Page *pPage = (Page *)pMyPage;
  5571  	Pager *pPager = pPage->pPager;
  5572  	int rc;
  5573  	/* Begin the write transaction */
  5574  	rc = vedisPagerBegin(pPager);
  5575  	if( rc != VEDIS_OK ){
  5576  		return rc;
  5577  	}
  5578  	if( pPager->iState == PAGER_WRITER_LOCKED ){
  5579  		/* The journal file needs to be opened. Higher level routines have already
  5580  		 ** obtained the necessary locks to begin the write-transaction, but the
  5581  		 ** rollback journal might not yet be open. Open it now if this is the case.
  5582  		 */
  5583  		rc = vedisOpenJournal(pPager);
  5584  		if( rc != VEDIS_OK ){
  5585  			return rc;
  5586  		}
  5587  	}
  5588  	if( pPager->nHot > 127 ){
  5589  		/* Write hot dirty pages */
  5590  		rc = pager_dirty_commit(pPager);
  5591  		if( rc != VEDIS_OK ){
  5592  			/* A rollback must be done */
  5593  			vedisGenError(pPager->pDb,"Please perform a rollback");
  5594  			return rc;
  5595  		}
  5596  	}
  5597  	/* Write the page to the journal file */
  5598  	rc = page_write(pPager,pPage);
  5599  	return rc;
  5600  }
  5601  /*
  5602  ** Acquire a reference to page number pgno in pager pPager (a page
  5603  ** reference has type vedis_page*). If the requested reference is 
  5604  ** successfully obtained, it is copied to *ppPage and VEDIS_OK returned.
  5605  **
  5606  ** If the requested page is already in the cache, it is returned. 
  5607  ** Otherwise, a new page object is allocated and populated with data
  5608  ** read from the database file.
  5609  */
  5610  static int vedisPagerAcquire(
  5611    Pager *pPager,      /* The pager open on the database file */
  5612    pgno pgno,          /* Page number to fetch */
  5613    vedis_page **ppPage,    /* OUT: Acquired page */
  5614    int fetchOnly,      /* Cache lookup only */
  5615    int noContent       /* Do not bother reading content from disk if true */
  5616  )
  5617  {
  5618  	Page *pPage;
  5619  	int rc;
  5620  	/* Acquire a shared lock (if not yet done) on the database and rollback any hot-journal if present */
  5621  	rc = pager_shared_lock(pPager);
  5622  	if( rc != VEDIS_OK ){
  5623  		return rc;
  5624  	}
  5625  	/* Fetch the page from the cache */
  5626  	pPage = pager_fetch_page(pPager,pgno);
  5627  	if( fetchOnly ){
  5628  		if( ppPage ){
  5629  			*ppPage = (vedis_page *)pPage;
  5630  		}
  5631  		return pPage ? VEDIS_OK : VEDIS_NOTFOUND;
  5632  	}
  5633  	if( pPage == 0 ){
  5634  		/* Allocate a new page */
  5635  		pPage = pager_alloc_page(pPager,pgno);
  5636  		if( pPage == 0 ){
  5637  			vedisGenOutofMem(pPager->pDb);
  5638  			return VEDIS_NOMEM;
  5639  		}
  5640  		/* Read page contents */
  5641  		rc = pager_get_page_contents(pPager,pPage,noContent);
  5642  		if( rc != VEDIS_OK ){
  5643  			SyMemBackendPoolFree(pPager->pAllocator,pPage);
  5644  			return rc;
  5645  		}
  5646  		/* Link the page */
  5647  		pager_link_page(pPager,pPage);
  5648  	}else{
  5649  		if( ppPage ){
  5650  			page_ref(pPage);
  5651  		}
  5652  	}
  5653  	/* All done, page is loaded in memeory */
  5654  	if( ppPage ){
  5655  		*ppPage = (vedis_page *)pPage;
  5656  	}
  5657  	return VEDIS_OK;
  5658  }
  5659  /*
  5660   * Return true if we are dealing with an in-memory database.
  5661   */
  5662  static int vedisInMemory(const char *zFilename)
  5663  {
  5664  	sxu32 n;
  5665  	if( SX_EMPTY_STR(zFilename) ){
  5666  		/* NULL or the empty string means an in-memory database */
  5667  		return TRUE;
  5668  	}
  5669  	n = SyStrlen(zFilename);
  5670  	if( n == sizeof(":mem:") - 1 && 
  5671  		SyStrnicmp(zFilename,":mem:",sizeof(":mem:") - 1) == 0 ){
  5672  			return TRUE;
  5673  	}
  5674  	if( n == sizeof(":memory:") - 1 && 
  5675  		SyStrnicmp(zFilename,":memory:",sizeof(":memory:") - 1) == 0 ){
  5676  			return TRUE;
  5677  	}
  5678  	return FALSE;
  5679  }
  5680  /*
  5681   * Allocate a new KV cursor.
  5682   */
  5683  VEDIS_PRIVATE int vedisInitCursor(vedis *pDb,vedis_kv_cursor **ppOut)
  5684  {
  5685  	vedis_kv_methods *pMethods;
  5686  	vedis_kv_cursor *pCur;
  5687  	sxu32 nByte;
  5688  	/* Storage engine methods */
  5689  	pMethods = pDb->pPager->pEngine->pIo->pMethods;
  5690  	if( pMethods->szCursor < 1 ){
  5691  		/* Implementation does not supprt cursors */
  5692  		vedisGenErrorFormat(pDb,"Storage engine '%s' does not support cursors",pMethods->zName);
  5693  		return VEDIS_NOTIMPLEMENTED;
  5694  	}
  5695  	nByte = pMethods->szCursor;
  5696  	if( nByte < sizeof(vedis_kv_cursor) ){
  5697  		nByte += sizeof(vedis_kv_cursor);
  5698  	}
  5699  	pCur = (vedis_kv_cursor *)SyMemBackendPoolAlloc(&pDb->sMem,nByte);
  5700  	if( pCur == 0 ){
  5701  		vedisGenOutofMem(pDb);
  5702  		return VEDIS_NOMEM;
  5703  	}
  5704  	/* Zero the structure */
  5705  	SyZero(pCur,nByte);
  5706  	/* Save the cursor */
  5707  	pCur->pStore = pDb->pPager->pEngine;
  5708  	/* Invoke the initialization callback if any */
  5709  	if( pMethods->xCursorInit ){
  5710  		pMethods->xCursorInit(pCur);
  5711  	}
  5712  	/* All done */
  5713  	*ppOut = pCur;
  5714  	return VEDIS_OK;
  5715  }
  5716  /*
  5717   * Release a cursor.
  5718   */
  5719  VEDIS_PRIVATE int vedisReleaseCursor(vedis *pDb,vedis_kv_cursor *pCur)
  5720  {
  5721  	vedis_kv_methods *pMethods;
  5722  	/* Storage engine methods */
  5723  	pMethods = pDb->pPager->pEngine->pIo->pMethods;
  5724  	/* Invoke the release callback if available */
  5725  	if( pMethods->xCursorRelease ){
  5726  		pMethods->xCursorRelease(pCur);
  5727  	}
  5728  	/* Finally, free the whole instance */
  5729  	SyMemBackendPoolFree(&pDb->sMem,pCur);
  5730  	return VEDIS_OK;
  5731  }
  5732  /*
  5733   * Release the underlying KV storage engine and invoke
  5734   * its associated callbacks if available.
  5735   */
  5736  static void pager_release_kv_engine(Pager *pPager)
  5737  {
  5738  	vedis_kv_engine *pEngine = pPager->pEngine;
  5739  	vedis *pStorage = pPager->pDb;
  5740  	if( pStorage->pCursor ){
  5741  		/* Release the associated cursor */
  5742  		vedisReleaseCursor(pPager->pDb,pStorage->pCursor);
  5743  		pStorage->pCursor = 0;
  5744  	}
  5745  	if( pEngine->pIo->pMethods->xRelease ){
  5746  		pEngine->pIo->pMethods->xRelease(pEngine);
  5747  	}
  5748  	/* Release the whole instance */
  5749  	SyMemBackendFree(&pPager->pDb->sMem,(void *)pEngine->pIo);
  5750  	SyMemBackendFree(&pPager->pDb->sMem,(void *)pEngine);
  5751  	pPager->pEngine = 0;
  5752  }
  5753  /* Forward declaration */
  5754  static int pager_kv_io_init(Pager *pPager,vedis_kv_methods *pMethods,vedis_kv_io *pIo);
  5755  /*
  5756   * Allocate, initialize and register a new KV storage engine
  5757   * within this database instance.
  5758   */
  5759  VEDIS_PRIVATE int vedisPagerRegisterKvEngine(Pager *pPager,vedis_kv_methods *pMethods)
  5760  {
  5761  	vedis *pStorage = pPager->pDb;
  5762  	vedis *pDb = pPager->pDb;
  5763  	vedis_kv_engine *pEngine;
  5764  	vedis_kv_io *pIo;
  5765  	sxu32 nByte;
  5766  	int rc;
  5767  	if( pPager->pEngine ){
  5768  		if( pMethods == pPager->pEngine->pIo->pMethods ){
  5769  			/* Ticket 1432: Same implementation */
  5770  			return VEDIS_OK;
  5771  		}
  5772  		/* Release the old KV engine */
  5773  		pager_release_kv_engine(pPager);
  5774  	}
  5775  	/* Allocate a new KV engine instance */
  5776  	nByte = (sxu32)pMethods->szKv;
  5777  	pEngine = (vedis_kv_engine *)SyMemBackendAlloc(&pDb->sMem,nByte);
  5778  	if( pEngine == 0 ){
  5779  		vedisGenOutofMem(pDb);
  5780  		return VEDIS_NOMEM;
  5781  	}
  5782  	pIo = (vedis_kv_io *)SyMemBackendAlloc(&pDb->sMem,sizeof(vedis_kv_io));
  5783  	if( pIo == 0 ){
  5784  		SyMemBackendFree(&pDb->sMem,pEngine);
  5785  		vedisGenOutofMem(pDb);
  5786  		return VEDIS_NOMEM;
  5787  	}
  5788  	/* Zero the structure */
  5789  	SyZero(pIo,sizeof(vedis_io_methods));
  5790  	SyZero(pEngine,nByte);
  5791  	/* Populate the IO structure */
  5792  	pager_kv_io_init(pPager,pMethods,pIo);
  5793  	pEngine->pIo = pIo;
  5794  	/* Invoke the init callback if avaialble */
  5795  	if( pMethods->xInit ){
  5796  		rc = pMethods->xInit(pEngine,vedisGetPageSize());
  5797  		if( rc != VEDIS_OK ){
  5798  			vedisGenErrorFormat(pDb,
  5799  				"xInit() method of the underlying KV engine '%z' failed",&pPager->sKv);
  5800  			goto fail;
  5801  		}
  5802  		pEngine->pIo = pIo;
  5803  	}
  5804  	pPager->pEngine = pEngine;
  5805  	/* Allocate a new cursor */
  5806  	rc = vedisInitCursor(pDb,&pStorage->pCursor);
  5807  	if( rc != VEDIS_OK ){
  5808  		goto fail;
  5809  	}
  5810  	return VEDIS_OK;
  5811  fail:
  5812  	SyMemBackendFree(&pDb->sMem,pEngine);
  5813  	SyMemBackendFree(&pDb->sMem,pIo);
  5814  	return rc;
  5815  }
  5816  /*
  5817   * Return the underlying KV storage engine instance.
  5818   */
  5819  VEDIS_PRIVATE vedis_kv_engine * vedisPagerGetKvEngine(vedis *pDb)
  5820  {
  5821  	return pDb->pPager->pEngine;
  5822  }
  5823  /*
  5824  * Allocate and initialize a new Pager object. The pager should
  5825  * eventually be freed by passing it to vedisPagerClose().
  5826  *
  5827  * The zFilename argument is the path to the database file to open.
  5828  * If zFilename is NULL or ":memory:" then all information is held
  5829  * in cache. It is never written to disk.  This can be used to implement
  5830  * an in-memory database.
  5831  */
  5832  VEDIS_PRIVATE int vedisPagerOpen(
  5833    vedis_vfs *pVfs,       /* The virtual file system to use */
  5834    vedis *pDb,            /* Database handle */
  5835    const char *zFilename,   /* Name of the database file to open */
  5836    unsigned int iFlags      /* flags controlling this file */
  5837    )
  5838  {
  5839  	vedis_kv_methods *pMethods = 0;
  5840  	int is_mem,rd_only,no_jrnl;
  5841  	Pager *pPager;
  5842  	sxu32 nByte;
  5843  	sxu32 nLen;
  5844  	int rc;
  5845  
  5846  	/* Select the appropriate KV storage subsytem  */
  5847  	if( (iFlags & VEDIS_OPEN_IN_MEMORY) || vedisInMemory(zFilename) ){
  5848  		/* An in-memory database, record that  */
  5849  		pMethods = vedisFindKVStore("mem",sizeof("mem") - 1); /* Always available */
  5850  		iFlags |= VEDIS_OPEN_IN_MEMORY;
  5851  	}else{
  5852  		/* Install the default key value storage subsystem [i.e. Linear Hash] */
  5853  		pMethods = vedisFindKVStore("hash",sizeof("hash")-1);
  5854  		if( pMethods == 0 ){
  5855  			/* Use the b+tree storage backend if the linear hash storage is not available */
  5856  			pMethods = vedisFindKVStore("btree",sizeof("btree")-1);
  5857  		}
  5858  	}
  5859  	if( pMethods == 0 ){
  5860  		/* Can't happen */
  5861  		vedisGenError(pDb,"Cannot install a default Key/Value storage engine");
  5862  		return VEDIS_NOTIMPLEMENTED;
  5863  	}
  5864  	is_mem = (iFlags & VEDIS_OPEN_IN_MEMORY) != 0;
  5865  	rd_only = (iFlags & VEDIS_OPEN_READONLY) != 0;
  5866  	no_jrnl = (iFlags & VEDIS_OPEN_OMIT_JOURNALING) != 0;
  5867  	rc = VEDIS_OK;
  5868  	if( is_mem ){
  5869  		/* Omit journaling for in-memory database */
  5870  		no_jrnl = 1;
  5871  	}
  5872  	/* Total number of bytes to allocate */
  5873  	nByte = sizeof(Pager);
  5874  	nLen = 0;
  5875  	if( !is_mem ){
  5876  		nLen = SyStrlen(zFilename);
  5877  		nByte += pVfs->mxPathname + nLen + sizeof(char) /* null termniator */;
  5878  	}
  5879  	/* Allocate */
  5880  	pPager = (Pager *)SyMemBackendAlloc(&pDb->sMem,nByte);
  5881  	if( pPager == 0 ){
  5882  		return VEDIS_NOMEM;
  5883  	}
  5884  	/* Zero the structure */
  5885  	SyZero(pPager,nByte);
  5886  	/* Fill-in the structure */
  5887  	pPager->pAllocator = &pDb->sMem;
  5888  	pPager->pDb = pDb;
  5889  	pDb->pPager = pPager;
  5890  	/* Allocate page table */
  5891  	pPager->nSize = 128; /* Must be a power of two */
  5892  	nByte = pPager->nSize * sizeof(Page *);
  5893  	pPager->apHash = (Page **)SyMemBackendAlloc(pPager->pAllocator,nByte);
  5894  	if( pPager->apHash == 0 ){
  5895  		rc = VEDIS_NOMEM;
  5896  		goto fail;
  5897  	}
  5898  	SyZero(pPager->apHash,nByte);
  5899  	pPager->is_mem = is_mem;
  5900  	pPager->no_jrnl = no_jrnl;
  5901  	pPager->is_rdonly = rd_only;
  5902  	pPager->iOpenFlags = iFlags;
  5903  	pPager->pVfs = pVfs;
  5904  	SyRandomnessInit(&pPager->sPrng,0,0);
  5905  	SyRandomness(&pPager->sPrng,(void *)&pPager->cksumInit,sizeof(sxu32));
  5906  	/* Unlimited cache size */
  5907  	pPager->nCacheMax = SXU32_HIGH;
  5908  	/* Copy filename and journal name */
  5909  	if( !is_mem ){
  5910  		pPager->zFilename = (char *)&pPager[1];
  5911  		rc = VEDIS_OK;
  5912  		if( pVfs->xFullPathname ){
  5913  			rc = pVfs->xFullPathname(pVfs,zFilename,pVfs->mxPathname + nLen,pPager->zFilename);
  5914  		}
  5915  		if( rc != VEDIS_OK ){
  5916  			/* Simple filename copy */
  5917  			SyMemcpy(zFilename,pPager->zFilename,nLen);
  5918  			pPager->zFilename[nLen] = 0;
  5919  			rc = VEDIS_OK;
  5920  		}else{
  5921  			nLen = SyStrlen(pPager->zFilename);
  5922  		}
  5923  		pPager->zJournal = (char *) SyMemBackendAlloc(pPager->pAllocator,nLen + sizeof(VEDIS_JOURNAL_FILE_SUFFIX) + sizeof(char));
  5924  		if( pPager->zJournal == 0 ){
  5925  			rc = VEDIS_NOMEM;
  5926  			goto fail;
  5927  		}
  5928  		/* Copy filename */
  5929  		SyMemcpy(pPager->zFilename,pPager->zJournal,nLen);
  5930  		/* Copy journal suffix */
  5931  		SyMemcpy(VEDIS_JOURNAL_FILE_SUFFIX,&pPager->zJournal[nLen],sizeof(VEDIS_JOURNAL_FILE_SUFFIX)-1);
  5932  		/* Append the nul terminator to the journal path */
  5933  		pPager->zJournal[nLen + ( sizeof(VEDIS_JOURNAL_FILE_SUFFIX) - 1)] = 0;
  5934  	}
  5935  	/* Finally, register the selected KV engine */
  5936  	rc = vedisPagerRegisterKvEngine(pPager,pMethods);
  5937  	if( rc != VEDIS_OK ){
  5938  		goto fail;
  5939  	}
  5940  	/* Set the pager state */
  5941  	if( pPager->is_mem ){
  5942  		pPager->iState = PAGER_WRITER_FINISHED;
  5943  		pPager->iLock = EXCLUSIVE_LOCK;
  5944  	}else{
  5945  		pPager->iState = PAGER_OPEN;
  5946  		pPager->iLock = NO_LOCK;
  5947  	}
  5948  	/* All done, ready for processing */
  5949  	return VEDIS_OK;
  5950  fail:
  5951  	SyMemBackendFree(&pDb->sMem,pPager);
  5952  	return rc;
  5953  }
  5954  /*
  5955   * Return TRUE if we are dealing with an in-memory database.
  5956   */
  5957  VEDIS_PRIVATE int vedisPagerisMemStore(vedis *pStore)
  5958  {
  5959  	return pStore->pPager->is_mem;
  5960  }
  5961  /*
  5962   * Set a cache limit. Note that, this is a simple hint, the pager is not
  5963   * forced to honor this limit.
  5964   */
  5965  VEDIS_PRIVATE int vedisPagerSetCachesize(Pager *pPager,int mxPage)
  5966  {
  5967  	if( mxPage < 256 ){
  5968  		return VEDIS_INVALID;
  5969  	}
  5970  	pPager->nCacheMax = mxPage;
  5971  	return VEDIS_OK;
  5972  }
  5973  /*
  5974   * Set the user commit callback.
  5975   */
  5976  VEDIS_PRIVATE int vedisPagerSetCommitCallback(Pager *pPager,int (*xCommit)(void *),void *pUserdata)
  5977  {
  5978  	pPager->xCommit = xCommit;
  5979  	pPager->pCommitData = pUserdata;
  5980  	return VEDIS_OK;
  5981  }
  5982  /*
  5983   * Shutdown the page cache. Free all memory and close the database file.
  5984   */
  5985  VEDIS_PRIVATE int vedisPagerClose(Pager *pPager)
  5986  {
  5987  	/* Release the KV engine */
  5988  	pager_release_kv_engine(pPager);
  5989  	if( pPager->iOpenFlags & VEDIS_OPEN_MMAP ){
  5990  		const vedis_vfs *pVfs = vedisExportBuiltinVfs();
  5991  		if( pVfs && pVfs->xUnmap && pPager->pMmap ){
  5992  			pVfs->xUnmap(pPager->pMmap,pPager->dbByteSize);
  5993  		}
  5994  	}
  5995  	if( !pPager->is_mem && pPager->iState > PAGER_OPEN ){
  5996  		/* Release all lock on this database handle */
  5997  		pager_unlock_db(pPager,NO_LOCK);
  5998  		/* Close the file  */
  5999  		vedisOsCloseFree(pPager->pAllocator,pPager->pfd);
  6000  	}
  6001  	if( pPager->pVec ){
  6002  		vedisBitvecDestroy(pPager->pVec);
  6003  		pPager->pVec = 0;
  6004  	}
  6005  	return VEDIS_OK;
  6006  }
  6007  /*
  6008   * Generate a random string.
  6009   */
  6010  VEDIS_PRIVATE void vedisPagerRandomString(Pager *pPager,char *zBuf,sxu32 nLen)
  6011  {
  6012  	static const char zBase[] = {"abcdefghijklmnopqrstuvwxyz"}; /* English Alphabet */
  6013  	sxu32 i;
  6014  	/* Generate a binary string first */
  6015  	SyRandomness(&pPager->sPrng,zBuf,nLen);
  6016  	/* Turn the binary string into english based alphabet */
  6017  	for( i = 0 ; i < nLen ; ++i ){
  6018  		 zBuf[i] = zBase[zBuf[i] % (sizeof(zBase)-1)];
  6019  	 }
  6020  }
  6021  /*
  6022   * Generate a random number.
  6023   */
  6024  VEDIS_PRIVATE sxu32 vedisPagerRandomNum(Pager *pPager)
  6025  {
  6026  	sxu32 iNum;
  6027  	SyRandomness(&pPager->sPrng,(void *)&iNum,sizeof(iNum));
  6028  	return iNum;
  6029  }
  6030  /* Exported KV IO Methods */
  6031  /* 
  6032   * Refer to [vedisPagerAcquire()]
  6033   */
  6034  static int vedisKvIoPageGet(vedis_kv_handle pHandle,pgno iNum,vedis_page **ppPage)
  6035  {
  6036  	int rc;
  6037  	rc = vedisPagerAcquire((Pager *)pHandle,iNum,ppPage,0,0);
  6038  	return rc;
  6039  }
  6040  /* 
  6041   * Refer to [vedisPagerAcquire()]
  6042   */
  6043  static int vedisKvIoPageLookup(vedis_kv_handle pHandle,pgno iNum,vedis_page **ppPage)
  6044  {
  6045  	int rc;
  6046  	rc = vedisPagerAcquire((Pager *)pHandle,iNum,ppPage,1,0);
  6047  	return rc;
  6048  }
  6049  /* 
  6050   * Refer to [vedisPagerAcquire()]
  6051   */
  6052  static int vedisKvIoNewPage(vedis_kv_handle pHandle,vedis_page **ppPage)
  6053  {
  6054  	Pager *pPager = (Pager *)pHandle;
  6055  	int rc;
  6056  	/* 
  6057  	 * Acquire a reader-lock first so that pPager->dbSize get initialized.
  6058  	 */
  6059  	rc = pager_shared_lock(pPager);
  6060  	if( rc == VEDIS_OK ){
  6061  		rc = vedisPagerAcquire(pPager,pPager->dbSize == 0 ? /* Page 0 is reserved */ 1 : pPager->dbSize ,ppPage,0,0);
  6062  	}
  6063  	return rc;
  6064  }
  6065  /* 
  6066   * Refer to [vedisPageWrite()]
  6067   */
  6068  static int vedisKvIopageWrite(vedis_page *pPage)
  6069  {
  6070  	int rc;
  6071  	if( pPage == 0 ){
  6072  		/* TICKET 1433-0348 */
  6073  		return VEDIS_OK;
  6074  	}
  6075  	rc = vedisPageWrite(pPage);
  6076  	return rc;
  6077  }
  6078  /* 
  6079   * Refer to [vedisPagerDontWrite()]
  6080   */
  6081  static int vedisKvIoPageDontWrite(vedis_page *pPage)
  6082  {
  6083  	int rc;
  6084  	if( pPage == 0 ){
  6085  		/* TICKET 1433-0348 */
  6086  		return VEDIS_OK;
  6087  	}
  6088  	rc = vedisPagerDontWrite(pPage);
  6089  	return rc;
  6090  }
  6091  /* 
  6092   * Refer to [vedisBitvecSet()]
  6093   */
  6094  static int vedisKvIoPageDontJournal(vedis_page *pRaw)
  6095  {
  6096  	Page *pPage = (Page *)pRaw;
  6097  	Pager *pPager;
  6098  	if( pPage == 0 ){
  6099  		/* TICKET 1433-0348 */
  6100  		return VEDIS_OK;
  6101  	}
  6102  	pPager = pPage->pPager;
  6103  	if( pPager->iState >= PAGER_WRITER_LOCKED ){
  6104  		if( !pPager->no_jrnl && pPager->pVec && !vedisBitvecTest(pPager->pVec,pPage->pgno) ){
  6105  			vedisBitvecSet(pPager->pVec,pPage->pgno);
  6106  		}
  6107  	}
  6108  	return VEDIS_OK;
  6109  }
  6110  /* 
  6111   * Do not add a page to the hot dirty list.
  6112   */
  6113  static int vedisKvIoPageDontMakeHot(vedis_page *pRaw)
  6114  {
  6115  	Page *pPage = (Page *)pRaw;
  6116  	
  6117  	if( pPage == 0 ){
  6118  		/* TICKET 1433-0348 */
  6119  		return VEDIS_OK;
  6120  	}
  6121  	pPage->flags |= PAGE_DONT_MAKE_HOT;
  6122  	return VEDIS_OK;
  6123  }
  6124  /* 
  6125   * Refer to [page_ref()]
  6126   */
  6127  static int vedisKvIopage_ref(vedis_page *pPage)
  6128  {
  6129  	if( pPage ){
  6130  		page_ref((Page *)pPage);
  6131  	}
  6132  	return VEDIS_OK;
  6133  }
  6134  /* 
  6135   * Refer to [page_unref()]
  6136   */
  6137  static int vedisKvIoPageUnRef(vedis_page *pPage)
  6138  {
  6139  	if( pPage ){
  6140  		page_unref((Page *)pPage);
  6141  	}
  6142  	return VEDIS_OK;
  6143  }
  6144  /* 
  6145   * Refer to the declaration of the [Pager] structure
  6146   */
  6147  static int vedisKvIoReadOnly(vedis_kv_handle pHandle)
  6148  {
  6149  	return ((Pager *)pHandle)->is_rdonly;
  6150  }
  6151  /* 
  6152   * Refer to the declaration of the [Pager] structure
  6153   */
  6154  static int vedisKvIoPageSize(vedis_kv_handle pHandle)
  6155  {
  6156  	return ((Pager *)pHandle)->iPageSize;
  6157  }
  6158  /* 
  6159   * Refer to the declaration of the [Pager] structure
  6160   */
  6161  static unsigned char * vedisKvIoTempPage(vedis_kv_handle pHandle)
  6162  {
  6163  	return ((Pager *)pHandle)->zTmpPage;
  6164  }
  6165  /* 
  6166   * Set a page unpin callback.
  6167   * Refer to the declaration of the [Pager] structure
  6168   */
  6169  static void vedisKvIoPageUnpin(vedis_kv_handle pHandle,void (*xPageUnpin)(void *))
  6170  {
  6171  	Pager *pPager = (Pager *)pHandle;
  6172  	pPager->xPageUnpin = xPageUnpin;
  6173  }
  6174  /* 
  6175   * Set a page reload callback.
  6176   * Refer to the declaration of the [Pager] structure
  6177   */
  6178  static void vedisKvIoPageReload(vedis_kv_handle pHandle,void (*xPageReload)(void *))
  6179  {
  6180  	Pager *pPager = (Pager *)pHandle;
  6181  	pPager->xPageReload = xPageReload;
  6182  }
  6183  /* 
  6184   * Log an error.
  6185   * Refer to the declaration of the [Pager] structure
  6186   */
  6187  static void vedisKvIoErr(vedis_kv_handle pHandle,const char *zErr)
  6188  {
  6189  	Pager *pPager = (Pager *)pHandle;
  6190  	vedisGenError(pPager->pDb,zErr);
  6191  }
  6192  /*
  6193   * Init an instance of the [vedis_kv_io] structure.
  6194   */
  6195  static int pager_kv_io_init(Pager *pPager,vedis_kv_methods *pMethods,vedis_kv_io *pIo)
  6196  {
  6197  	pIo->pHandle =  pPager;
  6198  	pIo->pMethods = pMethods;
  6199  	
  6200  	pIo->xGet    = vedisKvIoPageGet;
  6201  	pIo->xLookup = vedisKvIoPageLookup;
  6202  	pIo->xNew    = vedisKvIoNewPage;
  6203  	
  6204  	pIo->xWrite     = vedisKvIopageWrite; 
  6205  	pIo->xDontWrite = vedisKvIoPageDontWrite;
  6206  	pIo->xDontJournal = vedisKvIoPageDontJournal;
  6207  	pIo->xDontMkHot = vedisKvIoPageDontMakeHot;
  6208  
  6209  	pIo->xPageRef   = vedisKvIopage_ref;
  6210  	pIo->xPageUnref = vedisKvIoPageUnRef;
  6211  
  6212  	pIo->xPageSize = vedisKvIoPageSize;
  6213  	pIo->xReadOnly = vedisKvIoReadOnly;
  6214  
  6215  	pIo->xTmpPage =  vedisKvIoTempPage;
  6216  
  6217  	pIo->xSetUnpin = vedisKvIoPageUnpin;
  6218  	pIo->xSetReload = vedisKvIoPageReload;
  6219  
  6220  	pIo->xErr = vedisKvIoErr;
  6221  
  6222  	return VEDIS_OK;
  6223  }
  6224  /*
  6225   * ----------------------------------------------------------
  6226   * File: os_win.c
  6227   * MD5: 8f05b9895ac8989f395417dcf864fa74
  6228   * ----------------------------------------------------------
  6229   */
  6230  /*
  6231   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
  6232   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
  6233   * Version 1.1.6
  6234   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  6235   * please contact Symisc Systems via:
  6236   *       legal@symisc.net
  6237   *       licensing@symisc.net
  6238   *       contact@symisc.net
  6239   * or visit:
  6240   *      http://vedis.org/licensing.html
  6241   */
  6242   /* $SymiscID: os_win.c v1.2 Win7 2012-11-10 12:10 devel <chm@symisc.net> $ */
  6243  #ifndef VEDIS_AMALGAMATION
  6244  #include "vedisInt.h"
  6245  #endif
  6246  /* Omit the whole layer from the build if compiling for platforms other than Windows */
  6247  #ifdef __WINNT__
  6248  /* This file contains code that is specific to windows. (Mostly SQLite3 source tree) */
  6249  #include <Windows.h>
  6250  /*
  6251  ** Some microsoft compilers lack this definition.
  6252  */
  6253  #ifndef INVALID_FILE_ATTRIBUTES
  6254  # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 
  6255  #endif
  6256  /*
  6257  ** WinCE lacks native support for file locking so we have to fake it
  6258  ** with some code of our own.
  6259  */
  6260  #ifdef __WIN_CE__
  6261  typedef struct winceLock {
  6262    int nReaders;       /* Number of reader locks obtained */
  6263    BOOL bPending;      /* Indicates a pending lock has been obtained */
  6264    BOOL bReserved;     /* Indicates a reserved lock has been obtained */
  6265    BOOL bExclusive;    /* Indicates an exclusive lock has been obtained */
  6266  } winceLock;
  6267  #define AreFileApisANSI() 1
  6268  #define FormatMessageW(a,b,c,d,e,f,g) 0
  6269  #endif
  6270  
  6271  /*
  6272  ** The winFile structure is a subclass of vedis_file* specific to the win32
  6273  ** portability layer.
  6274  */
  6275  typedef struct winFile winFile;
  6276  struct winFile {
  6277    const vedis_io_methods *pMethod; /*** Must be first ***/
  6278    vedis_vfs *pVfs;      /* The VFS used to open this file */
  6279    HANDLE h;               /* Handle for accessing the file */
  6280    sxu8 locktype;          /* Type of lock currently held on this file */
  6281    short sharedLockByte;   /* Randomly chosen byte used as a shared lock */
  6282    DWORD lastErrno;        /* The Windows errno from the last I/O error */
  6283    DWORD sectorSize;       /* Sector size of the device file is on */
  6284    int szChunk;            /* Chunk size */
  6285  #ifdef __WIN_CE__
  6286    WCHAR *zDeleteOnClose;  /* Name of file to delete when closing */
  6287    HANDLE hMutex;          /* Mutex used to control access to shared lock */  
  6288    HANDLE hShared;         /* Shared memory segment used for locking */
  6289    winceLock local;        /* Locks obtained by this instance of winFile */
  6290    winceLock *shared;      /* Global shared lock memory for the file  */
  6291  #endif
  6292  };
  6293  /*
  6294  ** Convert a UTF-8 string to microsoft unicode (UTF-16?). 
  6295  **
  6296  ** Space to hold the returned string is obtained from HeapAlloc().
  6297  */
  6298  static WCHAR *utf8ToUnicode(const char *zFilename){
  6299    int nChar;
  6300    WCHAR *zWideFilename;
  6301  
  6302    nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0);
  6303    zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nChar*sizeof(zWideFilename[0]) );
  6304    if( zWideFilename==0 ){
  6305      return 0;
  6306    }
  6307    nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
  6308    if( nChar==0 ){
  6309      HeapFree(GetProcessHeap(),0,zWideFilename);
  6310      zWideFilename = 0;
  6311    }
  6312    return zWideFilename;
  6313  }
  6314  
  6315  /*
  6316  ** Convert microsoft unicode to UTF-8.  Space to hold the returned string is
  6317  ** obtained from malloc().
  6318  */
  6319  static char *unicodeToUtf8(const WCHAR *zWideFilename){
  6320    int nByte;
  6321    char *zFilename;
  6322  
  6323    nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
  6324    zFilename = (char *)HeapAlloc(GetProcessHeap(),0,nByte );
  6325    if( zFilename==0 ){
  6326      return 0;
  6327    }
  6328    nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
  6329                                0, 0);
  6330    if( nByte == 0 ){
  6331      HeapFree(GetProcessHeap(),0,zFilename);
  6332      zFilename = 0;
  6333    }
  6334    return zFilename;
  6335  }
  6336  
  6337  /*
  6338  ** Convert an ansi string to microsoft unicode, based on the
  6339  ** current codepage settings for file apis.
  6340  ** 
  6341  ** Space to hold the returned string is obtained
  6342  ** from malloc.
  6343  */
  6344  static WCHAR *mbcsToUnicode(const char *zFilename){
  6345    int nByte;
  6346    WCHAR *zMbcsFilename;
  6347    int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
  6348  
  6349    nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, 0,0)*sizeof(WCHAR);
  6350    zMbcsFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nByte*sizeof(zMbcsFilename[0]) );
  6351    if( zMbcsFilename==0 ){
  6352      return 0;
  6353    }
  6354    nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
  6355    if( nByte==0 ){
  6356      HeapFree(GetProcessHeap(),0,zMbcsFilename);
  6357      zMbcsFilename = 0;
  6358    }
  6359    return zMbcsFilename;
  6360  }
  6361  /*
  6362  ** Convert multibyte character string to UTF-8.  Space to hold the
  6363  ** returned string is obtained from malloc().
  6364  */
  6365  char *vedis_win32_mbcs_to_utf8(const char *zFilename){
  6366    char *zFilenameUtf8;
  6367    WCHAR *zTmpWide;
  6368  
  6369    zTmpWide = mbcsToUnicode(zFilename);
  6370    if( zTmpWide==0 ){
  6371      return 0;
  6372    }
  6373    zFilenameUtf8 = unicodeToUtf8(zTmpWide);
  6374    HeapFree(GetProcessHeap(),0,zTmpWide);
  6375    return zFilenameUtf8;
  6376  }
  6377  /*
  6378  ** Some microsoft compilers lack this definition.
  6379  */
  6380  #ifndef INVALID_SET_FILE_POINTER
  6381  # define INVALID_SET_FILE_POINTER ((DWORD)-1)
  6382  #endif
  6383  
  6384  /*
  6385  ** Move the current position of the file handle passed as the first 
  6386  ** argument to offset iOffset within the file. If successful, return 0. 
  6387  ** Otherwise, set pFile->lastErrno and return non-zero.
  6388  */
  6389  static int seekWinFile(winFile *pFile, vedis_int64 iOffset){
  6390    LONG upperBits;                 /* Most sig. 32 bits of new offset */
  6391    LONG lowerBits;                 /* Least sig. 32 bits of new offset */
  6392    DWORD dwRet;                    /* Value returned by SetFilePointer() */
  6393  
  6394    upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
  6395    lowerBits = (LONG)(iOffset & 0xffffffff);
  6396  
  6397    /* API oddity: If successful, SetFilePointer() returns a dword 
  6398    ** containing the lower 32-bits of the new file-offset. Or, if it fails,
  6399    ** it returns INVALID_SET_FILE_POINTER. However according to MSDN, 
  6400    ** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine 
  6401    ** whether an error has actually occured, it is also necessary to call 
  6402    ** GetLastError().
  6403    */
  6404    dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
  6405    if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
  6406      pFile->lastErrno = GetLastError();
  6407      return 1;
  6408    }
  6409    return 0;
  6410  }
  6411  /*
  6412  ** Close a file.
  6413  **
  6414  ** It is reported that an attempt to close a handle might sometimes
  6415  ** fail.  This is a very unreasonable result, but windows is notorious
  6416  ** for being unreasonable so I do not doubt that it might happen.  If
  6417  ** the close fails, we pause for 100 milliseconds and try again.  As
  6418  ** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before
  6419  ** giving up and returning an error.
  6420  */
  6421  #define MX_CLOSE_ATTEMPT 3
  6422  static int winClose(vedis_file *id)
  6423  {
  6424    int rc, cnt = 0;
  6425    winFile *pFile = (winFile*)id;
  6426    do{
  6427      rc = CloseHandle(pFile->h);
  6428    }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
  6429  
  6430    return rc ? VEDIS_OK : VEDIS_IOERR;
  6431  }
  6432  /*
  6433  ** Read data from a file into a buffer.  Return VEDIS_OK if all
  6434  ** bytes were read successfully and VEDIS_IOERR if anything goes
  6435  ** wrong.
  6436  */
  6437  static int winRead(
  6438    vedis_file *id,          /* File to read from */
  6439    void *pBuf,                /* Write content into this buffer */
  6440    vedis_int64 amt,        /* Number of bytes to read */
  6441    vedis_int64 offset       /* Begin reading at this offset */
  6442  ){
  6443    winFile *pFile = (winFile*)id;  /* file handle */
  6444    DWORD nRead;                    /* Number of bytes actually read from file */
  6445  
  6446    if( seekWinFile(pFile, offset) ){
  6447      return VEDIS_FULL;
  6448    }
  6449    if( !ReadFile(pFile->h, pBuf, (DWORD)amt, &nRead, 0) ){
  6450      pFile->lastErrno = GetLastError();
  6451      return VEDIS_IOERR;
  6452    }
  6453    if( nRead<(DWORD)amt ){
  6454      /* Unread parts of the buffer must be zero-filled */
  6455      SyZero(&((char*)pBuf)[nRead],(sxu32)(amt-nRead));
  6456      return VEDIS_IOERR;
  6457    }
  6458  
  6459    return VEDIS_OK;
  6460  }
  6461  
  6462  /*
  6463  ** Write data from a buffer into a file.  Return VEDIS_OK on success
  6464  ** or some other error code on failure.
  6465  */
  6466  static int winWrite(
  6467    vedis_file *id,               /* File to write into */
  6468    const void *pBuf,               /* The bytes to be written */
  6469    vedis_int64 amt,                        /* Number of bytes to write */
  6470    vedis_int64 offset            /* Offset into the file to begin writing at */
  6471  ){
  6472    int rc;                         /* True if error has occured, else false */
  6473    winFile *pFile = (winFile*)id;  /* File handle */
  6474  
  6475    rc = seekWinFile(pFile, offset);
  6476    if( rc==0 ){
  6477      sxu8 *aRem = (sxu8 *)pBuf;        /* Data yet to be written */
  6478      vedis_int64 nRem = amt;         /* Number of bytes yet to be written */
  6479      DWORD nWrite;                 /* Bytes written by each WriteFile() call */
  6480  
  6481      while( nRem>0 && WriteFile(pFile->h, aRem, (DWORD)nRem, &nWrite, 0) && nWrite>0 ){
  6482        aRem += nWrite;
  6483        nRem -= nWrite;
  6484      }
  6485      if( nRem>0 ){
  6486        pFile->lastErrno = GetLastError();
  6487        rc = 1;
  6488      }
  6489    }
  6490    if( rc ){
  6491      if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
  6492        return VEDIS_FULL;
  6493      }
  6494      return VEDIS_IOERR;
  6495    }
  6496    return VEDIS_OK;
  6497  }
  6498  
  6499  /*
  6500  ** Truncate an open file to a specified size
  6501  */
  6502  static int winTruncate(vedis_file *id, vedis_int64 nByte){
  6503    winFile *pFile = (winFile*)id;  /* File handle object */
  6504    int rc = VEDIS_OK;             /* Return code for this function */
  6505  
  6506  
  6507    /* If the user has configured a chunk-size for this file, truncate the
  6508    ** file so that it consists of an integer number of chunks (i.e. the
  6509    ** actual file size after the operation may be larger than the requested
  6510    ** size).
  6511    */
  6512    if( pFile->szChunk ){
  6513      nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  6514    }
  6515  
  6516    /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
  6517    if( seekWinFile(pFile, nByte) ){
  6518      rc = VEDIS_IOERR;
  6519    }else if( 0==SetEndOfFile(pFile->h) ){
  6520      pFile->lastErrno = GetLastError();
  6521      rc = VEDIS_IOERR;
  6522    }
  6523    return rc;
  6524  }
  6525  /*
  6526  ** Make sure all writes to a particular file are committed to disk.
  6527  */
  6528  static int winSync(vedis_file *id, int flags){
  6529    winFile *pFile = (winFile*)id;
  6530    SXUNUSED(flags); /* MSVC warning */
  6531    if( FlushFileBuffers(pFile->h) ){
  6532      return VEDIS_OK;
  6533    }else{
  6534      pFile->lastErrno = GetLastError();
  6535      return VEDIS_IOERR;
  6536    }
  6537  }
  6538  /*
  6539  ** Determine the current size of a file in bytes
  6540  */
  6541  static int winFileSize(vedis_file *id, vedis_int64 *pSize){
  6542    DWORD upperBits;
  6543    DWORD lowerBits;
  6544    winFile *pFile = (winFile*)id;
  6545    DWORD error;
  6546    lowerBits = GetFileSize(pFile->h, &upperBits);
  6547    if(   (lowerBits == INVALID_FILE_SIZE)
  6548       && ((error = GetLastError()) != NO_ERROR) )
  6549    {
  6550      pFile->lastErrno = error;
  6551      return VEDIS_IOERR;
  6552    }
  6553    *pSize = (((vedis_int64)upperBits)<<32) + lowerBits;
  6554    return VEDIS_OK;
  6555  }
  6556  /*
  6557  ** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems.
  6558  */
  6559  #ifndef LOCKFILE_FAIL_IMMEDIATELY
  6560  # define LOCKFILE_FAIL_IMMEDIATELY 1
  6561  #endif
  6562  
  6563  /*
  6564  ** Acquire a reader lock.
  6565  */
  6566  static int getReadLock(winFile *pFile){
  6567    int res;
  6568    OVERLAPPED ovlp;
  6569    ovlp.Offset = SHARED_FIRST;
  6570    ovlp.OffsetHigh = 0;
  6571    ovlp.hEvent = 0;
  6572    res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,0, SHARED_SIZE, 0, &ovlp);
  6573    if( res == 0 ){
  6574      pFile->lastErrno = GetLastError();
  6575    }
  6576    return res;
  6577  }
  6578  /*
  6579  ** Undo a readlock
  6580  */
  6581  static int unlockReadLock(winFile *pFile){
  6582    int res;
  6583    res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
  6584    if( res == 0 ){
  6585      pFile->lastErrno = GetLastError();
  6586    }
  6587    return res;
  6588  }
  6589  /*
  6590  ** Lock the file with the lock specified by parameter locktype - one
  6591  ** of the following:
  6592  **
  6593  **     (1) SHARED_LOCK
  6594  **     (2) RESERVED_LOCK
  6595  **     (3) PENDING_LOCK
  6596  **     (4) EXCLUSIVE_LOCK
  6597  **
  6598  ** Sometimes when requesting one lock state, additional lock states
  6599  ** are inserted in between.  The locking might fail on one of the later
  6600  ** transitions leaving the lock state different from what it started but
  6601  ** still short of its goal.  The following chart shows the allowed
  6602  ** transitions and the inserted intermediate states:
  6603  **
  6604  **    UNLOCKED -> SHARED
  6605  **    SHARED -> RESERVED
  6606  **    SHARED -> (PENDING) -> EXCLUSIVE
  6607  **    RESERVED -> (PENDING) -> EXCLUSIVE
  6608  **    PENDING -> EXCLUSIVE
  6609  **
  6610  ** This routine will only increase a lock.  The winUnlock() routine
  6611  ** erases all locks at once and returns us immediately to locking level 0.
  6612  ** It is not possible to lower the locking level one step at a time.  You
  6613  ** must go straight to locking level 0.
  6614  */
  6615  static int winLock(vedis_file *id, int locktype){
  6616    int rc = VEDIS_OK;    /* Return code from subroutines */
  6617    int res = 1;           /* Result of a windows lock call */
  6618    int newLocktype;       /* Set pFile->locktype to this value before exiting */
  6619    int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */
  6620    winFile *pFile = (winFile*)id;
  6621    DWORD error = NO_ERROR;
  6622  
  6623    /* If there is already a lock of this type or more restrictive on the
  6624    ** OsFile, do nothing.
  6625    */
  6626    if( pFile->locktype>=locktype ){
  6627      return VEDIS_OK;
  6628    }
  6629  
  6630    /* Make sure the locking sequence is correct
  6631    assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
  6632    assert( locktype!=PENDING_LOCK );
  6633    assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
  6634    */
  6635    /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
  6636    ** a SHARED lock.  If we are acquiring a SHARED lock, the acquisition of
  6637    ** the PENDING_LOCK byte is temporary.
  6638    */
  6639    newLocktype = pFile->locktype;
  6640    if(   (pFile->locktype==NO_LOCK)
  6641       || (   (locktype==EXCLUSIVE_LOCK)
  6642           && (pFile->locktype==RESERVED_LOCK))
  6643    ){
  6644      int cnt = 3;
  6645      while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){
  6646        /* Try 3 times to get the pending lock.  The pending lock might be
  6647        ** held by another reader process who will release it momentarily.
  6648  	  */
  6649        Sleep(1);
  6650      }
  6651      gotPendingLock = res;
  6652      if( !res ){
  6653        error = GetLastError();
  6654      }
  6655    }
  6656  
  6657    /* Acquire a shared lock
  6658    */
  6659    if( locktype==SHARED_LOCK && res ){
  6660     /* assert( pFile->locktype==NO_LOCK ); */
  6661      res = getReadLock(pFile);
  6662      if( res ){
  6663        newLocktype = SHARED_LOCK;
  6664      }else{
  6665        error = GetLastError();
  6666      }
  6667    }
  6668  
  6669    /* Acquire a RESERVED lock
  6670    */
  6671    if( locktype==RESERVED_LOCK && res ){
  6672      /* assert( pFile->locktype==SHARED_LOCK ); */
  6673      res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
  6674      if( res ){
  6675        newLocktype = RESERVED_LOCK;
  6676      }else{
  6677        error = GetLastError();
  6678      }
  6679    }
  6680  
  6681    /* Acquire a PENDING lock
  6682    */
  6683    if( locktype==EXCLUSIVE_LOCK && res ){
  6684      newLocktype = PENDING_LOCK;
  6685      gotPendingLock = 0;
  6686    }
  6687  
  6688    /* Acquire an EXCLUSIVE lock
  6689    */
  6690    if( locktype==EXCLUSIVE_LOCK && res ){
  6691      /* assert( pFile->locktype>=SHARED_LOCK ); */
  6692      res = unlockReadLock(pFile);
  6693      res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
  6694      if( res ){
  6695        newLocktype = EXCLUSIVE_LOCK;
  6696      }else{
  6697        error = GetLastError();
  6698        getReadLock(pFile);
  6699      }
  6700    }
  6701  
  6702    /* If we are holding a PENDING lock that ought to be released, then
  6703    ** release it now.
  6704    */
  6705    if( gotPendingLock && locktype==SHARED_LOCK ){
  6706      UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
  6707    }
  6708  
  6709    /* Update the state of the lock has held in the file descriptor then
  6710    ** return the appropriate result code.
  6711    */
  6712    if( res ){
  6713      rc = VEDIS_OK;
  6714    }else{
  6715      pFile->lastErrno = error;
  6716      rc = VEDIS_BUSY;
  6717    }
  6718    pFile->locktype = (sxu8)newLocktype;
  6719    return rc;
  6720  }
  6721  /*
  6722  ** This routine checks if there is a RESERVED lock held on the specified
  6723  ** file by this or any other process. If such a lock is held, return
  6724  ** non-zero, otherwise zero.
  6725  */
  6726  static int winCheckReservedLock(vedis_file *id, int *pResOut){
  6727    int rc;
  6728    winFile *pFile = (winFile*)id;
  6729    if( pFile->locktype>=RESERVED_LOCK ){
  6730      rc = 1;
  6731    }else{
  6732      rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
  6733      if( rc ){
  6734        UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
  6735      }
  6736      rc = !rc;
  6737    }
  6738    *pResOut = rc;
  6739    return VEDIS_OK;
  6740  }
  6741  /*
  6742  ** Lower the locking level on file descriptor id to locktype.  locktype
  6743  ** must be either NO_LOCK or SHARED_LOCK.
  6744  **
  6745  ** If the locking level of the file descriptor is already at or below
  6746  ** the requested locking level, this routine is a no-op.
  6747  **
  6748  ** It is not possible for this routine to fail if the second argument
  6749  ** is NO_LOCK.  If the second argument is SHARED_LOCK then this routine
  6750  ** might return VEDIS_IOERR;
  6751  */
  6752  static int winUnlock(vedis_file *id, int locktype){
  6753    int type;
  6754    winFile *pFile = (winFile*)id;
  6755    int rc = VEDIS_OK;
  6756  
  6757    type = pFile->locktype;
  6758    if( type>=EXCLUSIVE_LOCK ){
  6759      UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
  6760      if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
  6761        /* This should never happen.  We should always be able to
  6762        ** reacquire the read lock */
  6763        rc = VEDIS_IOERR;
  6764      }
  6765    }
  6766    if( type>=RESERVED_LOCK ){
  6767      UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
  6768    }
  6769    if( locktype==NO_LOCK && type>=SHARED_LOCK ){
  6770      unlockReadLock(pFile);
  6771    }
  6772    if( type>=PENDING_LOCK ){
  6773      UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0);
  6774    }
  6775    pFile->locktype = (sxu8)locktype;
  6776    return rc;
  6777  }
  6778  /*
  6779  ** Return the sector size in bytes of the underlying block device for
  6780  ** the specified file. This is almost always 512 bytes, but may be
  6781  ** larger for some devices.
  6782  **
  6783  */
  6784  static int winSectorSize(vedis_file *id){
  6785    return (int)(((winFile*)id)->sectorSize);
  6786  }
  6787  /*
  6788  ** This vector defines all the methods that can operate on an
  6789  ** vedis_file for Windows systems.
  6790  */
  6791  static const vedis_io_methods winIoMethod = {
  6792    1,                              /* iVersion */
  6793    winClose,                       /* xClose */
  6794    winRead,                        /* xRead */
  6795    winWrite,                       /* xWrite */
  6796    winTruncate,                    /* xTruncate */
  6797    winSync,                        /* xSync */
  6798    winFileSize,                    /* xFileSize */
  6799    winLock,                        /* xLock */
  6800    winUnlock,                      /* xUnlock */
  6801    winCheckReservedLock,           /* xCheckReservedLock */
  6802    winSectorSize,                  /* xSectorSize */
  6803  };
  6804  /*
  6805   * Windows VFS Methods.
  6806   */
  6807  /*
  6808  ** Convert a UTF-8 filename into whatever form the underlying
  6809  ** operating system wants filenames in.  Space to hold the result
  6810  ** is obtained from malloc and must be freed by the calling
  6811  ** function.
  6812  */
  6813  static void *convertUtf8Filename(const char *zFilename)
  6814  {
  6815    void *zConverted;
  6816    zConverted = utf8ToUnicode(zFilename);
  6817    /* caller will handle out of memory */
  6818    return zConverted;
  6819  }
  6820  /*
  6821  ** Delete the named file.
  6822  **
  6823  ** Note that windows does not allow a file to be deleted if some other
  6824  ** process has it open.  Sometimes a virus scanner or indexing program
  6825  ** will open a journal file shortly after it is created in order to do
  6826  ** whatever it does.  While this other process is holding the
  6827  ** file open, we will be unable to delete it.  To work around this
  6828  ** problem, we delay 100 milliseconds and try to delete again.  Up
  6829  ** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
  6830  ** up and returning an error.
  6831  */
  6832  #define MX_DELETION_ATTEMPTS 5
  6833  static int winDelete(
  6834    vedis_vfs *pVfs,          /* Not used on win32 */
  6835    const char *zFilename,      /* Name of file to delete */
  6836    int syncDir                 /* Not used on win32 */
  6837  ){
  6838    int cnt = 0;
  6839    DWORD rc;
  6840    DWORD error = 0;
  6841    void *zConverted;
  6842    zConverted = convertUtf8Filename(zFilename);
  6843    if( zConverted==0 ){
  6844  	   SXUNUSED(pVfs);
  6845  	   SXUNUSED(syncDir);
  6846      return VEDIS_NOMEM;
  6847    }
  6848    do{
  6849  	  DeleteFileW((LPCWSTR)zConverted);
  6850    }while(   (   ((rc = GetFileAttributesW((LPCWSTR)zConverted)) != INVALID_FILE_ATTRIBUTES)
  6851  	  || ((error = GetLastError()) == ERROR_ACCESS_DENIED))
  6852  	  && (++cnt < MX_DELETION_ATTEMPTS)
  6853  	  && (Sleep(100), 1)
  6854  	  );
  6855  	HeapFree(GetProcessHeap(),0,zConverted);
  6856   
  6857    return (   (rc == INVALID_FILE_ATTRIBUTES) 
  6858            && (error == ERROR_FILE_NOT_FOUND)) ? VEDIS_OK : VEDIS_IOERR;
  6859  }
  6860  /*
  6861  ** Check the existance and status of a file.
  6862  */
  6863  static int winAccess(
  6864    vedis_vfs *pVfs,         /* Not used  */
  6865    const char *zFilename,     /* Name of file to check */
  6866    int flags,                 /* Type of test to make on this file */
  6867    int *pResOut               /* OUT: Result */
  6868  ){
  6869    WIN32_FILE_ATTRIBUTE_DATA sAttrData;
  6870    DWORD attr;
  6871    int rc = 0;
  6872    void *zConverted;
  6873    SXUNUSED(pVfs);
  6874  
  6875    zConverted = convertUtf8Filename(zFilename);
  6876    if( zConverted==0 ){
  6877      return VEDIS_NOMEM;
  6878    }
  6879    SyZero(&sAttrData,sizeof(sAttrData));
  6880    if( GetFileAttributesExW((WCHAR*)zConverted,
  6881  	  GetFileExInfoStandard, 
  6882  	  &sAttrData) ){
  6883        /* For an VEDIS_ACCESS_EXISTS query, treat a zero-length file
  6884        ** as if it does not exist.
  6885        */
  6886        if(    flags==VEDIS_ACCESS_EXISTS
  6887            && sAttrData.nFileSizeHigh==0 
  6888            && sAttrData.nFileSizeLow==0 ){
  6889          attr = INVALID_FILE_ATTRIBUTES;
  6890        }else{
  6891          attr = sAttrData.dwFileAttributes;
  6892        }
  6893      }else{
  6894        if( GetLastError()!=ERROR_FILE_NOT_FOUND ){
  6895          HeapFree(GetProcessHeap(),0,zConverted);
  6896          return VEDIS_IOERR;
  6897        }else{
  6898          attr = INVALID_FILE_ATTRIBUTES;
  6899        }
  6900      }
  6901    HeapFree(GetProcessHeap(),0,zConverted);
  6902    switch( flags ){
  6903       case VEDIS_ACCESS_READWRITE:
  6904        rc = (attr & FILE_ATTRIBUTE_READONLY)==0;
  6905        break;
  6906      case VEDIS_ACCESS_READ:
  6907      case VEDIS_ACCESS_EXISTS:
  6908  	default:
  6909        rc = attr!=INVALID_FILE_ATTRIBUTES;
  6910        break;
  6911    }
  6912    *pResOut = rc;
  6913    return VEDIS_OK;
  6914  }
  6915  /*
  6916  ** Turn a relative pathname into a full pathname.  Write the full
  6917  ** pathname into zOut[].  zOut[] will be at least pVfs->mxPathname
  6918  ** bytes in size.
  6919  */
  6920  static int winFullPathname(
  6921    vedis_vfs *pVfs,            /* Pointer to vfs object */
  6922    const char *zRelative,        /* Possibly relative input path */
  6923    int nFull,                    /* Size of output buffer in bytes */
  6924    char *zFull                   /* Output buffer */
  6925  ){
  6926    int nByte;
  6927    void *zConverted;
  6928    WCHAR *zTemp;
  6929    char *zOut;
  6930    SXUNUSED(nFull);
  6931    zConverted = convertUtf8Filename(zRelative);
  6932    if( zConverted == 0 ){
  6933  	  return VEDIS_NOMEM;
  6934    }
  6935    nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
  6936    zTemp = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nByte*sizeof(zTemp[0]) );
  6937    if( zTemp==0 ){
  6938  	  HeapFree(GetProcessHeap(),0,zConverted);
  6939  	  return VEDIS_NOMEM;
  6940    }
  6941    GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
  6942    HeapFree(GetProcessHeap(),0,zConverted);
  6943    zOut = unicodeToUtf8(zTemp);
  6944    HeapFree(GetProcessHeap(),0,zTemp);
  6945    if( zOut == 0 ){
  6946      return VEDIS_NOMEM;
  6947    }
  6948    Systrcpy(zFull,(sxu32)pVfs->mxPathname,zOut,0);
  6949    HeapFree(GetProcessHeap(),0,zOut);
  6950    return VEDIS_OK;
  6951  }
  6952  /*
  6953  ** Get the sector size of the device used to store
  6954  ** file.
  6955  */
  6956  static int getSectorSize(
  6957      vedis_vfs *pVfs,
  6958      const char *zRelative     /* UTF-8 file name */
  6959  ){
  6960    DWORD bytesPerSector = VEDIS_DEFAULT_SECTOR_SIZE;
  6961    char zFullpath[MAX_PATH+1];
  6962    int rc;
  6963    DWORD dwRet = 0;
  6964    DWORD dwDummy;
  6965    /*
  6966    ** We need to get the full path name of the file
  6967    ** to get the drive letter to look up the sector
  6968    ** size.
  6969    */
  6970    rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath);
  6971    if( rc == VEDIS_OK )
  6972    {
  6973      void *zConverted = convertUtf8Filename(zFullpath);
  6974      if( zConverted ){
  6975          /* trim path to just drive reference */
  6976          WCHAR *p = (WCHAR *)zConverted;
  6977          for(;*p;p++){
  6978            if( *p == '\\' ){
  6979              *p = '\0';
  6980              break;
  6981            }
  6982          }
  6983          dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted,
  6984                                    &dwDummy,
  6985                                    &bytesPerSector,
  6986                                    &dwDummy,
  6987                                    &dwDummy);
  6988  		 HeapFree(GetProcessHeap(),0,zConverted);
  6989  	}
  6990      if( !dwRet ){
  6991        bytesPerSector = VEDIS_DEFAULT_SECTOR_SIZE;
  6992      }
  6993    }
  6994    return (int) bytesPerSector; 
  6995  }
  6996  /*
  6997  ** Sleep for a little while.  Return the amount of time slept.
  6998  */
  6999  static int winSleep(vedis_vfs *pVfs, int microsec){
  7000    Sleep((microsec+999)/1000);
  7001    SXUNUSED(pVfs);
  7002    return ((microsec+999)/1000)*1000;
  7003  }
  7004  /*
  7005   * Export the current system time.
  7006   */
  7007  static int winCurrentTime(vedis_vfs *pVfs,Sytm *pOut)
  7008  {
  7009  	SYSTEMTIME sSys;
  7010  	SXUNUSED(pVfs);
  7011  	GetSystemTime(&sSys);
  7012  	SYSTEMTIME_TO_SYTM(&sSys,pOut);
  7013  	return VEDIS_OK;
  7014  }
  7015  /*
  7016  ** The idea is that this function works like a combination of
  7017  ** GetLastError() and FormatMessage() on windows (or errno and
  7018  ** strerror_r() on unix). After an error is returned by an OS
  7019  ** function, UnQLite calls this function with zBuf pointing to
  7020  ** a buffer of nBuf bytes. The OS layer should populate the
  7021  ** buffer with a nul-terminated UTF-8 encoded error message
  7022  ** describing the last IO error to have occurred within the calling
  7023  ** thread.
  7024  **
  7025  ** If the error message is too large for the supplied buffer,
  7026  ** it should be truncated. The return value of xGetLastError
  7027  ** is zero if the error message fits in the buffer, or non-zero
  7028  ** otherwise (if the message was truncated). If non-zero is returned,
  7029  ** then it is not necessary to include the nul-terminator character
  7030  ** in the output buffer.
  7031  */
  7032  static int winGetLastError(vedis_vfs *pVfs, int nBuf, char *zBuf)
  7033  {
  7034    /* FormatMessage returns 0 on failure.  Otherwise it
  7035    ** returns the number of TCHARs written to the output
  7036    ** buffer, excluding the terminating null char.
  7037    */
  7038    DWORD error = GetLastError();
  7039    WCHAR *zTempWide = 0;
  7040    DWORD dwLen;
  7041    char *zOut = 0;
  7042  
  7043    SXUNUSED(pVfs);
  7044    dwLen = FormatMessageW(
  7045  	  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  7046  	  0,
  7047  	  error,
  7048  	  0,
  7049  	  (LPWSTR) &zTempWide,
  7050  	  0,
  7051  	  0
  7052  	  );
  7053      if( dwLen > 0 ){
  7054        /* allocate a buffer and convert to UTF8 */
  7055        zOut = unicodeToUtf8(zTempWide);
  7056        /* free the system buffer allocated by FormatMessage */
  7057        LocalFree(zTempWide);
  7058      }
  7059  	if( 0 == dwLen ){
  7060  		Systrcpy(zBuf,(sxu32)nBuf,"OS Error",sizeof("OS Error")-1);
  7061  	}else{
  7062  		/* copy a maximum of nBuf chars to output buffer */
  7063  		Systrcpy(zBuf,(sxu32)nBuf,zOut,0 /* Compute input length automatically */);
  7064  		/* free the UTF8 buffer */
  7065  		HeapFree(GetProcessHeap(),0,zOut);
  7066  	}
  7067    return 0;
  7068  }
  7069  /*
  7070  ** Open a file.
  7071  */
  7072  static int winOpen(
  7073    vedis_vfs *pVfs,        /* Not used */
  7074    const char *zName,        /* Name of the file (UTF-8) */
  7075    vedis_file *id,         /* Write the UnQLite file handle here */
  7076    unsigned int flags                /* Open mode flags */
  7077  ){
  7078    HANDLE h;
  7079    DWORD dwDesiredAccess;
  7080    DWORD dwShareMode;
  7081    DWORD dwCreationDisposition;
  7082    DWORD dwFlagsAndAttributes = 0;
  7083    winFile *pFile = (winFile*)id;
  7084    void *zConverted;              /* Filename in OS encoding */
  7085    const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
  7086    int isExclusive  = (flags & VEDIS_OPEN_EXCLUSIVE);
  7087    int isDelete     = (flags & VEDIS_OPEN_TEMP_DB);
  7088    int isCreate     = (flags & VEDIS_OPEN_CREATE);
  7089    int isReadWrite  = (flags & VEDIS_OPEN_READWRITE);
  7090  
  7091    pFile->h = INVALID_HANDLE_VALUE;
  7092    /* Convert the filename to the system encoding. */
  7093    zConverted = convertUtf8Filename(zUtf8Name);
  7094    if( zConverted==0 ){
  7095      return VEDIS_NOMEM;
  7096    }
  7097    if( isReadWrite ){
  7098      dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
  7099    }else{
  7100      dwDesiredAccess = GENERIC_READ;
  7101    }
  7102    /* VEDIS_OPEN_EXCLUSIVE is used to make sure that a new file is 
  7103    ** created.
  7104    */
  7105    if( isExclusive ){
  7106      /* Creates a new file, only if it does not already exist. */
  7107      /* If the file exists, it fails. */
  7108      dwCreationDisposition = CREATE_NEW;
  7109    }else if( isCreate ){
  7110      /* Open existing file, or create if it doesn't exist */
  7111      dwCreationDisposition = OPEN_ALWAYS;
  7112    }else{
  7113      /* Opens a file, only if it exists. */
  7114      dwCreationDisposition = OPEN_EXISTING;
  7115    }
  7116  
  7117    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  7118  
  7119    if( isDelete ){
  7120      dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY
  7121                                 | FILE_ATTRIBUTE_HIDDEN
  7122                                 | FILE_FLAG_DELETE_ON_CLOSE;
  7123    }else{
  7124      dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
  7125    }
  7126    h = CreateFileW((WCHAR*)zConverted,
  7127         dwDesiredAccess,
  7128         dwShareMode,
  7129         NULL,
  7130         dwCreationDisposition,
  7131         dwFlagsAndAttributes,
  7132         NULL
  7133      );
  7134    if( h==INVALID_HANDLE_VALUE ){
  7135      pFile->lastErrno = GetLastError();
  7136      HeapFree(GetProcessHeap(),0,zConverted);
  7137  	return VEDIS_IOERR;
  7138    }
  7139    SyZero(pFile,sizeof(*pFile));
  7140    pFile->pMethod = &winIoMethod;
  7141    pFile->h = h;
  7142    pFile->lastErrno = NO_ERROR;
  7143    pFile->pVfs = pVfs;
  7144    pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
  7145    HeapFree(GetProcessHeap(),0,zConverted);
  7146    return VEDIS_OK;
  7147  }
  7148  /* Open a file in a read-only mode */
  7149  static HANDLE OpenReadOnly(LPCWSTR pPath)
  7150  {
  7151  	DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
  7152  	DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
  7153  	DWORD dwAccess = GENERIC_READ;
  7154  	DWORD dwCreate = OPEN_EXISTING;	
  7155  	HANDLE pHandle;
  7156  	pHandle = CreateFileW(pPath, dwAccess, dwShare, 0, dwCreate, dwType, 0);
  7157  	if( pHandle == INVALID_HANDLE_VALUE){
  7158  		return 0;
  7159  	}
  7160  	return pHandle;
  7161  }
  7162  /* int (*xMmap)(const char *, void **, vedis_int64 *) */
  7163  static int winMmap(const char *zPath, void **ppMap,vedis_int64 *pSize)
  7164  {
  7165  	DWORD dwSizeLow, dwSizeHigh;
  7166  	HANDLE pHandle, pMapHandle;
  7167  	void *pConverted, *pView;
  7168  
  7169  	pConverted = convertUtf8Filename(zPath);
  7170  	if( pConverted == 0 ){
  7171  		return -1;
  7172  	}
  7173  	pHandle = OpenReadOnly((LPCWSTR)pConverted);
  7174  	HeapFree(GetProcessHeap(), 0, pConverted);
  7175  	if( pHandle == 0 ){
  7176  		return -1;
  7177  	}
  7178  	/* Get the file size */
  7179  	dwSizeLow = GetFileSize(pHandle, &dwSizeHigh);
  7180  	/* Create the mapping */
  7181  	pMapHandle = CreateFileMappingW(pHandle, 0, PAGE_READONLY, dwSizeHigh, dwSizeLow, 0);
  7182  	if( pMapHandle == 0 ){
  7183  		CloseHandle(pHandle);
  7184  		return -1;
  7185  	}
  7186  	*pSize = ((vedis_int64)dwSizeHigh << 32) | dwSizeLow;
  7187  	/* Obtain the view */
  7188  	pView = MapViewOfFile(pMapHandle, FILE_MAP_READ, 0, 0, (SIZE_T)(*pSize));
  7189  	if( pView ){
  7190  		/* Let the upper layer point to the view */
  7191  		*ppMap = pView;
  7192  	}
  7193  	/* Close the handle
  7194  	 * According to MSDN it is OK the close the HANDLES.
  7195  	 */
  7196  	CloseHandle(pMapHandle);
  7197  	CloseHandle(pHandle);
  7198  	return pView ? VEDIS_OK : -1;
  7199  }
  7200  /* void (*xUnmap)(void *, vedis_int64)  */
  7201  static void winUnmap(void *pView, vedis_int64 nSize)
  7202  {
  7203  	nSize = 0; /* Compiler warning */
  7204  	UnmapViewOfFile(pView);
  7205  }
  7206  /*
  7207   * Export the Windows Vfs.
  7208   */
  7209  VEDIS_PRIVATE const vedis_vfs * vedisExportBuiltinVfs(void)
  7210  {
  7211  	static const vedis_vfs sWinvfs = {
  7212  		"Windows",           /* Vfs name */
  7213  		1,                   /* Vfs structure version */
  7214  		sizeof(winFile),     /* szOsFile */
  7215  		MAX_PATH,            /* mxPathName */
  7216  		winOpen,             /* xOpen */
  7217  		winDelete,           /* xDelete */
  7218  		winAccess,           /* xAccess */
  7219  		winFullPathname,     /* xFullPathname */
  7220  		0,                   /* xTmp */
  7221  		winSleep,            /* xSleep */
  7222  		winCurrentTime,      /* xCurrentTime */
  7223  		winGetLastError,     /* xGetLastError */
  7224  		winMmap,            /* xMmap */
  7225  		winUnmap            /* xUnmap */
  7226  	};
  7227  	return &sWinvfs;
  7228  }
  7229  #endif /* __WINNT__ */
  7230  /*
  7231   * ----------------------------------------------------------
  7232   * File: os_unix.c
  7233   * MD5: 41ff547568152212b320903ae83fe8f8
  7234   * ----------------------------------------------------------
  7235   */
  7236  /*
  7237   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
  7238   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
  7239   * Version 1.1.6
  7240   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  7241   * please contact Symisc Systems via:
  7242   *       legal@symisc.net
  7243   *       licensing@symisc.net
  7244   *       contact@symisc.net
  7245   * or visit:
  7246   *      http://vedis.org/licensing.html
  7247   */
  7248   /* $SymiscID: os_unix.c v1.3 FreeBSD 2013-04-05 01:10 devel <chm@symisc.net> $ */
  7249  #ifndef VEDIS_AMALGAMATION
  7250  #include "vedisInt.h"
  7251  #endif
  7252  /* 
  7253   * Omit the whole layer from the build if compiling for platforms other than Unix (Linux, BSD, Solaris, OS X, etc.).
  7254   * Note: Mostly SQLite3 source tree.
  7255   */
  7256  #if defined(__UNIXES__)
  7257  /** This file contains the VFS implementation for unix-like operating systems
  7258  ** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others.
  7259  **
  7260  ** There are actually several different VFS implementations in this file.
  7261  ** The differences are in the way that file locking is done.  The default
  7262  ** implementation uses Posix Advisory Locks.  Alternative implementations
  7263  ** use flock(), dot-files, various proprietary locking schemas, or simply
  7264  ** skip locking all together.
  7265  **
  7266  ** This source file is organized into divisions where the logic for various
  7267  ** subfunctions is contained within the appropriate division.  PLEASE
  7268  ** KEEP THE STRUCTURE OF THIS FILE INTACT.  New code should be placed
  7269  ** in the correct division and should be clearly labeled.
  7270  **
  7271  */
  7272  /*
  7273  ** standard include files.
  7274  */
  7275  #include <sys/types.h>
  7276  #include <sys/stat.h>
  7277  #include <sys/uio.h>
  7278  #include <sys/file.h>
  7279  #include <sys/mman.h>
  7280  #include <fcntl.h>
  7281  #include <unistd.h>
  7282  #include <time.h>
  7283  #include <sys/time.h>
  7284  #include <errno.h>
  7285  #if defined(__APPLE__) 
  7286  # include <sys/mount.h>
  7287  #endif
  7288  /*
  7289  ** Allowed values of unixFile.fsFlags
  7290  */
  7291  #define VEDIS_FSFLAGS_IS_MSDOS     0x1
  7292  
  7293  /*
  7294  ** Default permissions when creating a new file
  7295  */
  7296  #ifndef VEDIS_DEFAULT_FILE_PERMISSIONS
  7297  # define VEDIS_DEFAULT_FILE_PERMISSIONS 0644
  7298  #endif
  7299  /*
  7300   ** Default permissions when creating auto proxy dir
  7301   */
  7302  #ifndef VEDIS_DEFAULT_PROXYDIR_PERMISSIONS
  7303  # define VEDIS_DEFAULT_PROXYDIR_PERMISSIONS 0755
  7304  #endif
  7305  /*
  7306  ** Maximum supported path-length.
  7307  */
  7308  #define MAX_PATHNAME 512
  7309  /*
  7310  ** Only set the lastErrno if the error code is a real error and not 
  7311  ** a normal expected return code of VEDIS_BUSY or VEDIS_OK
  7312  */
  7313  #define IS_LOCK_ERROR(x)  ((x != VEDIS_OK) && (x != VEDIS_BUSY))
  7314  /* Forward references */
  7315  typedef struct unixInodeInfo unixInodeInfo;   /* An i-node */
  7316  typedef struct UnixUnusedFd UnixUnusedFd;     /* An unused file descriptor */
  7317  /*
  7318  ** Sometimes, after a file handle is closed by SQLite, the file descriptor
  7319  ** cannot be closed immediately. In these cases, instances of the following
  7320  ** structure are used to store the file descriptor while waiting for an
  7321  ** opportunity to either close or reuse it.
  7322  */
  7323  struct UnixUnusedFd {
  7324    int fd;                   /* File descriptor to close */
  7325    int flags;                /* Flags this file descriptor was opened with */
  7326    UnixUnusedFd *pNext;      /* Next unused file descriptor on same file */
  7327  };
  7328  /*
  7329  ** The unixFile structure is subclass of vedis3_file specific to the unix
  7330  ** VFS implementations.
  7331  */
  7332  typedef struct unixFile unixFile;
  7333  struct unixFile {
  7334    const vedis_io_methods *pMethod;  /* Always the first entry */
  7335    unixInodeInfo *pInode;              /* Info about locks on this inode */
  7336    int h;                              /* The file descriptor */
  7337    int dirfd;                          /* File descriptor for the directory */
  7338    unsigned char eFileLock;            /* The type of lock held on this fd */
  7339    int lastErrno;                      /* The unix errno from last I/O error */
  7340    void *lockingContext;               /* Locking style specific state */
  7341    UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
  7342    int fileFlags;                      /* Miscellanous flags */
  7343    const char *zPath;                  /* Name of the file */
  7344    unsigned fsFlags;                   /* cached details from statfs() */
  7345  };
  7346  /*
  7347  ** The following macros define bits in unixFile.fileFlags
  7348  */
  7349  #define VEDIS_WHOLE_FILE_LOCKING  0x0001   /* Use whole-file locking */
  7350  /*
  7351  ** Define various macros that are missing from some systems.
  7352  */
  7353  #ifndef O_LARGEFILE
  7354  # define O_LARGEFILE 0
  7355  #endif
  7356  #ifndef O_NOFOLLOW
  7357  # define O_NOFOLLOW 0
  7358  #endif
  7359  #ifndef O_BINARY
  7360  # define O_BINARY 0
  7361  #endif
  7362  /*
  7363  ** Helper functions to obtain and relinquish the global mutex. The
  7364  ** global mutex is used to protect the unixInodeInfo and
  7365  ** vxworksFileId objects used by this file, all of which may be 
  7366  ** shared by multiple threads.
  7367  **
  7368  ** Function unixMutexHeld() is used to assert() that the global mutex 
  7369  ** is held when required. This function is only used as part of assert() 
  7370  ** statements. e.g.
  7371  **
  7372  **   unixEnterMutex()
  7373  **     assert( unixMutexHeld() );
  7374  **   unixEnterLeave()
  7375  */
  7376  static void unixEnterMutex(void){
  7377  #ifdef VEDIS_ENABLE_THREADS
  7378  	const SyMutexMethods *pMutexMethods = SyMutexExportMethods();
  7379  	if( pMutexMethods ){
  7380  		SyMutex *pMutex = pMutexMethods->xNew(SXMUTEX_TYPE_STATIC_2); /* pre-allocated, never fail */
  7381  		SyMutexEnter(pMutexMethods,pMutex);
  7382  	}
  7383  #endif /* VEDIS_ENABLE_THREADS */
  7384  }
  7385  static void unixLeaveMutex(void){
  7386  #ifdef VEDIS_ENABLE_THREADS
  7387    const SyMutexMethods *pMutexMethods = SyMutexExportMethods();
  7388    if( pMutexMethods ){
  7389  	 SyMutex *pMutex = pMutexMethods->xNew(SXMUTEX_TYPE_STATIC_2); /* pre-allocated, never fail */
  7390  	 SyMutexLeave(pMutexMethods,pMutex);
  7391    }
  7392  #endif /* VEDIS_ENABLE_THREADS */
  7393  }
  7394  /*
  7395  ** This routine translates a standard POSIX errno code into something
  7396  ** useful to the clients of the vedis3 functions.  Specifically, it is
  7397  ** intended to translate a variety of "try again" errors into VEDIS_BUSY
  7398  ** and a variety of "please close the file descriptor NOW" errors into 
  7399  ** VEDIS_IOERR
  7400  ** 
  7401  ** Errors during initialization of locks, or file system support for locks,
  7402  ** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
  7403  */
  7404  static int vedisErrorFromPosixError(int posixError, int vedisIOErr) {
  7405    switch (posixError) {
  7406    case 0: 
  7407      return VEDIS_OK;
  7408      
  7409    case EAGAIN:
  7410    case ETIMEDOUT:
  7411    case EBUSY:
  7412    case EINTR:
  7413    case ENOLCK:  
  7414      /* random NFS retry error, unless during file system support 
  7415       * introspection, in which it actually means what it says */
  7416      return VEDIS_BUSY;
  7417   
  7418    case EACCES: 
  7419      /* EACCES is like EAGAIN during locking operations, but not any other time*/
  7420        return VEDIS_BUSY;
  7421      
  7422    case EPERM: 
  7423      return VEDIS_PERM;
  7424      
  7425    case EDEADLK:
  7426      return VEDIS_IOERR;
  7427      
  7428  #if EOPNOTSUPP!=ENOTSUP
  7429    case EOPNOTSUPP: 
  7430      /* something went terribly awry, unless during file system support 
  7431       * introspection, in which it actually means what it says */
  7432  #endif
  7433  #ifdef ENOTSUP
  7434    case ENOTSUP: 
  7435      /* invalid fd, unless during file system support introspection, in which 
  7436       * it actually means what it says */
  7437  #endif
  7438    case EIO:
  7439    case EBADF:
  7440    case EINVAL:
  7441    case ENOTCONN:
  7442    case ENODEV:
  7443    case ENXIO:
  7444    case ENOENT:
  7445    case ESTALE:
  7446    case ENOSYS:
  7447      /* these should force the client to close the file and reconnect */
  7448      
  7449    default: 
  7450      return vedisIOErr;
  7451    }
  7452  }
  7453  /******************************************************************************
  7454  *************************** Posix Advisory Locking ****************************
  7455  **
  7456  ** POSIX advisory locks are broken by design.  ANSI STD 1003.1 (1996)
  7457  ** section 6.5.2.2 lines 483 through 490 specify that when a process
  7458  ** sets or clears a lock, that operation overrides any prior locks set
  7459  ** by the same process.  It does not explicitly say so, but this implies
  7460  ** that it overrides locks set by the same process using a different
  7461  ** file descriptor.  Consider this test case:
  7462  **
  7463  **       int fd1 = open("./file1", O_RDWR|O_CREAT, 0644);
  7464  **       int fd2 = open("./file2", O_RDWR|O_CREAT, 0644);
  7465  **
  7466  ** Suppose ./file1 and ./file2 are really the same file (because
  7467  ** one is a hard or symbolic link to the other) then if you set
  7468  ** an exclusive lock on fd1, then try to get an exclusive lock
  7469  ** on fd2, it works.  I would have expected the second lock to
  7470  ** fail since there was already a lock on the file due to fd1.
  7471  ** But not so.  Since both locks came from the same process, the
  7472  ** second overrides the first, even though they were on different
  7473  ** file descriptors opened on different file names.
  7474  **
  7475  ** This means that we cannot use POSIX locks to synchronize file access
  7476  ** among competing threads of the same process.  POSIX locks will work fine
  7477  ** to synchronize access for threads in separate processes, but not
  7478  ** threads within the same process.
  7479  **
  7480  ** To work around the problem, SQLite has to manage file locks internally
  7481  ** on its own.  Whenever a new database is opened, we have to find the
  7482  ** specific inode of the database file (the inode is determined by the
  7483  ** st_dev and st_ino fields of the stat structure that fstat() fills in)
  7484  ** and check for locks already existing on that inode.  When locks are
  7485  ** created or removed, we have to look at our own internal record of the
  7486  ** locks to see if another thread has previously set a lock on that same
  7487  ** inode.
  7488  **
  7489  ** (Aside: The use of inode numbers as unique IDs does not work on VxWorks.
  7490  ** For VxWorks, we have to use the alternative unique ID system based on
  7491  ** canonical filename and implemented in the previous division.)
  7492  **
  7493  ** There is one locking structure
  7494  ** per inode, so if the same inode is opened twice, both unixFile structures
  7495  ** point to the same locking structure.  The locking structure keeps
  7496  ** a reference count (so we will know when to delete it) and a "cnt"
  7497  ** field that tells us its internal lock status.  cnt==0 means the
  7498  ** file is unlocked.  cnt==-1 means the file has an exclusive lock.
  7499  ** cnt>0 means there are cnt shared locks on the file.
  7500  **
  7501  ** Any attempt to lock or unlock a file first checks the locking
  7502  ** structure.  The fcntl() system call is only invoked to set a 
  7503  ** POSIX lock if the internal lock structure transitions between
  7504  ** a locked and an unlocked state.
  7505  **
  7506  ** But wait:  there are yet more problems with POSIX advisory locks.
  7507  **
  7508  ** If you close a file descriptor that points to a file that has locks,
  7509  ** all locks on that file that are owned by the current process are
  7510  ** released.  To work around this problem, each unixInodeInfo object
  7511  ** maintains a count of the number of pending locks on that inode.
  7512  ** When an attempt is made to close an unixFile, if there are
  7513  ** other unixFile open on the same inode that are holding locks, the call
  7514  ** to close() the file descriptor is deferred until all of the locks clear.
  7515  ** The unixInodeInfo structure keeps a list of file descriptors that need to
  7516  ** be closed and that list is walked (and cleared) when the last lock
  7517  ** clears.
  7518  **
  7519  ** Yet another problem:  LinuxThreads do not play well with posix locks.
  7520  **
  7521  ** Many older versions of linux use the LinuxThreads library which is
  7522  ** not posix compliant.  Under LinuxThreads, a lock created by thread
  7523  ** A cannot be modified or overridden by a different thread B.
  7524  ** Only thread A can modify the lock.  Locking behavior is correct
  7525  ** if the appliation uses the newer Native Posix Thread Library (NPTL)
  7526  ** on linux - with NPTL a lock created by thread A can override locks
  7527  ** in thread B.  But there is no way to know at compile-time which
  7528  ** threading library is being used.  So there is no way to know at
  7529  ** compile-time whether or not thread A can override locks on thread B.
  7530  ** One has to do a run-time check to discover the behavior of the
  7531  ** current process.
  7532  **
  7533  */
  7534  
  7535  /*
  7536  ** An instance of the following structure serves as the key used
  7537  ** to locate a particular unixInodeInfo object.
  7538  */
  7539  struct unixFileId {
  7540    dev_t dev;                  /* Device number */
  7541    ino_t ino;                  /* Inode number */
  7542  };
  7543  /*
  7544  ** An instance of the following structure is allocated for each open
  7545  ** inode.  Or, on LinuxThreads, there is one of these structures for
  7546  ** each inode opened by each thread.
  7547  **
  7548  ** A single inode can have multiple file descriptors, so each unixFile
  7549  ** structure contains a pointer to an instance of this object and this
  7550  ** object keeps a count of the number of unixFile pointing to it.
  7551  */
  7552  struct unixInodeInfo {
  7553    struct unixFileId fileId;       /* The lookup key */
  7554    int nShared;                    /* Number of SHARED locks held */
  7555    int eFileLock;                  /* One of SHARED_LOCK, RESERVED_LOCK etc. */
  7556    int nRef;                       /* Number of pointers to this structure */
  7557    int nLock;                      /* Number of outstanding file locks */
  7558    UnixUnusedFd *pUnused;          /* Unused file descriptors to close */
  7559    unixInodeInfo *pNext;           /* List of all unixInodeInfo objects */
  7560    unixInodeInfo *pPrev;           /*    .... doubly linked */
  7561  };
  7562  
  7563  static unixInodeInfo *inodeList = 0;
  7564  /*
  7565   * Local memory allocation stuff.
  7566   */
  7567  static void * vedis_malloc(sxu32 nByte)
  7568  {
  7569  	SyMemBackend *pAlloc;
  7570  	void *p;
  7571  	pAlloc = (SyMemBackend *)vedisExportMemBackend();
  7572  	p = SyMemBackendAlloc(pAlloc,nByte);
  7573  	return p;
  7574  }
  7575  static void vedis_free(void *p)
  7576  {
  7577  	SyMemBackend *pAlloc;
  7578  	pAlloc = (SyMemBackend *)vedisExportMemBackend();
  7579  	SyMemBackendFree(pAlloc,p);
  7580  }
  7581  /*
  7582  ** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
  7583  ** If all such file descriptors are closed without error, the list is
  7584  ** cleared and VEDIS_OK returned.
  7585  **
  7586  ** Otherwise, if an error occurs, then successfully closed file descriptor
  7587  ** entries are removed from the list, and VEDIS_IOERR_CLOSE returned. 
  7588  ** not deleted and VEDIS_IOERR_CLOSE returned.
  7589  */ 
  7590  static int closePendingFds(unixFile *pFile){
  7591    int rc = VEDIS_OK;
  7592    unixInodeInfo *pInode = pFile->pInode;
  7593    UnixUnusedFd *pError = 0;
  7594    UnixUnusedFd *p;
  7595    UnixUnusedFd *pNext;
  7596    for(p=pInode->pUnused; p; p=pNext){
  7597      pNext = p->pNext;
  7598      if( close(p->fd) ){
  7599        pFile->lastErrno = errno;
  7600  	  rc = VEDIS_IOERR;
  7601        p->pNext = pError;
  7602        pError = p;
  7603      }else{
  7604        vedis_free(p);
  7605      }
  7606    }
  7607    pInode->pUnused = pError;
  7608    return rc;
  7609  }
  7610  /*
  7611  ** Release a unixInodeInfo structure previously allocated by findInodeInfo().
  7612  **
  7613  ** The mutex entered using the unixEnterMutex() function must be held
  7614  ** when this function is called.
  7615  */
  7616  static void releaseInodeInfo(unixFile *pFile){
  7617    unixInodeInfo *pInode = pFile->pInode;
  7618    if( pInode ){
  7619      pInode->nRef--;
  7620      if( pInode->nRef==0 ){
  7621        closePendingFds(pFile);
  7622        if( pInode->pPrev ){
  7623          pInode->pPrev->pNext = pInode->pNext;
  7624        }else{
  7625          inodeList = pInode->pNext;
  7626        }
  7627        if( pInode->pNext ){
  7628          pInode->pNext->pPrev = pInode->pPrev;
  7629        }
  7630        vedis_free(pInode);
  7631      }
  7632    }
  7633  }
  7634  /*
  7635  ** Given a file descriptor, locate the unixInodeInfo object that
  7636  ** describes that file descriptor.  Create a new one if necessary.  The
  7637  ** return value might be uninitialized if an error occurs.
  7638  **
  7639  ** The mutex entered using the unixEnterMutex() function must be held
  7640  ** when this function is called.
  7641  **
  7642  ** Return an appropriate error code.
  7643  */
  7644  static int findInodeInfo(
  7645    unixFile *pFile,               /* Unix file with file desc used in the key */
  7646    unixInodeInfo **ppInode        /* Return the unixInodeInfo object here */
  7647  ){
  7648    int rc;                        /* System call return code */
  7649    int fd;                        /* The file descriptor for pFile */
  7650    struct unixFileId fileId;      /* Lookup key for the unixInodeInfo */
  7651    struct stat statbuf;           /* Low-level file information */
  7652    unixInodeInfo *pInode = 0;     /* Candidate unixInodeInfo object */
  7653  
  7654    /* Get low-level information about the file that we can used to
  7655    ** create a unique name for the file.
  7656    */
  7657    fd = pFile->h;
  7658    rc = fstat(fd, &statbuf);
  7659    if( rc!=0 ){
  7660      pFile->lastErrno = errno;
  7661  #ifdef EOVERFLOW
  7662  	if( pFile->lastErrno==EOVERFLOW ) return VEDIS_NOTIMPLEMENTED;
  7663  #endif
  7664      return VEDIS_IOERR;
  7665    }
  7666  
  7667  #ifdef __APPLE__
  7668    /* On OS X on an msdos filesystem, the inode number is reported
  7669    ** incorrectly for zero-size files.  See ticket #3260.  To work
  7670    ** around this problem (we consider it a bug in OS X, not SQLite)
  7671    ** we always increase the file size to 1 by writing a single byte
  7672    ** prior to accessing the inode number.  The one byte written is
  7673    ** an ASCII 'S' character which also happens to be the first byte
  7674    ** in the header of every SQLite database.  In this way, if there
  7675    ** is a race condition such that another thread has already populated
  7676    ** the first page of the database, no damage is done.
  7677    */
  7678    if( statbuf.st_size==0 && (pFile->fsFlags & VEDIS_FSFLAGS_IS_MSDOS)!=0 ){
  7679      rc = write(fd, "S", 1);
  7680      if( rc!=1 ){
  7681        pFile->lastErrno = errno;
  7682        return VEDIS_IOERR;
  7683      }
  7684      rc = fstat(fd, &statbuf);
  7685      if( rc!=0 ){
  7686        pFile->lastErrno = errno;
  7687        return VEDIS_IOERR;
  7688      }
  7689    }
  7690  #endif
  7691    SyZero(&fileId,sizeof(fileId));
  7692    fileId.dev = statbuf.st_dev;
  7693    fileId.ino = statbuf.st_ino;
  7694    pInode = inodeList;
  7695    while( pInode && SyMemcmp((const void *)&fileId,(const void *)&pInode->fileId, sizeof(fileId)) ){
  7696      pInode = pInode->pNext;
  7697    }
  7698    if( pInode==0 ){
  7699      pInode = (unixInodeInfo *)vedis_malloc( sizeof(*pInode) );
  7700      if( pInode==0 ){
  7701        return VEDIS_NOMEM;
  7702      }
  7703      SyZero(pInode,sizeof(*pInode));
  7704  	SyMemcpy((const void *)&fileId,(void *)&pInode->fileId,sizeof(fileId));
  7705      pInode->nRef = 1;
  7706      pInode->pNext = inodeList;
  7707      pInode->pPrev = 0;
  7708      if( inodeList ) inodeList->pPrev = pInode;
  7709      inodeList = pInode;
  7710    }else{
  7711      pInode->nRef++;
  7712    }
  7713    *ppInode = pInode;
  7714    return VEDIS_OK;
  7715  }
  7716  /*
  7717  ** This routine checks if there is a RESERVED lock held on the specified
  7718  ** file by this or any other process. If such a lock is held, set *pResOut
  7719  ** to a non-zero value otherwise *pResOut is set to zero.  The return value
  7720  ** is set to VEDIS_OK unless an I/O error occurs during lock checking.
  7721  */
  7722  static int unixCheckReservedLock(vedis_file *id, int *pResOut){
  7723    int rc = VEDIS_OK;
  7724    int reserved = 0;
  7725    unixFile *pFile = (unixFile*)id;
  7726  
  7727   
  7728    unixEnterMutex(); /* Because pFile->pInode is shared across threads */
  7729  
  7730    /* Check if a thread in this process holds such a lock */
  7731    if( pFile->pInode->eFileLock>SHARED_LOCK ){
  7732      reserved = 1;
  7733    }
  7734  
  7735    /* Otherwise see if some other process holds it.
  7736    */
  7737    if( !reserved ){
  7738      struct flock lock;
  7739      lock.l_whence = SEEK_SET;
  7740      lock.l_start = RESERVED_BYTE;
  7741      lock.l_len = 1;
  7742      lock.l_type = F_WRLCK;
  7743      if (-1 == fcntl(pFile->h, F_GETLK, &lock)) {
  7744        int tErrno = errno;
  7745  	  rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  7746        pFile->lastErrno = tErrno;
  7747      } else if( lock.l_type!=F_UNLCK ){
  7748        reserved = 1;
  7749      }
  7750    }
  7751    
  7752    unixLeaveMutex();
  7753   
  7754    *pResOut = reserved;
  7755    return rc;
  7756  }
  7757  /*
  7758  ** Lock the file with the lock specified by parameter eFileLock - one
  7759  ** of the following:
  7760  **
  7761  **     (1) SHARED_LOCK
  7762  **     (2) RESERVED_LOCK
  7763  **     (3) PENDING_LOCK
  7764  **     (4) EXCLUSIVE_LOCK
  7765  **
  7766  ** Sometimes when requesting one lock state, additional lock states
  7767  ** are inserted in between.  The locking might fail on one of the later
  7768  ** transitions leaving the lock state different from what it started but
  7769  ** still short of its goal.  The following chart shows the allowed
  7770  ** transitions and the inserted intermediate states:
  7771  **
  7772  **    UNLOCKED -> SHARED
  7773  **    SHARED -> RESERVED
  7774  **    SHARED -> (PENDING) -> EXCLUSIVE
  7775  **    RESERVED -> (PENDING) -> EXCLUSIVE
  7776  **    PENDING -> EXCLUSIVE
  7777  **
  7778  ** This routine will only increase a lock.  Use the vedisOsUnlock()
  7779  ** routine to lower a locking level.
  7780  */
  7781  static int unixLock(vedis_file *id, int eFileLock){
  7782    /* The following describes the implementation of the various locks and
  7783    ** lock transitions in terms of the POSIX advisory shared and exclusive
  7784    ** lock primitives (called read-locks and write-locks below, to avoid
  7785    ** confusion with SQLite lock names). The algorithms are complicated
  7786    ** slightly in order to be compatible with unixdows systems simultaneously
  7787    ** accessing the same database file, in case that is ever required.
  7788    **
  7789    ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
  7790    ** byte', each single bytes at well known offsets, and the 'shared byte
  7791    ** range', a range of 510 bytes at a well known offset.
  7792    **
  7793    ** To obtain a SHARED lock, a read-lock is obtained on the 'pending
  7794    ** byte'.  If this is successful, a random byte from the 'shared byte
  7795    ** range' is read-locked and the lock on the 'pending byte' released.
  7796    **
  7797    ** A process may only obtain a RESERVED lock after it has a SHARED lock.
  7798    ** A RESERVED lock is implemented by grabbing a write-lock on the
  7799    ** 'reserved byte'. 
  7800    **
  7801    ** A process may only obtain a PENDING lock after it has obtained a
  7802    ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
  7803    ** on the 'pending byte'. This ensures that no new SHARED locks can be
  7804    ** obtained, but existing SHARED locks are allowed to persist. A process
  7805    ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
  7806    ** This property is used by the algorithm for rolling back a journal file
  7807    ** after a crash.
  7808    **
  7809    ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
  7810    ** implemented by obtaining a write-lock on the entire 'shared byte
  7811    ** range'. Since all other locks require a read-lock on one of the bytes
  7812    ** within this range, this ensures that no other locks are held on the
  7813    ** database. 
  7814    **
  7815    ** The reason a single byte cannot be used instead of the 'shared byte
  7816    ** range' is that some versions of unixdows do not support read-locks. By
  7817    ** locking a random byte from a range, concurrent SHARED locks may exist
  7818    ** even if the locking primitive used is always a write-lock.
  7819    */
  7820    int rc = VEDIS_OK;
  7821    unixFile *pFile = (unixFile*)id;
  7822    unixInodeInfo *pInode = pFile->pInode;
  7823    struct flock lock;
  7824    int s = 0;
  7825    int tErrno = 0;
  7826  
  7827    /* If there is already a lock of this type or more restrictive on the
  7828    ** unixFile, do nothing. Don't use the end_lock: exit path, as
  7829    ** unixEnterMutex() hasn't been called yet.
  7830    */
  7831    if( pFile->eFileLock>=eFileLock ){
  7832      return VEDIS_OK;
  7833    }
  7834    /* This mutex is needed because pFile->pInode is shared across threads
  7835    */
  7836    unixEnterMutex();
  7837    pInode = pFile->pInode;
  7838  
  7839    /* If some thread using this PID has a lock via a different unixFile*
  7840    ** handle that precludes the requested lock, return BUSY.
  7841    */
  7842    if( (pFile->eFileLock!=pInode->eFileLock && 
  7843            (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
  7844    ){
  7845      rc = VEDIS_BUSY;
  7846      goto end_lock;
  7847    }
  7848  
  7849    /* If a SHARED lock is requested, and some thread using this PID already
  7850    ** has a SHARED or RESERVED lock, then increment reference counts and
  7851    ** return VEDIS_OK.
  7852    */
  7853    if( eFileLock==SHARED_LOCK && 
  7854        (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
  7855      pFile->eFileLock = SHARED_LOCK;
  7856      pInode->nShared++;
  7857      pInode->nLock++;
  7858      goto end_lock;
  7859    }
  7860    /* A PENDING lock is needed before acquiring a SHARED lock and before
  7861    ** acquiring an EXCLUSIVE lock.  For the SHARED lock, the PENDING will
  7862    ** be released.
  7863    */
  7864    lock.l_len = 1L;
  7865    lock.l_whence = SEEK_SET;
  7866    if( eFileLock==SHARED_LOCK 
  7867        || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
  7868    ){
  7869      lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
  7870      lock.l_start = PENDING_BYTE;
  7871      s = fcntl(pFile->h, F_SETLK, &lock);
  7872      if( s==(-1) ){
  7873        tErrno = errno;
  7874        rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  7875        if( IS_LOCK_ERROR(rc) ){
  7876          pFile->lastErrno = tErrno;
  7877        }
  7878        goto end_lock;
  7879      }
  7880    }
  7881    /* If control gets to this point, then actually go ahead and make
  7882    ** operating system calls for the specified lock.
  7883    */
  7884    if( eFileLock==SHARED_LOCK ){
  7885      /* Now get the read-lock */
  7886      lock.l_start = SHARED_FIRST;
  7887      lock.l_len = SHARED_SIZE;
  7888      if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){
  7889        tErrno = errno;
  7890      }
  7891      /* Drop the temporary PENDING lock */
  7892      lock.l_start = PENDING_BYTE;
  7893      lock.l_len = 1L;
  7894      lock.l_type = F_UNLCK;
  7895      if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
  7896        if( s != -1 ){
  7897          /* This could happen with a network mount */
  7898          tErrno = errno; 
  7899          rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR); 
  7900          if( IS_LOCK_ERROR(rc) ){
  7901            pFile->lastErrno = tErrno;
  7902          }
  7903          goto end_lock;
  7904        }
  7905      }
  7906      if( s==(-1) ){
  7907  		rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  7908        if( IS_LOCK_ERROR(rc) ){
  7909          pFile->lastErrno = tErrno;
  7910        }
  7911      }else{
  7912        pFile->eFileLock = SHARED_LOCK;
  7913        pInode->nLock++;
  7914        pInode->nShared = 1;
  7915      }
  7916    }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
  7917      /* We are trying for an exclusive lock but another thread in this
  7918      ** same process is still holding a shared lock. */
  7919      rc = VEDIS_BUSY;
  7920    }else{
  7921      /* The request was for a RESERVED or EXCLUSIVE lock.  It is
  7922      ** assumed that there is a SHARED or greater lock on the file
  7923      ** already.
  7924      */
  7925      lock.l_type = F_WRLCK;
  7926      switch( eFileLock ){
  7927        case RESERVED_LOCK:
  7928          lock.l_start = RESERVED_BYTE;
  7929          break;
  7930        case EXCLUSIVE_LOCK:
  7931          lock.l_start = SHARED_FIRST;
  7932          lock.l_len = SHARED_SIZE;
  7933          break;
  7934        default:
  7935  		  /* Can't happen */
  7936          break;
  7937      }
  7938      s = fcntl(pFile->h, F_SETLK, &lock);
  7939      if( s==(-1) ){
  7940        tErrno = errno;
  7941        rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  7942        if( IS_LOCK_ERROR(rc) ){
  7943          pFile->lastErrno = tErrno;
  7944        }
  7945      }
  7946    }
  7947    if( rc==VEDIS_OK ){
  7948      pFile->eFileLock = eFileLock;
  7949      pInode->eFileLock = eFileLock;
  7950    }else if( eFileLock==EXCLUSIVE_LOCK ){
  7951      pFile->eFileLock = PENDING_LOCK;
  7952      pInode->eFileLock = PENDING_LOCK;
  7953    }
  7954  end_lock:
  7955    unixLeaveMutex();
  7956    return rc;
  7957  }
  7958  /*
  7959  ** Add the file descriptor used by file handle pFile to the corresponding
  7960  ** pUnused list.
  7961  */
  7962  static void setPendingFd(unixFile *pFile){
  7963    unixInodeInfo *pInode = pFile->pInode;
  7964    UnixUnusedFd *p = pFile->pUnused;
  7965    p->pNext = pInode->pUnused;
  7966    pInode->pUnused = p;
  7967    pFile->h = -1;
  7968    pFile->pUnused = 0;
  7969  }
  7970  /*
  7971  ** Lower the locking level on file descriptor pFile to eFileLock.  eFileLock
  7972  ** must be either NO_LOCK or SHARED_LOCK.
  7973  **
  7974  ** If the locking level of the file descriptor is already at or below
  7975  ** the requested locking level, this routine is a no-op.
  7976  ** 
  7977  ** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
  7978  ** the byte range is divided into 2 parts and the first part is unlocked then
  7979  ** set to a read lock, then the other part is simply unlocked.  This works 
  7980  ** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to 
  7981  ** remove the write lock on a region when a read lock is set.
  7982  */
  7983  static int _posixUnlock(vedis_file *id, int eFileLock, int handleNFSUnlock){
  7984    unixFile *pFile = (unixFile*)id;
  7985    unixInodeInfo *pInode;
  7986    struct flock lock;
  7987    int rc = VEDIS_OK;
  7988    int h;
  7989    int tErrno;                      /* Error code from system call errors */
  7990  
  7991     if( pFile->eFileLock<=eFileLock ){
  7992      return VEDIS_OK;
  7993    }
  7994    unixEnterMutex();
  7995    
  7996    h = pFile->h;
  7997    pInode = pFile->pInode;
  7998    
  7999    if( pFile->eFileLock>SHARED_LOCK ){
  8000      /* downgrading to a shared lock on NFS involves clearing the write lock
  8001      ** before establishing the readlock - to avoid a race condition we downgrade
  8002      ** the lock in 2 blocks, so that part of the range will be covered by a 
  8003      ** write lock until the rest is covered by a read lock:
  8004      **  1:   [WWWWW]
  8005      **  2:   [....W]
  8006      **  3:   [RRRRW]
  8007      **  4:   [RRRR.]
  8008      */
  8009      if( eFileLock==SHARED_LOCK ){
  8010        if( handleNFSUnlock ){
  8011          off_t divSize = SHARED_SIZE - 1;
  8012          
  8013          lock.l_type = F_UNLCK;
  8014          lock.l_whence = SEEK_SET;
  8015          lock.l_start = SHARED_FIRST;
  8016          lock.l_len = divSize;
  8017          if( fcntl(h, F_SETLK, &lock)==(-1) ){
  8018            tErrno = errno;
  8019  		  rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  8020            if( IS_LOCK_ERROR(rc) ){
  8021              pFile->lastErrno = tErrno;
  8022            }
  8023            goto end_unlock;
  8024          }
  8025          lock.l_type = F_RDLCK;
  8026          lock.l_whence = SEEK_SET;
  8027          lock.l_start = SHARED_FIRST;
  8028          lock.l_len = divSize;
  8029          if( fcntl(h, F_SETLK, &lock)==(-1) ){
  8030            tErrno = errno;
  8031  		  rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  8032            if( IS_LOCK_ERROR(rc) ){
  8033              pFile->lastErrno = tErrno;
  8034            }
  8035            goto end_unlock;
  8036          }
  8037          lock.l_type = F_UNLCK;
  8038          lock.l_whence = SEEK_SET;
  8039          lock.l_start = SHARED_FIRST+divSize;
  8040          lock.l_len = SHARED_SIZE-divSize;
  8041          if( fcntl(h, F_SETLK, &lock)==(-1) ){
  8042            tErrno = errno;
  8043  		  rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  8044            if( IS_LOCK_ERROR(rc) ){
  8045              pFile->lastErrno = tErrno;
  8046            }
  8047            goto end_unlock;
  8048          }
  8049        }else{
  8050          lock.l_type = F_RDLCK;
  8051          lock.l_whence = SEEK_SET;
  8052          lock.l_start = SHARED_FIRST;
  8053          lock.l_len = SHARED_SIZE;
  8054          if( fcntl(h, F_SETLK, &lock)==(-1) ){
  8055            tErrno = errno;
  8056  		  rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  8057            if( IS_LOCK_ERROR(rc) ){
  8058              pFile->lastErrno = tErrno;
  8059            }
  8060            goto end_unlock;
  8061          }
  8062        }
  8063      }
  8064      lock.l_type = F_UNLCK;
  8065      lock.l_whence = SEEK_SET;
  8066      lock.l_start = PENDING_BYTE;
  8067      lock.l_len = 2L;
  8068      if( fcntl(h, F_SETLK, &lock)!=(-1) ){
  8069        pInode->eFileLock = SHARED_LOCK;
  8070      }else{
  8071        tErrno = errno;
  8072  	  rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  8073        if( IS_LOCK_ERROR(rc) ){
  8074          pFile->lastErrno = tErrno;
  8075        }
  8076        goto end_unlock;
  8077      }
  8078    }
  8079    if( eFileLock==NO_LOCK ){
  8080      /* Decrement the shared lock counter.  Release the lock using an
  8081      ** OS call only when all threads in this same process have released
  8082      ** the lock.
  8083      */
  8084      pInode->nShared--;
  8085      if( pInode->nShared==0 ){
  8086        lock.l_type = F_UNLCK;
  8087        lock.l_whence = SEEK_SET;
  8088        lock.l_start = lock.l_len = 0L;
  8089        
  8090        if( fcntl(h, F_SETLK, &lock)!=(-1) ){
  8091          pInode->eFileLock = NO_LOCK;
  8092        }else{
  8093          tErrno = errno;
  8094  		rc = vedisErrorFromPosixError(tErrno, VEDIS_LOCKERR);
  8095          if( IS_LOCK_ERROR(rc) ){
  8096            pFile->lastErrno = tErrno;
  8097          }
  8098          pInode->eFileLock = NO_LOCK;
  8099          pFile->eFileLock = NO_LOCK;
  8100        }
  8101      }
  8102  
  8103      /* Decrement the count of locks against this same file.  When the
  8104      ** count reaches zero, close any other file descriptors whose close
  8105      ** was deferred because of outstanding locks.
  8106      */
  8107      pInode->nLock--;
  8108   
  8109      if( pInode->nLock==0 ){
  8110        int rc2 = closePendingFds(pFile);
  8111        if( rc==VEDIS_OK ){
  8112          rc = rc2;
  8113        }
  8114      }
  8115    }
  8116  	
  8117  end_unlock:
  8118  
  8119    unixLeaveMutex();
  8120    
  8121    if( rc==VEDIS_OK ) pFile->eFileLock = eFileLock;
  8122    return rc;
  8123  }
  8124  /*
  8125  ** Lower the locking level on file descriptor pFile to eFileLock.  eFileLock
  8126  ** must be either NO_LOCK or SHARED_LOCK.
  8127  **
  8128  ** If the locking level of the file descriptor is already at or below
  8129  ** the requested locking level, this routine is a no-op.
  8130  */
  8131  static int unixUnlock(vedis_file *id, int eFileLock){
  8132    return _posixUnlock(id, eFileLock, 0);
  8133  }
  8134  /*
  8135  ** This function performs the parts of the "close file" operation 
  8136  ** common to all locking schemes. It closes the directory and file
  8137  ** handles, if they are valid, and sets all fields of the unixFile
  8138  ** structure to 0.
  8139  **
  8140  */
  8141  static int closeUnixFile(vedis_file *id){
  8142    unixFile *pFile = (unixFile*)id;
  8143    if( pFile ){
  8144      if( pFile->dirfd>=0 ){
  8145        int err = close(pFile->dirfd);
  8146        if( err ){
  8147          pFile->lastErrno = errno;
  8148          return VEDIS_IOERR;
  8149        }else{
  8150          pFile->dirfd=-1;
  8151        }
  8152      }
  8153      if( pFile->h>=0 ){
  8154        int err = close(pFile->h);
  8155        if( err ){
  8156          pFile->lastErrno = errno;
  8157          return VEDIS_IOERR;
  8158        }
  8159      }
  8160      vedis_free(pFile->pUnused);
  8161      SyZero(pFile,sizeof(unixFile));
  8162    }
  8163    return VEDIS_OK;
  8164  }
  8165  /*
  8166  ** Close a file.
  8167  */
  8168  static int unixClose(vedis_file *id){
  8169    int rc = VEDIS_OK;
  8170    if( id ){
  8171      unixFile *pFile = (unixFile *)id;
  8172      unixUnlock(id, NO_LOCK);
  8173      unixEnterMutex();
  8174      if( pFile->pInode && pFile->pInode->nLock ){
  8175        /* If there are outstanding locks, do not actually close the file just
  8176        ** yet because that would clear those locks.  Instead, add the file
  8177        ** descriptor to pInode->pUnused list.  It will be automatically closed 
  8178        ** when the last lock is cleared.
  8179        */
  8180        setPendingFd(pFile);
  8181      }
  8182      releaseInodeInfo(pFile);
  8183      rc = closeUnixFile(id);
  8184      unixLeaveMutex();
  8185    }
  8186    return rc;
  8187  }
  8188  /************** End of the posix advisory lock implementation *****************
  8189  ******************************************************************************/
  8190  /*
  8191  **
  8192  ** The next division contains implementations for all methods of the 
  8193  ** vedis_file object other than the locking methods.  The locking
  8194  ** methods were defined in divisions above (one locking method per
  8195  ** division).  Those methods that are common to all locking modes
  8196  ** are gather together into this division.
  8197  */
  8198  /*
  8199  ** Seek to the offset passed as the second argument, then read cnt 
  8200  ** bytes into pBuf. Return the number of bytes actually read.
  8201  **
  8202  ** NB:  If you define USE_PREAD or USE_PREAD64, then it might also
  8203  ** be necessary to define _XOPEN_SOURCE to be 500.  This varies from
  8204  ** one system to another.  Since SQLite does not define USE_PREAD
  8205  ** any form by default, we will not attempt to define _XOPEN_SOURCE.
  8206  ** See tickets #2741 and #2681.
  8207  **
  8208  ** To avoid stomping the errno value on a failed read the lastErrno value
  8209  ** is set before returning.
  8210  */
  8211  static int seekAndRead(unixFile *id, vedis_int64 offset, void *pBuf, int cnt){
  8212    int got;
  8213  #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
  8214    vedis_int64 newOffset;
  8215  #endif
  8216   
  8217  #if defined(USE_PREAD)
  8218    got = pread(id->h, pBuf, cnt, offset);
  8219  #elif defined(USE_PREAD64)
  8220    got = pread64(id->h, pBuf, cnt, offset);
  8221  #else
  8222    newOffset = lseek(id->h, offset, SEEK_SET);
  8223    
  8224    if( newOffset!=offset ){
  8225      if( newOffset == -1 ){
  8226        ((unixFile*)id)->lastErrno = errno;
  8227      }else{
  8228        ((unixFile*)id)->lastErrno = 0;			
  8229      }
  8230      return -1;
  8231    }
  8232    got = read(id->h, pBuf, cnt);
  8233  #endif
  8234    if( got<0 ){
  8235      ((unixFile*)id)->lastErrno = errno;
  8236    }
  8237    return got;
  8238  }
  8239  /*
  8240  ** Read data from a file into a buffer.  Return VEDIS_OK if all
  8241  ** bytes were read successfully and VEDIS_IOERR if anything goes
  8242  ** wrong.
  8243  */
  8244  static int unixRead(
  8245    vedis_file *id, 
  8246    void *pBuf, 
  8247    vedis_int64 amt,
  8248    vedis_int64 offset
  8249  ){
  8250    unixFile *pFile = (unixFile *)id;
  8251    int got;
  8252    
  8253    got = seekAndRead(pFile, offset, pBuf, (int)amt);
  8254    if( got==(int)amt ){
  8255      return VEDIS_OK;
  8256    }else if( got<0 ){
  8257      /* lastErrno set by seekAndRead */
  8258      return VEDIS_IOERR;
  8259    }else{
  8260      pFile->lastErrno = 0; /* not a system error */
  8261      /* Unread parts of the buffer must be zero-filled */
  8262      SyZero(&((char*)pBuf)[got],(sxu32)amt-got);
  8263      return VEDIS_IOERR;
  8264    }
  8265  }
  8266  /*
  8267  ** Seek to the offset in id->offset then read cnt bytes into pBuf.
  8268  ** Return the number of bytes actually read.  Update the offset.
  8269  **
  8270  ** To avoid stomping the errno value on a failed write the lastErrno value
  8271  ** is set before returning.
  8272  */
  8273  static int seekAndWrite(unixFile *id, vedis_int64 offset, const void *pBuf, vedis_int64 cnt){
  8274    int got;
  8275  #if (!defined(USE_PREAD) && !defined(USE_PREAD64))
  8276    vedis_int64 newOffset;
  8277  #endif
  8278    
  8279  #if defined(USE_PREAD)
  8280    got = pwrite(id->h, pBuf, cnt, offset);
  8281  #elif defined(USE_PREAD64)
  8282    got = pwrite64(id->h, pBuf, cnt, offset);
  8283  #else
  8284    newOffset = lseek(id->h, offset, SEEK_SET);
  8285    if( newOffset!=offset ){
  8286      if( newOffset == -1 ){
  8287        ((unixFile*)id)->lastErrno = errno;
  8288      }else{
  8289        ((unixFile*)id)->lastErrno = 0;			
  8290      }
  8291      return -1;
  8292    }
  8293    got = write(id->h, pBuf, cnt);
  8294  #endif
  8295    if( got<0 ){
  8296      ((unixFile*)id)->lastErrno = errno;
  8297    }
  8298    return got;
  8299  }
  8300  /*
  8301  ** Write data from a buffer into a file.  Return VEDIS_OK on success
  8302  ** or some other error code on failure.
  8303  */
  8304  static int unixWrite(
  8305    vedis_file *id, 
  8306    const void *pBuf, 
  8307    vedis_int64 amt,
  8308    vedis_int64 offset 
  8309  ){
  8310    unixFile *pFile = (unixFile*)id;
  8311    int wrote = 0;
  8312  
  8313    while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
  8314      amt -= wrote;
  8315      offset += wrote;
  8316      pBuf = &((char*)pBuf)[wrote];
  8317    }
  8318    
  8319    if( amt>0 ){
  8320      if( wrote<0 ){
  8321        /* lastErrno set by seekAndWrite */
  8322        return VEDIS_IOERR;
  8323      }else{
  8324        pFile->lastErrno = 0; /* not a system error */
  8325        return VEDIS_FULL;
  8326      }
  8327    }
  8328    return VEDIS_OK;
  8329  }
  8330  /*
  8331  ** We do not trust systems to provide a working fdatasync().  Some do.
  8332  ** Others do no.  To be safe, we will stick with the (slower) fsync().
  8333  ** If you know that your system does support fdatasync() correctly,
  8334  ** then simply compile with -Dfdatasync=fdatasync
  8335  */
  8336  #if !defined(fdatasync) && !defined(__linux__)
  8337  # define fdatasync fsync
  8338  #endif
  8339  
  8340  /*
  8341  ** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
  8342  ** the F_FULLFSYNC macro is defined.  F_FULLFSYNC is currently
  8343  ** only available on Mac OS X.  But that could change.
  8344  */
  8345  #ifdef F_FULLFSYNC
  8346  # define HAVE_FULLFSYNC 1
  8347  #else
  8348  # define HAVE_FULLFSYNC 0
  8349  #endif
  8350  /*
  8351  ** The fsync() system call does not work as advertised on many
  8352  ** unix systems.  The following procedure is an attempt to make
  8353  ** it work better.
  8354  **
  8355  **
  8356  ** SQLite sets the dataOnly flag if the size of the file is unchanged.
  8357  ** The idea behind dataOnly is that it should only write the file content
  8358  ** to disk, not the inode.  We only set dataOnly if the file size is 
  8359  ** unchanged since the file size is part of the inode.  However, 
  8360  ** Ted Ts'o tells us that fdatasync() will also write the inode if the
  8361  ** file size has changed.  The only real difference between fdatasync()
  8362  ** and fsync(), Ted tells us, is that fdatasync() will not flush the
  8363  ** inode if the mtime or owner or other inode attributes have changed.
  8364  ** We only care about the file size, not the other file attributes, so
  8365  ** as far as SQLite is concerned, an fdatasync() is always adequate.
  8366  ** So, we always use fdatasync() if it is available, regardless of
  8367  ** the value of the dataOnly flag.
  8368  */
  8369  static int full_fsync(int fd, int fullSync, int dataOnly){
  8370    int rc;
  8371  #if HAVE_FULLFSYNC
  8372    SXUNUSED(dataOnly);
  8373  #else
  8374    SXUNUSED(fullSync);
  8375    SXUNUSED(dataOnly);
  8376  #endif
  8377  
  8378    /* If we compiled with the VEDIS_NO_SYNC flag, then syncing is a
  8379    ** no-op
  8380    */
  8381  #if HAVE_FULLFSYNC
  8382    if( fullSync ){
  8383      rc = fcntl(fd, F_FULLFSYNC, 0);
  8384    }else{
  8385      rc = 1;
  8386    }
  8387    /* If the FULLFSYNC failed, fall back to attempting an fsync().
  8388    ** It shouldn't be possible for fullfsync to fail on the local 
  8389    ** file system (on OSX), so failure indicates that FULLFSYNC
  8390    ** isn't supported for this file system. So, attempt an fsync 
  8391    ** and (for now) ignore the overhead of a superfluous fcntl call.  
  8392    ** It'd be better to detect fullfsync support once and avoid 
  8393    ** the fcntl call every time sync is called.
  8394    */
  8395    if( rc ) rc = fsync(fd);
  8396  
  8397  #elif defined(__APPLE__)
  8398    /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly
  8399    ** so currently we default to the macro that redefines fdatasync to fsync
  8400    */
  8401    rc = fsync(fd);
  8402  #else 
  8403    rc = fdatasync(fd);
  8404  #endif /* ifdef VEDIS_NO_SYNC elif HAVE_FULLFSYNC */
  8405    if( rc!= -1 ){
  8406      rc = 0;
  8407    }
  8408    return rc;
  8409  }
  8410  /*
  8411  ** Make sure all writes to a particular file are committed to disk.
  8412  **
  8413  ** If dataOnly==0 then both the file itself and its metadata (file
  8414  ** size, access time, etc) are synced.  If dataOnly!=0 then only the
  8415  ** file data is synced.
  8416  **
  8417  ** Under Unix, also make sure that the directory entry for the file
  8418  ** has been created by fsync-ing the directory that contains the file.
  8419  ** If we do not do this and we encounter a power failure, the directory
  8420  ** entry for the journal might not exist after we reboot.  The next
  8421  ** SQLite to access the file will not know that the journal exists (because
  8422  ** the directory entry for the journal was never created) and the transaction
  8423  ** will not roll back - possibly leading to database corruption.
  8424  */
  8425  static int unixSync(vedis_file *id, int flags){
  8426    int rc;
  8427    unixFile *pFile = (unixFile*)id;
  8428  
  8429    int isDataOnly = (flags&VEDIS_SYNC_DATAONLY);
  8430    int isFullsync = (flags&0x0F)==VEDIS_SYNC_FULL;
  8431  
  8432    rc = full_fsync(pFile->h, isFullsync, isDataOnly);
  8433  
  8434    if( rc ){
  8435      pFile->lastErrno = errno;
  8436      return VEDIS_IOERR;
  8437    }
  8438    if( pFile->dirfd>=0 ){
  8439      int err;
  8440  #ifndef VEDIS_DISABLE_DIRSYNC
  8441      /* The directory sync is only attempted if full_fsync is
  8442      ** turned off or unavailable.  If a full_fsync occurred above,
  8443      ** then the directory sync is superfluous.
  8444      */
  8445      if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){
  8446         /*
  8447         ** We have received multiple reports of fsync() returning
  8448         ** errors when applied to directories on certain file systems.
  8449         ** A failed directory sync is not a big deal.  So it seems
  8450         ** better to ignore the error.  Ticket #1657
  8451         */
  8452         /* pFile->lastErrno = errno; */
  8453         /* return VEDIS_IOERR; */
  8454      }
  8455  #endif
  8456      err = close(pFile->dirfd); /* Only need to sync once, so close the */
  8457      if( err==0 ){              /* directory when we are done */
  8458        pFile->dirfd = -1;
  8459      }else{
  8460        pFile->lastErrno = errno;
  8461        rc = VEDIS_IOERR;
  8462      }
  8463    }
  8464    return rc;
  8465  }
  8466  /*
  8467  ** Truncate an open file to a specified size
  8468  */
  8469  static int unixTruncate(vedis_file *id, sxi64 nByte){
  8470    unixFile *pFile = (unixFile *)id;
  8471    int rc;
  8472  
  8473    rc = ftruncate(pFile->h, (off_t)nByte);
  8474    if( rc ){
  8475      pFile->lastErrno = errno;
  8476      return VEDIS_IOERR;
  8477    }else{
  8478      return VEDIS_OK;
  8479    }
  8480  }
  8481  /*
  8482  ** Determine the current size of a file in bytes
  8483  */
  8484  static int unixFileSize(vedis_file *id,sxi64 *pSize){
  8485    int rc;
  8486    struct stat buf;
  8487    
  8488    rc = fstat(((unixFile*)id)->h, &buf);
  8489    
  8490    if( rc!=0 ){
  8491      ((unixFile*)id)->lastErrno = errno;
  8492      return VEDIS_IOERR;
  8493    }
  8494    *pSize = buf.st_size;
  8495  
  8496    /* When opening a zero-size database, the findInodeInfo() procedure
  8497    ** writes a single byte into that file in order to work around a bug
  8498    ** in the OS-X msdos filesystem.  In order to avoid problems with upper
  8499    ** layers, we need to report this file size as zero even though it is
  8500    ** really 1.   Ticket #3260.
  8501    */
  8502    if( *pSize==1 ) *pSize = 0;
  8503  
  8504    return VEDIS_OK;
  8505  }
  8506  /*
  8507  ** Return the sector size in bytes of the underlying block device for
  8508  ** the specified file. This is almost always 512 bytes, but may be
  8509  ** larger for some devices.
  8510  **
  8511  ** SQLite code assumes this function cannot fail. It also assumes that
  8512  ** if two files are created in the same file-system directory (i.e.
  8513  ** a database and its journal file) that the sector size will be the
  8514  ** same for both.
  8515  */
  8516  static int unixSectorSize(vedis_file *NotUsed){
  8517    SXUNUSED(NotUsed);
  8518    return VEDIS_DEFAULT_SECTOR_SIZE;
  8519  }
  8520  /*
  8521  ** This vector defines all the methods that can operate on an
  8522  ** vedis_file for Windows systems.
  8523  */
  8524  static const vedis_io_methods unixIoMethod = {
  8525    1,                              /* iVersion */
  8526    unixClose,                       /* xClose */
  8527    unixRead,                        /* xRead */
  8528    unixWrite,                       /* xWrite */
  8529    unixTruncate,                    /* xTruncate */
  8530    unixSync,                        /* xSync */
  8531    unixFileSize,                    /* xFileSize */
  8532    unixLock,                        /* xLock */
  8533    unixUnlock,                      /* xUnlock */
  8534    unixCheckReservedLock,           /* xCheckReservedLock */
  8535    unixSectorSize,                  /* xSectorSize */
  8536  };
  8537  /****************************************************************************
  8538  **************************** vedis_vfs methods ****************************
  8539  **
  8540  ** This division contains the implementation of methods on the
  8541  ** vedis_vfs object.
  8542  */
  8543  /*
  8544  ** Initialize the contents of the unixFile structure pointed to by pId.
  8545  */
  8546  static int fillInUnixFile(
  8547    vedis_vfs *pVfs,      /* Pointer to vfs object */
  8548    int h,                  /* Open file descriptor of file being opened */
  8549    int dirfd,              /* Directory file descriptor */
  8550    vedis_file *pId,      /* Write to the unixFile structure here */
  8551    const char *zFilename,  /* Name of the file being opened */
  8552    int noLock,             /* Omit locking if true */
  8553    int isDelete            /* Delete on close if true */
  8554  ){
  8555    const vedis_io_methods *pLockingStyle = &unixIoMethod;
  8556    unixFile *pNew = (unixFile *)pId;
  8557    int rc = VEDIS_OK;
  8558  
  8559    /* Parameter isDelete is only used on vxworks. Express this explicitly 
  8560    ** here to prevent compiler warnings about unused parameters.
  8561    */
  8562    SXUNUSED(isDelete);
  8563    SXUNUSED(noLock);
  8564    SXUNUSED(pVfs);
  8565  
  8566    pNew->h = h;
  8567    pNew->dirfd = dirfd;
  8568    pNew->fileFlags = 0;
  8569    pNew->zPath = zFilename;
  8570    
  8571    unixEnterMutex();
  8572    rc = findInodeInfo(pNew, &pNew->pInode);
  8573    if( rc!=VEDIS_OK ){
  8574        /* If an error occured in findInodeInfo(), close the file descriptor
  8575        ** immediately, before releasing the mutex. findInodeInfo() may fail
  8576        ** in two scenarios:
  8577        **
  8578        **   (a) A call to fstat() failed.
  8579        **   (b) A malloc failed.
  8580        **
  8581        ** Scenario (b) may only occur if the process is holding no other
  8582        ** file descriptors open on the same file. If there were other file
  8583        ** descriptors on this file, then no malloc would be required by
  8584        ** findInodeInfo(). If this is the case, it is quite safe to close
  8585        ** handle h - as it is guaranteed that no posix locks will be released
  8586        ** by doing so.
  8587        **
  8588        ** If scenario (a) caused the error then things are not so safe. The
  8589        ** implicit assumption here is that if fstat() fails, things are in
  8590        ** such bad shape that dropping a lock or two doesn't matter much.
  8591        */
  8592        close(h);
  8593        h = -1;
  8594    }
  8595    unixLeaveMutex();
  8596    
  8597    pNew->lastErrno = 0;
  8598    if( rc!=VEDIS_OK ){
  8599      if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */
  8600      if( h>=0 ) close(h);
  8601    }else{
  8602      pNew->pMethod = pLockingStyle;
  8603    }
  8604    return rc;
  8605  }
  8606  /*
  8607  ** Open a file descriptor to the directory containing file zFilename.
  8608  ** If successful, *pFd is set to the opened file descriptor and
  8609  ** VEDIS_OK is returned. If an error occurs, either VEDIS_NOMEM
  8610  ** or VEDIS_CANTOPEN is returned and *pFd is set to an undefined
  8611  ** value.
  8612  **
  8613  ** If VEDIS_OK is returned, the caller is responsible for closing
  8614  ** the file descriptor *pFd using close().
  8615  */
  8616  static int openDirectory(const char *zFilename, int *pFd){
  8617    sxu32 ii;
  8618    int fd = -1;
  8619    char zDirname[MAX_PATHNAME+1];
  8620    sxu32 n;
  8621    n = Systrcpy(zDirname,sizeof(zDirname),zFilename,0);
  8622    for(ii=n; ii>1 && zDirname[ii]!='/'; ii--);
  8623    if( ii>0 ){
  8624      zDirname[ii] = '\0';
  8625      fd = open(zDirname, O_RDONLY|O_BINARY, 0);
  8626      if( fd>=0 ){
  8627  #ifdef FD_CLOEXEC
  8628        fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
  8629  #endif
  8630      }
  8631    }
  8632    *pFd = fd;
  8633    return (fd>=0?VEDIS_OK: VEDIS_IOERR );
  8634  }
  8635  /*
  8636  ** Search for an unused file descriptor that was opened on the database 
  8637  ** file (not a journal or master-journal file) identified by pathname
  8638  ** zPath with VEDIS_OPEN_XXX flags matching those passed as the second
  8639  ** argument to this function.
  8640  **
  8641  ** Such a file descriptor may exist if a database connection was closed
  8642  ** but the associated file descriptor could not be closed because some
  8643  ** other file descriptor open on the same file is holding a file-lock.
  8644  ** Refer to comments in the unixClose() function and the lengthy comment
  8645  ** describing "Posix Advisory Locking" at the start of this file for 
  8646  ** further details. Also, ticket #4018.
  8647  **
  8648  ** If a suitable file descriptor is found, then it is returned. If no
  8649  ** such file descriptor is located, -1 is returned.
  8650  */
  8651  static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
  8652    UnixUnusedFd *pUnused = 0;
  8653    struct stat sStat;                   /* Results of stat() call */
  8654    /* A stat() call may fail for various reasons. If this happens, it is
  8655    ** almost certain that an open() call on the same path will also fail.
  8656    ** For this reason, if an error occurs in the stat() call here, it is
  8657    ** ignored and -1 is returned. The caller will try to open a new file
  8658    ** descriptor on the same path, fail, and return an error to SQLite.
  8659    **
  8660    ** Even if a subsequent open() call does succeed, the consequences of
  8661    ** not searching for a resusable file descriptor are not dire.  */
  8662    if( 0==stat(zPath, &sStat) ){
  8663      unixInodeInfo *pInode;
  8664  
  8665      unixEnterMutex();
  8666      pInode = inodeList;
  8667      while( pInode && (pInode->fileId.dev!=sStat.st_dev
  8668                       || pInode->fileId.ino!=sStat.st_ino) ){
  8669         pInode = pInode->pNext;
  8670      }
  8671      if( pInode ){
  8672        UnixUnusedFd **pp;
  8673        for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
  8674        pUnused = *pp;
  8675        if( pUnused ){
  8676          *pp = pUnused->pNext;
  8677        }
  8678      }
  8679      unixLeaveMutex();
  8680    }
  8681    return pUnused;
  8682  }
  8683  /*
  8684  ** This function is called by unixOpen() to determine the unix permissions
  8685  ** to create new files with. If no error occurs, then VEDIS_OK is returned
  8686  ** and a value suitable for passing as the third argument to open(2) is
  8687  ** written to *pMode. If an IO error occurs, an SQLite error code is 
  8688  ** returned and the value of *pMode is not modified.
  8689  **
  8690  ** If the file being opened is a temporary file, it is always created with
  8691  ** the octal permissions 0600 (read/writable by owner only). If the file
  8692  ** is a database or master journal file, it is created with the permissions 
  8693  ** mask VEDIS_DEFAULT_FILE_PERMISSIONS.
  8694  **
  8695  ** Finally, if the file being opened is a WAL or regular journal file, then 
  8696  ** this function queries the file-system for the permissions on the 
  8697  ** corresponding database file and sets *pMode to this value. Whenever 
  8698  ** possible, WAL and journal files are created using the same permissions 
  8699  ** as the associated database file.
  8700  */
  8701  static int findCreateFileMode(
  8702    const char *zPath,              /* Path of file (possibly) being created */
  8703    int flags,                      /* Flags passed as 4th argument to xOpen() */
  8704    mode_t *pMode                   /* OUT: Permissions to open file with */
  8705  ){
  8706    int rc = VEDIS_OK;             /* Return Code */
  8707    if( flags & VEDIS_OPEN_TEMP_DB ){
  8708      *pMode = 0600;
  8709       SXUNUSED(zPath);
  8710    }else{
  8711      *pMode = VEDIS_DEFAULT_FILE_PERMISSIONS;
  8712    }
  8713    return rc;
  8714  }
  8715  /*
  8716  ** Open the file zPath.
  8717  ** 
  8718  ** Previously, the SQLite OS layer used three functions in place of this
  8719  ** one:
  8720  **
  8721  **     vedisOsOpenReadWrite();
  8722  **     vedisOsOpenReadOnly();
  8723  **     vedisOsOpenExclusive();
  8724  **
  8725  ** These calls correspond to the following combinations of flags:
  8726  **
  8727  **     ReadWrite() ->     (READWRITE | CREATE)
  8728  **     ReadOnly()  ->     (READONLY) 
  8729  **     OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
  8730  **
  8731  ** The old OpenExclusive() accepted a boolean argument - "delFlag". If
  8732  ** true, the file was configured to be automatically deleted when the
  8733  ** file handle closed. To achieve the same effect using this new 
  8734  ** interface, add the DELETEONCLOSE flag to those specified above for 
  8735  ** OpenExclusive().
  8736  */
  8737  static int unixOpen(
  8738    vedis_vfs *pVfs,           /* The VFS for which this is the xOpen method */
  8739    const char *zPath,           /* Pathname of file to be opened */
  8740    vedis_file *pFile,         /* The file descriptor to be filled in */
  8741    unsigned int flags           /* Input flags to control the opening */
  8742  ){
  8743    unixFile *p = (unixFile *)pFile;
  8744    int fd = -1;                   /* File descriptor returned by open() */
  8745    int dirfd = -1;                /* Directory file descriptor */
  8746    int openFlags = 0;             /* Flags to pass to open() */
  8747    int noLock;                    /* True to omit locking primitives */
  8748    int rc = VEDIS_OK;            /* Function Return Code */
  8749    UnixUnusedFd *pUnused;
  8750    int isExclusive  = (flags & VEDIS_OPEN_EXCLUSIVE);
  8751    int isDelete     = (flags & VEDIS_OPEN_TEMP_DB);
  8752    int isCreate     = (flags & VEDIS_OPEN_CREATE);
  8753    int isReadonly   = (flags & VEDIS_OPEN_READONLY);
  8754    int isReadWrite  = (flags & VEDIS_OPEN_READWRITE);
  8755    /* If creating a master or main-file journal, this function will open
  8756    ** a file-descriptor on the directory too. The first time unixSync()
  8757    ** is called the directory file descriptor will be fsync()ed and close()d.
  8758    */
  8759    int isOpenDirectory = isCreate ;
  8760    const char *zName = zPath;
  8761  
  8762    SyZero(p,sizeof(unixFile));
  8763    
  8764    pUnused = findReusableFd(zName, flags);
  8765    if( pUnused ){
  8766  	  fd = pUnused->fd;
  8767    }else{
  8768  	  pUnused = vedis_malloc(sizeof(*pUnused));
  8769        if( !pUnused ){
  8770          return VEDIS_NOMEM;
  8771        }
  8772    }
  8773    p->pUnused = pUnused;
  8774    
  8775    /* Determine the value of the flags parameter passed to POSIX function
  8776    ** open(). These must be calculated even if open() is not called, as
  8777    ** they may be stored as part of the file handle and used by the 
  8778    ** 'conch file' locking functions later on.  */
  8779    if( isReadonly )  openFlags |= O_RDONLY;
  8780    if( isReadWrite ) openFlags |= O_RDWR;
  8781    if( isCreate )    openFlags |= O_CREAT;
  8782    if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  8783    openFlags |= (O_LARGEFILE|O_BINARY);
  8784  
  8785    if( fd<0 ){
  8786      mode_t openMode;              /* Permissions to create file with */
  8787      rc = findCreateFileMode(zName, flags, &openMode);
  8788      if( rc!=VEDIS_OK ){
  8789        return rc;
  8790      }
  8791      fd = open(zName, openFlags, openMode);
  8792      if( fd<0 ){
  8793  	  rc = VEDIS_IOERR;
  8794        goto open_finished;
  8795      }
  8796    }
  8797    
  8798    if( p->pUnused ){
  8799      p->pUnused->fd = fd;
  8800      p->pUnused->flags = flags;
  8801    }
  8802  
  8803    if( isDelete ){
  8804      unlink(zName);
  8805    }
  8806  
  8807    if( isOpenDirectory ){
  8808      rc = openDirectory(zPath, &dirfd);
  8809      if( rc!=VEDIS_OK ){
  8810        /* It is safe to close fd at this point, because it is guaranteed not
  8811        ** to be open on a database file. If it were open on a database file,
  8812        ** it would not be safe to close as this would release any locks held
  8813        ** on the file by this process.  */
  8814        close(fd);             /* silently leak if fail, already in error */
  8815        goto open_finished;
  8816      }
  8817    }
  8818  
  8819  #ifdef FD_CLOEXEC
  8820    fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
  8821  #endif
  8822  
  8823    noLock = 0;
  8824  
  8825  #if defined(__APPLE__) 
  8826    struct statfs fsInfo;
  8827    if( fstatfs(fd, &fsInfo) == -1 ){
  8828      ((unixFile*)pFile)->lastErrno = errno;
  8829      if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */
  8830      close(fd); /* silently leak if fail, in error */
  8831      return VEDIS_IOERR;
  8832    }
  8833    if (0 == SyStrncmp("msdos", fsInfo.f_fstypename, 5)) {
  8834      ((unixFile*)pFile)->fsFlags |= VEDIS_FSFLAGS_IS_MSDOS;
  8835    }
  8836  #endif
  8837    
  8838    rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete);
  8839  open_finished:
  8840    if( rc!=VEDIS_OK ){
  8841      vedis_free(p->pUnused);
  8842    }
  8843    return rc;
  8844  }
  8845  /*
  8846  ** Delete the file at zPath. If the dirSync argument is true, fsync()
  8847  ** the directory after deleting the file.
  8848  */
  8849  static int unixDelete(
  8850    vedis_vfs *NotUsed,     /* VFS containing this as the xDelete method */
  8851    const char *zPath,        /* Name of file to be deleted */
  8852    int dirSync               /* If true, fsync() directory after deleting file */
  8853  ){
  8854    int rc = VEDIS_OK;
  8855    SXUNUSED(NotUsed);
  8856    
  8857    if( unlink(zPath)==(-1) && errno!=ENOENT ){
  8858  	  return VEDIS_IOERR;
  8859    }
  8860  #ifndef VEDIS_DISABLE_DIRSYNC
  8861    if( dirSync ){
  8862      int fd;
  8863      rc = openDirectory(zPath, &fd);
  8864      if( rc==VEDIS_OK ){
  8865        if( fsync(fd) )
  8866        {
  8867          rc = VEDIS_IOERR;
  8868        }
  8869        if( close(fd) && !rc ){
  8870          rc = VEDIS_IOERR;
  8871        }
  8872      }
  8873    }
  8874  #endif
  8875    return rc;
  8876  }
  8877  /*
  8878  ** Sleep for a little while.  Return the amount of time slept.
  8879  ** The argument is the number of microseconds we want to sleep.
  8880  ** The return value is the number of microseconds of sleep actually
  8881  ** requested from the underlying operating system, a number which
  8882  ** might be greater than or equal to the argument, but not less
  8883  ** than the argument.
  8884  */
  8885  static int unixSleep(vedis_vfs *NotUsed, int microseconds)
  8886  {
  8887  #if defined(HAVE_USLEEP) && HAVE_USLEEP
  8888    usleep(microseconds);
  8889    SXUNUSED(NotUsed);
  8890    return microseconds;
  8891  #else
  8892    int seconds = (microseconds+999999)/1000000;
  8893    SXUNUSED(NotUsed);
  8894    sleep(seconds);
  8895    return seconds*1000000;
  8896  #endif
  8897  }
  8898  /*
  8899   * Export the current system time.
  8900   */
  8901  static int unixCurrentTime(vedis_vfs *pVfs,Sytm *pOut)
  8902  {
  8903  	struct tm *pTm;
  8904  	time_t tt;
  8905  	SXUNUSED(pVfs);
  8906  	time(&tt);
  8907  	pTm = gmtime(&tt);
  8908  	if( pTm ){ /* Yes, it can fail */
  8909  		STRUCT_TM_TO_SYTM(pTm,pOut);
  8910  	}
  8911  	return VEDIS_OK;
  8912  }
  8913  /*
  8914  ** Test the existance of or access permissions of file zPath. The
  8915  ** test performed depends on the value of flags:
  8916  **
  8917  **     VEDIS_ACCESS_EXISTS: Return 1 if the file exists
  8918  **     VEDIS_ACCESS_READWRITE: Return 1 if the file is read and writable.
  8919  **     VEDIS_ACCESS_READONLY: Return 1 if the file is readable.
  8920  **
  8921  ** Otherwise return 0.
  8922  */
  8923  static int unixAccess(
  8924    vedis_vfs *NotUsed,   /* The VFS containing this xAccess method */
  8925    const char *zPath,      /* Path of the file to examine */
  8926    int flags,              /* What do we want to learn about the zPath file? */
  8927    int *pResOut            /* Write result boolean here */
  8928  ){
  8929    int amode = 0;
  8930    SXUNUSED(NotUsed);
  8931    switch( flags ){
  8932      case VEDIS_ACCESS_EXISTS:
  8933        amode = F_OK;
  8934        break;
  8935      case VEDIS_ACCESS_READWRITE:
  8936        amode = W_OK|R_OK;
  8937        break;
  8938      case VEDIS_ACCESS_READ:
  8939        amode = R_OK;
  8940        break;
  8941      default:
  8942  		/* Can't happen */
  8943        break;
  8944    }
  8945    *pResOut = (access(zPath, amode)==0);
  8946    if( flags==VEDIS_ACCESS_EXISTS && *pResOut ){
  8947      struct stat buf;
  8948      if( 0==stat(zPath, &buf) && buf.st_size==0 ){
  8949        *pResOut = 0;
  8950      }
  8951    }
  8952    return VEDIS_OK;
  8953  }
  8954  /*
  8955  ** Turn a relative pathname into a full pathname. The relative path
  8956  ** is stored as a nul-terminated string in the buffer pointed to by
  8957  ** zPath. 
  8958  **
  8959  ** zOut points to a buffer of at least vedis_vfs.mxPathname bytes 
  8960  ** (in this case, MAX_PATHNAME bytes). The full-path is written to
  8961  ** this buffer before returning.
  8962  */
  8963  static int unixFullPathname(
  8964    vedis_vfs *pVfs,            /* Pointer to vfs object */
  8965    const char *zPath,            /* Possibly relative input path */
  8966    int nOut,                     /* Size of output buffer in bytes */
  8967    char *zOut                    /* Output buffer */
  8968  ){
  8969    if( zPath[0]=='/' ){
  8970  	  Systrcpy(zOut,(sxu32)nOut,zPath,0);
  8971  	  SXUNUSED(pVfs);
  8972    }else{
  8973      sxu32 nCwd;
  8974  	zOut[nOut-1] = '\0';
  8975      if( getcwd(zOut, nOut-1)==0 ){
  8976  		return VEDIS_IOERR;
  8977      }
  8978      nCwd = SyStrlen(zOut);
  8979      SyBufferFormat(&zOut[nCwd],(sxu32)nOut-nCwd,"/%s",zPath);
  8980    }
  8981    return VEDIS_OK;
  8982  }
  8983  /* int (*xMmap)(const char *, void **, vedis_int64 *) */
  8984  static int UnixMmap(const char *zPath, void **ppMap, vedis_int64 *pSize)
  8985  {
  8986  	struct stat st;
  8987  	void *pMap;
  8988  	int fd;
  8989  	int rc;
  8990  	/* Open the file in a read-only mode */
  8991  	fd = open(zPath, O_RDONLY);
  8992  	if( fd < 0 ){
  8993  		return -1;
  8994  	}
  8995  	/* stat the handle */
  8996  	fstat(fd, &st);
  8997  	/* Obtain a memory view of the whole file */
  8998  	pMap = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE|MAP_FILE, fd, 0);
  8999  	rc = VEDIS_OK;
  9000  	if( pMap == MAP_FAILED ){
  9001  		rc = -1;
  9002  	}else{
  9003  		/* Point to the memory view */
  9004  		*ppMap = pMap;
  9005  		*pSize = (vedis_int64)st.st_size;
  9006  	}
  9007  	close(fd);
  9008  	return rc;
  9009  }
  9010  /* void (*xUnmap)(void *, vedis_int64)  */
  9011  static void UnixUnmap(void *pView, vedis_int64 nSize)
  9012  {
  9013  	munmap(pView, (size_t)nSize);
  9014  }
  9015  /*
  9016   * Export the Unix Vfs.
  9017   */
  9018  VEDIS_PRIVATE const vedis_vfs * vedisExportBuiltinVfs(void)
  9019  {
  9020  	static const vedis_vfs sUnixvfs = {
  9021  		"Unix",              /* Vfs name */
  9022  		1,                   /* Vfs structure version */
  9023  		sizeof(unixFile),    /* szOsFile */
  9024  		MAX_PATHNAME,        /* mxPathName */
  9025  		unixOpen,            /* xOpen */
  9026  		unixDelete,          /* xDelete */
  9027  		unixAccess,          /* xAccess */
  9028  		unixFullPathname,    /* xFullPathname */
  9029  		0,                   /* xTmp */
  9030  		unixSleep,           /* xSleep */
  9031  		unixCurrentTime,     /* xCurrentTime */
  9032  		0,                   /* xGetLastError */
  9033  		UnixMmap,            /* xMmap */
  9034  		UnixUnmap            /* xUnmap */
  9035  	};
  9036  	return &sUnixvfs;
  9037  }
  9038  
  9039  #endif /* __UNIXES__ */
  9040  
  9041  /*
  9042   * ----------------------------------------------------------
  9043   * File: os.c
  9044   * MD5: b04f646dc8cef1afabca3f8c053f648b
  9045   * ----------------------------------------------------------
  9046   */
  9047  /*
  9048   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
  9049   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
  9050   * Version 1.1.6
  9051   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  9052   * please contact Symisc Systems via:
  9053   *       legal@symisc.net
  9054   *       licensing@symisc.net
  9055   *       contact@symisc.net
  9056   * or visit:
  9057   *      http://vedis.org/licensing.html
  9058   */
  9059   /* $SymiscID: os.c v1.0 FreeBSD 2012-11-12 21:27 devel <chm@symisc.net> $ */
  9060  #ifndef VEDIS_AMALGAMATION
  9061  #include "vedisInt.h"
  9062  #endif
  9063  /* OS interfaces abstraction layers: Mostly SQLite3 source tree */
  9064  /*
  9065  ** The following routines are convenience wrappers around methods
  9066  ** of the vedis_file object.  This is mostly just syntactic sugar. All
  9067  ** of this would be completely automatic if UnQLite were coded using
  9068  ** C++ instead of plain old C.
  9069  */
  9070  VEDIS_PRIVATE int vedisOsRead(vedis_file *id, void *pBuf, vedis_int64 amt, vedis_int64 offset)
  9071  {
  9072    return id->pMethods->xRead(id, pBuf, amt, offset);
  9073  }
  9074  VEDIS_PRIVATE int vedisOsWrite(vedis_file *id, const void *pBuf, vedis_int64 amt, vedis_int64 offset)
  9075  {
  9076    return id->pMethods->xWrite(id, pBuf, amt, offset);
  9077  }
  9078  VEDIS_PRIVATE int vedisOsTruncate(vedis_file *id, vedis_int64 size)
  9079  {
  9080    return id->pMethods->xTruncate(id, size);
  9081  }
  9082  VEDIS_PRIVATE int vedisOsSync(vedis_file *id, int flags)
  9083  {
  9084    return id->pMethods->xSync(id, flags);
  9085  }
  9086  VEDIS_PRIVATE int vedisOsFileSize(vedis_file *id, vedis_int64 *pSize)
  9087  {
  9088    return id->pMethods->xFileSize(id, pSize);
  9089  }
  9090  VEDIS_PRIVATE int vedisOsLock(vedis_file *id, int lockType)
  9091  {
  9092    return id->pMethods->xLock(id, lockType);
  9093  }
  9094  VEDIS_PRIVATE int vedisOsUnlock(vedis_file *id, int lockType)
  9095  {
  9096    return id->pMethods->xUnlock(id, lockType);
  9097  }
  9098  VEDIS_PRIVATE int vedisOsCheckReservedLock(vedis_file *id, int *pResOut)
  9099  {
  9100    return id->pMethods->xCheckReservedLock(id, pResOut);
  9101  }
  9102  VEDIS_PRIVATE int vedisOsSectorSize(vedis_file *id)
  9103  {
  9104    if( id->pMethods->xSectorSize ){
  9105  	  return id->pMethods->xSectorSize(id);
  9106    }
  9107    return  VEDIS_DEFAULT_SECTOR_SIZE;
  9108  }
  9109  /*
  9110  ** The next group of routines are convenience wrappers around the
  9111  ** VFS methods.
  9112  */
  9113  VEDIS_PRIVATE int vedisOsOpen(
  9114    vedis_vfs *pVfs,
  9115    SyMemBackend *pAlloc,
  9116    const char *zPath, 
  9117    vedis_file **ppOut, 
  9118    unsigned int flags 
  9119  )
  9120  {
  9121  	vedis_file *pFile;
  9122  	int rc;
  9123  	*ppOut = 0;
  9124  	if( zPath == 0 ){
  9125  		/* May happen if dealing with an in-memory database */
  9126  		return SXERR_EMPTY;
  9127  	}
  9128  	/* Allocate a new instance */
  9129  	pFile = (vedis_file *)SyMemBackendAlloc(pAlloc,sizeof(vedis_file)+pVfs->szOsFile);
  9130  	if( pFile == 0 ){
  9131  		return VEDIS_NOMEM;
  9132  	}
  9133  	/* Zero the structure */
  9134  	SyZero(pFile,sizeof(vedis_file)+pVfs->szOsFile);
  9135  	/* Invoke the xOpen method of the underlying VFS */
  9136  	rc = pVfs->xOpen(pVfs, zPath, pFile, flags);
  9137  	if( rc != VEDIS_OK ){
  9138  		SyMemBackendFree(pAlloc,pFile);
  9139  		pFile = 0;
  9140  	}
  9141  	*ppOut = pFile;
  9142  	return rc;
  9143  }
  9144  VEDIS_PRIVATE int vedisOsCloseFree(SyMemBackend *pAlloc,vedis_file *pId)
  9145  {
  9146  	int rc = VEDIS_OK;
  9147  	if( pId ){
  9148  		rc = pId->pMethods->xClose(pId);
  9149  		SyMemBackendFree(pAlloc,pId);
  9150  	}
  9151  	return rc;
  9152  }
  9153  VEDIS_PRIVATE int vedisOsDelete(vedis_vfs *pVfs, const char *zPath, int dirSync){
  9154    return pVfs->xDelete(pVfs, zPath, dirSync);
  9155  }
  9156  VEDIS_PRIVATE int vedisOsAccess(
  9157    vedis_vfs *pVfs, 
  9158    const char *zPath, 
  9159    int flags, 
  9160    int *pResOut
  9161  ){
  9162    return pVfs->xAccess(pVfs, zPath, flags, pResOut);
  9163  }
  9164  /*
  9165   * ----------------------------------------------------------
  9166   * File: obj.c
  9167   * MD5: 5d0b5f8c634519f435585ccae3a25ef7
  9168   * ----------------------------------------------------------
  9169   */
  9170  /*
  9171   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
  9172   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
  9173   * Version 1.2.6
  9174   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  9175   * please contact Symisc Systems via:
  9176   *       legal@symisc.net
  9177   *       licensing@symisc.net
  9178   *       contact@symisc.net
  9179   * or visit:
  9180   *      http://vedis.symisc.net/
  9181   */
  9182  /* $SymiscID: obj.c v1.6 Linux 2013-07-10 03:52 stable <chm@symisc.net> $ */
  9183  #ifndef VEDIS_AMALGAMATION
  9184  #include "vedisInt.h"
  9185  #endif
  9186  /* This file manage low-level stuff related to indexed memory objects [i.e: vedis_value] */
  9187  /*
  9188   * Notes on memory objects [i.e: vedis_value].
  9189   * Internally, the VEDIS engine manipulates nearly all VEDIS values
  9190   * [i.e: string, int, float, resource, object, bool, null..] as vedis_values structures.
  9191   * Each vedis_values struct may cache multiple representations (string, 
  9192   * integer etc.) of the same value.
  9193   */
  9194  /*
  9195   * Convert a 64-bit IEEE double into a 64-bit signed integer.
  9196   * If the double is too large, return 0x8000000000000000.
  9197   *
  9198   * Most systems appear to do this simply by assigning ariables and without
  9199   * the extra range tests.
  9200   * But there are reports that windows throws an expection if the floating 
  9201   * point value is out of range.
  9202   */
  9203  static sxi64 MemObjRealToInt(vedis_value *pObj)
  9204  {
  9205  #ifdef VEDIS_OMIT_FLOATING_POINT
  9206  	/* Real and 64bit integer are the same when floating point arithmetic
  9207  	 * is omitted from the build.
  9208  	 */
  9209  	return pObj->x.rVal;
  9210  #else
  9211   /*
  9212    ** Many compilers we encounter do not define constants for the
  9213    ** minimum and maximum 64-bit integers, or they define them
  9214    ** inconsistently.  And many do not understand the "LL" notation.
  9215    ** So we define our own static constants here using nothing
  9216    ** larger than a 32-bit integer constant.
  9217    */
  9218    static const sxi64 maxInt = LARGEST_INT64;
  9219    static const sxi64 minInt = SMALLEST_INT64;
  9220    vedis_real r = pObj->x.rVal;
  9221    if( r<(vedis_real)minInt ){
  9222      return minInt;
  9223    }else if( r>(vedis_real)maxInt ){
  9224      /* minInt is correct here - not maxInt.  It turns out that assigning
  9225      ** a very large positive number to an integer results in a very large
  9226      ** negative integer.  This makes no sense, but it is what x86 hardware
  9227      ** does so for compatibility we will do the same in software. */
  9228      return minInt;
  9229    }else{
  9230      return (sxi64)r;
  9231    }
  9232  #endif
  9233  }
  9234  /*
  9235   * Convert a raw token value typically a stream of digit [i.e: hex, octal, binary or decimal] 
  9236   * to a 64-bit integer.
  9237   */
  9238  VEDIS_PRIVATE sxi64 vedisTokenValueToInt64(SyString *pVal)
  9239  {
  9240  	sxi64 iVal = 0;
  9241  	if( pVal->nByte <= 0 ){
  9242  		return 0;
  9243  	}
  9244  	if( pVal->zString[0] == '0' ){
  9245  		sxi32 c;
  9246  		if( pVal->nByte == sizeof(char) ){
  9247  			return 0;
  9248  		}
  9249  		c = pVal->zString[1];
  9250  		if( c  == 'x' || c == 'X' ){
  9251  			/* Hex digit stream */
  9252  			SyHexStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  9253  		}else if( c == 'b' || c == 'B' ){
  9254  			/* Binary digit stream */
  9255  			SyBinaryStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  9256  		}else{
  9257  			/* Octal digit stream */
  9258  			SyOctalStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  9259  		}
  9260  	}else{
  9261  		/* Decimal digit stream */
  9262  		SyStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0);
  9263  	}
  9264  	return iVal;
  9265  }
  9266  /*
  9267   * Return some kind of 64-bit integer value which is the best we can
  9268   * do at representing the value that pObj describes as a string
  9269   * representation.
  9270   */
  9271  static sxi64 MemObjStringToInt(vedis_value *pObj)
  9272  {
  9273  	SyString sVal;
  9274  	SyStringInitFromBuf(&sVal, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  9275  	return vedisTokenValueToInt64(&sVal);	
  9276  }
  9277  /*
  9278   * Return some kind of integer value which is the best we can
  9279   * do at representing the value that pObj describes as an integer.
  9280   * If pObj is an integer, then the value is exact. If pObj is
  9281   * a floating-point then  the value returned is the integer part.
  9282   * If pObj is a string, then we make an attempt to convert it into
  9283   * a integer and return that. 
  9284   * If pObj represents a NULL value, return 0.
  9285   */
  9286  static sxi64 MemObjIntValue(vedis_value *pObj)
  9287  {
  9288  	sxi32 iFlags;
  9289  	iFlags = pObj->iFlags;
  9290  	if (iFlags & MEMOBJ_REAL ){
  9291  		return MemObjRealToInt(&(*pObj));
  9292  	}else if( iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){
  9293  		return pObj->x.iVal;
  9294  	}else if (iFlags & MEMOBJ_STRING) {
  9295  		return MemObjStringToInt(&(*pObj));
  9296  	}else if( iFlags & MEMOBJ_NULL ){
  9297  		return 0;
  9298  	}else if( iFlags & MEMOBJ_HASHMAP ){
  9299  		vedis_hashmap *pMap = (vedis_hashmap *)pObj->x.pOther;
  9300  		sxu32 n = vedisHashmapCount(pMap);
  9301  		vedisHashmapUnref(pMap);
  9302  		/* Return total number of entries in the hashmap */
  9303  		return n; 
  9304  	}
  9305  	/* CANT HAPPEN */
  9306  	return 0;
  9307  }
  9308  /*
  9309   * Return some kind of real value which is the best we can
  9310   * do at representing the value that pObj describes as a real.
  9311   * If pObj is a real, then the value is exact.If pObj is an
  9312   * integer then the integer  is promoted to real and that value
  9313   * is returned.
  9314   * If pObj is a string, then we make an attempt to convert it
  9315   * into a real and return that. 
  9316   * If pObj represents a NULL value, return 0.0
  9317   */
  9318  static vedis_real MemObjRealValue(vedis_value *pObj)
  9319  {
  9320  	sxi32 iFlags;
  9321  	iFlags = pObj->iFlags;
  9322  	if( iFlags & MEMOBJ_REAL ){
  9323  		return pObj->x.rVal;
  9324  	}else if (iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){
  9325  		return (vedis_real)pObj->x.iVal;
  9326  	}else if (iFlags & MEMOBJ_STRING){
  9327  		SyString sString;
  9328  #ifdef VEDIS_OMIT_FLOATING_POINT
  9329  		vedis_real rVal = 0;
  9330  #else
  9331  		vedis_real rVal = 0.0;
  9332  #endif
  9333  		SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  9334  		if( SyBlobLength(&pObj->sBlob) > 0 ){
  9335  			/* Convert as much as we can */
  9336  #ifdef VEDIS_OMIT_FLOATING_POINT
  9337  			rVal = MemObjStringToInt(&(*pObj));
  9338  #else
  9339  			SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0);
  9340  #endif
  9341  		}
  9342  		return rVal;
  9343  	}else if( iFlags & MEMOBJ_NULL ){
  9344  #ifdef VEDIS_OMIT_FLOATING_POINT
  9345  		return 0;
  9346  #else
  9347  		return 0.0;
  9348  #endif
  9349  	}else if( iFlags & MEMOBJ_HASHMAP ){
  9350  		/* Return the total number of entries in the hashmap */
  9351  		vedis_hashmap *pMap = (vedis_hashmap *)pObj->x.pOther;
  9352  		vedis_real n = (vedis_real)vedisHashmapCount(pMap);
  9353  		vedisHashmapUnref(pMap);
  9354  		return n;
  9355  	}
  9356  	/* NOT REACHED  */
  9357  	return 0;
  9358  }
  9359  /* 
  9360   * Return the string representation of a given vedis_value.
  9361   * This function never fail and always return SXRET_OK.
  9362   */
  9363  static sxi32 MemObjStringValue(SyBlob *pOut,vedis_value *pObj)
  9364  {
  9365  	if( pObj->iFlags & MEMOBJ_REAL ){
  9366  		SyBlobFormat(&(*pOut), "%.15g", pObj->x.rVal);
  9367  	}else if( pObj->iFlags & MEMOBJ_INT ){
  9368  		SyBlobFormat(&(*pOut), "%qd", pObj->x.iVal);
  9369  		/* %qd (BSD quad) is equivalent to %lld in the libc printf */
  9370  	}else if( pObj->iFlags & MEMOBJ_BOOL ){
  9371  		if( pObj->x.iVal ){
  9372  			SyBlobAppend(&(*pOut),"true", sizeof("true")-1);
  9373  		}else{
  9374  			SyBlobAppend(&(*pOut),"false", sizeof("false")-1);
  9375  		}
  9376  	}else if( pObj->iFlags & MEMOBJ_HASHMAP ){
  9377  		/* Serialize JSON object or array */
  9378  		vedisJsonSerialize(pObj,pOut);
  9379  		vedisHashmapUnref((vedis_hashmap *)pObj->x.pOther);
  9380  	}
  9381  	return SXRET_OK;
  9382  }
  9383  /*
  9384   * Return some kind of boolean value which is the best we can do
  9385   * at representing the value that pObj describes as a boolean.
  9386   * When converting to boolean, the following values are considered FALSE:
  9387   * NULL
  9388   * the boolean FALSE itself.
  9389   * the integer 0 (zero).
  9390   * the real 0.0 (zero).
  9391   * the empty string, a stream of zero [i.e: "0", "00", "000", ...] and the string
  9392   * "false".
  9393   * an array with zero elements. 
  9394   */
  9395  static sxi32 MemObjBooleanValue(vedis_value *pObj)
  9396  {
  9397  	sxi32 iFlags;	
  9398  	iFlags = pObj->iFlags;
  9399  	if (iFlags & MEMOBJ_REAL ){
  9400  #ifdef VEDIS_OMIT_FLOATING_POINT
  9401  		return pObj->x.rVal ? 1 : 0;
  9402  #else
  9403  		return pObj->x.rVal != 0.0 ? 1 : 0;
  9404  #endif
  9405  	}else if( iFlags & MEMOBJ_INT ){
  9406  		return pObj->x.iVal ? 1 : 0;
  9407  	}else if (iFlags & MEMOBJ_STRING) {
  9408  		SyString sString;
  9409  		SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  9410  		if( sString.nByte == 0 ){
  9411  			/* Empty string */
  9412  			return 0;
  9413  		}else if( (sString.nByte == sizeof("true") - 1 && SyStrnicmp(sString.zString, "true", sizeof("true")-1) == 0) ||
  9414  			(sString.nByte == sizeof("on") - 1 && SyStrnicmp(sString.zString, "on", sizeof("on")-1) == 0) ||
  9415  			(sString.nByte == sizeof("yes") - 1 && SyStrnicmp(sString.zString, "yes", sizeof("yes")-1) == 0) ){
  9416  				return 1;
  9417  		}else if( sString.nByte == sizeof("false") - 1 && SyStrnicmp(sString.zString, "false", sizeof("false")-1) == 0 ){
  9418  			return 0;
  9419  		}else{
  9420  			const char *zIn, *zEnd;
  9421  			zIn = sString.zString;
  9422  			zEnd = &zIn[sString.nByte];
  9423  			while( zIn < zEnd && zIn[0] == '0' ){
  9424  				zIn++;
  9425  			}
  9426  			return zIn >= zEnd ? 0 : 1;
  9427  		}
  9428  	}else if( iFlags & MEMOBJ_NULL ){
  9429  		return 0;
  9430  	}else if( iFlags & MEMOBJ_HASHMAP ){
  9431  		vedis_hashmap *pMap = (vedis_hashmap *)pObj->x.pOther;
  9432  		sxu32 n = vedisHashmapCount(pMap);
  9433  		vedisHashmapUnref(pMap);
  9434  		return n > 0 ? TRUE : FALSE;
  9435  	}
  9436  	/* NOT REACHED */
  9437  	return 0;
  9438  }
  9439  /*
  9440   * If the vedis_value is of type real, try to make it an integer also.
  9441   */
  9442  static sxi32 MemObjTryIntger(vedis_value *pObj)
  9443  {
  9444  	sxi64 iVal = MemObjRealToInt(&(*pObj));
  9445    /* Only mark the value as an integer if
  9446    **
  9447    **    (1) the round-trip conversion real->int->real is a no-op, and
  9448    **    (2) The integer is neither the largest nor the smallest
  9449    **        possible integer
  9450    **
  9451    ** The second and third terms in the following conditional enforces
  9452    ** the second condition under the assumption that addition overflow causes
  9453    ** values to wrap around.  On x86 hardware, the third term is always
  9454    ** true and could be omitted.  But we leave it in because other
  9455    ** architectures might behave differently.
  9456    */
  9457  	if( pObj->x.rVal ==(vedis_real)iVal && iVal>SMALLEST_INT64 && iVal<LARGEST_INT64 ){
  9458  		pObj->x.iVal = iVal; 
  9459  		pObj->iFlags = MEMOBJ_INT;
  9460  	}
  9461  	return SXRET_OK;
  9462  }
  9463  /*
  9464   * Check whether the vedis_value is numeric [i.e: int/float/bool] or looks
  9465   * like a numeric number [i.e: if the vedis_value is of type string.].
  9466   * Return TRUE if numeric.FALSE otherwise.
  9467   */
  9468  VEDIS_PRIVATE sxi32 vedisMemObjIsNumeric(vedis_value *pObj)
  9469  {
  9470  	if( pObj->iFlags & ( MEMOBJ_BOOL|MEMOBJ_INT|MEMOBJ_REAL) ){
  9471  		return TRUE;
  9472  	}else if( pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_HASHMAP) ){
  9473  		return FALSE;
  9474  	}else if( pObj->iFlags & MEMOBJ_STRING ){
  9475  		SyString sStr;
  9476  		sxi32 rc;
  9477  		SyStringInitFromBuf(&sStr, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
  9478  		if( sStr.nByte <= 0 ){
  9479  			/* Empty string */
  9480  			return FALSE;
  9481  		}
  9482  		/* Check if the string representation looks like a numeric number */
  9483  		rc = SyStrIsNumeric(sStr.zString, sStr.nByte, 0, 0);
  9484  		return rc == SXRET_OK ? TRUE : FALSE;
  9485  	}
  9486  	/* NOT REACHED */
  9487  	return FALSE;
  9488  }
  9489  /*
  9490   * Convert a vedis_value to type integer.Invalidate any prior representations.
  9491   */
  9492  VEDIS_PRIVATE sxi32 vedisMemObjToInteger(vedis_value *pObj)
  9493  {
  9494  	if( (pObj->iFlags & MEMOBJ_INT) == 0 ){
  9495  		/* Preform the conversion */
  9496  		pObj->x.iVal = MemObjIntValue(&(*pObj));
  9497  		/* Invalidate any prior representations */
  9498  		SyBlobRelease(&pObj->sBlob);
  9499  		MemObjSetType(pObj, MEMOBJ_INT);
  9500  	}
  9501  	return SXRET_OK;
  9502  }
  9503  /*
  9504   * Try a get an integer representation of the given vedis_value.
  9505   * If the vedis_value is not of type real, this function is a no-op.
  9506   */
  9507  VEDIS_PRIVATE sxi32 vedisMemObjTryInteger(vedis_value *pObj)
  9508  {
  9509  	if( pObj->iFlags & MEMOBJ_REAL ){
  9510  		/* Work only with reals */
  9511  		MemObjTryIntger(&(*pObj));
  9512  	}
  9513  	return SXRET_OK;
  9514  }
  9515  /*
  9516   * Convert a vedis_value to type real (Try to get an integer representation also).
  9517   * Invalidate any prior representations
  9518   */
  9519  VEDIS_PRIVATE sxi32 vedisMemObjToReal(vedis_value *pObj)
  9520  {
  9521  	if((pObj->iFlags & MEMOBJ_REAL) == 0 ){
  9522  		/* Preform the conversion */
  9523  		pObj->x.rVal = MemObjRealValue(&(*pObj));
  9524  		/* Invalidate any prior representations */
  9525  		SyBlobRelease(&pObj->sBlob);
  9526  		MemObjSetType(pObj, MEMOBJ_REAL);
  9527  	}
  9528  	return SXRET_OK;
  9529  }
  9530  /*
  9531   * Convert a vedis_value to type boolean.Invalidate any prior representations.
  9532   */
  9533  VEDIS_PRIVATE sxi32 vedisMemObjToBool(vedis_value *pObj)
  9534  {
  9535  	if( (pObj->iFlags & MEMOBJ_BOOL) == 0 ){
  9536  		/* Preform the conversion */
  9537  		pObj->x.iVal = MemObjBooleanValue(&(*pObj));
  9538  		/* Invalidate any prior representations */
  9539  		SyBlobRelease(&pObj->sBlob);
  9540  		MemObjSetType(pObj, MEMOBJ_BOOL);
  9541  	}
  9542  	return SXRET_OK;
  9543  }
  9544  /*
  9545   * Convert a vedis_value to type string. Prior representations are NOT invalidated.
  9546   */
  9547  VEDIS_PRIVATE sxi32 vedisMemObjToString(vedis_value *pObj)
  9548  {
  9549  	sxi32 rc = SXRET_OK;
  9550  	if( (pObj->iFlags & MEMOBJ_STRING) == 0 ){
  9551  		/* Perform the conversion */
  9552  		SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */
  9553  		rc = MemObjStringValue(&pObj->sBlob, &(*pObj));
  9554  		MemObjSetType(pObj, MEMOBJ_STRING);
  9555  	}
  9556  	return rc;
  9557  }
  9558  /*
  9559   * Nullify a vedis_value.In other words invalidate any prior
  9560   * representation.
  9561   */
  9562  VEDIS_PRIVATE sxi32 vedisMemObjToNull(vedis_value *pObj)
  9563  {
  9564  	return vedisMemObjRelease(pObj);
  9565  }
  9566  /*
  9567   * Invalidate any prior representation of a given vedis_value.
  9568   */
  9569  VEDIS_PRIVATE sxi32 vedisMemObjRelease(vedis_value *pObj)
  9570  {
  9571  	if( (pObj->iFlags & MEMOBJ_NULL) == 0 ){
  9572  		if( pObj->iFlags & MEMOBJ_HASHMAP ){
  9573  			vedisHashmapUnref((vedis_hashmap *)pObj->x.pOther);
  9574  		}
  9575  		/* Release the internal buffer */
  9576  		SyBlobRelease(&pObj->sBlob);
  9577  		/* Invalidate any prior representation */
  9578  		pObj->iFlags = MEMOBJ_NULL;
  9579  	}
  9580  	return SXRET_OK;
  9581  }
  9582  /*
  9583   * Duplicate the contents of a vedis_value.
  9584   */
  9585  VEDIS_PRIVATE sxi32 vedisMemObjStore(vedis_value *pSrc,vedis_value *pDest)
  9586  {
  9587  	vedis_hashmap *pMap = 0;
  9588  	sxi32 rc;
  9589  	if( pSrc->iFlags & MEMOBJ_HASHMAP ){
  9590  		/* Increment reference count */
  9591  		vedisHashmapRef((vedis_hashmap *)pSrc->x.pOther);
  9592  	}
  9593  	if( pDest->iFlags & MEMOBJ_HASHMAP ){
  9594  		pMap = (vedis_hashmap *)pDest->x.pOther;
  9595  	}
  9596  	SyMemcpy((const void *)&(*pSrc), &(*pDest), sizeof(vedis_value)-sizeof(SyBlob));
  9597  	rc = SXRET_OK;
  9598  	if( SyBlobLength(&pSrc->sBlob) > 0 ){
  9599  		SyBlobReset(&pDest->sBlob);
  9600  		rc = SyBlobDup(&pSrc->sBlob, &pDest->sBlob);
  9601  	}else{
  9602  		if( SyBlobLength(&pDest->sBlob) > 0 ){
  9603  			SyBlobRelease(&pDest->sBlob);
  9604  		}
  9605  	}
  9606  	if( pMap ){
  9607  		vedisHashmapUnref(pMap);
  9608  	}
  9609  	return rc;
  9610  }
  9611  VEDIS_PRIVATE void vedisMemObjInit(vedis *pVedis,vedis_value *pObj)
  9612  {
  9613  	/* Zero the structure */
  9614  	SyZero(pObj,sizeof(vedis_value));
  9615  	/* Init */
  9616  	SyBlobInit(&pObj->sBlob,&pVedis->sMem);
  9617  	/* Set the NULL type */
  9618  	pObj->iFlags = MEMOBJ_NULL;
  9619  }
  9620  /*
  9621   * Initialize a vedis_value to the integer type.
  9622   */
  9623  VEDIS_PRIVATE sxi32 vedisMemObjInitFromInt(vedis *pStore, vedis_value *pObj, sxi64 iVal)
  9624  {
  9625  	/* Zero the structure */
  9626  	SyZero(pObj, sizeof(vedis_value));
  9627  	/* Initialize fields */
  9628  	SyBlobInit(&pObj->sBlob, &pStore->sMem);
  9629  	/* Set the desired type */
  9630  	pObj->x.iVal = iVal;
  9631  	pObj->iFlags = MEMOBJ_INT;
  9632  	return SXRET_OK;
  9633  }
  9634  /*
  9635   * Initialize a vedis_value to the string type.
  9636   */
  9637  VEDIS_PRIVATE sxi32 vedisMemObjInitFromString(vedis *pStore, vedis_value *pObj, const SyString *pVal)
  9638  {
  9639  	/* Zero the structure */
  9640  	SyZero(pObj, sizeof(vedis_value));
  9641  	/* Initialize fields */
  9642  	SyBlobInit(&pObj->sBlob, &pStore->sMem);
  9643  	if( pVal && pVal->nByte > 0){
  9644  		/* Append contents */
  9645  		SyBlobAppend(&pObj->sBlob, (const void *)pVal->zString, pVal->nByte);
  9646  	}
  9647  	/* Set the desired type */
  9648  	pObj->iFlags = MEMOBJ_STRING;
  9649  	return SXRET_OK;
  9650  }
  9651  VEDIS_PRIVATE vedis_value * vedisNewObjectValue(vedis *pVedis,SyToken *pToken)
  9652  {
  9653  	vedis_value *pObj;
  9654  	/* Allocate a new instance */
  9655  	pObj = (vedis_value *)SyMemBackendPoolAlloc(&pVedis->sMem,sizeof(vedis_value));
  9656  	if( pObj == 0 ){
  9657  		return 0;
  9658  	}
  9659  	if( pToken ){
  9660  		SyString *pValue = &pToken->sData;
  9661  		/* Switch to the appropriate type */
  9662  		vedisMemObjInitFromString(pVedis,pObj,pValue);
  9663  		if( pToken->nType & VEDIS_TK_INTEGER ){
  9664  			vedisMemObjToInteger(pObj);
  9665  		}else if( pToken->nType & VEDIS_TK_REAL ){
  9666  			vedisMemObjToReal(pObj);
  9667  		}
  9668  	}else{
  9669  		/* Default to nil */
  9670  		vedisMemObjInit(pVedis,pObj);
  9671  	}
  9672  	return pObj;
  9673  }
  9674  VEDIS_PRIVATE vedis_value * vedisNewObjectArrayValue(vedis *pVedis)
  9675  {
  9676  	vedis_hashmap *pMap;
  9677  	vedis_value *pObj;
  9678  	/* Allocate a new instance */
  9679  	pObj = (vedis_value *)SyMemBackendPoolAlloc(&pVedis->sMem,sizeof(vedis_value));
  9680  	if( pObj == 0 ){
  9681  		return 0;
  9682  	}
  9683  	vedisMemObjInit(pVedis,pObj);
  9684  	/* Allocate a new hashmap instance */
  9685  	pMap = vedisNewHashmap(pVedis,0,0); 
  9686  	if( pMap == 0 ){
  9687  		/* Discard */
  9688  		SyMemBackendPoolFree(&pVedis->sMem,pObj);
  9689  		return 0;
  9690  	}
  9691  	/* Set the array type */
  9692  	MemObjSetType(pObj, MEMOBJ_HASHMAP);
  9693  	pObj->x.pOther = pMap;
  9694  	return pObj;
  9695  }
  9696  VEDIS_PRIVATE void vedisObjectValueDestroy(vedis *pVedis,vedis_value *pValue)
  9697  {
  9698  	/* Invalidate any prior representation */
  9699  	vedisMemObjRelease(pValue);
  9700  	/* Discard */
  9701  	SyMemBackendPoolFree(&pVedis->sMem,pValue);
  9702  }
  9703  VEDIS_PRIVATE SyBlob * vedisObjectValueBlob(vedis_value *pValue)
  9704  {
  9705  	return &pValue->sBlob;
  9706  }
  9707  /*
  9708   * ----------------------------------------------------------
  9709   * File: mem_kv.c
  9710   * MD5: 1ca85d6c931aac2bd2a40b799a91125a
  9711   * ----------------------------------------------------------
  9712   */
  9713  /*
  9714   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
  9715   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
  9716   * Version 1.1.6
  9717   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
  9718   * please contact Symisc Systems via:
  9719   *       legal@symisc.net
  9720   *       licensing@symisc.net
  9721   *       contact@symisc.net
  9722   * or visit:
  9723   *      http://vedis.org/licensing.html
  9724   */
  9725   /* $SymiscID: mem_kv.c v1.7 Win7 2012-11-28 01:41 stable <chm@symisc.net> $ */
  9726  #ifndef VEDIS_AMALGAMATION
  9727  #include "vedisInt.h"
  9728  #endif
  9729  /* 
  9730   * This file implements an in-memory key value storage engine for Vedis.
  9731   * Note that this storage engine does not support transactions.
  9732   *
  9733   * Normaly, I (chm@symisc.net) planned to implement a red-black tree
  9734   * which is suitable for this kind of operation, but due to the lack
  9735   * of time, I decided to implement a tunned hashtable which everybody
  9736   * know works very well for this kind of operation.
  9737   * Again, I insist on a red-black tree implementation for future version
  9738   * of Unqlite.
  9739   */
  9740  /* Forward declaration */
  9741  typedef struct mem_hash_kv_engine mem_hash_kv_engine;
  9742  /*
  9743   * Each record is storead in an instance of the following structure.
  9744   */
  9745  typedef struct mem_hash_record mem_hash_record;
  9746  struct mem_hash_record
  9747  {
  9748  	mem_hash_kv_engine *pEngine;    /* Storage engine */
  9749  	sxu32 nHash;                    /* Hash of the key */
  9750  	const void *pKey;               /* Key */
  9751  	sxu32 nKeyLen;                  /* Key size (Max 1GB) */
  9752  	const void *pData;              /* Data */
  9753  	sxu32 nDataLen;                 /* Data length (Max 4GB) */
  9754  	mem_hash_record *pNext,*pPrev;  /* Link to other records */
  9755  	mem_hash_record *pNextHash,*pPrevHash; /* Collision link */
  9756  };
  9757  /*
  9758   * Each in-memory KV engine is represented by an instance
  9759   * of the following structure.
  9760   */
  9761  struct mem_hash_kv_engine
  9762  {
  9763  	const vedis_kv_io *pIo; /* IO methods: MUST be first */
  9764  	/* Private data */
  9765  	SyMemBackend sAlloc;        /* Private memory allocator */
  9766  	ProcHash    xHash;          /* Default hash function */
  9767  	ProcCmp     xCmp;           /* Default comparison function */
  9768  	sxu32 nRecord;              /* Total number of records  */
  9769  	sxu32 nBucket;              /* Bucket size: Must be a power of two */
  9770  	mem_hash_record **apBucket; /* Hash bucket */
  9771  	mem_hash_record *pFirst;    /* First inserted entry */
  9772  	mem_hash_record *pLast;     /* Last inserted entry */
  9773  };
  9774  /*
  9775   * Allocate a new hash record.
  9776   */
  9777  static mem_hash_record * MemHashNewRecord(
  9778  	mem_hash_kv_engine *pEngine,
  9779  	const void *pKey,int nKey,
  9780  	const void *pData,vedis_int64 nData,
  9781  	sxu32 nHash
  9782  	)
  9783  {
  9784  	SyMemBackend *pAlloc = &pEngine->sAlloc;
  9785  	mem_hash_record *pRecord;
  9786  	void *pDupData;
  9787  	sxu32 nByte;
  9788  	char *zPtr;
  9789  	
  9790  	/* Total number of bytes to alloc */
  9791  	nByte = sizeof(mem_hash_record) + nKey;
  9792  	/* Allocate a new instance */
  9793  	pRecord = (mem_hash_record *)SyMemBackendAlloc(pAlloc,nByte);
  9794  	if( pRecord == 0 ){
  9795  		return 0;
  9796  	}
  9797  	pDupData = (void *)SyMemBackendAlloc(pAlloc,(sxu32)nData);
  9798  	if( pDupData == 0 ){
  9799  		SyMemBackendFree(pAlloc,pRecord);
  9800  		return 0;
  9801  	}
  9802  	zPtr = (char *)pRecord;
  9803  	zPtr += sizeof(mem_hash_record);
  9804  	/* Zero the structure */
  9805  	SyZero(pRecord,sizeof(mem_hash_record));
  9806  	/* Fill in the structure */
  9807  	pRecord->pEngine = pEngine;
  9808  	pRecord->nDataLen = (sxu32)nData;
  9809  	pRecord->nKeyLen = (sxu32)nKey;
  9810  	pRecord->nHash = nHash;
  9811  	SyMemcpy(pKey,zPtr,pRecord->nKeyLen);
  9812  	pRecord->pKey = (const void *)zPtr;
  9813  	SyMemcpy(pData,pDupData,pRecord->nDataLen);
  9814  	pRecord->pData = pDupData;
  9815  	/* All done */
  9816  	return pRecord;
  9817  }
  9818  /*
  9819   * Install a given record in the hashtable.
  9820   */
  9821  static void MemHashLinkRecord(mem_hash_kv_engine *pEngine,mem_hash_record *pRecord)
  9822  {
  9823  	sxu32 nBucket = pRecord->nHash & (pEngine->nBucket - 1);
  9824  	pRecord->pNextHash = pEngine->apBucket[nBucket];
  9825  	if( pEngine->apBucket[nBucket] ){
  9826  		pEngine->apBucket[nBucket]->pPrevHash = pRecord;
  9827  	}
  9828  	pEngine->apBucket[nBucket] = pRecord;
  9829  	if( pEngine->pFirst == 0 ){
  9830  		pEngine->pFirst = pEngine->pLast = pRecord;
  9831  	}else{
  9832  		MACRO_LD_PUSH(pEngine->pLast,pRecord);
  9833  	}
  9834  	pEngine->nRecord++;
  9835  }
  9836  /*
  9837   * Unlink a given record from the hashtable.
  9838   */
  9839  static void MemHashUnlinkRecord(mem_hash_kv_engine *pEngine,mem_hash_record *pEntry)
  9840  {
  9841  	sxu32 nBucket = pEntry->nHash & (pEngine->nBucket - 1);
  9842  	SyMemBackend *pAlloc = &pEngine->sAlloc;
  9843  	if( pEntry->pPrevHash == 0 ){
  9844  		pEngine->apBucket[nBucket] = pEntry->pNextHash;
  9845  	}else{
  9846  		pEntry->pPrevHash->pNextHash = pEntry->pNextHash;
  9847  	}
  9848  	if( pEntry->pNextHash ){
  9849  		pEntry->pNextHash->pPrevHash = pEntry->pPrevHash;
  9850  	}
  9851  	MACRO_LD_REMOVE(pEngine->pLast,pEntry);
  9852  	if( pEntry == pEngine->pFirst ){
  9853  		pEngine->pFirst = pEntry->pPrev;
  9854  	}
  9855  	pEngine->nRecord--;
  9856  	/* Release the entry */
  9857  	SyMemBackendFree(pAlloc,(void *)pEntry->pData);
  9858  	SyMemBackendFree(pAlloc,pEntry); /* Key is also stored here */
  9859  }
  9860  /*
  9861   * Perform a lookup for a given entry.
  9862   */
  9863  static mem_hash_record * MemHashGetEntry(
  9864  	mem_hash_kv_engine *pEngine,
  9865  	const void *pKey,int nKeyLen
  9866  	)
  9867  {
  9868  	mem_hash_record *pEntry;
  9869  	sxu32 nHash,nBucket;
  9870  	/* Hash the entry */
  9871  	nHash = pEngine->xHash(pKey,(sxu32)nKeyLen);
  9872  	nBucket = nHash & (pEngine->nBucket - 1);
  9873  	pEntry = pEngine->apBucket[nBucket];
  9874  	for(;;){
  9875  		if( pEntry == 0 ){
  9876  			break;
  9877  		}
  9878  		if( pEntry->nHash == nHash && pEntry->nKeyLen == (sxu32)nKeyLen && 
  9879  			pEngine->xCmp(pEntry->pKey,pKey,pEntry->nKeyLen) == 0 ){
  9880  				return pEntry;
  9881  		}
  9882  		pEntry = pEntry->pNextHash;
  9883  	}
  9884  	/* No such entry */
  9885  	return 0;
  9886  }
  9887  /*
  9888   * Rehash all the entries in the given table.
  9889   */
  9890  static int MemHashGrowTable(mem_hash_kv_engine *pEngine)
  9891  {
  9892  	sxu32 nNewSize = pEngine->nBucket << 1;
  9893  	mem_hash_record *pEntry;
  9894  	mem_hash_record **apNew;
  9895  	sxu32 n,iBucket;
  9896  	/* Allocate a new larger table */
  9897  	apNew = (mem_hash_record **)SyMemBackendAlloc(&pEngine->sAlloc, nNewSize * sizeof(mem_hash_record *));
  9898  	if( apNew == 0 ){
  9899  		/* Not so fatal, simply a performance hit */
  9900  		return VEDIS_OK;
  9901  	}
  9902  	/* Zero the new table */
  9903  	SyZero((void *)apNew, nNewSize * sizeof(mem_hash_record *));
  9904  	/* Rehash all entries */
  9905  	n = 0;
  9906  	pEntry = pEngine->pLast;
  9907  	for(;;){
  9908  		
  9909  		/* Loop one */
  9910  		if( n >= pEngine->nRecord ){
  9911  			break;
  9912  		}
  9913  		pEntry->pNextHash = pEntry->pPrevHash = 0;
  9914  		/* Install in the new bucket */
  9915  		iBucket = pEntry->nHash & (nNewSize - 1);
  9916  		pEntry->pNextHash = apNew[iBucket];
  9917  		if( apNew[iBucket] ){
  9918  			apNew[iBucket]->pPrevHash = pEntry;
  9919  		}
  9920  		apNew[iBucket] = pEntry;
  9921  		/* Point to the next entry */
  9922  		pEntry = pEntry->pNext;
  9923  		n++;
  9924  
  9925  		/* Loop two */
  9926  		if( n >= pEngine->nRecord ){
  9927  			break;
  9928  		}
  9929  		pEntry->pNextHash = pEntry->pPrevHash = 0;
  9930  		/* Install in the new bucket */
  9931  		iBucket = pEntry->nHash & (nNewSize - 1);
  9932  		pEntry->pNextHash = apNew[iBucket];
  9933  		if( apNew[iBucket] ){
  9934  			apNew[iBucket]->pPrevHash = pEntry;
  9935  		}
  9936  		apNew[iBucket] = pEntry;
  9937  		/* Point to the next entry */
  9938  		pEntry = pEntry->pNext;
  9939  		n++;
  9940  
  9941  		/* Loop three */
  9942  		if( n >= pEngine->nRecord ){
  9943  			break;
  9944  		}
  9945  		pEntry->pNextHash = pEntry->pPrevHash = 0;
  9946  		/* Install in the new bucket */
  9947  		iBucket = pEntry->nHash & (nNewSize - 1);
  9948  		pEntry->pNextHash = apNew[iBucket];
  9949  		if( apNew[iBucket] ){
  9950  			apNew[iBucket]->pPrevHash = pEntry;
  9951  		}
  9952  		apNew[iBucket] = pEntry;
  9953  		/* Point to the next entry */
  9954  		pEntry = pEntry->pNext;
  9955  		n++;
  9956  
  9957  		/* Loop four */
  9958  		if( n >= pEngine->nRecord ){
  9959  			break;
  9960  		}
  9961  		pEntry->pNextHash = pEntry->pPrevHash = 0;
  9962  		/* Install in the new bucket */
  9963  		iBucket = pEntry->nHash & (nNewSize - 1);
  9964  		pEntry->pNextHash = apNew[iBucket];
  9965  		if( apNew[iBucket] ){
  9966  			apNew[iBucket]->pPrevHash = pEntry;
  9967  		}
  9968  		apNew[iBucket] = pEntry;
  9969  		/* Point to the next entry */
  9970  		pEntry = pEntry->pNext;
  9971  		n++;
  9972  	}
  9973  	/* Release the old table and reflect the change */
  9974  	SyMemBackendFree(&pEngine->sAlloc,(void *)pEngine->apBucket);
  9975  	pEngine->apBucket = apNew;
  9976  	pEngine->nBucket  = nNewSize;
  9977  	return VEDIS_OK;
  9978  }
  9979  /*
  9980   * Exported Interfaces.
  9981   */
  9982  /*
  9983   * Each public cursor is identified by an instance of this structure.
  9984   */
  9985  typedef struct mem_hash_cursor mem_hash_cursor;
  9986  struct mem_hash_cursor
  9987  {
  9988  	vedis_kv_engine *pStore; /* Must be first */
  9989  	/* Private fields */
  9990  	mem_hash_record *pCur;     /* Current hash record */
  9991  };
  9992  /*
  9993   * Initialize the cursor.
  9994   */
  9995  static void MemHashInitCursor(vedis_kv_cursor *pCursor)
  9996  {
  9997  	 mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore;
  9998  	 mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
  9999  	 /* Point to the first inserted entry */
 10000  	 pMem->pCur = pEngine->pFirst;
 10001  }
 10002  /*
 10003   * Point to the first entry.
 10004   */
 10005  static int MemHashCursorFirst(vedis_kv_cursor *pCursor)
 10006  {
 10007  	 mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore;
 10008  	 mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10009  	 pMem->pCur = pEngine->pFirst;
 10010  	 return VEDIS_OK;
 10011  }
 10012  /*
 10013   * Point to the last entry.
 10014   */
 10015  static int MemHashCursorLast(vedis_kv_cursor *pCursor)
 10016  {
 10017  	 mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore;
 10018  	 mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10019  	 pMem->pCur = pEngine->pLast;
 10020  	 return VEDIS_OK;
 10021  }
 10022  /*
 10023   * is a Valid Cursor.
 10024   */
 10025  static int MemHashCursorValid(vedis_kv_cursor *pCursor)
 10026  {
 10027  	 mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10028  	 return pMem->pCur != 0 ? 1 : 0;
 10029  }
 10030  /*
 10031   * Point to the next entry.
 10032   */
 10033  static int MemHashCursorNext(vedis_kv_cursor *pCursor)
 10034  {
 10035  	 mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10036  	 if( pMem->pCur == 0){
 10037  		 return VEDIS_EOF;
 10038  	 }
 10039  	 pMem->pCur = pMem->pCur->pPrev; /* Reverse link: Not a Bug */
 10040  	 return VEDIS_OK;
 10041  }
 10042  /*
 10043   * Point to the previous entry.
 10044   */
 10045  static int MemHashCursorPrev(vedis_kv_cursor *pCursor)
 10046  {
 10047  	 mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10048  	 if( pMem->pCur == 0){
 10049  		 return VEDIS_EOF;
 10050  	 }
 10051  	 pMem->pCur = pMem->pCur->pNext; /* Reverse link: Not a Bug */
 10052  	 return VEDIS_OK;
 10053  }
 10054  /*
 10055   * Return key length.
 10056   */
 10057  static int MemHashCursorKeyLength(vedis_kv_cursor *pCursor,int *pLen)
 10058  {
 10059  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10060  	if( pMem->pCur == 0){
 10061  		 return VEDIS_EOF;
 10062  	}
 10063  	*pLen = (int)pMem->pCur->nKeyLen;
 10064  	return VEDIS_OK;
 10065  }
 10066  /*
 10067   * Return data length.
 10068   */
 10069  static int MemHashCursorDataLength(vedis_kv_cursor *pCursor,vedis_int64 *pLen)
 10070  {
 10071  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10072  	if( pMem->pCur == 0 ){
 10073  		 return VEDIS_EOF;
 10074  	}
 10075  	*pLen = pMem->pCur->nDataLen;
 10076  	return VEDIS_OK;
 10077  }
 10078  /*
 10079   * Consume the key.
 10080   */
 10081  static int MemHashCursorKey(vedis_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 10082  {
 10083  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10084  	int rc;
 10085  	if( pMem->pCur == 0){
 10086  		 return VEDIS_EOF;
 10087  	}
 10088  	/* Invoke the callback */
 10089  	rc = xConsumer(pMem->pCur->pKey,pMem->pCur->nKeyLen,pUserData);
 10090  	/* Callback result */
 10091  	return rc;
 10092  }
 10093  /*
 10094   * Consume the data.
 10095   */
 10096  static int MemHashCursorData(vedis_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 10097  {
 10098  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10099  	int rc;
 10100  	if( pMem->pCur == 0){
 10101  		 return VEDIS_EOF;
 10102  	}
 10103  	/* Invoke the callback */
 10104  	rc = xConsumer(pMem->pCur->pData,pMem->pCur->nDataLen,pUserData);
 10105  	/* Callback result */
 10106  	return rc;
 10107  }
 10108  /*
 10109   * Reset the cursor.
 10110   */
 10111  static void MemHashCursorReset(vedis_kv_cursor *pCursor)
 10112  {
 10113  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10114  	pMem->pCur = ((mem_hash_kv_engine *)pCursor->pStore)->pFirst;
 10115  }
 10116  /*
 10117   * Remove a particular record.
 10118   */
 10119  static int MemHashCursorDelete(vedis_kv_cursor *pCursor)
 10120  {
 10121  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10122  	mem_hash_record *pNext;
 10123  	if( pMem->pCur == 0 ){
 10124  		/* Cursor does not point to anything */
 10125  		return VEDIS_NOTFOUND;
 10126  	}
 10127  	pNext = pMem->pCur->pPrev;
 10128  	/* Perform the deletion */
 10129  	MemHashUnlinkRecord(pMem->pCur->pEngine,pMem->pCur);
 10130  	/* Point to the next entry */
 10131  	pMem->pCur = pNext;
 10132  	return VEDIS_OK;
 10133  }
 10134  /*
 10135   * Find a particular record.
 10136   */
 10137  static int MemHashCursorSeek(vedis_kv_cursor *pCursor,const void *pKey,int nByte,int iPos)
 10138  {
 10139  	mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore;
 10140  	mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor;
 10141  	/* Perform the lookup */
 10142  	pMem->pCur = MemHashGetEntry(pEngine,pKey,nByte);
 10143  	if( pMem->pCur == 0 ){
 10144  		if( iPos != VEDIS_CURSOR_MATCH_EXACT ){
 10145  			/* noop; */
 10146  		}
 10147  		/* No such record */
 10148  		return VEDIS_NOTFOUND;
 10149  	}
 10150  	return VEDIS_OK;
 10151  }
 10152  /*
 10153   * Builtin hash function.
 10154   */
 10155  static sxu32 MemHashFunc(const void *pSrc,sxu32 nLen)
 10156  {
 10157  	register unsigned char *zIn = (unsigned char *)pSrc;
 10158  	unsigned char *zEnd;
 10159  	sxu32 nH = 5381;
 10160  	zEnd = &zIn[nLen];
 10161  	for(;;){
 10162  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 10163  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 10164  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 10165  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 10166  	}	
 10167  	return nH;
 10168  }
 10169  /* Default bucket size */
 10170  #define MEM_HASH_BUCKET_SIZE 64
 10171  /* Default fill factor */
 10172  #define MEM_HASH_FILL_FACTOR 4 /* or 3 */
 10173  /*
 10174   * Initialize the in-memory storage engine.
 10175   */
 10176  static int MemHashInit(vedis_kv_engine *pKvEngine,int iPageSize)
 10177  {
 10178  	mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKvEngine;
 10179  	/* Note that this instance is already zeroed */	
 10180  	/* Memory backend */
 10181  	SyMemBackendInitFromParent(&pEngine->sAlloc,vedisExportMemBackend());
 10182  #if defined(VEDIS_ENABLE_THREADS)
 10183  	/* Already protected by the upper layers */
 10184  	SyMemBackendDisbaleMutexing(&pEngine->sAlloc);
 10185  #endif
 10186  	/* Default hash & comparison function */
 10187  	pEngine->xHash = MemHashFunc;
 10188  	pEngine->xCmp = SyMemcmp;
 10189  	/* Allocate a new bucket */
 10190  	pEngine->apBucket = (mem_hash_record **)SyMemBackendAlloc(&pEngine->sAlloc,MEM_HASH_BUCKET_SIZE * sizeof(mem_hash_record *));
 10191  	if( pEngine->apBucket == 0 ){
 10192  		SXUNUSED(iPageSize); /* cc warning */
 10193  		return VEDIS_NOMEM;
 10194  	}
 10195  	/* Zero the bucket */
 10196  	SyZero(pEngine->apBucket,MEM_HASH_BUCKET_SIZE * sizeof(mem_hash_record *));
 10197  	pEngine->nRecord = 0;
 10198  	pEngine->nBucket = MEM_HASH_BUCKET_SIZE;
 10199  	return VEDIS_OK;
 10200  }
 10201  /*
 10202   * Release the in-memory storage engine.
 10203   */
 10204  static void MemHashRelease(vedis_kv_engine *pKvEngine)
 10205  {
 10206  	mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKvEngine;
 10207  	/* Release the private memory backend */
 10208  	SyMemBackendRelease(&pEngine->sAlloc);
 10209  }
 10210  /*
 10211   * Configure the in-memory storage engine.
 10212   */
 10213  static int MemHashConfigure(vedis_kv_engine *pKvEngine,int iOp,va_list ap)
 10214  {
 10215  	mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKvEngine;
 10216  	int rc = VEDIS_OK;
 10217  	switch(iOp){
 10218  	case VEDIS_KV_CONFIG_HASH_FUNC:{
 10219  		/* Use a default hash function */
 10220  		if( pEngine->nRecord > 0 ){
 10221  			rc = VEDIS_LOCKED;
 10222  		}else{
 10223  			ProcHash xHash = va_arg(ap,ProcHash);
 10224  			if( xHash ){
 10225  				pEngine->xHash = xHash;
 10226  			}
 10227  		}
 10228  		break;
 10229  									 }
 10230  	case VEDIS_KV_CONFIG_CMP_FUNC: {
 10231  		/* Default comparison function */
 10232  		ProcCmp xCmp = va_arg(ap,ProcCmp);
 10233  		if( xCmp ){
 10234  			pEngine->xCmp = xCmp;
 10235  		}
 10236  		break;
 10237  									 }
 10238  	default:
 10239  		/* Unknown configuration option */
 10240  		rc = VEDIS_UNKNOWN;
 10241  	}
 10242  	return rc;
 10243  }
 10244  /*
 10245   * Replace method.
 10246   */
 10247  static int MemHashReplace(
 10248  	  vedis_kv_engine *pKv,
 10249  	  const void *pKey,int nKeyLen,
 10250  	  const void *pData,vedis_int64 nDataLen
 10251  	  )
 10252  {
 10253  	mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKv;
 10254  	mem_hash_record *pRecord;
 10255  	if( nDataLen > SXU32_HIGH ){
 10256  		/* Database limit */
 10257  		pEngine->pIo->xErr(pEngine->pIo->pHandle,"Record size limit reached");
 10258  		return VEDIS_LIMIT;
 10259  	}
 10260  	/* Fetch the record first */
 10261  	pRecord = MemHashGetEntry(pEngine,pKey,nKeyLen);
 10262  	if( pRecord == 0 ){
 10263  		/* Allocate a new record */
 10264  		pRecord = MemHashNewRecord(pEngine,
 10265  			pKey,nKeyLen,
 10266  			pData,nDataLen,
 10267  			pEngine->xHash(pKey,nKeyLen)
 10268  			);
 10269  		if( pRecord == 0 ){
 10270  			return VEDIS_NOMEM;
 10271  		}
 10272  		/* Link the entry */
 10273  		MemHashLinkRecord(pEngine,pRecord);
 10274  		if( (pEngine->nRecord >= pEngine->nBucket * MEM_HASH_FILL_FACTOR) && pEngine->nRecord < 100000 ){
 10275  			/* Rehash the table */
 10276  			MemHashGrowTable(pEngine);
 10277  		}
 10278  	}else{
 10279  		sxu32 nData = (sxu32)nDataLen;
 10280  		void *pNew;
 10281  		/* Replace an existing record */
 10282  		if( nData == pRecord->nDataLen ){
 10283  			/* No need to free the old chunk */
 10284  			pNew = (void *)pRecord->pData;
 10285  		}else{
 10286  			pNew = SyMemBackendAlloc(&pEngine->sAlloc,nData);
 10287  			if( pNew == 0 ){
 10288  				return VEDIS_NOMEM;
 10289  			}
 10290  			/* Release the old data */
 10291  			SyMemBackendFree(&pEngine->sAlloc,(void *)pRecord->pData);
 10292  		}
 10293  		/* Reflect the change */
 10294  		pRecord->nDataLen = nData;
 10295  		SyMemcpy(pData,pNew,nData);
 10296  		pRecord->pData = pNew;
 10297  	}
 10298  	return VEDIS_OK;
 10299  }
 10300  /*
 10301   * Append method.
 10302   */
 10303  static int MemHashAppend(
 10304  	  vedis_kv_engine *pKv,
 10305  	  const void *pKey,int nKeyLen,
 10306  	  const void *pData,vedis_int64 nDataLen
 10307  	  )
 10308  {
 10309  	mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKv;
 10310  	mem_hash_record *pRecord;
 10311  	if( nDataLen > SXU32_HIGH ){
 10312  		/* Database limit */
 10313  		pEngine->pIo->xErr(pEngine->pIo->pHandle,"Record size limit reached");
 10314  		return VEDIS_LIMIT;
 10315  	}
 10316  	/* Fetch the record first */
 10317  	pRecord = MemHashGetEntry(pEngine,pKey,nKeyLen);
 10318  	if( pRecord == 0 ){
 10319  		/* Allocate a new record */
 10320  		pRecord = MemHashNewRecord(pEngine,
 10321  			pKey,nKeyLen,
 10322  			pData,nDataLen,
 10323  			pEngine->xHash(pKey,nKeyLen)
 10324  			);
 10325  		if( pRecord == 0 ){
 10326  			return VEDIS_NOMEM;
 10327  		}
 10328  		/* Link the entry */
 10329  		MemHashLinkRecord(pEngine,pRecord);
 10330  		if( pEngine->nRecord * MEM_HASH_FILL_FACTOR >= pEngine->nBucket && pEngine->nRecord < 100000 ){
 10331  			/* Rehash the table */
 10332  			MemHashGrowTable(pEngine);
 10333  		}
 10334  	}else{
 10335  		vedis_int64 nNew = pRecord->nDataLen + nDataLen;
 10336  		void *pOld = (void *)pRecord->pData;
 10337  		sxu32 nData;
 10338  		char *zNew;
 10339  		/* Append data to the existing record */
 10340  		if( nNew > SXU32_HIGH ){
 10341  			/* Overflow */
 10342  			pEngine->pIo->xErr(pEngine->pIo->pHandle,"Append operation will cause data overflow");	
 10343  			return VEDIS_LIMIT;
 10344  		}
 10345  		nData = (sxu32)nNew;
 10346  		/* Allocate bigger chunk */
 10347  		zNew = (char *)SyMemBackendRealloc(&pEngine->sAlloc,pOld,nData);
 10348  		if( zNew == 0 ){
 10349  			return VEDIS_NOMEM;
 10350  		}
 10351  		/* Reflect the change */
 10352  		SyMemcpy(pData,&zNew[pRecord->nDataLen],(sxu32)nDataLen);
 10353  		pRecord->pData = (const void *)zNew;
 10354  		pRecord->nDataLen = nData;
 10355  	}
 10356  	return VEDIS_OK;
 10357  }
 10358  /*
 10359   * Export the in-memory storage engine.
 10360   */
 10361  VEDIS_PRIVATE const vedis_kv_methods * vedisExportMemKvStorage(void)
 10362  {
 10363  	static const vedis_kv_methods sMemStore = {
 10364  		"mem",                      /* zName */
 10365  		sizeof(mem_hash_kv_engine), /* szKv */
 10366  		sizeof(mem_hash_cursor),    /* szCursor */
 10367  		1,                          /* iVersion */
 10368  		MemHashInit,                /* xInit */
 10369  		MemHashRelease,             /* xRelease */
 10370  		MemHashConfigure,           /* xConfig */
 10371  		0,                          /* xOpen */
 10372  		MemHashReplace,             /* xReplace */
 10373  		MemHashAppend,              /* xAppend */
 10374  		MemHashInitCursor,          /* xCursorInit */
 10375  		MemHashCursorSeek,          /* xSeek */
 10376  		MemHashCursorFirst,         /* xFirst */
 10377  		MemHashCursorLast,          /* xLast */
 10378  		MemHashCursorValid,         /* xValid */
 10379  		MemHashCursorNext,          /* xNext */
 10380  		MemHashCursorPrev,          /* xPrev */
 10381  		MemHashCursorDelete,        /* xDelete */
 10382  		MemHashCursorKeyLength,     /* xKeyLength */
 10383  		MemHashCursorKey,           /* xKey */
 10384  		MemHashCursorDataLength,    /* xDataLength */
 10385  		MemHashCursorData,          /* xData */
 10386  		MemHashCursorReset,         /* xReset */
 10387  		0        /* xRelease */                        
 10388  	};
 10389  	return &sMemStore;
 10390  }
 10391  /*
 10392   * ----------------------------------------------------------
 10393   * File: lib.c
 10394   * MD5: 5c88bf62c65357b1845e119f319d9721
 10395   * ----------------------------------------------------------
 10396   */
 10397  /*
 10398   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
 10399   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
 10400   * Version 1.2.6
 10401   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 10402   * please contact Symisc Systems via:
 10403   *       legal@symisc.net
 10404   *       licensing@symisc.net
 10405   *       contact@symisc.net
 10406   * or visit:
 10407   *      http://vedis.symisc.net/
 10408   */
 10409   /* $SymiscID: lib.c v5.1 Win7 2012-08-08 04:19 stable <chm@symisc.net> $ */
 10410  /*
 10411   * Symisc Run-Time API: A modern thread safe replacement of the standard libc
 10412   * Copyright (C) Symisc Systems 2007-2012, http://www.symisc.net/
 10413   *
 10414   * The Symisc Run-Time API is an independent project developed by symisc systems
 10415   * internally as a secure replacement of the standard libc.
 10416   * The library is re-entrant, thread-safe and platform independent.
 10417   */
 10418  #ifndef VEDIS_AMALGAMATION
 10419  #include "vedisInt.h"
 10420  #endif
 10421  #if defined(__WINNT__)
 10422  #include <Windows.h>
 10423  #else
 10424  #include <stdlib.h>
 10425  #endif
 10426  #if defined(VEDIS_ENABLE_THREADS)
 10427  /* SyRunTimeApi: sxmutex.c */
 10428  #if defined(__WINNT__)
 10429  struct SyMutex
 10430  {
 10431  	CRITICAL_SECTION sMutex;
 10432  	sxu32 nType; /* Mutex type, one of SXMUTEX_TYPE_* */
 10433  };
 10434  /* Preallocated static mutex */
 10435  static SyMutex aStaticMutexes[] = {
 10436  		{{0}, SXMUTEX_TYPE_STATIC_1}, 
 10437  		{{0}, SXMUTEX_TYPE_STATIC_2}, 
 10438  		{{0}, SXMUTEX_TYPE_STATIC_3}, 
 10439  		{{0}, SXMUTEX_TYPE_STATIC_4}, 
 10440  		{{0}, SXMUTEX_TYPE_STATIC_5}, 
 10441  		{{0}, SXMUTEX_TYPE_STATIC_6}
 10442  };
 10443  static BOOL winMutexInit = FALSE;
 10444  static LONG winMutexLock = 0;
 10445  
 10446  static sxi32 WinMutexGlobaInit(void)
 10447  {
 10448  	LONG rc;
 10449  	rc = InterlockedCompareExchange(&winMutexLock, 1, 0);
 10450  	if ( rc == 0 ){
 10451  		sxu32 n;
 10452  		for( n = 0 ; n  < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){
 10453  			InitializeCriticalSection(&aStaticMutexes[n].sMutex);
 10454  		}
 10455  		winMutexInit = TRUE;
 10456  	}else{
 10457  		/* Someone else is doing this for us */
 10458  		while( winMutexInit == FALSE ){
 10459  			Sleep(1);
 10460  		}
 10461  	}
 10462  	return SXRET_OK;
 10463  }
 10464  static void WinMutexGlobalRelease(void)
 10465  {
 10466  	LONG rc;
 10467  	rc = InterlockedCompareExchange(&winMutexLock, 0, 1);
 10468  	if( rc == 1 ){
 10469  		/* The first to decrement to zero does the actual global release */
 10470  		if( winMutexInit == TRUE ){
 10471  			sxu32 n;
 10472  			for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){
 10473  				DeleteCriticalSection(&aStaticMutexes[n].sMutex);
 10474  			}
 10475  			winMutexInit = FALSE;
 10476  		}
 10477  	}
 10478  }
 10479  static SyMutex * WinMutexNew(int nType)
 10480  {
 10481  	SyMutex *pMutex = 0;
 10482  	if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){
 10483  		/* Allocate a new mutex */
 10484  		pMutex = (SyMutex *)HeapAlloc(GetProcessHeap(), 0, sizeof(SyMutex));
 10485  		if( pMutex == 0 ){
 10486  			return 0;
 10487  		}
 10488  		InitializeCriticalSection(&pMutex->sMutex);
 10489  	}else{
 10490  		/* Use a pre-allocated static mutex */
 10491  		if( nType > SXMUTEX_TYPE_STATIC_6 ){
 10492  			nType = SXMUTEX_TYPE_STATIC_6;
 10493  		}
 10494  		pMutex = &aStaticMutexes[nType - 3];
 10495  	}
 10496  	pMutex->nType = nType;
 10497  	return pMutex;
 10498  }
 10499  static void WinMutexRelease(SyMutex *pMutex)
 10500  {
 10501  	if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){
 10502  		DeleteCriticalSection(&pMutex->sMutex);
 10503  		HeapFree(GetProcessHeap(), 0, pMutex);
 10504  	}
 10505  }
 10506  static void WinMutexEnter(SyMutex *pMutex)
 10507  {
 10508  	EnterCriticalSection(&pMutex->sMutex);
 10509  }
 10510  static sxi32 WinMutexTryEnter(SyMutex *pMutex)
 10511  {
 10512  #ifdef _WIN32_WINNT
 10513  	BOOL rc;
 10514  	/* Only WindowsNT platforms */
 10515  	rc = TryEnterCriticalSection(&pMutex->sMutex);
 10516  	if( rc ){
 10517  		return SXRET_OK;
 10518  	}else{
 10519  		return SXERR_BUSY;
 10520  	}
 10521  #else
 10522  	return SXERR_NOTIMPLEMENTED;
 10523  #endif
 10524  }
 10525  static void WinMutexLeave(SyMutex *pMutex)
 10526  {
 10527  	LeaveCriticalSection(&pMutex->sMutex);
 10528  }
 10529  /* Export Windows mutex interfaces */
 10530  static const SyMutexMethods sWinMutexMethods = {
 10531  	WinMutexGlobaInit,  /* xGlobalInit() */
 10532  	WinMutexGlobalRelease, /* xGlobalRelease() */
 10533  	WinMutexNew,     /* xNew() */
 10534  	WinMutexRelease, /* xRelease() */
 10535  	WinMutexEnter,   /* xEnter() */
 10536  	WinMutexTryEnter, /* xTryEnter() */
 10537  	WinMutexLeave     /* xLeave() */
 10538  };
 10539  VEDIS_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
 10540  {
 10541  	return &sWinMutexMethods;
 10542  }
 10543  #elif defined(__UNIXES__)
 10544  #include <pthread.h>
 10545  struct SyMutex
 10546  {
 10547  	pthread_mutex_t sMutex;
 10548  	sxu32 nType;
 10549  };
 10550  static SyMutex * UnixMutexNew(int nType)
 10551  {
 10552  	static SyMutex aStaticMutexes[] = {
 10553  		{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_1}, 
 10554  		{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_2}, 
 10555  		{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_3}, 
 10556  		{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_4}, 
 10557  		{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_5}, 
 10558  		{PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_6}
 10559  	};
 10560  	SyMutex *pMutex;
 10561  	
 10562  	if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){
 10563  		pthread_mutexattr_t sRecursiveAttr;
 10564    		/* Allocate a new mutex */
 10565    		pMutex = (SyMutex *)malloc(sizeof(SyMutex));
 10566    		if( pMutex == 0 ){
 10567    			return 0;
 10568    		}
 10569    		if( nType == SXMUTEX_TYPE_RECURSIVE ){
 10570    			pthread_mutexattr_init(&sRecursiveAttr);
 10571    			pthread_mutexattr_settype(&sRecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
 10572    		}
 10573    		pthread_mutex_init(&pMutex->sMutex, nType == SXMUTEX_TYPE_RECURSIVE ? &sRecursiveAttr : 0 );
 10574  		if(	nType == SXMUTEX_TYPE_RECURSIVE ){
 10575     			pthread_mutexattr_destroy(&sRecursiveAttr);
 10576  		}
 10577  	}else{
 10578  		/* Use a pre-allocated static mutex */
 10579  		if( nType > SXMUTEX_TYPE_STATIC_6 ){
 10580  			nType = SXMUTEX_TYPE_STATIC_6;
 10581  		}
 10582  		pMutex = &aStaticMutexes[nType - 3];
 10583  	}
 10584    pMutex->nType = nType;
 10585    
 10586    return pMutex;
 10587  }
 10588  static void UnixMutexRelease(SyMutex *pMutex)
 10589  {
 10590  	if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){
 10591  		pthread_mutex_destroy(&pMutex->sMutex);
 10592  		free(pMutex);
 10593  	}
 10594  }
 10595  static void UnixMutexEnter(SyMutex *pMutex)
 10596  {
 10597  	pthread_mutex_lock(&pMutex->sMutex);
 10598  }
 10599  static void UnixMutexLeave(SyMutex *pMutex)
 10600  {
 10601  	pthread_mutex_unlock(&pMutex->sMutex);
 10602  }
 10603  /* Export pthread mutex interfaces */
 10604  static const SyMutexMethods sPthreadMutexMethods = {
 10605  	0, /* xGlobalInit() */
 10606  	0, /* xGlobalRelease() */
 10607  	UnixMutexNew,      /* xNew() */
 10608  	UnixMutexRelease,  /* xRelease() */
 10609  	UnixMutexEnter,    /* xEnter() */
 10610  	0,                 /* xTryEnter() */
 10611  	UnixMutexLeave     /* xLeave() */
 10612  };
 10613  VEDIS_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
 10614  {
 10615  	return &sPthreadMutexMethods;
 10616  }
 10617  #else
 10618  /* Host application must register their own mutex subsystem if the target
 10619   * platform is not an UNIX-like or windows systems.
 10620   */
 10621  struct SyMutex
 10622  {
 10623  	sxu32 nType;
 10624  };
 10625  static SyMutex * DummyMutexNew(int nType)
 10626  {
 10627  	static SyMutex sMutex;
 10628  	SXUNUSED(nType);
 10629  	return &sMutex;
 10630  }
 10631  static void DummyMutexRelease(SyMutex *pMutex)
 10632  {
 10633  	SXUNUSED(pMutex);
 10634  }
 10635  static void DummyMutexEnter(SyMutex *pMutex)
 10636  {
 10637  	SXUNUSED(pMutex);
 10638  }
 10639  static void DummyMutexLeave(SyMutex *pMutex)
 10640  {
 10641  	SXUNUSED(pMutex);
 10642  }
 10643  /* Export the dummy mutex interfaces */
 10644  static const SyMutexMethods sDummyMutexMethods = {
 10645  	0, /* xGlobalInit() */
 10646  	0, /* xGlobalRelease() */
 10647  	DummyMutexNew,      /* xNew() */
 10648  	DummyMutexRelease,  /* xRelease() */
 10649  	DummyMutexEnter,    /* xEnter() */
 10650  	0,                  /* xTryEnter() */
 10651  	DummyMutexLeave     /* xLeave() */
 10652  };
 10653  VEDIS_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
 10654  {
 10655  	return &sDummyMutexMethods;
 10656  }
 10657  #endif /* __WINNT__ */
 10658  #endif /* VEDIS_ENABLE_THREADS */
 10659  static void * SyOSHeapAlloc(sxu32 nByte)
 10660  {
 10661  	void *pNew;
 10662  #if defined(__WINNT__)
 10663  	pNew = HeapAlloc(GetProcessHeap(), 0, nByte);
 10664  #else
 10665  	pNew = malloc((size_t)nByte);
 10666  #endif
 10667  	return pNew;
 10668  }
 10669  static void * SyOSHeapRealloc(void *pOld, sxu32 nByte)
 10670  {
 10671  	void *pNew;
 10672  #if defined(__WINNT__)
 10673  	pNew = HeapReAlloc(GetProcessHeap(), 0, pOld, nByte);
 10674  #else
 10675  	pNew = realloc(pOld, (size_t)nByte);
 10676  #endif
 10677  	return pNew;	
 10678  }
 10679  static void SyOSHeapFree(void *pPtr)
 10680  {
 10681  #if defined(__WINNT__)
 10682  	HeapFree(GetProcessHeap(), 0, pPtr);
 10683  #else
 10684  	free(pPtr);
 10685  #endif
 10686  }
 10687  /* SyRunTimeApi:sxstr.c */
 10688  VEDIS_PRIVATE sxu32 SyStrlen(const char *zSrc)
 10689  {
 10690  	register const char *zIn = zSrc;
 10691  #if defined(UNTRUST)
 10692  	if( zIn == 0 ){
 10693  		return 0;
 10694  	}
 10695  #endif
 10696  	for(;;){
 10697  		if( !zIn[0] ){ break; } zIn++;
 10698  		if( !zIn[0] ){ break; } zIn++;
 10699  		if( !zIn[0] ){ break; } zIn++;
 10700  		if( !zIn[0] ){ break; } zIn++;	
 10701  	}
 10702  	return (sxu32)(zIn - zSrc);
 10703  }
 10704  #if defined(__APPLE__)
 10705  VEDIS_PRIVATE sxi32 SyStrncmp(const char *zLeft, const char *zRight, sxu32 nLen)
 10706  {
 10707  	const unsigned char *zP = (const unsigned char *)zLeft;
 10708  	const unsigned char *zQ = (const unsigned char *)zRight;
 10709  
 10710  	if( SX_EMPTY_STR(zP) || SX_EMPTY_STR(zQ)  ){
 10711  			return SX_EMPTY_STR(zP) ? (SX_EMPTY_STR(zQ) ? 0 : -1) :1;
 10712  	}
 10713  	if( nLen <= 0 ){
 10714  		return 0;
 10715  	}
 10716  	for(;;){
 10717  		if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
 10718  		if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
 10719  		if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
 10720  		if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
 10721  	}
 10722  	return (sxi32)(zP[0] - zQ[0]);
 10723  }	
 10724  #endif
 10725  VEDIS_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight, sxu32 SLen)
 10726  {
 10727    	register unsigned char *p = (unsigned char *)zLeft;
 10728  	register unsigned char *q = (unsigned char *)zRight;
 10729  	
 10730  	if( SX_EMPTY_STR(p) || SX_EMPTY_STR(q) ){
 10731  		return SX_EMPTY_STR(p)? SX_EMPTY_STR(q) ? 0 : -1 :1;
 10732  	}
 10733  	for(;;){
 10734  		if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
 10735  		if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
 10736  		if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
 10737  		if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
 10738  		
 10739  	}
 10740  	return (sxi32)(SyCharToLower(p[0]) - SyCharToLower(q[0]));
 10741  }
 10742  VEDIS_PRIVATE sxu32 Systrcpy(char *zDest, sxu32 nDestLen, const char *zSrc, sxu32 nLen)
 10743  {
 10744  	unsigned char *zBuf = (unsigned char *)zDest;
 10745  	unsigned char *zIn = (unsigned char *)zSrc;
 10746  	unsigned char *zEnd;
 10747  #if defined(UNTRUST)
 10748  	if( zSrc == (const char *)zDest ){
 10749  			return 0;
 10750  	}
 10751  #endif
 10752  	if( nLen <= 0 ){
 10753  		nLen = SyStrlen(zSrc);
 10754  	}
 10755  	zEnd = &zBuf[nDestLen - 1]; /* reserve a room for the null terminator */
 10756  	for(;;){
 10757  		if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
 10758  		if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
 10759  		if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
 10760  		if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
 10761  	}
 10762  	zBuf[0] = 0;
 10763  	return (sxu32)(zBuf-(unsigned char *)zDest);
 10764  }
 10765  /* SyRunTimeApi:sxmem.c */
 10766  VEDIS_PRIVATE void SyZero(void *pSrc, sxu32 nSize)
 10767  {
 10768  	register unsigned char *zSrc = (unsigned char *)pSrc;
 10769  	unsigned char *zEnd;
 10770  #if defined(UNTRUST)
 10771  	if( zSrc == 0 || nSize <= 0 ){
 10772  		return ;
 10773  	}
 10774  #endif
 10775  	zEnd = &zSrc[nSize];
 10776  	for(;;){
 10777  		if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
 10778  		if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
 10779  		if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
 10780  		if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
 10781  	}
 10782  }
 10783  VEDIS_PRIVATE sxi32 SyMemcmp(const void *pB1, const void *pB2, sxu32 nSize)
 10784  {
 10785  	sxi32 rc;
 10786  	if( nSize <= 0 ){
 10787  		return 0;
 10788  	}
 10789  	if( pB1 == 0 || pB2 == 0 ){
 10790  		return pB1 != 0 ? 1 : (pB2 == 0 ? 0 : -1);
 10791  	}
 10792  	SX_MACRO_FAST_CMP(pB1, pB2, nSize, rc);
 10793  	return rc;
 10794  }
 10795  VEDIS_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen)
 10796  {
 10797  	if( pSrc == 0 || pDest == 0 ){
 10798  		return 0;
 10799  	}
 10800  	if( pSrc == (const void *)pDest ){
 10801  		return nLen;
 10802  	}
 10803  	SX_MACRO_FAST_MEMCPY(pSrc, pDest, nLen);
 10804  	return nLen;
 10805  }
 10806  static void * MemOSAlloc(sxu32 nBytes)
 10807  {
 10808  	sxu32 *pChunk;
 10809  	pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32));
 10810  	if( pChunk == 0 ){
 10811  		return 0;
 10812  	}
 10813  	pChunk[0] = nBytes;
 10814  	return (void *)&pChunk[1];
 10815  }
 10816  static void * MemOSRealloc(void *pOld, sxu32 nBytes)
 10817  {
 10818  	sxu32 *pOldChunk;
 10819  	sxu32 *pChunk;
 10820  	pOldChunk = (sxu32 *)(((char *)pOld)-sizeof(sxu32));
 10821  	if( pOldChunk[0] >= nBytes ){
 10822  		return pOld;
 10823  	}
 10824  	pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk, nBytes + sizeof(sxu32));
 10825  	if( pChunk == 0 ){
 10826  		return 0;
 10827  	}
 10828  	pChunk[0] = nBytes;
 10829  	return (void *)&pChunk[1];
 10830  }
 10831  static void MemOSFree(void *pBlock)
 10832  {
 10833  	void *pChunk;
 10834  	pChunk = (void *)(((char *)pBlock)-sizeof(sxu32));
 10835  	SyOSHeapFree(pChunk);
 10836  }
 10837  static sxu32 MemOSChunkSize(void *pBlock)
 10838  {
 10839  	sxu32 *pChunk;
 10840  	pChunk = (sxu32 *)(((char *)pBlock)-sizeof(sxu32));
 10841  	return pChunk[0];
 10842  }
 10843  /* Export OS allocation methods */
 10844  static const SyMemMethods sOSAllocMethods = {
 10845  	MemOSAlloc, 
 10846  	MemOSRealloc, 
 10847  	MemOSFree, 
 10848  	MemOSChunkSize, 
 10849  	0, 
 10850  	0, 
 10851  	0
 10852  };
 10853  static void * MemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte)
 10854  {
 10855  	SyMemBlock *pBlock;
 10856  	sxi32 nRetry = 0;
 10857  
 10858  	/* Append an extra block so we can tracks allocated chunks and avoid memory
 10859  	 * leaks.
 10860  	 */
 10861  	nByte += sizeof(SyMemBlock);
 10862  	for(;;){
 10863  		pBlock = (SyMemBlock *)pBackend->pMethods->xAlloc(nByte);
 10864  		if( pBlock != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY 
 10865  			|| SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){
 10866  				break;
 10867  		}
 10868  		nRetry++;
 10869  	}
 10870  	if( pBlock  == 0 ){
 10871  		return 0;
 10872  	}
 10873  	pBlock->pNext = pBlock->pPrev = 0;
 10874  	/* Link to the list of already tracked blocks */
 10875  	MACRO_LD_PUSH(pBackend->pBlocks, pBlock);
 10876  #if defined(UNTRUST)
 10877  	pBlock->nGuard = SXMEM_BACKEND_MAGIC;
 10878  #endif
 10879  	pBackend->nBlock++;
 10880  	return (void *)&pBlock[1];
 10881  }
 10882  VEDIS_PRIVATE void * SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte)
 10883  {
 10884  	void *pChunk;
 10885  #if defined(UNTRUST)
 10886  	if( SXMEM_BACKEND_CORRUPT(pBackend) ){
 10887  		return 0;
 10888  	}
 10889  #endif
 10890  	if( pBackend->pMutexMethods ){
 10891  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 10892  	}
 10893  	pChunk = MemBackendAlloc(&(*pBackend), nByte);
 10894  	if( pBackend->pMutexMethods ){
 10895  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 10896  	}
 10897  	return pChunk;
 10898  }
 10899  static void * MemBackendRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
 10900  {
 10901  	SyMemBlock *pBlock, *pNew, *pPrev, *pNext;
 10902  	sxu32 nRetry = 0;
 10903  
 10904  	if( pOld == 0 ){
 10905  		return MemBackendAlloc(&(*pBackend), nByte);
 10906  	}
 10907  	pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock));
 10908  #if defined(UNTRUST)
 10909  	if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){
 10910  		return 0;
 10911  	}
 10912  #endif
 10913  	nByte += sizeof(SyMemBlock);
 10914  	pPrev = pBlock->pPrev;
 10915  	pNext = pBlock->pNext;
 10916  	for(;;){
 10917  		pNew = (SyMemBlock *)pBackend->pMethods->xRealloc(pBlock, nByte);
 10918  		if( pNew != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY ||
 10919  			SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){
 10920  				break;
 10921  		}
 10922  		nRetry++;
 10923  	}
 10924  	if( pNew == 0 ){
 10925  		return 0;
 10926  	}
 10927  	if( pNew != pBlock ){
 10928  		if( pPrev == 0 ){
 10929  			pBackend->pBlocks = pNew;
 10930  		}else{
 10931  			pPrev->pNext = pNew;
 10932  		}
 10933  		if( pNext ){
 10934  			pNext->pPrev = pNew;
 10935  		}
 10936  #if defined(UNTRUST)
 10937  		pNew->nGuard = SXMEM_BACKEND_MAGIC;
 10938  #endif
 10939  	}
 10940  	return (void *)&pNew[1];
 10941  }
 10942  VEDIS_PRIVATE void * SyMemBackendRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
 10943  {
 10944  	void *pChunk;
 10945  #if defined(UNTRUST)
 10946  	if( SXMEM_BACKEND_CORRUPT(pBackend)  ){
 10947  		return 0;
 10948  	}
 10949  #endif
 10950  	if( pBackend->pMutexMethods ){
 10951  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 10952  	}
 10953  	pChunk = MemBackendRealloc(&(*pBackend), pOld, nByte);
 10954  	if( pBackend->pMutexMethods ){
 10955  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 10956  	}
 10957  	return pChunk;
 10958  }
 10959  static sxi32 MemBackendFree(SyMemBackend *pBackend, void * pChunk)
 10960  {
 10961  	SyMemBlock *pBlock;
 10962  	pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock));
 10963  #if defined(UNTRUST)
 10964  	if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){
 10965  		return SXERR_CORRUPT;
 10966  	}
 10967  #endif
 10968  	/* Unlink from the list of active blocks */
 10969  	if( pBackend->nBlock > 0 ){
 10970  		/* Release the block */
 10971  #if defined(UNTRUST)
 10972  		/* Mark as stale block */
 10973  		pBlock->nGuard = 0x635B;
 10974  #endif
 10975  		MACRO_LD_REMOVE(pBackend->pBlocks, pBlock);
 10976  		pBackend->nBlock--;
 10977  		pBackend->pMethods->xFree(pBlock);
 10978  	}
 10979  	return SXRET_OK;
 10980  }
 10981  VEDIS_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend, void * pChunk)
 10982  {
 10983  	sxi32 rc;
 10984  #if defined(UNTRUST)
 10985  	if( SXMEM_BACKEND_CORRUPT(pBackend) ){
 10986  		return SXERR_CORRUPT;
 10987  	}
 10988  #endif
 10989  	if( pChunk == 0 ){
 10990  		return SXRET_OK;
 10991  	}
 10992  	if( pBackend->pMutexMethods ){
 10993  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 10994  	}
 10995  	rc = MemBackendFree(&(*pBackend), pChunk);
 10996  	if( pBackend->pMutexMethods ){
 10997  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 10998  	}
 10999  	return rc;
 11000  }
 11001  #if defined(VEDIS_ENABLE_THREADS)
 11002  VEDIS_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend, const SyMutexMethods *pMethods)
 11003  {
 11004  	SyMutex *pMutex;
 11005  #if defined(UNTRUST)
 11006  	if( SXMEM_BACKEND_CORRUPT(pBackend) || pMethods == 0 || pMethods->xNew == 0){
 11007  		return SXERR_CORRUPT;
 11008  	}
 11009  #endif
 11010  	pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
 11011  	if( pMutex == 0 ){
 11012  		return SXERR_OS;
 11013  	}
 11014  	/* Attach the mutex to the memory backend */
 11015  	pBackend->pMutex = pMutex;
 11016  	pBackend->pMutexMethods = pMethods;
 11017  	return SXRET_OK;
 11018  }
 11019  VEDIS_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend)
 11020  {
 11021  #if defined(UNTRUST)
 11022  	if( SXMEM_BACKEND_CORRUPT(pBackend) ){
 11023  		return SXERR_CORRUPT;
 11024  	}
 11025  #endif
 11026  	if( pBackend->pMutex == 0 ){
 11027  		/* There is no mutex subsystem at all */
 11028  		return SXRET_OK;
 11029  	}
 11030  	SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex);
 11031  	pBackend->pMutexMethods = 0;
 11032  	pBackend->pMutex = 0; 
 11033  	return SXRET_OK;
 11034  }
 11035  #endif
 11036  /*
 11037   * Memory pool allocator
 11038   */
 11039  #define SXMEM_POOL_MAGIC		0xDEAD
 11040  #define SXMEM_POOL_MAXALLOC		(1<<(SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR)) 
 11041  #define SXMEM_POOL_MINALLOC		(1<<(SXMEM_POOL_INCR))
 11042  static sxi32 MemPoolBucketAlloc(SyMemBackend *pBackend, sxu32 nBucket)
 11043  {
 11044  	char *zBucket, *zBucketEnd;
 11045  	SyMemHeader *pHeader;
 11046  	sxu32 nBucketSize;
 11047  	
 11048  	/* Allocate one big block first */
 11049  	zBucket = (char *)MemBackendAlloc(&(*pBackend), SXMEM_POOL_MAXALLOC);
 11050  	if( zBucket == 0 ){
 11051  		return SXERR_MEM;
 11052  	}
 11053  	zBucketEnd = &zBucket[SXMEM_POOL_MAXALLOC];
 11054  	/* Divide the big block into mini bucket pool */
 11055  	nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
 11056  	pBackend->apPool[nBucket] = pHeader = (SyMemHeader *)zBucket;
 11057  	for(;;){
 11058  		if( &zBucket[nBucketSize] >= zBucketEnd ){
 11059  			break;
 11060  		}
 11061  		pHeader->pNext = (SyMemHeader *)&zBucket[nBucketSize];
 11062  		/* Advance the cursor to the next available chunk */
 11063  		pHeader = pHeader->pNext;
 11064  		zBucket += nBucketSize;	
 11065  	}
 11066  	pHeader->pNext = 0;
 11067  	
 11068  	return SXRET_OK;
 11069  }
 11070  static void * MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte)
 11071  {
 11072  	SyMemHeader *pBucket, *pNext;
 11073  	sxu32 nBucketSize;
 11074  	sxu32 nBucket;
 11075  
 11076  	if( nByte + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC ){
 11077  		/* Allocate a big chunk directly */
 11078  		pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nByte+sizeof(SyMemHeader));
 11079  		if( pBucket == 0 ){
 11080  			return 0;
 11081  		}
 11082  		/* Record as big block */
 11083  		pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
 11084  		return (void *)(pBucket+1);
 11085  	}
 11086  	/* Locate the appropriate bucket */
 11087  	nBucket = 0;
 11088  	nBucketSize = SXMEM_POOL_MINALLOC;
 11089  	while( nByte + sizeof(SyMemHeader) > nBucketSize  ){
 11090  		nBucketSize <<= 1;
 11091  		nBucket++;
 11092  	}
 11093  	pBucket = pBackend->apPool[nBucket];
 11094  	if( pBucket == 0 ){
 11095  		sxi32 rc;
 11096  		rc = MemPoolBucketAlloc(&(*pBackend), nBucket);
 11097  		if( rc != SXRET_OK ){
 11098  			return 0;
 11099  		}
 11100  		pBucket = pBackend->apPool[nBucket];
 11101  	}
 11102  	/* Remove from the free list */
 11103  	pNext = pBucket->pNext;
 11104  	pBackend->apPool[nBucket] = pNext;
 11105  	/* Record bucket&magic number */
 11106  	pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket;
 11107  	return (void *)&pBucket[1];
 11108  }
 11109  VEDIS_PRIVATE void * SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte)
 11110  {
 11111  	void *pChunk;
 11112  #if defined(UNTRUST)
 11113  	if( SXMEM_BACKEND_CORRUPT(pBackend) ){
 11114  		return 0;
 11115  	}
 11116  #endif
 11117  	if( pBackend->pMutexMethods ){
 11118  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 11119  	}
 11120  	pChunk = MemBackendPoolAlloc(&(*pBackend), nByte);
 11121  	if( pBackend->pMutexMethods ){
 11122  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 11123  	}
 11124  	return pChunk;
 11125  }
 11126  static sxi32 MemBackendPoolFree(SyMemBackend *pBackend, void * pChunk)
 11127  {
 11128  	SyMemHeader *pHeader;
 11129  	sxu32 nBucket;
 11130  	/* Get the corresponding bucket */
 11131  	pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader));
 11132  	/* Sanity check to avoid misuse */
 11133  	if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){
 11134  		return SXERR_CORRUPT;
 11135  	}
 11136  	nBucket = pHeader->nBucket & 0xFFFF;
 11137  	if( nBucket == SXU16_HIGH ){
 11138  		/* Free the big block */
 11139  		MemBackendFree(&(*pBackend), pHeader);
 11140  	}else{
 11141  		/* Return to the free list */
 11142  		pHeader->pNext = pBackend->apPool[nBucket & 0x0f];
 11143  		pBackend->apPool[nBucket & 0x0f] = pHeader;
 11144  	}
 11145  	return SXRET_OK;
 11146  }
 11147  VEDIS_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend, void * pChunk)
 11148  {
 11149  	sxi32 rc;
 11150  #if defined(UNTRUST)
 11151  	if( SXMEM_BACKEND_CORRUPT(pBackend) || pChunk == 0 ){
 11152  		return SXERR_CORRUPT;
 11153  	}
 11154  #endif
 11155  	if( pBackend->pMutexMethods ){
 11156  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 11157  	}
 11158  	rc = MemBackendPoolFree(&(*pBackend), pChunk);
 11159  	if( pBackend->pMutexMethods ){
 11160  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 11161  	}
 11162  	return rc;
 11163  }
 11164  #if 0
 11165  static void * MemBackendPoolRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
 11166  {
 11167  	sxu32 nBucket, nBucketSize;
 11168  	SyMemHeader *pHeader;
 11169  	void * pNew;
 11170  
 11171  	if( pOld == 0 ){
 11172  		/* Allocate a new pool */
 11173  		pNew = MemBackendPoolAlloc(&(*pBackend), nByte);
 11174  		return pNew;
 11175  	}
 11176  	/* Get the corresponding bucket */
 11177  	pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader));
 11178  	/* Sanity check to avoid misuse */
 11179  	if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){
 11180  		return 0;
 11181  	}
 11182  	nBucket = pHeader->nBucket & 0xFFFF;
 11183  	if( nBucket == SXU16_HIGH ){
 11184  		/* Big block */
 11185  		return MemBackendRealloc(&(*pBackend), pHeader, nByte);
 11186  	}
 11187  	nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
 11188  	if( nBucketSize >= nByte + sizeof(SyMemHeader) ){
 11189  		/* The old bucket can honor the requested size */
 11190  		return pOld;
 11191  	}
 11192  	/* Allocate a new pool */
 11193  	pNew = MemBackendPoolAlloc(&(*pBackend), nByte);
 11194  	if( pNew == 0 ){
 11195  		return 0;
 11196  	}
 11197  	/* Copy the old data into the new block */
 11198  	SyMemcpy(pOld, pNew, nBucketSize);
 11199  	/* Free the stale block */
 11200  	MemBackendPoolFree(&(*pBackend), pOld);
 11201  	return pNew;
 11202  }
 11203  VEDIS_PRIVATE void * SyMemBackendPoolRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte)
 11204  {
 11205  	void *pChunk;
 11206  #if defined(UNTRUST)
 11207  	if( SXMEM_BACKEND_CORRUPT(pBackend) ){
 11208  		return 0;
 11209  	}
 11210  #endif
 11211  	if( pBackend->pMutexMethods ){
 11212  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 11213  	}
 11214  	pChunk = MemBackendPoolRealloc(&(*pBackend), pOld, nByte);
 11215  	if( pBackend->pMutexMethods ){
 11216  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 11217  	}
 11218  	return pChunk;
 11219  }
 11220  #endif
 11221  VEDIS_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend, ProcMemError xMemErr, void * pUserData)
 11222  {
 11223  #if defined(UNTRUST)
 11224  	if( pBackend == 0 ){
 11225  		return SXERR_EMPTY;
 11226  	}
 11227  #endif
 11228  	/* Zero the allocator first */
 11229  	SyZero(&(*pBackend), sizeof(SyMemBackend));
 11230  	pBackend->xMemError = xMemErr;
 11231  	pBackend->pUserData = pUserData;
 11232  	/* Switch to the OS memory allocator */
 11233  	pBackend->pMethods = &sOSAllocMethods;
 11234  	if( pBackend->pMethods->xInit ){
 11235  		/* Initialize the backend  */
 11236  		if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){
 11237  			return SXERR_ABORT;
 11238  		}
 11239  	}
 11240  #if defined(UNTRUST)
 11241  	pBackend->nMagic = SXMEM_BACKEND_MAGIC;
 11242  #endif
 11243  	return SXRET_OK;
 11244  }
 11245  VEDIS_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend, const SyMemMethods *pMethods, ProcMemError xMemErr, void * pUserData)
 11246  {
 11247  #if defined(UNTRUST)
 11248  	if( pBackend == 0 || pMethods == 0){
 11249  		return SXERR_EMPTY;
 11250  	}
 11251  #endif
 11252  	if( pMethods->xAlloc == 0 || pMethods->xRealloc == 0 || pMethods->xFree == 0 || pMethods->xChunkSize == 0 ){
 11253  		/* mandatory methods are missing */
 11254  		return SXERR_INVALID;
 11255  	}
 11256  	/* Zero the allocator first */
 11257  	SyZero(&(*pBackend), sizeof(SyMemBackend));
 11258  	pBackend->xMemError = xMemErr;
 11259  	pBackend->pUserData = pUserData;
 11260  	/* Switch to the host application memory allocator */
 11261  	pBackend->pMethods = pMethods;
 11262  	if( pBackend->pMethods->xInit ){
 11263  		/* Initialize the backend  */
 11264  		if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){
 11265  			return SXERR_ABORT;
 11266  		}
 11267  	}
 11268  #if defined(UNTRUST)
 11269  	pBackend->nMagic = SXMEM_BACKEND_MAGIC;
 11270  #endif
 11271  	return SXRET_OK;
 11272  }
 11273  VEDIS_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,const SyMemBackend *pParent)
 11274  {
 11275  	sxu8 bInheritMutex;
 11276  #if defined(UNTRUST)
 11277  	if( pBackend == 0 || SXMEM_BACKEND_CORRUPT(pParent) ){
 11278  		return SXERR_CORRUPT;
 11279  	}
 11280  #endif
 11281  	/* Zero the allocator first */
 11282  	SyZero(&(*pBackend), sizeof(SyMemBackend));
 11283  	pBackend->pMethods  = pParent->pMethods;
 11284  	pBackend->xMemError = pParent->xMemError;
 11285  	pBackend->pUserData = pParent->pUserData;
 11286  	bInheritMutex = pParent->pMutexMethods ? TRUE : FALSE;
 11287  	if( bInheritMutex ){
 11288  		pBackend->pMutexMethods = pParent->pMutexMethods;
 11289  		/* Create a private mutex */
 11290  		pBackend->pMutex = pBackend->pMutexMethods->xNew(SXMUTEX_TYPE_FAST);
 11291  		if( pBackend->pMutex ==  0){
 11292  			return SXERR_OS;
 11293  		}
 11294  	}
 11295  #if defined(UNTRUST)
 11296  	pBackend->nMagic = SXMEM_BACKEND_MAGIC;
 11297  #endif
 11298  	return SXRET_OK;
 11299  }
 11300  static sxi32 MemBackendRelease(SyMemBackend *pBackend)
 11301  {
 11302  	SyMemBlock *pBlock, *pNext;
 11303  
 11304  	pBlock = pBackend->pBlocks;
 11305  	for(;;){
 11306  		if( pBackend->nBlock == 0 ){
 11307  			break;
 11308  		}
 11309  		pNext  = pBlock->pNext;
 11310  		pBackend->pMethods->xFree(pBlock);
 11311  		pBlock = pNext;
 11312  		pBackend->nBlock--;
 11313  		/* LOOP ONE */
 11314  		if( pBackend->nBlock == 0 ){
 11315  			break;
 11316  		}
 11317  		pNext  = pBlock->pNext;
 11318  		pBackend->pMethods->xFree(pBlock);
 11319  		pBlock = pNext;
 11320  		pBackend->nBlock--;
 11321  		/* LOOP TWO */
 11322  		if( pBackend->nBlock == 0 ){
 11323  			break;
 11324  		}
 11325  		pNext  = pBlock->pNext;
 11326  		pBackend->pMethods->xFree(pBlock);
 11327  		pBlock = pNext;
 11328  		pBackend->nBlock--;
 11329  		/* LOOP THREE */
 11330  		if( pBackend->nBlock == 0 ){
 11331  			break;
 11332  		}
 11333  		pNext  = pBlock->pNext;
 11334  		pBackend->pMethods->xFree(pBlock);
 11335  		pBlock = pNext;
 11336  		pBackend->nBlock--;
 11337  		/* LOOP FOUR */
 11338  	}
 11339  	if( pBackend->pMethods->xRelease ){
 11340  		pBackend->pMethods->xRelease(pBackend->pMethods->pUserData);
 11341  	}
 11342  	pBackend->pMethods = 0;
 11343  	pBackend->pBlocks  = 0;
 11344  #if defined(UNTRUST)
 11345  	pBackend->nMagic = 0x2626;
 11346  #endif
 11347  	return SXRET_OK;
 11348  }
 11349  VEDIS_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend)
 11350  {
 11351  	sxi32 rc;
 11352  #if defined(UNTRUST)
 11353  	if( SXMEM_BACKEND_CORRUPT(pBackend) ){
 11354  		return SXERR_INVALID;
 11355  	}
 11356  #endif
 11357  	if( pBackend->pMutexMethods ){
 11358  		SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
 11359  	}
 11360  	rc = MemBackendRelease(&(*pBackend));
 11361  	if( pBackend->pMutexMethods ){
 11362  		SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
 11363  		SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex);
 11364  	}
 11365  	return rc;
 11366  }
 11367  VEDIS_PRIVATE void * SyMemBackendDup(SyMemBackend *pBackend, const void *pSrc, sxu32 nSize)
 11368  {
 11369  	void *pNew;
 11370  #if defined(UNTRUST)
 11371  	if( pSrc == 0 || nSize <= 0 ){
 11372  		return 0;
 11373  	}
 11374  #endif
 11375  	pNew = SyMemBackendAlloc(&(*pBackend), nSize);
 11376  	if( pNew ){
 11377  		SyMemcpy(pSrc, pNew, nSize);
 11378  	}
 11379  	return pNew;
 11380  }
 11381  VEDIS_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob, void *pBuffer, sxu32 nSize)
 11382  {
 11383  #if defined(UNTRUST)
 11384  	if( pBlob == 0 || pBuffer == 0 || nSize < 1 ){
 11385  		return SXERR_EMPTY;
 11386  	}
 11387  #endif
 11388  	pBlob->pBlob = pBuffer;
 11389  	pBlob->mByte = nSize;
 11390  	pBlob->nByte = 0;
 11391  	pBlob->pAllocator = 0;
 11392  	pBlob->nFlags = SXBLOB_LOCKED|SXBLOB_STATIC;
 11393  	return SXRET_OK;
 11394  }
 11395  VEDIS_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob, SyMemBackend *pAllocator)
 11396  {
 11397  #if defined(UNTRUST)
 11398  	if( pBlob == 0  ){
 11399  		return SXERR_EMPTY;
 11400  	}
 11401  #endif
 11402  	pBlob->pBlob = 0;
 11403  	pBlob->mByte = pBlob->nByte	= 0;
 11404  	pBlob->pAllocator = &(*pAllocator);
 11405  	pBlob->nFlags = 0;
 11406  	return SXRET_OK;
 11407  }
 11408  #ifndef SXBLOB_MIN_GROWTH
 11409  #define SXBLOB_MIN_GROWTH 16
 11410  #endif
 11411  static sxi32 BlobPrepareGrow(SyBlob *pBlob, sxu32 *pByte)
 11412  {
 11413  	sxu32 nByte;
 11414  	void *pNew;
 11415  	nByte = *pByte;
 11416  	if( pBlob->nFlags & (SXBLOB_LOCKED|SXBLOB_STATIC) ){
 11417  		if ( SyBlobFreeSpace(pBlob) < nByte ){
 11418  			*pByte = SyBlobFreeSpace(pBlob);
 11419  			if( (*pByte) == 0 ){
 11420  				return SXERR_SHORT;
 11421  			}
 11422  		}
 11423  		return SXRET_OK;
 11424  	}
 11425  	if( pBlob->nFlags & SXBLOB_RDONLY ){
 11426  		/* Make a copy of the read-only item */
 11427  		if( pBlob->nByte > 0 ){
 11428  			pNew = SyMemBackendDup(pBlob->pAllocator, pBlob->pBlob, pBlob->nByte);
 11429  			if( pNew == 0 ){
 11430  				return SXERR_MEM;
 11431  			}
 11432  			pBlob->pBlob = pNew;
 11433  			pBlob->mByte = pBlob->nByte;
 11434  		}else{
 11435  			pBlob->pBlob = 0;
 11436  			pBlob->mByte = 0;
 11437  		}
 11438  		/* Remove the read-only flag */
 11439  		pBlob->nFlags &= ~SXBLOB_RDONLY;
 11440  	}
 11441  	if( SyBlobFreeSpace(pBlob) >= nByte ){
 11442  		return SXRET_OK;
 11443  	}
 11444  	if( pBlob->mByte > 0 ){
 11445  		nByte = nByte + pBlob->mByte * 2 + SXBLOB_MIN_GROWTH;
 11446  	}else if ( nByte < SXBLOB_MIN_GROWTH ){
 11447  		nByte = SXBLOB_MIN_GROWTH;
 11448  	}
 11449  	pNew = SyMemBackendRealloc(pBlob->pAllocator, pBlob->pBlob, nByte);
 11450  	if( pNew == 0 ){
 11451  		return SXERR_MEM;
 11452  	}
 11453  	pBlob->pBlob = pNew;
 11454  	pBlob->mByte = nByte;
 11455  	return SXRET_OK;
 11456  }
 11457  VEDIS_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob, const void *pData, sxu32 nSize)
 11458  {
 11459  	sxu8 *zBlob;
 11460  	sxi32 rc;
 11461  	if( nSize < 1 ){
 11462  		return SXRET_OK;
 11463  	}
 11464  	rc = BlobPrepareGrow(&(*pBlob), &nSize);
 11465  	if( SXRET_OK != rc ){
 11466  		return rc;
 11467  	}
 11468  	if( pData ){
 11469  		zBlob = (sxu8 *)pBlob->pBlob ;
 11470  		zBlob = &zBlob[pBlob->nByte];
 11471  		pBlob->nByte += nSize;
 11472  		SX_MACRO_FAST_MEMCPY(pData, zBlob, nSize);
 11473  	}
 11474  	return SXRET_OK;
 11475  }
 11476  VEDIS_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob)
 11477  {
 11478  	sxi32 rc;
 11479  	sxu32 n;
 11480  	n = pBlob->nByte;
 11481  	rc = SyBlobAppend(&(*pBlob), (const void *)"\0", sizeof(char));
 11482  	if (rc == SXRET_OK ){
 11483  		pBlob->nByte = n;
 11484  	}
 11485  	return rc;
 11486  }
 11487  VEDIS_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc, SyBlob *pDest)
 11488  {
 11489  	sxi32 rc = SXRET_OK;
 11490  	if( pSrc->nByte > 0 ){
 11491  		rc = SyBlobAppend(&(*pDest), pSrc->pBlob, pSrc->nByte);
 11492  	}
 11493  	return rc;
 11494  }
 11495  VEDIS_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob)
 11496  {
 11497  	pBlob->nByte = 0;
 11498  	if( pBlob->nFlags & SXBLOB_RDONLY ){
 11499  		/* Read-only (Not malloced chunk) */
 11500  		pBlob->pBlob = 0;
 11501  		pBlob->mByte = 0;
 11502  		pBlob->nFlags &= ~SXBLOB_RDONLY;
 11503  	}
 11504  	return SXRET_OK;
 11505  }
 11506  VEDIS_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob)
 11507  {
 11508  	if( (pBlob->nFlags & (SXBLOB_STATIC|SXBLOB_RDONLY)) == 0 && pBlob->mByte > 0 ){
 11509  		SyMemBackendFree(pBlob->pAllocator, pBlob->pBlob);
 11510  	}
 11511  	pBlob->pBlob = 0;
 11512  	pBlob->nByte = pBlob->mByte = 0;
 11513  	pBlob->nFlags = 0;
 11514  	return SXRET_OK;
 11515  }
 11516  /* SyRunTimeApi:sxds.c */
 11517  VEDIS_PRIVATE sxi32 SySetInit(SySet *pSet, SyMemBackend *pAllocator, sxu32 ElemSize)
 11518  {
 11519  	pSet->nSize = 0 ;
 11520  	pSet->nUsed = 0;
 11521  	pSet->nCursor = 0;
 11522  	pSet->eSize = ElemSize;
 11523  	pSet->pAllocator = pAllocator;
 11524  	pSet->pBase =  0;
 11525  	pSet->pUserData = 0;
 11526  	return SXRET_OK;
 11527  }
 11528  VEDIS_PRIVATE sxi32 SySetPut(SySet *pSet, const void *pItem)
 11529  {
 11530  	unsigned char *zbase;
 11531  	if( pSet->nUsed >= pSet->nSize ){
 11532  		void *pNew;
 11533  		if( pSet->pAllocator == 0 ){
 11534  			return  SXERR_LOCKED;
 11535  		}
 11536  		if( pSet->nSize <= 0 ){
 11537  			pSet->nSize = 4;
 11538  		}
 11539  		pNew = SyMemBackendRealloc(pSet->pAllocator, pSet->pBase, pSet->eSize * pSet->nSize * 2);
 11540  		if( pNew == 0 ){
 11541  			return SXERR_MEM;
 11542  		}
 11543  		pSet->pBase = pNew;
 11544  		pSet->nSize <<= 1;
 11545  	}
 11546  	zbase = (unsigned char *)pSet->pBase;
 11547  	SX_MACRO_FAST_MEMCPY(pItem, &zbase[pSet->nUsed * pSet->eSize], pSet->eSize);
 11548  	pSet->nUsed++;	
 11549  	return SXRET_OK;
 11550  } 
 11551  VEDIS_PRIVATE sxi32 SySetReset(SySet *pSet)
 11552  {
 11553  	pSet->nUsed   = 0;
 11554  	pSet->nCursor = 0;
 11555  	return SXRET_OK;
 11556  }
 11557  VEDIS_PRIVATE sxi32 SySetRelease(SySet *pSet)
 11558  {
 11559  	sxi32 rc = SXRET_OK;
 11560  	if( pSet->pAllocator && pSet->pBase ){
 11561  		rc = SyMemBackendFree(pSet->pAllocator, pSet->pBase);
 11562  	}
 11563  	pSet->pBase = 0;
 11564  	pSet->nUsed = 0;
 11565  	pSet->nCursor = 0;
 11566  	return rc;
 11567  }
 11568  VEDIS_PRIVATE void * SySetPeek(SySet *pSet)
 11569  {
 11570  	const char *zBase;
 11571  	if( pSet->nUsed <= 0 ){
 11572  		return 0;
 11573  	}
 11574  	zBase = (const char *)pSet->pBase;
 11575  	return (void *)&zBase[(pSet->nUsed - 1) * pSet->eSize]; 
 11576  }
 11577  VEDIS_PRIVATE void * SySetPop(SySet *pSet)
 11578  {
 11579  	const char *zBase;
 11580  	void *pData;
 11581  	if( pSet->nUsed <= 0 ){
 11582  		return 0;
 11583  	}
 11584  	zBase = (const char *)pSet->pBase;
 11585  	pSet->nUsed--;
 11586  	pData =  (void *)&zBase[pSet->nUsed * pSet->eSize]; 
 11587  	return pData;
 11588  }
 11589  /* SyRunTimeApi:sxutils.c */
 11590  VEDIS_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc, sxu32 nLen, sxu8 *pReal, const char  **pzTail)
 11591  {
 11592  	const char *zCur, *zEnd;
 11593  #ifdef UNTRUST
 11594  	if( SX_EMPTY_STR(zSrc) ){
 11595  		return SXERR_EMPTY;
 11596  	}
 11597  #endif
 11598  	zEnd = &zSrc[nLen];
 11599  	/* Jump leading white spaces */
 11600  	while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0  && SyisSpace(zSrc[0]) ){
 11601  		zSrc++;
 11602  	}
 11603  	if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
 11604  		zSrc++;
 11605  	}
 11606  	zCur = zSrc;
 11607  	if( pReal ){
 11608  		*pReal = FALSE;
 11609  	}
 11610  	for(;;){
 11611  		if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
 11612  		if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
 11613  		if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
 11614  		if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
 11615  	};
 11616  	if( zSrc < zEnd && zSrc > zCur ){
 11617  		int c = zSrc[0];
 11618  		if( c == '.' ){
 11619  			zSrc++;
 11620  			if( pReal ){
 11621  				*pReal = TRUE;
 11622  			}
 11623  			if( pzTail ){
 11624  				while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
 11625  					zSrc++;
 11626  				}
 11627  				if( zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E') ){
 11628  					zSrc++;
 11629  					if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
 11630  						zSrc++;
 11631  					}
 11632  					while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
 11633  						zSrc++;
 11634  					}
 11635  				}
 11636  			}
 11637  		}else if( c == 'e' || c == 'E' ){
 11638  			zSrc++;
 11639  			if( pReal ){
 11640  				*pReal = TRUE;
 11641  			}
 11642  			if( pzTail ){
 11643  				if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
 11644  					zSrc++;
 11645  				}
 11646  				while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
 11647  					zSrc++;
 11648  				}
 11649  			}
 11650  		}
 11651  	}
 11652  	if( pzTail ){
 11653  		/* Point to the non numeric part */
 11654  		*pzTail = zSrc;
 11655  	}
 11656  	return zSrc > zCur ? SXRET_OK /* String prefix is numeric */ : SXERR_INVALID /* Not a digit stream */;
 11657  }
 11658  #define SXINT32_MIN_STR		"2147483648"
 11659  #define SXINT32_MAX_STR		"2147483647"
 11660  #define SXINT64_MIN_STR		"9223372036854775808"
 11661  #define SXINT64_MAX_STR		"9223372036854775807"
 11662  VEDIS_PRIVATE sxi32 SyStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
 11663  {
 11664  	int isNeg = FALSE;
 11665  	const char *zEnd;
 11666  	sxi64 nVal;
 11667  	sxi16 i;
 11668  #if defined(UNTRUST)
 11669  	if( SX_EMPTY_STR(zSrc) ){
 11670  		if( pOutVal ){
 11671  			*(sxi32 *)pOutVal = 0;
 11672  		}
 11673  		return SXERR_EMPTY;
 11674  	}
 11675  #endif
 11676  	zEnd = &zSrc[nLen];
 11677  	while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11678  		zSrc++;
 11679  	}
 11680  	if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
 11681  		isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
 11682  		zSrc++;
 11683  	}
 11684  	/* Skip leading zero */
 11685  	while(zSrc < zEnd && zSrc[0] == '0' ){
 11686  		zSrc++;
 11687  	}
 11688  	i = 19;
 11689  	if( (sxu32)(zEnd-zSrc) >= 19 ){
 11690  		i = SyMemcmp(zSrc, isNeg ? SXINT64_MIN_STR : SXINT64_MAX_STR, 19) <= 0 ? 19 : 18 ;
 11691  	}
 11692  	nVal = 0;
 11693  	for(;;){
 11694  		if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
 11695  		if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
 11696  		if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
 11697  		if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
 11698  	}
 11699  	/* Skip trailing spaces */
 11700  	while(zSrc < zEnd && SyisSpace(zSrc[0])){
 11701  		zSrc++;
 11702  	}
 11703  	if( zRest ){
 11704  		*zRest = (char *)zSrc;
 11705  	}	
 11706  	if( pOutVal ){
 11707  		if( isNeg == TRUE && nVal != 0 ){
 11708  			nVal = -nVal;
 11709  		}
 11710  		*(sxi64 *)pOutVal = nVal;
 11711  	}
 11712  	return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
 11713  }
 11714  VEDIS_PRIVATE sxi32 SyHexToint(sxi32 c)
 11715  {
 11716  	switch(c){
 11717  	case '0': return 0;
 11718  	case '1': return 1;
 11719  	case '2': return 2;
 11720  	case '3': return 3;
 11721  	case '4': return 4;
 11722  	case '5': return 5;
 11723  	case '6': return 6;
 11724  	case '7': return 7;
 11725  	case '8': return 8;
 11726  	case '9': return 9;
 11727  	case 'A': case 'a': return 10;
 11728  	case 'B': case 'b': return 11;
 11729  	case 'C': case 'c': return 12;
 11730  	case 'D': case 'd': return 13;
 11731  	case 'E': case 'e': return 14;
 11732  	case 'F': case 'f': return 15;
 11733  	}
 11734  	return -1; 	
 11735  }
 11736  VEDIS_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
 11737  {
 11738  	const char *zIn, *zEnd;
 11739  	int isNeg = FALSE;
 11740  	sxi64 nVal = 0;
 11741  #if defined(UNTRUST)
 11742  	if( SX_EMPTY_STR(zSrc) ){
 11743  		if( pOutVal ){
 11744  			*(sxi32 *)pOutVal = 0;
 11745  		}
 11746  		return SXERR_EMPTY;
 11747  	}
 11748  #endif
 11749  	zEnd = &zSrc[nLen];
 11750  	while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11751  		zSrc++;
 11752  	}
 11753  	if( zSrc < zEnd && ( *zSrc == '-' || *zSrc == '+' ) ){
 11754  		isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
 11755  		zSrc++;
 11756  	}
 11757  	if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'x' || zSrc[1] == 'X') ){
 11758  		/* Bypass hex prefix */
 11759  		zSrc += sizeof(char) * 2;
 11760  	}	
 11761  	/* Skip leading zero */
 11762  	while(zSrc < zEnd && zSrc[0] == '0' ){
 11763  		zSrc++;
 11764  	}
 11765  	zIn = zSrc;
 11766  	for(;;){
 11767  		if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]);  zSrc++ ;
 11768  		if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]);  zSrc++ ;
 11769  		if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]);  zSrc++ ;
 11770  		if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]);  zSrc++ ;
 11771  	}
 11772  	while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11773  		zSrc++;
 11774  	}	
 11775  	if( zRest ){
 11776  		*zRest = zSrc;
 11777  	}
 11778  	if( pOutVal ){
 11779  		if( isNeg == TRUE && nVal != 0 ){
 11780  			nVal = -nVal;
 11781  		}
 11782  		*(sxi64 *)pOutVal = nVal;
 11783  	}
 11784  	return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX;
 11785  }
 11786  VEDIS_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
 11787  {
 11788  	const char *zIn, *zEnd;
 11789  	int isNeg = FALSE;
 11790  	sxi64 nVal = 0;
 11791  	int c;
 11792  #if defined(UNTRUST)
 11793  	if( SX_EMPTY_STR(zSrc) ){
 11794  		if( pOutVal ){
 11795  			*(sxi32 *)pOutVal = 0;
 11796  		}
 11797  		return SXERR_EMPTY;
 11798  	}
 11799  #endif
 11800  	zEnd = &zSrc[nLen];
 11801  	while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11802  		zSrc++;
 11803  	}
 11804  	if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
 11805  		isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
 11806  		zSrc++;
 11807  	}
 11808  	/* Skip leading zero */
 11809  	while(zSrc < zEnd && zSrc[0] == '0' ){
 11810  		zSrc++; 
 11811  	}
 11812  	zIn = zSrc;
 11813  	for(;;){
 11814  		if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 +  c; zSrc++;
 11815  		if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 +  c; zSrc++;
 11816  		if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 +  c; zSrc++;
 11817  		if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 +  c; zSrc++;
 11818  	}
 11819  	/* Skip trailing spaces */
 11820  	while(zSrc < zEnd && SyisSpace(zSrc[0])){
 11821  		zSrc++;
 11822  	}
 11823  	if( zRest ){
 11824  		*zRest = zSrc;
 11825  	}	
 11826  	if( pOutVal ){
 11827  		if( isNeg == TRUE && nVal != 0 ){
 11828  			nVal = -nVal;
 11829  		}
 11830  		*(sxi64 *)pOutVal = nVal;
 11831  	}
 11832  	return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
 11833  }
 11834  VEDIS_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
 11835  {
 11836  	const char *zIn, *zEnd;
 11837  	int isNeg = FALSE;
 11838  	sxi64 nVal = 0;
 11839  	int c;
 11840  #if defined(UNTRUST)
 11841  	if( SX_EMPTY_STR(zSrc) ){
 11842  		if( pOutVal ){
 11843  			*(sxi32 *)pOutVal = 0;
 11844  		}
 11845  		return SXERR_EMPTY;
 11846  	}
 11847  #endif
 11848  	zEnd = &zSrc[nLen];
 11849  	while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11850  		zSrc++;
 11851  	}
 11852  	if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
 11853  		isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
 11854  		zSrc++;
 11855  	}
 11856  	if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'b' || zSrc[1] == 'B') ){
 11857  		/* Bypass binary prefix */
 11858  		zSrc += sizeof(char) * 2;
 11859  	}
 11860  	/* Skip leading zero */
 11861  	while(zSrc < zEnd && zSrc[0] == '0' ){
 11862  		zSrc++; 
 11863  	}
 11864  	zIn = zSrc;
 11865  	for(;;){
 11866  		if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
 11867  		if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
 11868  		if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
 11869  		if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
 11870  	}
 11871  	/* Skip trailing spaces */
 11872  	while(zSrc < zEnd && SyisSpace(zSrc[0])){
 11873  		zSrc++;
 11874  	}
 11875  	if( zRest ){
 11876  		*zRest = zSrc;
 11877  	}	
 11878  	if( pOutVal ){
 11879  		if( isNeg == TRUE && nVal != 0 ){
 11880  			nVal = -nVal;
 11881  		}
 11882  		*(sxi64 *)pOutVal = nVal;
 11883  	}
 11884  	return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
 11885  }
 11886  VEDIS_PRIVATE sxi32 SyStrToReal(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest)
 11887  {
 11888  #define SXDBL_DIG        15
 11889  #define SXDBL_MAX_EXP    308
 11890  #define SXDBL_MIN_EXP_PLUS	307
 11891  	static const sxreal aTab[] = {
 11892  	10, 
 11893  	1.0e2, 
 11894  	1.0e4, 
 11895  	1.0e8, 
 11896  	1.0e16, 
 11897  	1.0e32, 
 11898  	1.0e64, 
 11899  	1.0e128, 
 11900  	1.0e256
 11901  	};
 11902  	sxu8 neg = FALSE;
 11903  	sxreal Val = 0.0;
 11904  	const char *zEnd;
 11905  	sxi32 Lim, exp;
 11906  	sxreal *p = 0;
 11907  #ifdef UNTRUST
 11908  	if( SX_EMPTY_STR(zSrc)  ){
 11909  		if( pOutVal ){
 11910  			*(sxreal *)pOutVal = 0.0;
 11911  		}
 11912  		return SXERR_EMPTY;
 11913  	}
 11914  #endif
 11915  	zEnd = &zSrc[nLen];
 11916  	while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11917  		zSrc++; 
 11918  	}
 11919  	if( zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+' ) ){
 11920  		neg =  zSrc[0] == '-' ? TRUE : FALSE ;
 11921  		zSrc++;
 11922  	}
 11923  	Lim = SXDBL_DIG ;
 11924  	for(;;){
 11925  		if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
 11926  		if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
 11927  		if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
 11928  		if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
 11929  	}
 11930  	if( zSrc < zEnd && ( zSrc[0] == '.' || zSrc[0] == ',' ) ){
 11931  		sxreal dec = 1.0;
 11932  		zSrc++;
 11933  		for(;;){
 11934  			if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
 11935  			if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
 11936  			if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
 11937  			if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
 11938  		}
 11939  		Val /= dec;
 11940  	}
 11941  	if( neg == TRUE && Val != 0.0 ) {
 11942  		Val = -Val ; 
 11943  	}
 11944  	if( Lim <= 0 ){
 11945  		/* jump overflow digit */
 11946  		while( zSrc < zEnd ){
 11947  			if( zSrc[0] == 'e' || zSrc[0] == 'E' ){
 11948  				break;  
 11949  			}
 11950  			zSrc++;
 11951  		}
 11952  	}
 11953  	neg = FALSE;
 11954  	if( zSrc < zEnd && ( zSrc[0] == 'e' || zSrc[0] == 'E' ) ){
 11955  		zSrc++;
 11956  		if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+') ){
 11957  			neg = zSrc[0] == '-' ? TRUE : FALSE ;
 11958  			zSrc++;
 11959  		}
 11960  		exp = 0;
 11961  		while( zSrc < zEnd && SyisDigit(zSrc[0]) && exp < SXDBL_MAX_EXP ){
 11962  			exp = exp * 10 + (zSrc[0] - '0');
 11963  			zSrc++;
 11964  		}
 11965  		if( neg  ){
 11966  			if( exp > SXDBL_MIN_EXP_PLUS ) exp = SXDBL_MIN_EXP_PLUS ;
 11967  		}else if ( exp > SXDBL_MAX_EXP ){
 11968  			exp = SXDBL_MAX_EXP; 
 11969  		}		
 11970  		for( p = (sxreal *)aTab ; exp ; exp >>= 1 , p++ ){
 11971  			if( exp & 01 ){
 11972  				if( neg ){
 11973  					Val /= *p ;
 11974  				}else{
 11975  					Val *= *p;
 11976  				}
 11977  			}
 11978  		}
 11979  	}
 11980  	while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
 11981  		zSrc++;
 11982  	}
 11983  	if( zRest ){
 11984  		*zRest = zSrc; 
 11985  	}
 11986  	if( pOutVal ){
 11987  		*(sxreal *)pOutVal = Val;
 11988  	}
 11989  	return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX;
 11990  }
 11991  /* SyRunTimeApi:sxlib.c  */
 11992  VEDIS_PRIVATE sxu32 SyBinHash(const void *pSrc, sxu32 nLen)
 11993  {
 11994  	register unsigned char *zIn = (unsigned char *)pSrc;
 11995  	unsigned char *zEnd;
 11996  	sxu32 nH = 5381;
 11997  	zEnd = &zIn[nLen];
 11998  	for(;;){
 11999  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 12000  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 12001  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 12002  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 12003  	}	
 12004  	return nH;
 12005  }
 12006  VEDIS_PRIVATE sxi32 SyBase64Encode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData)
 12007  {
 12008  	static const unsigned char zBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 12009  	unsigned char *zIn = (unsigned char *)zSrc;
 12010  	unsigned char z64[4];
 12011  	sxu32 i;
 12012  	sxi32 rc;
 12013  #if defined(UNTRUST)
 12014  	if( SX_EMPTY_STR(zSrc) || xConsumer == 0){
 12015  		return SXERR_EMPTY;
 12016  	}
 12017  #endif
 12018  	for(i = 0; i + 2 < nLen; i += 3){
 12019  		z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
 12020  		z64[1] = zBase64[( ((zIn[i] & 0x03) << 4)   | (zIn[i+1] >> 4)) & 0x3F]; 
 12021  		z64[2] = zBase64[( ((zIn[i+1] & 0x0F) << 2) | (zIn[i + 2] >> 6) ) & 0x3F];
 12022  		z64[3] = zBase64[ zIn[i + 2] & 0x3F];
 12023  		
 12024  		rc = xConsumer((const void *)z64, sizeof(z64), pUserData);
 12025  		if( rc != SXRET_OK ){return SXERR_ABORT;}
 12026  
 12027  	}	
 12028  	if ( i+1 < nLen ){
 12029  		z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
 12030  		z64[1] = zBase64[( ((zIn[i] & 0x03) << 4)   | (zIn[i+1] >> 4)) & 0x3F]; 
 12031  		z64[2] = zBase64[(zIn[i+1] & 0x0F) << 2 ];
 12032  		z64[3] = '=';
 12033  		
 12034  		rc = xConsumer((const void *)z64, sizeof(z64), pUserData);
 12035  		if( rc != SXRET_OK ){return SXERR_ABORT;}
 12036  
 12037  	}else if( i < nLen ){
 12038  		z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
 12039  		z64[1]   = zBase64[(zIn[i] & 0x03) << 4];
 12040  		z64[2] = '=';
 12041  		z64[3] = '=';
 12042  		
 12043  		rc = xConsumer((const void *)z64, sizeof(z64), pUserData);
 12044  		if( rc != SXRET_OK ){return SXERR_ABORT;}
 12045  	}
 12046  
 12047  	return SXRET_OK;
 12048  }
 12049  VEDIS_PRIVATE sxi32 SyBase64Decode(const char *zB64, sxu32 nLen, ProcConsumer xConsumer, void *pUserData)
 12050  {
 12051  	static const sxu32 aBase64Trans[] = {
 12052  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 12053  	0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 
 12054  	5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 
 12055  	28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 
 12056  	0, 0, 0
 12057  	};
 12058  	sxu32 n, w, x, y, z;
 12059  	sxi32 rc;
 12060  	unsigned char zOut[10];
 12061  #if defined(UNTRUST)
 12062  	if( SX_EMPTY_STR(zB64) || xConsumer == 0 ){
 12063  		return SXERR_EMPTY;
 12064  	}
 12065  #endif
 12066  	while(nLen > 0 && zB64[nLen - 1] == '=' ){
 12067  		nLen--;
 12068  	}
 12069  	for( n = 0 ; n+3<nLen ; n += 4){
 12070  		w = aBase64Trans[zB64[n] & 0x7F];
 12071  		x = aBase64Trans[zB64[n+1] & 0x7F];
 12072  		y = aBase64Trans[zB64[n+2] & 0x7F];
 12073  		z = aBase64Trans[zB64[n+3] & 0x7F];
 12074  		zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
 12075  		zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F);
 12076  		zOut[2] = ((y<<6) & 0xC0) | (z & 0x3F);
 12077  
 12078  		rc = xConsumer((const void *)zOut, sizeof(unsigned char)*3, pUserData);
 12079  		if( rc != SXRET_OK ){ return SXERR_ABORT;}
 12080  	}
 12081  	if( n+2 < nLen ){
 12082  		w = aBase64Trans[zB64[n] & 0x7F];
 12083  		x = aBase64Trans[zB64[n+1] & 0x7F];
 12084  		y = aBase64Trans[zB64[n+2] & 0x7F];
 12085  
 12086  		zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
 12087  		zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F);
 12088  
 12089  		rc = xConsumer((const void *)zOut, sizeof(unsigned char)*2, pUserData);
 12090  		if( rc != SXRET_OK ){ return SXERR_ABORT;}
 12091  	}else if( n+1 < nLen ){
 12092  		w = aBase64Trans[zB64[n] & 0x7F];
 12093  		x = aBase64Trans[zB64[n+1] & 0x7F];
 12094  
 12095  		zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
 12096  
 12097  		rc = xConsumer((const void *)zOut, sizeof(unsigned char)*1, pUserData);
 12098  		if( rc != SXRET_OK ){ return SXERR_ABORT;}
 12099  	}
 12100  	return SXRET_OK;
 12101  }
 12102  
 12103  #define INVALID_LEXER(LEX)	(  LEX == 0  || LEX->xTokenizer == 0 )
 12104  VEDIS_PRIVATE sxi32 SyLexInit(SyLex *pLex, SySet *pSet, ProcTokenizer xTokenizer, void *pUserData)
 12105  {
 12106  	SyStream *pStream;
 12107  #if defined (UNTRUST)
 12108  	if ( pLex == 0 || xTokenizer == 0 ){
 12109  		return SXERR_CORRUPT;
 12110  	}
 12111  #endif
 12112  	pLex->pTokenSet = 0;
 12113  	/* Initialize lexer fields */
 12114  	if( pSet ){
 12115  		if ( SySetElemSize(pSet) != sizeof(SyToken) ){
 12116  			return SXERR_INVALID;
 12117  		}
 12118  		pLex->pTokenSet = pSet;
 12119  	}
 12120  	pStream = &pLex->sStream;
 12121  	pLex->xTokenizer = xTokenizer;
 12122  	pLex->pUserData = pUserData;
 12123  	
 12124  	pStream->nLine = 1;
 12125  	pStream->nIgn  = 0;
 12126  	pStream->zText = pStream->zEnd = 0;
 12127  	pStream->pSet  = pSet;
 12128  	return SXRET_OK;
 12129  }
 12130  VEDIS_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex, const char *zInput, sxu32 nLen, void *pCtxData, ProcSort xSort, ProcCmp xCmp)
 12131  {
 12132  	const unsigned char *zCur;
 12133  	SyStream *pStream;
 12134  	SyToken sToken;
 12135  	sxi32 rc;
 12136  #if defined (UNTRUST)
 12137  	if ( INVALID_LEXER(pLex) || zInput == 0 ){
 12138  		return SXERR_CORRUPT;
 12139  	}
 12140  #endif
 12141  	pStream = &pLex->sStream;
 12142  	/* Point to the head of the input */
 12143  	pStream->zText = pStream->zInput = (const unsigned char *)zInput;
 12144  	/* Point to the end of the input */
 12145  	pStream->zEnd = &pStream->zInput[nLen];
 12146  	for(;;){
 12147  		if( pStream->zText >= pStream->zEnd ){
 12148  			/* End of the input reached */
 12149  			break;
 12150  		}
 12151  		zCur = pStream->zText;
 12152  		/* Call the tokenizer callback */
 12153  		rc = pLex->xTokenizer(pStream, &sToken, pLex->pUserData, pCtxData);
 12154  		if( rc != SXRET_OK && rc != SXERR_CONTINUE ){
 12155  			/* Tokenizer callback request an operation abort */
 12156  			if( rc == SXERR_ABORT ){
 12157  				return SXERR_ABORT;
 12158  			}
 12159  			break;
 12160  		}
 12161  		if( rc == SXERR_CONTINUE ){
 12162  			/* Request to ignore this token */
 12163  			pStream->nIgn++;
 12164  		}else if( pLex->pTokenSet  ){
 12165  			/* Put the token in the set */
 12166  			rc = SySetPut(pLex->pTokenSet, (const void *)&sToken);
 12167  			if( rc != SXRET_OK ){
 12168  				break;
 12169  			}
 12170  		}
 12171  		if( zCur >= pStream->zText ){
 12172  			/* Automatic advance of the stream cursor */
 12173  			pStream->zText = &zCur[1];
 12174  		}
 12175  	}
 12176  	if( xSort &&  pLex->pTokenSet ){
 12177  		SyToken *aToken = (SyToken *)SySetBasePtr(pLex->pTokenSet);
 12178  		/* Sort the extrated tokens */
 12179  		if( xCmp == 0 ){
 12180  			/* Use a default comparison function */
 12181  			xCmp = SyMemcmp;
 12182  		}
 12183  		xSort(aToken, SySetUsed(pLex->pTokenSet), sizeof(SyToken), xCmp);
 12184  	}
 12185  	return SXRET_OK;
 12186  }
 12187  VEDIS_PRIVATE sxi32 SyLexRelease(SyLex *pLex)
 12188  {
 12189  	sxi32 rc = SXRET_OK;
 12190  #if defined (UNTRUST)
 12191  	if ( INVALID_LEXER(pLex) ){
 12192  		return SXERR_CORRUPT;
 12193  	}
 12194  #else
 12195  	SXUNUSED(pLex); /* Prevent compiler warning */
 12196  #endif
 12197  	return rc;
 12198  }
 12199  /* SyRunTimeApi: sxfmt.c */
 12200  #define SXFMT_BUFSIZ 1024 /* Conversion buffer size */
 12201  /*
 12202  ** Conversion types fall into various categories as defined by the
 12203  ** following enumeration.
 12204  */
 12205  #define SXFMT_RADIX       1 /* Integer types.%d, %x, %o, and so forth */
 12206  #define SXFMT_FLOAT       2 /* Floating point.%f */
 12207  #define SXFMT_EXP         3 /* Exponentional notation.%e and %E */
 12208  #define SXFMT_GENERIC     4 /* Floating or exponential, depending on exponent.%g */
 12209  #define SXFMT_SIZE        5 /* Total number of characters processed so far.%n */
 12210  #define SXFMT_STRING      6 /* Strings.%s */
 12211  #define SXFMT_PERCENT     7 /* Percent symbol.%% */
 12212  #define SXFMT_CHARX       8 /* Characters.%c */
 12213  #define SXFMT_ERROR       9 /* Used to indicate no such conversion type */
 12214  /* Extension by Symisc Systems */
 12215  #define SXFMT_RAWSTR     13 /* %z Pointer to raw string (SyString *) */
 12216  #define SXFMT_UNUSED     15 
 12217  /*
 12218  ** Allowed values for SyFmtInfo.flags
 12219  */
 12220  #define SXFLAG_SIGNED	0x01
 12221  #define SXFLAG_UNSIGNED 0x02
 12222  /* Allowed values for SyFmtConsumer.nType */
 12223  #define SXFMT_CONS_PROC		1	/* Consumer is a procedure */
 12224  #define SXFMT_CONS_STR		2	/* Consumer is a managed string */
 12225  #define SXFMT_CONS_FILE		5	/* Consumer is an open File */
 12226  #define SXFMT_CONS_BLOB		6	/* Consumer is a BLOB */
 12227  /*
 12228  ** Each builtin conversion character (ex: the 'd' in "%d") is described
 12229  ** by an instance of the following structure
 12230  */
 12231  typedef struct SyFmtInfo SyFmtInfo;
 12232  struct SyFmtInfo
 12233  {
 12234    char fmttype;  /* The format field code letter [i.e: 'd', 's', 'x'] */
 12235    sxu8 base;     /* The base for radix conversion */
 12236    int flags;    /* One or more of SXFLAG_ constants below */
 12237    sxu8 type;     /* Conversion paradigm */
 12238    char *charset; /* The character set for conversion */
 12239    char *prefix;  /* Prefix on non-zero values in alt format */
 12240  };
 12241  typedef struct SyFmtConsumer SyFmtConsumer;
 12242  struct SyFmtConsumer
 12243  {
 12244  	sxu32 nLen; /* Total output length */
 12245  	sxi32 nType; /* Type of the consumer see below */
 12246  	sxi32 rc;	/* Consumer return value;Abort processing if rc != SXRET_OK */
 12247   union{
 12248  	struct{	
 12249  	ProcConsumer xUserConsumer;
 12250  	void *pUserData;
 12251  	}sFunc;  
 12252  	SyBlob *pBlob;
 12253   }uConsumer;	
 12254  }; 
 12255  #ifndef SX_OMIT_FLOATINGPOINT
 12256  static int getdigit(sxlongreal *val, int *cnt)
 12257  {
 12258    sxlongreal d;
 12259    int digit;
 12260  
 12261    if( (*cnt)++ >= 16 ){
 12262  	  return '0';
 12263    }
 12264    digit = (int)*val;
 12265    d = digit;
 12266     *val = (*val - d)*10.0;
 12267    return digit + '0' ;
 12268  }
 12269  #endif /* SX_OMIT_FLOATINGPOINT */
 12270  /*
 12271   * The following routine was taken from the SQLITE2 source tree and was
 12272   * extended by Symisc Systems to fit its need.
 12273   * Status: Public Domain
 12274   */
 12275  static sxi32 InternFormat(ProcConsumer xConsumer, void *pUserData, const char *zFormat, va_list ap)
 12276  {
 12277  	/*
 12278  	 * The following table is searched linearly, so it is good to put the most frequently
 12279  	 * used conversion types first.
 12280  	 */
 12281  static const SyFmtInfo aFmt[] = {
 12282    {  'd', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789", 0    }, 
 12283    {  's',  0, 0, SXFMT_STRING,     0,                  0    }, 
 12284    {  'c',  0, 0, SXFMT_CHARX,      0,                  0    }, 
 12285    {  'x', 16, 0, SXFMT_RADIX,      "0123456789abcdef", "x0" }, 
 12286    {  'X', 16, 0, SXFMT_RADIX,      "0123456789ABCDEF", "X0" }, 
 12287           /* -- Extensions by Symisc Systems -- */
 12288    {  'z',  0, 0, SXFMT_RAWSTR,     0,                   0   }, /* Pointer to a raw string (SyString *) */
 12289    {  'B',  2, 0, SXFMT_RADIX,      "01",                "b0"}, 
 12290           /* -- End of Extensions -- */
 12291    {  'o',  8, 0, SXFMT_RADIX,      "01234567",         "0"  }, 
 12292    {  'u', 10, 0, SXFMT_RADIX,      "0123456789",       0    }, 
 12293  #ifndef SX_OMIT_FLOATINGPOINT
 12294    {  'f',  0, SXFLAG_SIGNED, SXFMT_FLOAT,       0,     0    }, 
 12295    {  'e',  0, SXFLAG_SIGNED, SXFMT_EXP,        "e",    0    }, 
 12296    {  'E',  0, SXFLAG_SIGNED, SXFMT_EXP,        "E",    0    }, 
 12297    {  'g',  0, SXFLAG_SIGNED, SXFMT_GENERIC,    "e",    0    }, 
 12298    {  'G',  0, SXFLAG_SIGNED, SXFMT_GENERIC,    "E",    0    }, 
 12299  #endif
 12300    {  'i', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789", 0    }, 
 12301    {  'n',  0, 0, SXFMT_SIZE,       0,                  0    }, 
 12302    {  '%',  0, 0, SXFMT_PERCENT,    0,                  0    }, 
 12303    {  'p', 10, 0, SXFMT_RADIX,      "0123456789",       0    }
 12304  };
 12305    int c;                     /* Next character in the format string */
 12306    char *bufpt;               /* Pointer to the conversion buffer */
 12307    int precision;             /* Precision of the current field */
 12308    int length;                /* Length of the field */
 12309    int idx;                   /* A general purpose loop counter */
 12310    int width;                 /* Width of the current field */
 12311    sxu8 flag_leftjustify;   /* True if "-" flag is present */
 12312    sxu8 flag_plussign;      /* True if "+" flag is present */
 12313    sxu8 flag_blanksign;     /* True if " " flag is present */
 12314    sxu8 flag_alternateform; /* True if "#" flag is present */
 12315    sxu8 flag_zeropad;       /* True if field width constant starts with zero */
 12316    sxu8 flag_long;          /* True if "l" flag is present */
 12317    sxi64 longvalue;         /* Value for integer types */
 12318    const SyFmtInfo *infop;  /* Pointer to the appropriate info structure */
 12319    char buf[SXFMT_BUFSIZ];  /* Conversion buffer */
 12320    char prefix;             /* Prefix character."+" or "-" or " " or '\0'.*/
 12321    sxu8 errorflag = 0;      /* True if an error is encountered */
 12322    sxu8 xtype;              /* Conversion paradigm */
 12323    char *zExtra;    
 12324    static char spaces[] = "                                                  ";
 12325  #define etSPACESIZE ((int)sizeof(spaces)-1)
 12326  #ifndef SX_OMIT_FLOATINGPOINT
 12327    sxlongreal realvalue;    /* Value for real types */
 12328    int  exp;                /* exponent of real numbers */
 12329    double rounder;          /* Used for rounding floating point values */
 12330    sxu8 flag_dp;            /* True if decimal point should be shown */
 12331    sxu8 flag_rtz;           /* True if trailing zeros should be removed */
 12332    sxu8 flag_exp;           /* True to force display of the exponent */
 12333    int nsd;                 /* Number of significant digits returned */
 12334  #endif
 12335    int rc;
 12336  
 12337    length = 0;
 12338    bufpt = 0;
 12339    for(; (c=(*zFormat))!=0; ++zFormat){
 12340      if( c!='%' ){
 12341        unsigned int amt;
 12342        bufpt = (char *)zFormat;
 12343        amt = 1;
 12344        while( (c=(*++zFormat))!='%' && c!=0 ) amt++;
 12345  	  rc = xConsumer((const void *)bufpt, amt, pUserData);
 12346  	  if( rc != SXRET_OK ){
 12347  		  return SXERR_ABORT; /* Consumer routine request an operation abort */
 12348  	  }
 12349        if( c==0 ){
 12350  		  return errorflag > 0 ? SXERR_FORMAT : SXRET_OK;
 12351  	  }
 12352      }
 12353      if( (c=(*++zFormat))==0 ){
 12354        errorflag = 1;
 12355  	  rc = xConsumer("%", sizeof("%")-1, pUserData);
 12356  	  if( rc != SXRET_OK ){
 12357  		  return SXERR_ABORT; /* Consumer routine request an operation abort */
 12358  	  }
 12359        return errorflag > 0 ? SXERR_FORMAT : SXRET_OK;
 12360      }
 12361      /* Find out what flags are present */
 12362      flag_leftjustify = flag_plussign = flag_blanksign = 
 12363       flag_alternateform = flag_zeropad = 0;
 12364      do{
 12365        switch( c ){
 12366          case '-':   flag_leftjustify = 1;     c = 0;   break;
 12367          case '+':   flag_plussign = 1;        c = 0;   break;
 12368          case ' ':   flag_blanksign = 1;       c = 0;   break;
 12369          case '#':   flag_alternateform = 1;   c = 0;   break;
 12370          case '0':   flag_zeropad = 1;         c = 0;   break;
 12371          default:                                       break;
 12372        }
 12373      }while( c==0 && (c=(*++zFormat))!=0 );
 12374      /* Get the field width */
 12375      width = 0;
 12376      if( c=='*' ){
 12377        width = va_arg(ap, int);
 12378        if( width<0 ){
 12379          flag_leftjustify = 1;
 12380          width = -width;
 12381        }
 12382        c = *++zFormat;
 12383      }else{
 12384        while( c>='0' && c<='9' ){
 12385          width = width*10 + c - '0';
 12386          c = *++zFormat;
 12387        }
 12388      }
 12389      if( width > SXFMT_BUFSIZ-10 ){
 12390        width = SXFMT_BUFSIZ-10;
 12391      }
 12392      /* Get the precision */
 12393  	precision = -1;
 12394      if( c=='.' ){
 12395        precision = 0;
 12396        c = *++zFormat;
 12397        if( c=='*' ){
 12398          precision = va_arg(ap, int);
 12399          if( precision<0 ) precision = -precision;
 12400          c = *++zFormat;
 12401        }else{
 12402          while( c>='0' && c<='9' ){
 12403            precision = precision*10 + c - '0';
 12404            c = *++zFormat;
 12405          }
 12406        }
 12407      }
 12408      /* Get the conversion type modifier */
 12409  	flag_long = 0;
 12410      if( c=='l' || c == 'q' /* BSD quad (expect a 64-bit integer) */ ){
 12411        flag_long = (c == 'q') ? 2 : 1;
 12412        c = *++zFormat;
 12413  	  if( c == 'l' ){
 12414  		  /* Standard printf emulation 'lld' (expect a 64bit integer) */
 12415  		  flag_long = 2;
 12416  	  }
 12417      }
 12418      /* Fetch the info entry for the field */
 12419      infop = 0;
 12420      xtype = SXFMT_ERROR;
 12421  	for(idx=0; idx< (int)SX_ARRAYSIZE(aFmt); idx++){
 12422        if( c==aFmt[idx].fmttype ){
 12423          infop = &aFmt[idx];
 12424  		xtype = infop->type;
 12425          break;
 12426        }
 12427      }
 12428      zExtra = 0;
 12429  
 12430      /*
 12431      ** At this point, variables are initialized as follows:
 12432      **
 12433      **   flag_alternateform          TRUE if a '#' is present.
 12434      **   flag_plussign               TRUE if a '+' is present.
 12435      **   flag_leftjustify            TRUE if a '-' is present or if the
 12436      **                               field width was negative.
 12437      **   flag_zeropad                TRUE if the width began with 0.
 12438      **   flag_long                   TRUE if the letter 'l' (ell) or 'q'(BSD quad) prefixed
 12439      **                               the conversion character.
 12440      **   flag_blanksign              TRUE if a ' ' is present.
 12441      **   width                       The specified field width.This is
 12442      **                               always non-negative.Zero is the default.
 12443      **   precision                   The specified precision.The default
 12444      **                               is -1.
 12445      **   xtype                       The object of the conversion.
 12446      **   infop                       Pointer to the appropriate info struct.
 12447      */
 12448      switch( xtype ){
 12449        case SXFMT_RADIX:
 12450          if( flag_long > 0 ){
 12451  			if( flag_long > 1 ){
 12452  				/* BSD quad: expect a 64-bit integer */
 12453  				longvalue = va_arg(ap, sxi64);
 12454  			}else{
 12455  				longvalue = va_arg(ap, sxlong);
 12456  			}
 12457  		}else{
 12458  			if( infop->flags & SXFLAG_SIGNED ){
 12459  				longvalue = va_arg(ap, sxi32);
 12460  			}else{
 12461  				longvalue = va_arg(ap, sxu32);
 12462  			}
 12463  		}
 12464  		/* Limit the precision to prevent overflowing buf[] during conversion */
 12465        if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40;
 12466  #if 1
 12467          /* For the format %#x, the value zero is printed "0" not "0x0".
 12468          ** I think this is stupid.*/
 12469          if( longvalue==0 ) flag_alternateform = 0;
 12470  #else
 12471          /* More sensible: turn off the prefix for octal (to prevent "00"), 
 12472          ** but leave the prefix for hex.*/
 12473          if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
 12474  #endif
 12475          if( infop->flags & SXFLAG_SIGNED ){
 12476            if( longvalue<0 ){ 
 12477              longvalue = -longvalue;
 12478  			/* Ticket 1433-003 */
 12479  			if( longvalue < 0 ){
 12480  				/* Overflow */
 12481  				longvalue= 0x7FFFFFFFFFFFFFFF;
 12482  			}
 12483              prefix = '-';
 12484            }else if( flag_plussign )  prefix = '+';
 12485            else if( flag_blanksign )  prefix = ' ';
 12486            else                       prefix = 0;
 12487          }else{
 12488  			if( longvalue<0 ){
 12489  				longvalue = -longvalue;
 12490  				/* Ticket 1433-003 */
 12491  				if( longvalue < 0 ){
 12492  					/* Overflow */
 12493  					longvalue= 0x7FFFFFFFFFFFFFFF;
 12494  				}
 12495  			}
 12496  			prefix = 0;
 12497  		}
 12498          if( flag_zeropad && precision<width-(prefix!=0) ){
 12499            precision = width-(prefix!=0);
 12500          }
 12501          bufpt = &buf[SXFMT_BUFSIZ-1];
 12502          {
 12503            register char *cset;      /* Use registers for speed */
 12504            register int base;
 12505            cset = infop->charset;
 12506            base = infop->base;
 12507            do{                                           /* Convert to ascii */
 12508              *(--bufpt) = cset[longvalue%base];
 12509              longvalue = longvalue/base;
 12510            }while( longvalue>0 );
 12511          }
 12512          length = &buf[SXFMT_BUFSIZ-1]-bufpt;
 12513          for(idx=precision-length; idx>0; idx--){
 12514            *(--bufpt) = '0';                             /* Zero pad */
 12515          }
 12516          if( prefix ) *(--bufpt) = prefix;               /* Add sign */
 12517          if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
 12518            char *pre, x;
 12519            pre = infop->prefix;
 12520            if( *bufpt!=pre[0] ){
 12521              for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
 12522            }
 12523          }
 12524          length = &buf[SXFMT_BUFSIZ-1]-bufpt;
 12525          break;
 12526        case SXFMT_FLOAT:
 12527        case SXFMT_EXP:
 12528        case SXFMT_GENERIC:
 12529  #ifndef SX_OMIT_FLOATINGPOINT
 12530  		realvalue = va_arg(ap, double);
 12531          if( precision<0 ) precision = 6;         /* Set default precision */
 12532          if( precision>SXFMT_BUFSIZ-40) precision = SXFMT_BUFSIZ-40;
 12533          if( realvalue<0.0 ){
 12534            realvalue = -realvalue;
 12535            prefix = '-';
 12536          }else{
 12537            if( flag_plussign )          prefix = '+';
 12538            else if( flag_blanksign )    prefix = ' ';
 12539            else                         prefix = 0;
 12540          }
 12541          if( infop->type==SXFMT_GENERIC && precision>0 ) precision--;
 12542          rounder = 0.0;
 12543  #if 0
 12544          /* Rounding works like BSD when the constant 0.4999 is used.Wierd! */
 12545          for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
 12546  #else
 12547          /* It makes more sense to use 0.5 */
 12548          for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
 12549  #endif
 12550          if( infop->type==SXFMT_FLOAT ) realvalue += rounder;
 12551          /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
 12552          exp = 0;
 12553          if( realvalue>0.0 ){
 12554            while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
 12555            while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
 12556            while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
 12557            while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
 12558            if( exp>350 || exp<-350 ){
 12559              bufpt = "NaN";
 12560              length = 3;
 12561              break;
 12562            }
 12563          }
 12564          bufpt = buf;
 12565          /*
 12566          ** If the field type is etGENERIC, then convert to either etEXP
 12567          ** or etFLOAT, as appropriate.
 12568          */
 12569          flag_exp = xtype==SXFMT_EXP;
 12570          if( xtype!=SXFMT_FLOAT ){
 12571            realvalue += rounder;
 12572            if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
 12573          }
 12574          if( xtype==SXFMT_GENERIC ){
 12575            flag_rtz = !flag_alternateform;
 12576            if( exp<-4 || exp>precision ){
 12577              xtype = SXFMT_EXP;
 12578            }else{
 12579              precision = precision - exp;
 12580              xtype = SXFMT_FLOAT;
 12581            }
 12582          }else{
 12583            flag_rtz = 0;
 12584          }
 12585          /*
 12586          ** The "exp+precision" test causes output to be of type etEXP if
 12587          ** the precision is too large to fit in buf[].
 12588          */
 12589          nsd = 0;
 12590          if( xtype==SXFMT_FLOAT && exp+precision<SXFMT_BUFSIZ-30 ){
 12591            flag_dp = (precision>0 || flag_alternateform);
 12592            if( prefix ) *(bufpt++) = prefix;         /* Sign */
 12593            if( exp<0 )  *(bufpt++) = '0';            /* Digits before "." */
 12594            else for(; exp>=0; exp--) *(bufpt++) = (char)getdigit(&realvalue, &nsd);
 12595            if( flag_dp ) *(bufpt++) = '.';           /* The decimal point */
 12596            for(exp++; exp<0 && precision>0; precision--, exp++){
 12597              *(bufpt++) = '0';
 12598            }
 12599            while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue, &nsd);
 12600            *(bufpt--) = 0;                           /* Null terminate */
 12601            if( flag_rtz && flag_dp ){     /* Remove trailing zeros and "." */
 12602              while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
 12603              if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
 12604            }
 12605            bufpt++;                            /* point to next free slot */
 12606          }else{    /* etEXP or etGENERIC */
 12607            flag_dp = (precision>0 || flag_alternateform);
 12608            if( prefix ) *(bufpt++) = prefix;   /* Sign */
 12609            *(bufpt++) = (char)getdigit(&realvalue, &nsd);  /* First digit */
 12610            if( flag_dp ) *(bufpt++) = '.';     /* Decimal point */
 12611            while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue, &nsd);
 12612            bufpt--;                            /* point to last digit */
 12613            if( flag_rtz && flag_dp ){          /* Remove tail zeros */
 12614              while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
 12615              if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
 12616            }
 12617            bufpt++;                            /* point to next free slot */
 12618            if( exp || flag_exp ){
 12619              *(bufpt++) = infop->charset[0];
 12620              if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
 12621              else       { *(bufpt++) = '+'; }
 12622              if( exp>=100 ){
 12623                *(bufpt++) = (char)((exp/100)+'0');                /* 100's digit */
 12624                exp %= 100;
 12625              }
 12626              *(bufpt++) = (char)(exp/10+'0');                     /* 10's digit */
 12627              *(bufpt++) = (char)(exp%10+'0');                     /* 1's digit */
 12628            }
 12629          }
 12630          /* The converted number is in buf[] and zero terminated.Output it.
 12631          ** Note that the number is in the usual order, not reversed as with
 12632          ** integer conversions.*/
 12633          length = bufpt-buf;
 12634          bufpt = buf;
 12635  
 12636          /* Special case:  Add leading zeros if the flag_zeropad flag is
 12637          ** set and we are not left justified */
 12638          if( flag_zeropad && !flag_leftjustify && length < width){
 12639            int i;
 12640            int nPad = width - length;
 12641            for(i=width; i>=nPad; i--){
 12642              bufpt[i] = bufpt[i-nPad];
 12643            }
 12644            i = prefix!=0;
 12645            while( nPad-- ) bufpt[i++] = '0';
 12646            length = width;
 12647          }
 12648  #else
 12649           bufpt = " ";
 12650  		 length = (int)sizeof(" ") - 1;
 12651  #endif /* SX_OMIT_FLOATINGPOINT */
 12652          break;
 12653        case SXFMT_SIZE:{
 12654  		 int *pSize = va_arg(ap, int *);
 12655  		 *pSize = ((SyFmtConsumer *)pUserData)->nLen;
 12656  		 length = width = 0;
 12657  					  }
 12658          break;
 12659        case SXFMT_PERCENT:
 12660          buf[0] = '%';
 12661          bufpt = buf;
 12662          length = 1;
 12663          break;
 12664        case SXFMT_CHARX:
 12665          c = va_arg(ap, int);
 12666  		buf[0] = (char)c;
 12667  		/* Limit the precision to prevent overflowing buf[] during conversion */
 12668  		if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40;
 12669          if( precision>=0 ){
 12670            for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
 12671            length = precision;
 12672          }else{
 12673            length =1;
 12674          }
 12675          bufpt = buf;
 12676          break;
 12677        case SXFMT_STRING:
 12678          bufpt = va_arg(ap, char*);
 12679          if( bufpt==0 ){
 12680            bufpt = " ";
 12681  		  length = (int)sizeof(" ")-1;
 12682  		  break;
 12683          }
 12684  		length = precision;
 12685  		if( precision < 0 ){
 12686  			/* Symisc extension */
 12687  			length = (int)SyStrlen(bufpt);
 12688  		}
 12689          if( precision>=0 && precision<length ) length = precision;
 12690          break;
 12691  	case SXFMT_RAWSTR:{
 12692  		/* Symisc extension */
 12693  		SyString *pStr = va_arg(ap, SyString *);
 12694  		if( pStr == 0 || pStr->zString == 0 ){
 12695  			 bufpt = " ";
 12696  		     length = (int)sizeof(char);
 12697  		     break;
 12698  		}
 12699  		bufpt = (char *)pStr->zString;
 12700  		length = (int)pStr->nByte;
 12701  		break;
 12702  					  }
 12703        case SXFMT_ERROR:
 12704          buf[0] = '?';
 12705          bufpt = buf;
 12706  		length = (int)sizeof(char);
 12707          if( c==0 ) zFormat--;
 12708          break;
 12709      }/* End switch over the format type */
 12710      /*
 12711      ** The text of the conversion is pointed to by "bufpt" and is
 12712      ** "length" characters long.The field width is "width".Do
 12713      ** the output.
 12714      */
 12715      if( !flag_leftjustify ){
 12716        register int nspace;
 12717        nspace = width-length;
 12718        if( nspace>0 ){
 12719          while( nspace>=etSPACESIZE ){
 12720  			rc = xConsumer(spaces, etSPACESIZE, pUserData);
 12721  			if( rc != SXRET_OK ){
 12722  				return SXERR_ABORT; /* Consumer routine request an operation abort */
 12723  			}
 12724  			nspace -= etSPACESIZE;
 12725          }
 12726          if( nspace>0 ){
 12727  			rc = xConsumer(spaces, (unsigned int)nspace, pUserData);
 12728  			if( rc != SXRET_OK ){
 12729  				return SXERR_ABORT; /* Consumer routine request an operation abort */
 12730  			}
 12731  		}
 12732        }
 12733      }
 12734      if( length>0 ){
 12735  		rc = xConsumer(bufpt, (unsigned int)length, pUserData);
 12736  		if( rc != SXRET_OK ){
 12737  		  return SXERR_ABORT; /* Consumer routine request an operation abort */
 12738  		}
 12739      }
 12740      if( flag_leftjustify ){
 12741        register int nspace;
 12742        nspace = width-length;
 12743        if( nspace>0 ){
 12744          while( nspace>=etSPACESIZE ){
 12745  			rc = xConsumer(spaces, etSPACESIZE, pUserData);
 12746  			if( rc != SXRET_OK ){
 12747  				return SXERR_ABORT; /* Consumer routine request an operation abort */
 12748  			}
 12749  			nspace -= etSPACESIZE;
 12750          }
 12751          if( nspace>0 ){
 12752  			rc = xConsumer(spaces, (unsigned int)nspace, pUserData);
 12753  			if( rc != SXRET_OK ){
 12754  				return SXERR_ABORT; /* Consumer routine request an operation abort */
 12755  			}
 12756  		}
 12757        }
 12758      }
 12759    }/* End for loop over the format string */
 12760    return errorflag ? SXERR_FORMAT : SXRET_OK;
 12761  } 
 12762  static sxi32 FormatConsumer(const void *pSrc, unsigned int nLen, void *pData)
 12763  {
 12764  	SyFmtConsumer *pConsumer = (SyFmtConsumer *)pData;
 12765  	sxi32 rc = SXERR_ABORT;
 12766  	switch(pConsumer->nType){
 12767  	case SXFMT_CONS_PROC:
 12768  			/* User callback */
 12769  			rc = pConsumer->uConsumer.sFunc.xUserConsumer(pSrc, nLen, pConsumer->uConsumer.sFunc.pUserData);
 12770  			break;
 12771  	case SXFMT_CONS_BLOB:
 12772  			/* Blob consumer */
 12773  			rc = SyBlobAppend(pConsumer->uConsumer.pBlob, pSrc, (sxu32)nLen);
 12774  			break;
 12775  		default: 
 12776  			/* Unknown consumer */
 12777  			break;
 12778  	}
 12779  	/* Update total number of bytes consumed so far */
 12780  	pConsumer->nLen += nLen;
 12781  	pConsumer->rc = rc;
 12782  	return rc;	
 12783  }
 12784  static sxi32 FormatMount(sxi32 nType, void *pConsumer, ProcConsumer xUserCons, void *pUserData, sxu32 *pOutLen, const char *zFormat, va_list ap)
 12785  {
 12786  	SyFmtConsumer sCons;
 12787  	sCons.nType = nType;
 12788  	sCons.rc = SXRET_OK;
 12789  	sCons.nLen = 0;
 12790  	if( pOutLen ){
 12791  		*pOutLen = 0;
 12792  	}
 12793  	switch(nType){
 12794  	case SXFMT_CONS_PROC:
 12795  #if defined(UNTRUST)
 12796  			if( xUserCons == 0 ){
 12797  				return SXERR_EMPTY;
 12798  			}
 12799  #endif
 12800  			sCons.uConsumer.sFunc.xUserConsumer = xUserCons;
 12801  			sCons.uConsumer.sFunc.pUserData	    = pUserData;
 12802  		break;
 12803  		case SXFMT_CONS_BLOB:
 12804  			sCons.uConsumer.pBlob = (SyBlob *)pConsumer;
 12805  			break;
 12806  		default: 
 12807  			return SXERR_UNKNOWN;
 12808  	}
 12809  	InternFormat(FormatConsumer, &sCons, zFormat, ap); 
 12810  	if( pOutLen ){
 12811  		*pOutLen = sCons.nLen;
 12812  	}
 12813  	return sCons.rc;
 12814  }
 12815  VEDIS_PRIVATE sxu32 SyBlobFormat(SyBlob *pBlob, const char *zFormat, ...)
 12816  {
 12817  	va_list ap;
 12818  	sxu32 n;
 12819  #if defined(UNTRUST)	
 12820  	if( SX_EMPTY_STR(zFormat) ){
 12821  		return 0;
 12822  	}
 12823  #endif			
 12824  	va_start(ap, zFormat);
 12825  	FormatMount(SXFMT_CONS_BLOB, &(*pBlob), 0, 0, &n, zFormat, ap);
 12826  	va_end(ap);
 12827  	return n;
 12828  }
 12829  VEDIS_PRIVATE sxu32 SyBlobFormatAp(SyBlob *pBlob, const char *zFormat, va_list ap)
 12830  {
 12831  	sxu32 n = 0; /* cc warning */
 12832  #if defined(UNTRUST)	
 12833  	if( SX_EMPTY_STR(zFormat) ){
 12834  		return 0;
 12835  	}
 12836  #endif	
 12837  	FormatMount(SXFMT_CONS_BLOB, &(*pBlob), 0, 0, &n, zFormat, ap);
 12838  	return n;
 12839  }
 12840  #ifdef __UNIXES__
 12841  VEDIS_PRIVATE sxu32 SyBufferFormat(char *zBuf, sxu32 nLen, const char *zFormat, ...)
 12842  {
 12843  	SyBlob sBlob;
 12844  	va_list ap;
 12845  	sxu32 n;
 12846  #if defined(UNTRUST)	
 12847  	if( SX_EMPTY_STR(zFormat) ){
 12848  		return 0;
 12849  	}
 12850  #endif	
 12851  	if( SXRET_OK != SyBlobInitFromBuf(&sBlob, zBuf, nLen - 1) ){
 12852  		return 0;
 12853  	}		
 12854  	va_start(ap, zFormat);
 12855  	FormatMount(SXFMT_CONS_BLOB, &sBlob, 0, 0, 0, zFormat, ap);
 12856  	va_end(ap);
 12857  	n = SyBlobLength(&sBlob);
 12858  	/* Append the null terminator */
 12859  	sBlob.mByte++;
 12860  	SyBlobAppend(&sBlob, "\0", sizeof(char));
 12861  	return n;
 12862  }
 12863  #endif /* __UNIXES__ */ 
 12864  /*
 12865   * Psuedo Random Number Generator (PRNG)
 12866   * @authors: SQLite authors <http://www.sqlite.org/>
 12867   * @status: Public Domain
 12868   * NOTE:
 12869   *  Nothing in this file or anywhere else in the library does any kind of
 12870   *  encryption.The RC4 algorithm is being used as a PRNG (pseudo-random
 12871   *  number generator) not as an encryption device.
 12872   */
 12873  #define SXPRNG_MAGIC	0x13C4
 12874  #ifdef __UNIXES__
 12875  #include <sys/types.h>
 12876  #include <sys/stat.h>
 12877  #include <fcntl.h>
 12878  #include <unistd.h>
 12879  #include <errno.h>
 12880  #include <time.h>
 12881  #include <sys/time.h>
 12882  #endif
 12883  static sxi32 SyOSUtilRandomSeed(void *pBuf, sxu32 nLen, void *pUnused)
 12884  {
 12885  	char *zBuf = (char *)pBuf;
 12886  #ifdef __WINNT__
 12887  	DWORD nProcessID; /* Yes, keep it uninitialized when compiling using the MinGW32 builds tools */
 12888  #elif defined(__UNIXES__)
 12889  	pid_t pid;
 12890  	int fd;
 12891  #else
 12892  	char zGarbage[128]; /* Yes, keep this buffer uninitialized */
 12893  #endif
 12894  	SXUNUSED(pUnused);
 12895  #ifdef __WINNT__
 12896  #ifndef __MINGW32__
 12897  	nProcessID = GetProcessId(GetCurrentProcess());
 12898  #endif
 12899  	SyMemcpy((const void *)&nProcessID, zBuf, SXMIN(nLen, sizeof(DWORD)));
 12900  	if( (sxu32)(&zBuf[nLen] - &zBuf[sizeof(DWORD)]) >= sizeof(SYSTEMTIME)  ){
 12901  		GetSystemTime((LPSYSTEMTIME)&zBuf[sizeof(DWORD)]);
 12902  	}
 12903  #elif defined(__UNIXES__)
 12904  	fd = open("/dev/urandom", O_RDONLY);
 12905  	if (fd >= 0 ){
 12906  		if( read(fd, zBuf, nLen) > 0 ){
 12907  			return SXRET_OK;
 12908  		}
 12909  		/* FALL THRU */
 12910  	}
 12911  	pid = getpid();
 12912  	SyMemcpy((const void *)&pid, zBuf, SXMIN(nLen, sizeof(pid_t)));
 12913  	if( &zBuf[nLen] - &zBuf[sizeof(pid_t)] >= (int)sizeof(struct timeval)  ){
 12914  		gettimeofday((struct timeval *)&zBuf[sizeof(pid_t)], 0);
 12915  	}
 12916  #else
 12917  	/* Fill with uninitialized data */
 12918  	SyMemcpy(zGarbage, zBuf, SXMIN(nLen, sizeof(zGarbage)));
 12919  #endif
 12920  	return SXRET_OK;
 12921  }
 12922  VEDIS_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx, ProcRandomSeed xSeed, void * pUserData)
 12923  {
 12924  	char zSeed[256];
 12925  	sxu8 t;
 12926  	sxi32 rc;
 12927  	sxu32 i;
 12928  	if( pCtx->nMagic == SXPRNG_MAGIC ){
 12929  		return SXRET_OK; /* Already initialized */
 12930  	}
 12931   /* Initialize the state of the random number generator once, 
 12932    ** the first time this routine is called.The seed value does
 12933    ** not need to contain a lot of randomness since we are not
 12934    ** trying to do secure encryption or anything like that...
 12935    */	
 12936  	if( xSeed == 0 ){
 12937  		xSeed = SyOSUtilRandomSeed;
 12938  	}
 12939  	rc = xSeed(zSeed, sizeof(zSeed), pUserData);
 12940  	if( rc != SXRET_OK ){
 12941  		return rc;
 12942  	}
 12943  	pCtx->i = pCtx->j = 0;
 12944  	for(i=0; i < SX_ARRAYSIZE(pCtx->s) ; i++){
 12945  		pCtx->s[i] = (unsigned char)i;
 12946      }
 12947      for(i=0; i < sizeof(zSeed) ; i++){
 12948        pCtx->j += pCtx->s[i] + zSeed[i];
 12949        t = pCtx->s[pCtx->j];
 12950        pCtx->s[pCtx->j] = pCtx->s[i];
 12951        pCtx->s[i] = t;
 12952      }
 12953  	pCtx->nMagic = SXPRNG_MAGIC;
 12954  	
 12955  	return SXRET_OK;
 12956  }
 12957  /*
 12958   * Get a single 8-bit random value using the RC4 PRNG.
 12959   */
 12960  static sxu8 randomByte(SyPRNGCtx *pCtx)
 12961  {
 12962    sxu8 t;
 12963    
 12964    /* Generate and return single random byte */
 12965    pCtx->i++;
 12966    t = pCtx->s[pCtx->i];
 12967    pCtx->j += t;
 12968    pCtx->s[pCtx->i] = pCtx->s[pCtx->j];
 12969    pCtx->s[pCtx->j] = t;
 12970    t += pCtx->s[pCtx->i];
 12971    return pCtx->s[t];
 12972  }
 12973  VEDIS_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx, void *pBuf, sxu32 nLen)
 12974  {
 12975  	unsigned char *zBuf = (unsigned char *)pBuf;
 12976  	unsigned char *zEnd = &zBuf[nLen];
 12977  #if defined(UNTRUST)
 12978  	if( pCtx == 0 || pBuf == 0 || nLen <= 0 ){
 12979  		return SXERR_EMPTY;
 12980  	}
 12981  #endif
 12982  	if(pCtx->nMagic != SXPRNG_MAGIC ){
 12983  		return SXERR_CORRUPT;
 12984  	}
 12985  	for(;;){
 12986  		if( zBuf >= zEnd ){break;}	zBuf[0] = randomByte(pCtx);	zBuf++;	
 12987  		if( zBuf >= zEnd ){break;}	zBuf[0] = randomByte(pCtx);	zBuf++;	
 12988  		if( zBuf >= zEnd ){break;}	zBuf[0] = randomByte(pCtx);	zBuf++;	
 12989  		if( zBuf >= zEnd ){break;}	zBuf[0] = randomByte(pCtx);	zBuf++;	
 12990  	}
 12991  	return SXRET_OK;  
 12992  }
 12993  #ifdef VEDIS_ENABLE_HASH_CMD
 12994  /* SyRunTimeApi: sxhash.c */
 12995  /*
 12996   * This code implements the MD5 message-digest algorithm.
 12997   * The algorithm is due to Ron Rivest.This code was
 12998   * written by Colin Plumb in 1993, no copyright is claimed.
 12999   * This code is in the public domain; do with it what you wish.
 13000   *
 13001   * Equivalent code is available from RSA Data Security, Inc.
 13002   * This code has been tested against that, and is equivalent, 
 13003   * except that you don't need to include two pages of legalese
 13004   * with every copy.
 13005   *
 13006   * To compute the message digest of a chunk of bytes, declare an
 13007   * MD5Context structure, pass it to MD5Init, call MD5Update as
 13008   * needed on buffers full of bytes, and then call MD5Final, which
 13009   * will fill a supplied 16-byte array with the digest.
 13010   */
 13011  #define SX_MD5_BINSZ	16
 13012  #define SX_MD5_HEXSZ	32
 13013  /*
 13014   * Note: this code is harmless on little-endian machines.
 13015   */
 13016  static void byteReverse (unsigned char *buf, unsigned longs)
 13017  {
 13018  	sxu32 t;
 13019          do {
 13020                  t = (sxu32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
 13021                              ((unsigned)buf[1]<<8 | buf[0]);
 13022                  *(sxu32*)buf = t;
 13023                  buf += 4;
 13024          } while (--longs);
 13025  }
 13026  /* The four core functions - F1 is optimized somewhat */
 13027  
 13028  /* #define F1(x, y, z) (x & y | ~x & z) */
 13029  #ifdef F1
 13030  #undef F1
 13031  #endif
 13032  #ifdef F2
 13033  #undef F2
 13034  #endif
 13035  #ifdef F3
 13036  #undef F3
 13037  #endif
 13038  #ifdef F4
 13039  #undef F4
 13040  #endif
 13041  
 13042  #define F1(x, y, z) (z ^ (x & (y ^ z)))
 13043  #define F2(x, y, z) F1(z, x, y)
 13044  #define F3(x, y, z) (x ^ y ^ z)
 13045  #define F4(x, y, z) (y ^ (x | ~z))
 13046  
 13047  /* This is the central step in the MD5 algorithm.*/
 13048  #define SX_MD5STEP(f, w, x, y, z, data, s) \
 13049          ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
 13050  
 13051  /*
 13052   * The core of the MD5 algorithm, this alters an existing MD5 hash to
 13053   * reflect the addition of 16 longwords of new data.MD5Update blocks
 13054   * the data and converts bytes into longwords for this routine.
 13055   */
 13056  static void MD5Transform(sxu32 buf[4], const sxu32 in[16])
 13057  {
 13058  	register sxu32 a, b, c, d;
 13059  
 13060          a = buf[0];
 13061          b = buf[1];
 13062          c = buf[2];
 13063          d = buf[3];
 13064  
 13065          SX_MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
 13066          SX_MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
 13067          SX_MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
 13068          SX_MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
 13069          SX_MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
 13070          SX_MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
 13071          SX_MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
 13072          SX_MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
 13073          SX_MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
 13074          SX_MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
 13075          SX_MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
 13076          SX_MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
 13077          SX_MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
 13078          SX_MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
 13079          SX_MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
 13080          SX_MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
 13081  
 13082          SX_MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
 13083          SX_MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
 13084          SX_MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
 13085          SX_MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
 13086          SX_MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
 13087          SX_MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
 13088          SX_MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
 13089          SX_MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
 13090          SX_MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
 13091          SX_MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
 13092          SX_MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
 13093          SX_MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
 13094          SX_MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
 13095          SX_MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
 13096          SX_MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
 13097          SX_MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
 13098  
 13099          SX_MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
 13100          SX_MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
 13101          SX_MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
 13102          SX_MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
 13103          SX_MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
 13104          SX_MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
 13105          SX_MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
 13106          SX_MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
 13107          SX_MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
 13108          SX_MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
 13109          SX_MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
 13110          SX_MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
 13111          SX_MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
 13112          SX_MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
 13113          SX_MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
 13114          SX_MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
 13115  
 13116          SX_MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
 13117          SX_MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
 13118          SX_MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
 13119          SX_MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
 13120          SX_MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
 13121          SX_MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
 13122          SX_MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
 13123          SX_MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
 13124          SX_MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
 13125          SX_MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
 13126          SX_MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
 13127          SX_MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
 13128          SX_MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
 13129          SX_MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
 13130          SX_MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
 13131          SX_MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
 13132  
 13133          buf[0] += a;
 13134          buf[1] += b;
 13135          buf[2] += c;
 13136          buf[3] += d;
 13137  }
 13138  /*
 13139   * Update context to reflect the concatenation of another buffer full
 13140   * of bytes.
 13141   */
 13142  VEDIS_PRIVATE void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len)
 13143  {
 13144  	sxu32 t;
 13145  
 13146          /* Update bitcount */
 13147          t = ctx->bits[0];
 13148          if ((ctx->bits[0] = t + ((sxu32)len << 3)) < t)
 13149                  ctx->bits[1]++; /* Carry from low to high */
 13150          ctx->bits[1] += len >> 29;
 13151          t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
 13152          /* Handle any leading odd-sized chunks */
 13153          if ( t ) {
 13154                  unsigned char *p = (unsigned char *)ctx->in + t;
 13155  
 13156                  t = 64-t;
 13157                  if (len < t) {
 13158                          SyMemcpy(buf, p, len);
 13159                          return;
 13160                  }
 13161                  SyMemcpy(buf, p, t);
 13162                  byteReverse(ctx->in, 16);
 13163                  MD5Transform(ctx->buf, (sxu32*)ctx->in);
 13164                  buf += t;
 13165                  len -= t;
 13166          }
 13167          /* Process data in 64-byte chunks */
 13168          while (len >= 64) {
 13169                  SyMemcpy(buf, ctx->in, 64);
 13170                  byteReverse(ctx->in, 16);
 13171                  MD5Transform(ctx->buf, (sxu32*)ctx->in);
 13172                  buf += 64;
 13173                  len -= 64;
 13174          }
 13175          /* Handle any remaining bytes of data.*/
 13176          SyMemcpy(buf, ctx->in, len);
 13177  }
 13178  /*
 13179   * Final wrapup - pad to 64-byte boundary with the bit pattern 
 13180   * 1 0* (64-bit count of bits processed, MSB-first)
 13181   */
 13182  VEDIS_PRIVATE void MD5Final(unsigned char digest[16], MD5Context *ctx){
 13183          unsigned count;
 13184          unsigned char *p;
 13185  
 13186          /* Compute number of bytes mod 64 */
 13187          count = (ctx->bits[0] >> 3) & 0x3F;
 13188  
 13189          /* Set the first char of padding to 0x80.This is safe since there is
 13190             always at least one byte free */
 13191          p = ctx->in + count;
 13192          *p++ = 0x80;
 13193  
 13194          /* Bytes of padding needed to make 64 bytes */
 13195          count = 64 - 1 - count;
 13196  
 13197          /* Pad out to 56 mod 64 */
 13198          if (count < 8) {
 13199                  /* Two lots of padding:  Pad the first block to 64 bytes */
 13200                 SyZero(p, count);
 13201                  byteReverse(ctx->in, 16);
 13202                  MD5Transform(ctx->buf, (sxu32*)ctx->in);
 13203  
 13204                  /* Now fill the next block with 56 bytes */
 13205                  SyZero(ctx->in, 56);
 13206          } else {
 13207                  /* Pad block to 56 bytes */
 13208                  SyZero(p, count-8);
 13209          }
 13210          byteReverse(ctx->in, 14);
 13211  
 13212          /* Append length in bits and transform */
 13213          ((sxu32*)ctx->in)[ 14 ] = ctx->bits[0];
 13214          ((sxu32*)ctx->in)[ 15 ] = ctx->bits[1];
 13215  
 13216          MD5Transform(ctx->buf, (sxu32*)ctx->in);
 13217          byteReverse((unsigned char *)ctx->buf, 4);
 13218          SyMemcpy(ctx->buf, digest, 0x10);
 13219          SyZero(ctx, sizeof(ctx));    /* In case it's sensitive */
 13220  }
 13221  #undef F1
 13222  #undef F2
 13223  #undef F3
 13224  #undef F4
 13225  VEDIS_PRIVATE sxi32 MD5Init(MD5Context *pCtx)
 13226  {	
 13227  	pCtx->buf[0] = 0x67452301;
 13228      pCtx->buf[1] = 0xefcdab89;
 13229      pCtx->buf[2] = 0x98badcfe;
 13230      pCtx->buf[3] = 0x10325476;
 13231      pCtx->bits[0] = 0;
 13232      pCtx->bits[1] = 0;
 13233     
 13234     return SXRET_OK;
 13235  }
 13236  VEDIS_PRIVATE sxi32 SyMD5Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[16])
 13237  {
 13238  	MD5Context sCtx;
 13239  	MD5Init(&sCtx);
 13240  	MD5Update(&sCtx, (const unsigned char *)pIn, nLen);
 13241  	MD5Final(zDigest, &sCtx);	
 13242  	return SXRET_OK;
 13243  }
 13244  /*
 13245   * SHA-1 in C
 13246   * By Steve Reid <steve@edmweb.com>
 13247   * Status: Public Domain
 13248   */
 13249  /*
 13250   * blk0() and blk() perform the initial expand.
 13251   * I got the idea of expanding during the round function from SSLeay
 13252   *
 13253   * blk0le() for little-endian and blk0be() for big-endian.
 13254   */
 13255  #if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
 13256  /*
 13257   * GCC by itself only generates left rotates.  Use right rotates if
 13258   * possible to be kinder to dinky implementations with iterative rotate
 13259   * instructions.
 13260   */
 13261  #define SHA_ROT(op, x, k) \
 13262          ({ unsigned int y; asm(op " %1, %0" : "=r" (y) : "I" (k), "0" (x)); y; })
 13263  #define rol(x, k) SHA_ROT("roll", x, k)
 13264  #define ror(x, k) SHA_ROT("rorl", x, k)
 13265  
 13266  #else
 13267  /* Generic C equivalent */
 13268  #define SHA_ROT(x, l, r) ((x) << (l) | (x) >> (r))
 13269  #define rol(x, k) SHA_ROT(x, k, 32-(k))
 13270  #define ror(x, k) SHA_ROT(x, 32-(k), k)
 13271  #endif
 13272  
 13273  #define blk0le(i) (block[i] = (ror(block[i], 8)&0xFF00FF00) \
 13274      |(rol(block[i], 8)&0x00FF00FF))
 13275  #define blk0be(i) block[i]
 13276  #define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
 13277      ^block[(i+2)&15]^block[i&15], 1))
 13278  
 13279  /*
 13280   * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
 13281   *
 13282   * Rl0() for little-endian and Rb0() for big-endian.  Endianness is 
 13283   * determined at run-time.
 13284   */
 13285  #define Rl0(v, w, x, y, z, i) \
 13286      z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v, 5);w=ror(w, 2);
 13287  #define Rb0(v, w, x, y, z, i) \
 13288      z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v, 5);w=ror(w, 2);
 13289  #define R1(v, w, x, y, z, i) \
 13290      z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v, 5);w=ror(w, 2);
 13291  #define R2(v, w, x, y, z, i) \
 13292      z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v, 5);w=ror(w, 2);
 13293  #define R3(v, w, x, y, z, i) \
 13294      z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v, 5);w=ror(w, 2);
 13295  #define R4(v, w, x, y, z, i) \
 13296      z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v, 5);w=ror(w, 2);
 13297  
 13298  /*
 13299   * Hash a single 512-bit block. This is the core of the algorithm.
 13300   */
 13301  #define a qq[0]
 13302  #define b qq[1]
 13303  #define c qq[2]
 13304  #define d qq[3]
 13305  #define e qq[4]
 13306  
 13307  static void SHA1Transform(unsigned int state[5], const unsigned char buffer[64])
 13308  {
 13309    unsigned int qq[5]; /* a, b, c, d, e; */
 13310    static int one = 1;
 13311    unsigned int block[16];
 13312    SyMemcpy(buffer, (void *)block, 64);
 13313    SyMemcpy(state, qq, 5*sizeof(unsigned int));
 13314  
 13315    /* Copy context->state[] to working vars */
 13316    /*
 13317    a = state[0];
 13318    b = state[1];
 13319    c = state[2];
 13320    d = state[3];
 13321    e = state[4];
 13322    */
 13323  
 13324    /* 4 rounds of 20 operations each. Loop unrolled. */
 13325    if( 1 == *(unsigned char*)&one ){
 13326      Rl0(a, b, c, d, e, 0); Rl0(e, a, b, c, d, 1); Rl0(d, e, a, b, c, 2); Rl0(c, d, e, a, b, 3);
 13327      Rl0(b, c, d, e, a, 4); Rl0(a, b, c, d, e, 5); Rl0(e, a, b, c, d, 6); Rl0(d, e, a, b, c, 7);
 13328      Rl0(c, d, e, a, b, 8); Rl0(b, c, d, e, a, 9); Rl0(a, b, c, d, e, 10); Rl0(e, a, b, c, d, 11);
 13329      Rl0(d, e, a, b, c, 12); Rl0(c, d, e, a, b, 13); Rl0(b, c, d, e, a, 14); Rl0(a, b, c, d, e, 15);
 13330    }else{
 13331      Rb0(a, b, c, d, e, 0); Rb0(e, a, b, c, d, 1); Rb0(d, e, a, b, c, 2); Rb0(c, d, e, a, b, 3);
 13332      Rb0(b, c, d, e, a, 4); Rb0(a, b, c, d, e, 5); Rb0(e, a, b, c, d, 6); Rb0(d, e, a, b, c, 7);
 13333      Rb0(c, d, e, a, b, 8); Rb0(b, c, d, e, a, 9); Rb0(a, b, c, d, e, 10); Rb0(e, a, b, c, d, 11);
 13334      Rb0(d, e, a, b, c, 12); Rb0(c, d, e, a, b, 13); Rb0(b, c, d, e, a, 14); Rb0(a, b, c, d, e, 15);
 13335    }
 13336    R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19);
 13337    R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23);
 13338    R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27);
 13339    R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31);
 13340    R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35);
 13341    R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39);
 13342    R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43);
 13343    R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47);
 13344    R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51);
 13345    R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55);
 13346    R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59);
 13347    R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63);
 13348    R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67);
 13349    R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71);
 13350    R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75);
 13351    R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79);
 13352  
 13353    /* Add the working vars back into context.state[] */
 13354    state[0] += a;
 13355    state[1] += b;
 13356    state[2] += c;
 13357    state[3] += d;
 13358    state[4] += e;
 13359  }
 13360  #undef a
 13361  #undef b
 13362  #undef c
 13363  #undef d
 13364  #undef e
 13365  /*
 13366   * SHA1Init - Initialize new context
 13367   */
 13368  VEDIS_PRIVATE void SHA1Init(SHA1Context *context){
 13369      /* SHA1 initialization constants */
 13370      context->state[0] = 0x67452301;
 13371      context->state[1] = 0xEFCDAB89;
 13372      context->state[2] = 0x98BADCFE;
 13373      context->state[3] = 0x10325476;
 13374      context->state[4] = 0xC3D2E1F0;
 13375      context->count[0] = context->count[1] = 0;
 13376  }
 13377  /*
 13378   * Run your data through this.
 13379   */
 13380  VEDIS_PRIVATE void SHA1Update(SHA1Context *context, const unsigned char *data, unsigned int len){
 13381      unsigned int i, j;
 13382  
 13383      j = context->count[0];
 13384      if ((context->count[0] += len << 3) < j)
 13385  	context->count[1] += (len>>29)+1;
 13386      j = (j >> 3) & 63;
 13387      if ((j + len) > 63) {
 13388  		(void)SyMemcpy(data, &context->buffer[j],  (i = 64-j));
 13389  	SHA1Transform(context->state, context->buffer);
 13390  	for ( ; i + 63 < len; i += 64)
 13391  	    SHA1Transform(context->state, &data[i]);
 13392  	j = 0;
 13393      } else {
 13394  	i = 0;
 13395      }
 13396  	(void)SyMemcpy(&data[i], &context->buffer[j], len - i);
 13397  }
 13398  /*
 13399   * Add padding and return the message digest.
 13400   */
 13401  VEDIS_PRIVATE void SHA1Final(SHA1Context *context, unsigned char digest[20]){
 13402      unsigned int i;
 13403      unsigned char finalcount[8];
 13404  
 13405      for (i = 0; i < 8; i++) {
 13406  	finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
 13407  	 >> ((3-(i & 3)) * 8) ) & 255);	 /* Endian independent */
 13408      }
 13409      SHA1Update(context, (const unsigned char *)"\200", 1);
 13410      while ((context->count[0] & 504) != 448)
 13411  	SHA1Update(context, (const unsigned char *)"\0", 1);
 13412      SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
 13413  
 13414      if (digest) {
 13415  	for (i = 0; i < 20; i++)
 13416  	    digest[i] = (unsigned char)
 13417  		((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
 13418      }
 13419  }
 13420  #undef Rl0
 13421  #undef Rb0
 13422  #undef R1
 13423  #undef R2
 13424  #undef R3
 13425  #undef R4
 13426  
 13427  VEDIS_PRIVATE sxi32 SySha1Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[20])
 13428  {
 13429  	SHA1Context sCtx;
 13430  	SHA1Init(&sCtx);
 13431  	SHA1Update(&sCtx, (const unsigned char *)pIn, nLen);
 13432  	SHA1Final(&sCtx, zDigest);
 13433  	return SXRET_OK;
 13434  }
 13435  static const sxu32 crc32_table[] = {
 13436  	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 
 13437  	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 
 13438  	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 
 13439  	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 
 13440  	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 
 13441  	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 
 13442  	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 
 13443  	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 
 13444  	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 
 13445  	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 
 13446  	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 
 13447  	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 
 13448  	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 
 13449  	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 
 13450  	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 
 13451  	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 
 13452  	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 
 13453  	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 
 13454  	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 
 13455  	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 
 13456  	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 
 13457  	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 
 13458  	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 
 13459  	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 
 13460  	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 
 13461  	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 
 13462  	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 
 13463  	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 
 13464  	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 
 13465  	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 
 13466  	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 
 13467  	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 
 13468  	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 
 13469  	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 
 13470  	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 
 13471  	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 
 13472  	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 
 13473  	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 
 13474  	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 
 13475  	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 
 13476  	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 
 13477  	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 
 13478  	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 
 13479  	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 
 13480  	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 
 13481  	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 
 13482  	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 
 13483  	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 
 13484  	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 
 13485  	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 
 13486  	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 
 13487  	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 
 13488  	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 
 13489  	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 
 13490  	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 
 13491  	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 
 13492  	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 
 13493  	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 
 13494  	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 
 13495  	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 
 13496  	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 
 13497  	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 
 13498  	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 
 13499  	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 
 13500  };
 13501  #define CRC32C(c, d) (c = ( crc32_table[(c ^ (d)) & 0xFF] ^ (c>>8) ) )
 13502  static sxu32 SyCrc32Update(sxu32 crc32, const void *pSrc, sxu32 nLen)
 13503  {
 13504  	register unsigned char *zIn = (unsigned char *)pSrc;
 13505  	unsigned char *zEnd;
 13506  	if( zIn == 0 ){
 13507  		return crc32;
 13508  	}
 13509  	zEnd = &zIn[nLen];
 13510  	for(;;){
 13511  		if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
 13512  		if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
 13513  		if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
 13514  		if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++;
 13515  	}
 13516  		
 13517  	return crc32;
 13518  }
 13519  VEDIS_PRIVATE sxu32 SyCrc32(const void *pSrc, sxu32 nLen)
 13520  {
 13521  	return SyCrc32Update(SXU32_HIGH, pSrc, nLen);
 13522  }
 13523  VEDIS_PRIVATE sxi32 SyBinToHexConsumer(const void *pIn, sxu32 nLen, ProcConsumer xConsumer, void *pConsumerData)
 13524  {
 13525  	static const unsigned char zHexTab[] = "0123456789abcdef";
 13526  	const unsigned char *zIn, *zEnd;
 13527  	unsigned char zOut[3];
 13528  	sxi32 rc;
 13529  #if defined(UNTRUST)
 13530  	if( pIn == 0 || xConsumer == 0 ){
 13531  		return SXERR_EMPTY;
 13532  	}
 13533  #endif
 13534  	zIn   = (const unsigned char *)pIn;
 13535  	zEnd  = &zIn[nLen];
 13536  	for(;;){
 13537  		if( zIn >= zEnd  ){
 13538  			break;
 13539  		}
 13540  		zOut[0] = zHexTab[zIn[0] >> 4];  zOut[1] = zHexTab[zIn[0] & 0x0F];
 13541  		rc = xConsumer((const void *)zOut, sizeof(char)*2, pConsumerData);
 13542  		if( rc != SXRET_OK ){
 13543  			return rc;
 13544  		}
 13545  		zIn++; 
 13546  	}
 13547  	return SXRET_OK;
 13548  }
 13549  #endif /* VEDIS_ENABLE_HASH_CMD */
 13550  VEDIS_PRIVATE void SyBigEndianPack32(unsigned char *buf,sxu32 nb)
 13551  {
 13552  	buf[3] = nb & 0xFF ; nb >>=8;
 13553  	buf[2] = nb & 0xFF ; nb >>=8;
 13554  	buf[1] = nb & 0xFF ; nb >>=8;
 13555  	buf[0] = (unsigned char)nb ;
 13556  }
 13557  VEDIS_PRIVATE void SyBigEndianUnpack32(const unsigned char *buf,sxu32 *uNB)
 13558  {
 13559  	*uNB = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24);
 13560  }
 13561  VEDIS_PRIVATE void SyBigEndianPack16(unsigned char *buf,sxu16 nb)
 13562  {
 13563  	buf[1] = nb & 0xFF ; nb >>=8;
 13564  	buf[0] = (unsigned char)nb ;
 13565  }
 13566  VEDIS_PRIVATE void SyBigEndianUnpack16(const unsigned char *buf,sxu16 *uNB)
 13567  {
 13568  	*uNB = buf[1] + (buf[0] << 8);
 13569  }
 13570  VEDIS_PRIVATE void SyBigEndianPack64(unsigned char *buf,sxu64 n64)
 13571  {
 13572  	buf[7] = n64 & 0xFF; n64 >>=8;
 13573  	buf[6] = n64 & 0xFF; n64 >>=8;
 13574  	buf[5] = n64 & 0xFF; n64 >>=8;
 13575  	buf[4] = n64 & 0xFF; n64 >>=8;
 13576  	buf[3] = n64 & 0xFF; n64 >>=8;
 13577  	buf[2] = n64 & 0xFF; n64 >>=8;
 13578  	buf[1] = n64 & 0xFF; n64 >>=8;
 13579  	buf[0] = (sxu8)n64 ; 
 13580  }
 13581  VEDIS_PRIVATE void SyBigEndianUnpack64(const unsigned char *buf,sxu64 *n64)
 13582  {
 13583  	sxu32 u1,u2;
 13584  	u1 = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
 13585  	u2 = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24);
 13586  	*n64 = (((sxu64)u2) << 32) | u1;
 13587  }
 13588  #if 0
 13589  VEDIS_PRIVATE sxi32 SyBlobAppendBig64(SyBlob *pBlob,sxu64 n64)
 13590  {
 13591  	unsigned char zBuf[8];
 13592  	sxi32 rc;
 13593  	SyBigEndianPack64(zBuf,n64);
 13594  	rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf));
 13595  	return rc;
 13596  }
 13597  #endif
 13598  VEDIS_PRIVATE sxi32 SyBlobAppendBig32(SyBlob *pBlob,sxu32 n32)
 13599  {
 13600  	unsigned char zBuf[4];
 13601  	sxi32 rc;
 13602  	SyBigEndianPack32(zBuf,n32);
 13603  	rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf));
 13604  	return rc;
 13605  }
 13606  VEDIS_PRIVATE sxi32 SyBlobAppendBig16(SyBlob *pBlob,sxu16 n16)
 13607  {
 13608  	unsigned char zBuf[2];
 13609  	sxi32 rc;
 13610  	SyBigEndianPack16(zBuf,n16);
 13611  	rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf));
 13612  	return rc;
 13613  }
 13614  VEDIS_PRIVATE void SyTimeFormatToDos(Sytm *pFmt,sxu32 *pOut)
 13615  {
 13616  	sxi32 nDate,nTime;
 13617  	nDate = ((pFmt->tm_year - 1980) << 9) + (pFmt->tm_mon << 5) + pFmt->tm_mday;
 13618  	nTime = (pFmt->tm_hour << 11) + (pFmt->tm_min << 5)+ (pFmt->tm_sec >> 1);
 13619  	*pOut = (nDate << 16) | nTime;
 13620  }
 13621  VEDIS_PRIVATE void SyDosTimeFormat(sxu32 nDosDate, Sytm *pOut)
 13622  {
 13623  	sxu16 nDate;
 13624  	sxu16 nTime;
 13625  	nDate = nDosDate >> 16;
 13626  	nTime = nDosDate & 0xFFFF;
 13627  	pOut->tm_isdst  = 0;
 13628  	pOut->tm_year 	= 1980 + (nDate >> 9);
 13629  	pOut->tm_mon	= (nDate % (1<<9))>>5;
 13630  	pOut->tm_mday	= (nDate % (1<<9))&0x1F;
 13631  	pOut->tm_hour	= nTime >> 11;
 13632  	pOut->tm_min	= (nTime % (1<<11)) >> 5;
 13633  	pOut->tm_sec	= ((nTime % (1<<11))& 0x1F )<<1;
 13634  }
 13635  /*
 13636   * ----------------------------------------------------------
 13637   * File: lhash_kv.c
 13638   * MD5: 8d719faf8d557b1132dd0f52e2f5560b
 13639   * ----------------------------------------------------------
 13640   */
 13641  /*
 13642   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
 13643   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
 13644   * Version 1.1.6
 13645   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 13646   * please contact Symisc Systems via:
 13647   *       legal@symisc.net
 13648   *       licensing@symisc.net
 13649   *       contact@symisc.net
 13650   * or visit:
 13651   *      http://vedis.org/licensing.html
 13652   */
 13653   /* $SymiscID: lhash_kv.c v1.7 Solaris 2013-01-14 12:56 stable <chm@symisc.net> $ */
 13654  #ifndef VEDIS_AMALGAMATION
 13655  #include "vedisInt.h"
 13656  #endif
 13657  /* 
 13658   * This file implements disk based hashtable using the linear hashing algorithm.
 13659   * This implementation is the one decribed in the paper:
 13660   *  LINEAR HASHING : A NEW TOOL FOR FILE AND TABLE ADDRESSING. Witold Litwin. I. N. Ft. I. A.. 78 150 Le Chesnay, France.
 13661   * Plus a smart extension called Virtual Bucket Table. (contact devel@symisc.net for additional information).
 13662   */
 13663  /* Magic number identifying a valid storage image */
 13664  #define L_HASH_MAGIC 0xDE671CEF
 13665  /*
 13666   * Magic word to hash to identify a valid hash function.
 13667   */
 13668  #define L_HASH_WORD "chm@symisc"
 13669  /*
 13670   * Cell size on disk. 
 13671   */
 13672  #define L_HASH_CELL_SZ (4/*Hash*/+4/*Key*/+8/*Data*/+2/* Offset of the next cell */+8/*Overflow*/)
 13673  /*
 13674   * Primary page (not overflow pages) header size on disk.
 13675   */
 13676  #define L_HASH_PAGE_HDR_SZ (2/* Cell offset*/+2/* Free block offset*/+8/*Slave page number*/)
 13677  /*
 13678   * The maximum amount of payload (in bytes) that can be stored locally for
 13679   * a database entry.  If the entry contains more data than this, the
 13680   * extra goes onto overflow pages.
 13681  */
 13682  #define L_HASH_MX_PAYLOAD(PageSize)  (PageSize-(L_HASH_PAGE_HDR_SZ+L_HASH_CELL_SZ))
 13683  /*
 13684   * Maxium free space on a single page.
 13685   */
 13686  #define L_HASH_MX_FREE_SPACE(PageSize) (PageSize - (L_HASH_PAGE_HDR_SZ))
 13687  /*
 13688  ** The maximum number of bytes of payload allowed on a single overflow page.
 13689  */
 13690  #define L_HASH_OVERFLOW_SIZE(PageSize) (PageSize-8)
 13691  /* Forward declaration */
 13692  typedef struct lhash_kv_engine lhash_kv_engine;
 13693  typedef struct lhpage lhpage;
 13694  /*
 13695   * Each record in the database is identified either in-memory or in
 13696   * disk by an instance of the following structure.
 13697   */
 13698  typedef struct lhcell lhcell;
 13699  struct lhcell
 13700  {
 13701  	/* Disk-data (Big-Endian) */
 13702  	sxu32 nHash;   /* Hash of the key: 4 bytes */
 13703  	sxu32 nKey;    /* Key length: 4 bytes */
 13704  	sxu64 nData;   /* Data length: 8 bytes */
 13705  	sxu16 iNext;   /* Offset of the next cell: 2 bytes */
 13706  	pgno iOvfl;    /* Overflow page number if any: 8 bytes */
 13707  	/* In-memory data only */
 13708  	lhpage *pPage;     /* Page this cell belongs */
 13709  	sxu16 iStart;      /* Offset of this cell */
 13710  	pgno iDataPage;    /* Data page number when overflow */
 13711  	sxu16 iDataOfft;   /* Offset of the data in iDataPage */
 13712  	SyBlob sKey;       /* Record key for fast lookup (Kept in-memory if < 256KB ) */
 13713  	lhcell *pNext,*pPrev;         /* Linked list of the loaded memory cells */
 13714  	lhcell *pNextCol,*pPrevCol;   /* Collison chain  */
 13715  };
 13716  /*
 13717  ** Each database page has a header that is an instance of this
 13718  ** structure.
 13719  */
 13720  typedef struct lhphdr lhphdr;
 13721  struct lhphdr 
 13722  {
 13723    sxu16 iOfft; /* Offset of the first cell */
 13724    sxu16 iFree; /* Offset of the first free block*/
 13725    pgno iSlave; /* Slave page number */
 13726  };
 13727  /*
 13728   * Each loaded primary disk page is represented in-memory using
 13729   * an instance of the following structure.
 13730   */
 13731  struct lhpage
 13732  {
 13733  	lhash_kv_engine *pHash;  /* KV Storage engine that own this page */
 13734  	vedis_page *pRaw;      /* Raw page contents */
 13735  	lhphdr sHdr;             /* Processed page header */
 13736  	lhcell **apCell;         /* Cell buckets */
 13737  	lhcell *pList,*pFirst;   /* Linked list of cells */
 13738  	sxu32 nCell;             /* Total number of cells */
 13739  	sxu32 nCellSize;         /* apCell[] size */
 13740  	lhpage *pMaster;         /* Master page in case we are dealing with a slave page */
 13741  	lhpage *pSlave;          /* List of slave pages */
 13742  	lhpage *pNextSlave;      /* Next slave page on the list */
 13743  	sxi32 iSlave;            /* Total number of slave pages */
 13744  	sxu16 nFree;             /* Amount of free space available in the page */
 13745  };
 13746  /*
 13747   * A Bucket map record which is used to map logical bucket number to real
 13748   * bucket number is represented by an instance of the following structure.
 13749   */
 13750  typedef struct lhash_bmap_rec lhash_bmap_rec;
 13751  struct lhash_bmap_rec
 13752  {
 13753  	pgno iLogic;                   /* Logical bucket number */
 13754  	pgno iReal;                    /* Real bucket number */
 13755  	lhash_bmap_rec *pNext,*pPrev;  /* Link to other bucket map */     
 13756  	lhash_bmap_rec *pNextCol,*pPrevCol; /* Collision links */
 13757  };
 13758  typedef struct lhash_bmap_page lhash_bmap_page;
 13759  struct lhash_bmap_page
 13760  {
 13761  	pgno iNum;   /* Page number where this entry is stored */
 13762  	sxu16 iPtr;  /* Offset to start reading/writing from */
 13763  	sxu32 nRec;  /* Total number of records in this page */
 13764  	pgno iNext;  /* Next map page */
 13765  };
 13766  /*
 13767   * An in memory linear hash implemenation is represented by in an isntance
 13768   * of the following structure.
 13769   */
 13770  struct lhash_kv_engine
 13771  {
 13772  	const vedis_kv_io *pIo;     /* IO methods: Must be first */
 13773  	/* Private fields */
 13774  	SyMemBackend sAllocator;      /* Private memory backend */
 13775  	ProcHash xHash;               /* Default hash function */
 13776  	ProcCmp xCmp;                 /* Default comparison function */
 13777  	vedis_page *pHeader;        /* Page one to identify a valid implementation */
 13778  	lhash_bmap_rec **apMap;       /* Buckets map records */
 13779  	sxu32 nBuckRec;               /* Total number of bucket map records */
 13780  	sxu32 nBuckSize;              /* apMap[] size  */
 13781  	lhash_bmap_rec *pList;        /* List of bucket map records */
 13782  	lhash_bmap_rec *pFirst;       /* First record*/
 13783  	lhash_bmap_page sPageMap;     /* Primary bucket map */
 13784  	int iPageSize;                /* Page size */
 13785  	pgno nFreeList;               /* List of free pages */
 13786  	pgno split_bucket;            /* Current split bucket: MUST BE A POWER OF TWO */
 13787  	pgno max_split_bucket;        /* Maximum split bucket: MUST BE A POWER OF TWO */
 13788  	pgno nmax_split_nucket;       /* Next maximum split bucket (1 << nMsb): In-memory only */
 13789  	sxu32 nMagic;                 /* Magic number to identify a valid linear hash disk database */
 13790  };
 13791  /*
 13792   * Given a logical bucket number, return the record associated with it.
 13793   */
 13794  static lhash_bmap_rec * lhMapFindBucket(lhash_kv_engine *pEngine,pgno iLogic)
 13795  {
 13796  	lhash_bmap_rec *pRec;
 13797  	if( pEngine->nBuckRec < 1 ){
 13798  		/* Don't bother */
 13799  		return 0;
 13800  	}
 13801  	pRec = pEngine->apMap[iLogic & (pEngine->nBuckSize - 1)];
 13802  	for(;;){
 13803  		if( pRec == 0 ){
 13804  			break;
 13805  		}
 13806  		if( pRec->iLogic == iLogic ){
 13807  			return pRec;
 13808  		}
 13809  		/* Point to the next entry */
 13810  		pRec = pRec->pNextCol;
 13811  	}
 13812  	/* No such record */
 13813  	return 0;
 13814  }
 13815  /*
 13816   * Install a new bucket map record.
 13817   */
 13818  static int lhMapInstallBucket(lhash_kv_engine *pEngine,pgno iLogic,pgno iReal)
 13819  {
 13820  	lhash_bmap_rec *pRec;
 13821  	sxu32 iBucket;
 13822  	/* Allocate a new instance */
 13823  	pRec = (lhash_bmap_rec *)SyMemBackendPoolAlloc(&pEngine->sAllocator,sizeof(lhash_bmap_rec));
 13824  	if( pRec == 0 ){
 13825  		return VEDIS_NOMEM;
 13826  	}
 13827  	/* Zero the structure */
 13828  	SyZero(pRec,sizeof(lhash_bmap_rec));
 13829  	/* Fill in the structure */
 13830  	pRec->iLogic = iLogic;
 13831  	pRec->iReal = iReal;
 13832  	iBucket = iLogic & (pEngine->nBuckSize - 1);
 13833  	pRec->pNextCol = pEngine->apMap[iBucket];
 13834  	if( pEngine->apMap[iBucket] ){
 13835  		pEngine->apMap[iBucket]->pPrevCol = pRec;
 13836  	}
 13837  	pEngine->apMap[iBucket] = pRec;
 13838  	/* Link */
 13839  	if( pEngine->pFirst == 0 ){
 13840  		pEngine->pFirst = pEngine->pList = pRec;
 13841  	}else{
 13842  		MACRO_LD_PUSH(pEngine->pList,pRec);
 13843  	}
 13844  	pEngine->nBuckRec++;
 13845  	if( (pEngine->nBuckRec >= pEngine->nBuckSize * 3) && pEngine->nBuckRec < 100000 ){
 13846  		/* Allocate a new larger table */
 13847  		sxu32 nNewSize = pEngine->nBuckSize << 1;
 13848  		lhash_bmap_rec *pEntry;
 13849  		lhash_bmap_rec **apNew;
 13850  		sxu32 n;
 13851  		
 13852  		apNew = (lhash_bmap_rec **)SyMemBackendAlloc(&pEngine->sAllocator, nNewSize * sizeof(lhash_bmap_rec *));
 13853  		if( apNew ){
 13854  			/* Zero the new table */
 13855  			SyZero((void *)apNew, nNewSize * sizeof(lhash_bmap_rec *));
 13856  			/* Rehash all entries */
 13857  			n = 0;
 13858  			pEntry = pEngine->pList;
 13859  			for(;;){
 13860  				/* Loop one */
 13861  				if( n >= pEngine->nBuckRec ){
 13862  					break;
 13863  				}
 13864  				pEntry->pNextCol = pEntry->pPrevCol = 0;
 13865  				/* Install in the new bucket */
 13866  				iBucket = pEntry->iLogic & (nNewSize - 1);
 13867  				pEntry->pNextCol = apNew[iBucket];
 13868  				if( apNew[iBucket] ){
 13869  					apNew[iBucket]->pPrevCol = pEntry;
 13870  				}
 13871  				apNew[iBucket] = pEntry;
 13872  				/* Point to the next entry */
 13873  				pEntry = pEntry->pNext;
 13874  				n++;
 13875  			}
 13876  			/* Release the old table and reflect the change */
 13877  			SyMemBackendFree(&pEngine->sAllocator,(void *)pEngine->apMap);
 13878  			pEngine->apMap = apNew;
 13879  			pEngine->nBuckSize  = nNewSize;
 13880  		}
 13881  	}
 13882  	return VEDIS_OK;
 13883  }
 13884  /*
 13885   * Process a raw bucket map record.
 13886   */
 13887  static int lhMapLoadPage(lhash_kv_engine *pEngine,lhash_bmap_page *pMap,const unsigned char *zRaw)
 13888  {
 13889  	const unsigned char *zEnd = &zRaw[pEngine->iPageSize];
 13890  	const unsigned char *zPtr = zRaw;
 13891  	pgno iLogic,iReal;
 13892  	sxu32 n;
 13893  	int rc;
 13894  	if( pMap->iPtr == 0 ){
 13895  		/* Read the map header */
 13896  		SyBigEndianUnpack64(zRaw,&pMap->iNext);
 13897  		zRaw += 8;
 13898  		SyBigEndianUnpack32(zRaw,&pMap->nRec);
 13899  		zRaw += 4;
 13900  	}else{
 13901  		/* Mostly page one of the database */
 13902  		zRaw += pMap->iPtr;
 13903  	}
 13904  	/* Start processing */
 13905  	for( n = 0; n < pMap->nRec ; ++n ){
 13906  		if( zRaw >= zEnd ){
 13907  			break;
 13908  		}
 13909  		/* Extract the logical and real bucket number */
 13910  		SyBigEndianUnpack64(zRaw,&iLogic);
 13911  		zRaw += 8;
 13912  		SyBigEndianUnpack64(zRaw,&iReal);
 13913  		zRaw += 8;
 13914  		/* Install the record in the map */
 13915  		rc = lhMapInstallBucket(pEngine,iLogic,iReal);
 13916  		if( rc != VEDIS_OK ){
 13917  			return rc;
 13918  		}
 13919  	}
 13920  	pMap->iPtr = (sxu16)(zRaw-zPtr);
 13921  	/* All done */
 13922  	return VEDIS_OK;
 13923  }
 13924  /* 
 13925   * Allocate a new cell instance.
 13926   */
 13927  static lhcell * lhNewCell(lhash_kv_engine *pEngine,lhpage *pPage)
 13928  {
 13929  	lhcell *pCell;
 13930  	pCell = (lhcell *)SyMemBackendPoolAlloc(&pEngine->sAllocator,sizeof(lhcell));
 13931  	if( pCell == 0 ){
 13932  		return 0;
 13933  	}
 13934  	/* Zero the structure */
 13935  	SyZero(pCell,sizeof(lhcell));
 13936  	/* Fill in the structure */
 13937  	SyBlobInit(&pCell->sKey,&pEngine->sAllocator);
 13938  	pCell->pPage = pPage;
 13939  	return pCell;
 13940  }
 13941  /*
 13942   * Discard a cell from the page table.
 13943   */
 13944  static void lhCellDiscard(lhcell *pCell)
 13945  {
 13946  	lhpage *pPage = pCell->pPage->pMaster;	
 13947  	
 13948  	if( pCell->pPrevCol ){
 13949  		pCell->pPrevCol->pNextCol = pCell->pNextCol;
 13950  	}else{
 13951  		pPage->apCell[pCell->nHash & (pPage->nCellSize - 1)] = pCell->pNextCol;
 13952  	}
 13953  	if( pCell->pNextCol ){
 13954  		pCell->pNextCol->pPrevCol = pCell->pPrevCol;
 13955  	}
 13956  	MACRO_LD_REMOVE(pPage->pList,pCell);
 13957  	if( pCell == pPage->pFirst ){
 13958  		pPage->pFirst = pCell->pPrev;
 13959  	}
 13960  	pPage->nCell--;
 13961  	/* Release the cell */
 13962  	SyBlobRelease(&pCell->sKey);
 13963  	SyMemBackendPoolFree(&pPage->pHash->sAllocator,pCell);
 13964  }
 13965  /*
 13966   * Install a cell in the page table.
 13967   */
 13968  static int lhInstallCell(lhcell *pCell)
 13969  {
 13970  	lhpage *pPage = pCell->pPage->pMaster;
 13971  	sxu32 iBucket;
 13972  	if( pPage->nCell < 1 ){
 13973  		sxu32 nTableSize = 32; /* Must be a power of two */
 13974  		lhcell **apTable;
 13975  		/* Allocate a new cell table */
 13976  		apTable = (lhcell **)SyMemBackendAlloc(&pPage->pHash->sAllocator, nTableSize * sizeof(lhcell *));
 13977  		if( apTable == 0 ){
 13978  			return VEDIS_NOMEM;
 13979  		}
 13980  		/* Zero the new table */
 13981  		SyZero((void *)apTable, nTableSize * sizeof(lhcell *));
 13982  		/* Install it */
 13983  		pPage->apCell = apTable;
 13984  		pPage->nCellSize = nTableSize;
 13985  	}
 13986  	iBucket = pCell->nHash & (pPage->nCellSize - 1);
 13987  	pCell->pNextCol = pPage->apCell[iBucket];
 13988  	if( pPage->apCell[iBucket] ){
 13989  		pPage->apCell[iBucket]->pPrevCol = pCell;
 13990  	}
 13991  	pPage->apCell[iBucket] = pCell;
 13992  	if( pPage->pFirst == 0 ){
 13993  		pPage->pFirst = pPage->pList = pCell;
 13994  	}else{
 13995  		MACRO_LD_PUSH(pPage->pList,pCell);
 13996  	}
 13997  	pPage->nCell++;
 13998  	if( (pPage->nCell >= pPage->nCellSize * 3) && pPage->nCell < 100000 ){
 13999  		/* Allocate a new larger table */
 14000  		sxu32 nNewSize = pPage->nCellSize << 1;
 14001  		lhcell *pEntry;
 14002  		lhcell **apNew;
 14003  		sxu32 n;
 14004  		
 14005  		apNew = (lhcell **)SyMemBackendAlloc(&pPage->pHash->sAllocator, nNewSize * sizeof(lhcell *));
 14006  		if( apNew ){
 14007  			/* Zero the new table */
 14008  			SyZero((void *)apNew, nNewSize * sizeof(lhcell *));
 14009  			/* Rehash all entries */
 14010  			n = 0;
 14011  			pEntry = pPage->pList;
 14012  			for(;;){
 14013  				/* Loop one */
 14014  				if( n >= pPage->nCell ){
 14015  					break;
 14016  				}
 14017  				pEntry->pNextCol = pEntry->pPrevCol = 0;
 14018  				/* Install in the new bucket */
 14019  				iBucket = pEntry->nHash & (nNewSize - 1);
 14020  				pEntry->pNextCol = apNew[iBucket];
 14021  				if( apNew[iBucket]  ){
 14022  					apNew[iBucket]->pPrevCol = pEntry;
 14023  				}
 14024  				apNew[iBucket] = pEntry;
 14025  				/* Point to the next entry */
 14026  				pEntry = pEntry->pNext;
 14027  				n++;
 14028  			}
 14029  			/* Release the old table and reflect the change */
 14030  			SyMemBackendFree(&pPage->pHash->sAllocator,(void *)pPage->apCell);
 14031  			pPage->apCell = apNew;
 14032  			pPage->nCellSize  = nNewSize;
 14033  		}
 14034  	}
 14035  	return VEDIS_OK;
 14036  }
 14037  /*
 14038   * Private data of lhKeyCmp().
 14039   */
 14040  struct lhash_key_cmp
 14041  {
 14042  	const char *zIn;  /* Start of the stream */
 14043  	const char *zEnd; /* End of the stream */
 14044  	ProcCmp xCmp;     /* Comparison function */
 14045  };
 14046  /*
 14047   * Comparsion callback for large key > 256 KB
 14048   */
 14049  static int lhKeyCmp(const void *pData,sxu32 nLen,void *pUserData)
 14050  {
 14051  	struct lhash_key_cmp *pCmp = (struct lhash_key_cmp *)pUserData;
 14052  	int rc;
 14053  	if( pCmp->zIn >= pCmp->zEnd ){
 14054  		if( nLen > 0 ){
 14055  			return VEDIS_ABORT;
 14056  		}
 14057  		return VEDIS_OK;
 14058  	}
 14059  	/* Perform the comparison */
 14060  	rc = pCmp->xCmp((const void *)pCmp->zIn,pData,nLen);
 14061  	if( rc != 0 ){
 14062  		/* Abort comparison */
 14063  		return VEDIS_ABORT;
 14064  	}
 14065  	/* Advance the cursor */
 14066  	pCmp->zIn += nLen;
 14067  	return VEDIS_OK;
 14068  }
 14069  /* Forward declaration */
 14070  static int lhConsumeCellkey(lhcell *pCell,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData,int offt_only);
 14071  /*
 14072   * given a key, return the cell associated with it on success. NULL otherwise.
 14073   */
 14074  static lhcell * lhFindCell(
 14075  	lhpage *pPage,    /* Target page */
 14076  	const void *pKey, /* Lookup key */
 14077  	sxu32 nByte,      /* Key length */
 14078  	sxu32 nHash       /* Hash of the key */
 14079  	)
 14080  {
 14081  	lhcell *pEntry;
 14082  	if( pPage->nCell < 1 ){
 14083  		/* Don't bother hashing */
 14084  		return 0;
 14085  	}
 14086  	/* Point to the corresponding bucket */
 14087  	pEntry = pPage->apCell[nHash & (pPage->nCellSize - 1)];
 14088  	for(;;){
 14089  		if( pEntry == 0 ){
 14090  			break;
 14091  		}
 14092  		if( pEntry->nHash == nHash && pEntry->nKey == nByte ){
 14093  			if( SyBlobLength(&pEntry->sKey) < 1 ){
 14094  				/* Large key (> 256 KB) are not kept in-memory */
 14095  				struct lhash_key_cmp sCmp;
 14096  				int rc;
 14097  				/* Fill-in the structure */
 14098  				sCmp.zIn = (const char *)pKey;
 14099  				sCmp.zEnd = &sCmp.zIn[nByte];
 14100  				sCmp.xCmp = pPage->pHash->xCmp;
 14101  				/* Fetch the key from disk and perform the comparison */
 14102  				rc = lhConsumeCellkey(pEntry,lhKeyCmp,&sCmp,0);
 14103  				if( rc == VEDIS_OK ){
 14104  					/* Cell found */
 14105  					return pEntry;
 14106  				}
 14107  			}else if ( pPage->pHash->xCmp(pKey,SyBlobData(&pEntry->sKey),nByte) == 0 ){
 14108  				/* Cell found */
 14109  				return pEntry;
 14110  			}
 14111  		}
 14112  		/* Point to the next entry */
 14113  		pEntry = pEntry->pNextCol;
 14114  	}
 14115  	/* No such entry */
 14116  	return 0;
 14117  }
 14118  /*
 14119   * Parse a raw cell fetched from disk.
 14120   */
 14121  static int lhParseOneCell(lhpage *pPage,const unsigned char *zRaw,const unsigned char *zEnd,lhcell **ppOut)
 14122  {
 14123  	sxu16 iNext,iOfft;
 14124  	sxu32 iHash,nKey;
 14125  	lhcell *pCell;
 14126  	sxu64 nData;
 14127  	int rc;
 14128  	/* Offset this cell is stored */
 14129  	iOfft = (sxu16)(zRaw - (const unsigned char *)pPage->pRaw->zData);
 14130  	/* 4 byte hash number */
 14131  	SyBigEndianUnpack32(zRaw,&iHash);
 14132  	zRaw += 4;	
 14133  	/* 4 byte key length  */
 14134  	SyBigEndianUnpack32(zRaw,&nKey);
 14135  	zRaw += 4;	
 14136  	/* 8 byte data length */
 14137  	SyBigEndianUnpack64(zRaw,&nData);
 14138  	zRaw += 8;
 14139  	/* 2 byte offset of the next cell */
 14140  	SyBigEndianUnpack16(zRaw,&iNext);
 14141  	/* Perform a sanity check */
 14142  	if( iNext > 0 && &pPage->pRaw->zData[iNext] >= zEnd ){
 14143  		return VEDIS_CORRUPT;
 14144  	}
 14145  	zRaw += 2;
 14146  	pCell = lhNewCell(pPage->pHash,pPage);
 14147  	if( pCell == 0 ){
 14148  		return VEDIS_NOMEM;
 14149  	}
 14150  	/* Fill in the structure */
 14151  	pCell->iNext = iNext;
 14152  	pCell->nKey  = nKey;
 14153  	pCell->nData = nData;
 14154  	pCell->nHash = iHash;
 14155  	/* Overflow page if any */
 14156  	SyBigEndianUnpack64(zRaw,&pCell->iOvfl);
 14157  	zRaw += 8;
 14158  	/* Cell offset */
 14159  	pCell->iStart = iOfft;
 14160  	/* Consume the key */
 14161  	rc = lhConsumeCellkey(pCell,vedisDataConsumer,&pCell->sKey,pCell->nKey > 262144 /* 256 KB */? 1 : 0);
 14162  	if( rc != VEDIS_OK ){
 14163  		/* TICKET: 14-32-chm@symisc.net: Key too large for memory */
 14164  		SyBlobRelease(&pCell->sKey);
 14165  	}
 14166  	/* Finally install the cell */
 14167  	rc = lhInstallCell(pCell);
 14168  	if( rc != VEDIS_OK ){
 14169  		return rc;
 14170  	}
 14171  	if( ppOut ){
 14172  		*ppOut = pCell;
 14173  	}
 14174  	return VEDIS_OK;
 14175  }
 14176  /*
 14177   * Compute the total number of free space on a given page.
 14178   */
 14179  static int lhPageFreeSpace(lhpage *pPage)
 14180  {
 14181  	const unsigned char *zEnd,*zRaw = pPage->pRaw->zData;
 14182  	lhphdr *pHdr = &pPage->sHdr;
 14183  	sxu16 iNext,iAmount;
 14184  	sxu16 nFree = 0;
 14185  	if( pHdr->iFree < 1 ){
 14186  		/* Don't bother processing, the page is full */
 14187  		pPage->nFree = 0;
 14188  		return VEDIS_OK;
 14189  	}
 14190  	/* Point to first free block */
 14191  	zEnd = &zRaw[pPage->pHash->iPageSize];
 14192  	zRaw += pHdr->iFree;
 14193  	for(;;){
 14194  		/* Offset of the next free block */
 14195  		SyBigEndianUnpack16(zRaw,&iNext);
 14196  		zRaw += 2;
 14197  		/* Available space on this block */
 14198  		SyBigEndianUnpack16(zRaw,&iAmount);
 14199  		nFree += iAmount;
 14200  		if( iNext < 1 ){
 14201  			/* No more free blocks */
 14202  			break;
 14203  		}
 14204  		/* Point to the next free block*/
 14205  		zRaw = &pPage->pRaw->zData[iNext];
 14206  		if( zRaw >= zEnd ){
 14207  			/* Corrupt page */
 14208  			return VEDIS_CORRUPT;
 14209  		}
 14210  	}
 14211  	/* Save the amount of free space */
 14212  	pPage->nFree = nFree;
 14213  	return VEDIS_OK;
 14214  }
 14215  /*
 14216   * Given a primary page, load all its cell.
 14217   */
 14218  static int lhLoadCells(lhpage *pPage)
 14219  {
 14220  	const unsigned char *zEnd,*zRaw = pPage->pRaw->zData;
 14221  	lhphdr *pHdr = &pPage->sHdr;
 14222  	lhcell *pCell = 0; /* cc warning */
 14223  	int rc;
 14224  	/* Calculate the amount of free space available first */
 14225  	rc = lhPageFreeSpace(pPage);
 14226  	if( rc != VEDIS_OK ){
 14227  		return rc;
 14228  	}
 14229  	if( pHdr->iOfft < 1 ){
 14230  		/* Don't bother processing, the page is empty */
 14231  		return VEDIS_OK;
 14232  	}
 14233  	/* Point to first cell */
 14234  	zRaw += pHdr->iOfft;
 14235  	zEnd = &zRaw[pPage->pHash->iPageSize];
 14236  	for(;;){
 14237  		/* Parse a single cell */
 14238  		rc = lhParseOneCell(pPage,zRaw,zEnd,&pCell);
 14239  		if( rc != VEDIS_OK ){
 14240  			return rc;
 14241  		}
 14242  		if( pCell->iNext < 1 ){
 14243  			/* No more cells */
 14244  			break;
 14245  		}
 14246  		/* Point to the next cell */
 14247  		zRaw = &pPage->pRaw->zData[pCell->iNext];
 14248  		if( zRaw >= zEnd ){
 14249  			/* Corrupt page */
 14250  			return VEDIS_CORRUPT;
 14251  		}
 14252  	}
 14253  	/* All done */
 14254  	return VEDIS_OK;
 14255  }
 14256  /*
 14257   * Given a page, parse its raw headers.
 14258   */
 14259  static int lhParsePageHeader(lhpage *pPage)
 14260  {
 14261  	const unsigned char *zRaw = pPage->pRaw->zData;
 14262  	lhphdr *pHdr = &pPage->sHdr;
 14263  	/* Offset of the first cell */
 14264  	SyBigEndianUnpack16(zRaw,&pHdr->iOfft);
 14265  	zRaw += 2;
 14266  	/* Offset of the first free block */
 14267  	SyBigEndianUnpack16(zRaw,&pHdr->iFree);
 14268  	zRaw += 2;
 14269  	/* Slave page number */
 14270  	SyBigEndianUnpack64(zRaw,&pHdr->iSlave);
 14271  	/* All done */
 14272  	return VEDIS_OK;
 14273  }
 14274  /*
 14275   * Allocate a new page instance.
 14276   */
 14277  static lhpage * lhNewPage(
 14278  	lhash_kv_engine *pEngine, /* KV store which own this instance */
 14279  	vedis_page *pRaw,       /* Raw page contents */
 14280  	lhpage *pMaster           /* Master page in case we are dealing with a slave page */
 14281  	)
 14282  {
 14283  	lhpage *pPage;
 14284  	/* Allocate a new instance */
 14285  	pPage = (lhpage *)SyMemBackendPoolAlloc(&pEngine->sAllocator,sizeof(lhpage));
 14286  	if( pPage == 0 ){
 14287  		return 0;
 14288  	}
 14289  	/* Zero the structure */
 14290  	SyZero(pPage,sizeof(lhpage));
 14291  	/* Fill-in the structure */
 14292  	pPage->pHash = pEngine;
 14293  	pPage->pRaw = pRaw;
 14294  	pPage->pMaster = pMaster ? pMaster /* Slave page */ : pPage /* Master page */ ;
 14295  	if( pPage->pMaster != pPage ){
 14296  		/* Slave page, attach it to its master */
 14297  		pPage->pNextSlave = pMaster->pSlave;
 14298  		pMaster->pSlave = pPage;
 14299  		pMaster->iSlave++;
 14300  	}
 14301  	/* Save this instance for future fast lookup */
 14302  	pRaw->pUserData = pPage;
 14303  	/* All done */
 14304  	return pPage;
 14305  }
 14306  /*
 14307   * Load a primary and its associated slave pages from disk.
 14308   */
 14309  static int lhLoadPage(lhash_kv_engine *pEngine,pgno pnum,lhpage *pMaster,lhpage **ppOut,int iNest)
 14310  {
 14311  	vedis_page *pRaw;
 14312  	lhpage *pPage = 0; /* cc warning */
 14313  	int rc;
 14314  	/* Aquire the page from the pager first */
 14315  	rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pnum,&pRaw);
 14316  	if( rc != VEDIS_OK ){
 14317  		return rc;
 14318  	}
 14319  	if( pRaw->pUserData ){
 14320  		/* The page is already parsed and loaded in memory. Point to it */
 14321  		pPage = (lhpage *)pRaw->pUserData;
 14322  	}else{
 14323  		/* Allocate a new page */
 14324  		pPage = lhNewPage(pEngine,pRaw,pMaster);
 14325  		if( pPage == 0 ){
 14326  			return VEDIS_NOMEM;
 14327  		}
 14328  		/* Process the page */
 14329  		rc = lhParsePageHeader(pPage);
 14330  		if( rc == VEDIS_OK ){
 14331  			/* Load cells */
 14332  			rc = lhLoadCells(pPage);
 14333  		}
 14334  		if( rc != VEDIS_OK ){
 14335  			pEngine->pIo->xPageUnref(pPage->pRaw); /* pPage will be released inside this call */
 14336  			return rc;
 14337  		}
 14338  		if( pPage->sHdr.iSlave > 0 && iNest < 128 ){
 14339  			if( pMaster == 0 ){
 14340  				pMaster = pPage;
 14341  			}
 14342  			/* Slave page. Not a fatal error if something goes wrong here */
 14343  			lhLoadPage(pEngine,pPage->sHdr.iSlave,pMaster,0,iNest++);
 14344  		}
 14345  	}
 14346  	if( ppOut ){
 14347  		*ppOut = pPage;
 14348  	}
 14349  	return VEDIS_OK;
 14350  }
 14351  /*
 14352   * Given a cell, Consume its key by invoking the given callback for each extracted chunk.
 14353   */
 14354  static int lhConsumeCellkey(
 14355  	lhcell *pCell, /* Target cell */
 14356  	int (*xConsumer)(const void *,unsigned int,void *), /* Consumer callback */
 14357  	void *pUserData, /* Last argument to xConsumer() */
 14358  	int offt_only
 14359  	)
 14360  {
 14361  	lhpage *pPage = pCell->pPage;
 14362  	const unsigned char *zRaw = pPage->pRaw->zData;
 14363  	const unsigned char *zPayload;
 14364  	int rc;
 14365  	/* Point to the payload area */
 14366  	zPayload = &zRaw[pCell->iStart];
 14367  	if( pCell->iOvfl == 0 ){
 14368  		/* Best scenario, consume the key directly without any overflow page */
 14369  		zPayload += L_HASH_CELL_SZ;
 14370  		rc = xConsumer((const void *)zPayload,pCell->nKey,pUserData);
 14371  		if( rc != VEDIS_OK ){
 14372  			rc = VEDIS_ABORT;
 14373  		}
 14374  	}else{
 14375  		lhash_kv_engine *pEngine = pPage->pHash;
 14376  		sxu32 nByte,nData = pCell->nKey;
 14377  		vedis_page *pOvfl;
 14378  		int data_offset = 0;
 14379  		pgno iOvfl;
 14380  		/* Overflow page */
 14381  		iOvfl = pCell->iOvfl;
 14382  		/* Total usable bytes in an overflow page */
 14383  		nByte = L_HASH_OVERFLOW_SIZE(pEngine->iPageSize);
 14384  		for(;;){
 14385  			if( iOvfl == 0 || nData < 1 ){
 14386  				/* no more overflow page */
 14387  				break;
 14388  			}
 14389  			/* Point to the overflow page */
 14390  			rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pOvfl);
 14391  			if( rc != VEDIS_OK ){
 14392  				return rc;
 14393  			}
 14394  			zPayload = &pOvfl->zData[8];
 14395  			/* Point to the raw content */
 14396  			if( !data_offset ){
 14397  				/* Get the data page and offset */
 14398  				SyBigEndianUnpack64(zPayload,&pCell->iDataPage);
 14399  				zPayload += 8;
 14400  				SyBigEndianUnpack16(zPayload,&pCell->iDataOfft);
 14401  				zPayload += 2;
 14402  				if( offt_only ){
 14403  					/* Key too large, grab the data offset and return */
 14404  					pEngine->pIo->xPageUnref(pOvfl);
 14405  					return VEDIS_OK;
 14406  				}
 14407  				data_offset = 1;
 14408  			}
 14409  			/* Consume the key */
 14410  			if( nData <= nByte ){
 14411  				rc = xConsumer((const void *)zPayload,nData,pUserData);
 14412  				if( rc != VEDIS_OK ){
 14413  					pEngine->pIo->xPageUnref(pOvfl);
 14414  					return VEDIS_ABORT;
 14415  				}
 14416  				nData = 0;
 14417  			}else{
 14418  				rc = xConsumer((const void *)zPayload,nByte,pUserData);
 14419  				if( rc != VEDIS_OK ){
 14420  					pEngine->pIo->xPageUnref(pOvfl);
 14421  					return VEDIS_ABORT;
 14422  				}
 14423  				nData -= nByte;
 14424  			}
 14425  			/* Next overflow page in the chain */
 14426  			SyBigEndianUnpack64(pOvfl->zData,&iOvfl);
 14427  			/* Unref the page */
 14428  			pEngine->pIo->xPageUnref(pOvfl);
 14429  		}
 14430  		rc = VEDIS_OK;
 14431  	}
 14432  	return rc;
 14433  }
 14434  /*
 14435   * Given a cell, Consume its data by invoking the given callback for each extracted chunk.
 14436   */
 14437  static int lhConsumeCellData(
 14438  	lhcell *pCell, /* Target cell */
 14439  	int (*xConsumer)(const void *,unsigned int,void *), /* Data consumer callback */
 14440  	void *pUserData /* Last argument to xConsumer() */
 14441  	)
 14442  {
 14443  	lhpage *pPage = pCell->pPage;
 14444  	const unsigned char *zRaw = pPage->pRaw->zData;
 14445  	const unsigned char *zPayload;
 14446  	int rc;
 14447  	/* Point to the payload area */
 14448  	zPayload = &zRaw[pCell->iStart];
 14449  	if( pCell->iOvfl == 0 ){
 14450  		/* Best scenario, consume the data directly without any overflow page */
 14451  		zPayload += L_HASH_CELL_SZ + pCell->nKey;
 14452  		rc = xConsumer((const void *)zPayload,(sxu32)pCell->nData,pUserData);
 14453  		if( rc != VEDIS_OK ){
 14454  			rc = VEDIS_ABORT;
 14455  		}
 14456  	}else{
 14457  		lhash_kv_engine *pEngine = pPage->pHash;
 14458  		sxu64 nData = pCell->nData;
 14459  		vedis_page *pOvfl;
 14460  		int fix_offset = 0;
 14461  		sxu32 nByte;
 14462  		pgno iOvfl;
 14463  		/* Overflow page where data is stored */
 14464  		iOvfl = pCell->iDataPage;
 14465  		for(;;){
 14466  			if( iOvfl == 0 || nData < 1 ){
 14467  				/* no more overflow page */
 14468  				break;
 14469  			}
 14470  			/* Point to the overflow page */
 14471  			rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pOvfl);
 14472  			if( rc != VEDIS_OK ){
 14473  				return rc;
 14474  			}
 14475  			/* Point to the raw content */
 14476  			zPayload = pOvfl->zData;
 14477  			if( !fix_offset ){
 14478  				/* Point to the data */
 14479  				zPayload += pCell->iDataOfft;
 14480  				nByte = pEngine->iPageSize - pCell->iDataOfft;
 14481  				fix_offset = 1;
 14482  			}else{
 14483  				zPayload += 8;
 14484  				/* Total usable bytes in an overflow page */
 14485  				nByte = L_HASH_OVERFLOW_SIZE(pEngine->iPageSize);
 14486  			}
 14487  			/* Consume the data */
 14488  			if( nData <= (sxu64)nByte ){
 14489  				rc = xConsumer((const void *)zPayload,(unsigned int)nData,pUserData);
 14490  				if( rc != VEDIS_OK ){
 14491  					pEngine->pIo->xPageUnref(pOvfl);
 14492  					return VEDIS_ABORT;
 14493  				}
 14494  				nData = 0;
 14495  			}else{
 14496  				if( nByte > 0 ){
 14497  					rc = xConsumer((const void *)zPayload,nByte,pUserData);
 14498  					if( rc != VEDIS_OK ){
 14499  						pEngine->pIo->xPageUnref(pOvfl);
 14500  						return VEDIS_ABORT;
 14501  					}
 14502  					nData -= nByte;
 14503  				}
 14504  			}
 14505  			/* Next overflow page in the chain */
 14506  			SyBigEndianUnpack64(pOvfl->zData,&iOvfl);
 14507  			/* Unref the page */
 14508  			pEngine->pIo->xPageUnref(pOvfl);
 14509  		}
 14510  		rc = VEDIS_OK;
 14511  	}
 14512  	return rc;
 14513  }
 14514  /*
 14515   * Read the linear hash header (Page one of the database).
 14516   */
 14517  static int lhash_read_header(lhash_kv_engine *pEngine,vedis_page *pHeader)
 14518  {
 14519  	const unsigned char *zRaw = pHeader->zData;
 14520  	lhash_bmap_page *pMap;
 14521  	sxu32 nHash;
 14522  	int rc;
 14523  	pEngine->pHeader = pHeader;
 14524  	/* 4 byte magic number */
 14525  	SyBigEndianUnpack32(zRaw,&pEngine->nMagic);
 14526  	zRaw += 4;
 14527  	if( pEngine->nMagic != L_HASH_MAGIC ){
 14528  		/* Corrupt implementation */
 14529  		return VEDIS_CORRUPT;
 14530  	}
 14531  	/* 4 byte hash value to identify a valid hash function */
 14532  	SyBigEndianUnpack32(zRaw,&nHash);
 14533  	zRaw += 4;
 14534  	/* Sanity check */
 14535  	if( pEngine->xHash(L_HASH_WORD,sizeof(L_HASH_WORD)-1) != nHash ){
 14536  		/* Different hash function */
 14537  		pEngine->pIo->xErr(pEngine->pIo->pHandle,"Invalid hash function");
 14538  		return VEDIS_INVALID;
 14539  	}
 14540  	/* List of free pages */
 14541  	SyBigEndianUnpack64(zRaw,&pEngine->nFreeList);
 14542  	zRaw += 8;
 14543  	/* Current split bucket */
 14544  	SyBigEndianUnpack64(zRaw,&pEngine->split_bucket);
 14545  	zRaw += 8;
 14546  	/* Maximum split bucket */
 14547  	SyBigEndianUnpack64(zRaw,&pEngine->max_split_bucket);
 14548  	zRaw += 8;
 14549  	/* Next generation */
 14550  	pEngine->nmax_split_nucket = pEngine->max_split_bucket << 1;
 14551  	/* Initialiaze the bucket map */
 14552  	pMap = &pEngine->sPageMap;
 14553  	/* Fill in the structure */
 14554  	pMap->iNum = pHeader->pgno;
 14555  	/* Next page in the bucket map */
 14556  	SyBigEndianUnpack64(zRaw,&pMap->iNext);
 14557  	zRaw += 8;
 14558  	/* Total number of records in the bucket map (This page only) */
 14559  	SyBigEndianUnpack32(zRaw,&pMap->nRec);
 14560  	zRaw += 4;
 14561  	pMap->iPtr = (sxu16)(zRaw - pHeader->zData);
 14562  	/* Load the map in memory */
 14563  	rc = lhMapLoadPage(pEngine,pMap,pHeader->zData);
 14564  	if( rc != VEDIS_OK ){
 14565  		return rc;
 14566  	}
 14567  	/* Load the bucket map chain if any */
 14568  	for(;;){
 14569  		pgno iNext = pMap->iNext;
 14570  		vedis_page *pPage;
 14571  		if( iNext == 0 ){
 14572  			/* No more map pages */
 14573  			break;
 14574  		}
 14575  		/* Point to the target page */
 14576  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iNext,&pPage);
 14577  		if( rc != VEDIS_OK ){
 14578  			return rc;
 14579  		}
 14580  		/* Fill in the structure */
 14581  		pMap->iNum = iNext;
 14582  		pMap->iPtr = 0;
 14583  		/* Load the map in memory */
 14584  		rc = lhMapLoadPage(pEngine,pMap,pPage->zData);
 14585  		if( rc != VEDIS_OK ){
 14586  			return rc;
 14587  		}
 14588  	}
 14589  	/* All done */
 14590  	return VEDIS_OK;
 14591  }
 14592  /*
 14593   * Perform a record lookup.
 14594   */
 14595  static int lhRecordLookup(
 14596  	lhash_kv_engine *pEngine, /* KV storage engine */
 14597  	const void *pKey,         /* Lookup key */
 14598  	sxu32 nByte,              /* Key length */
 14599  	lhcell **ppCell           /* OUT: Target cell on success */
 14600  	)
 14601  {
 14602  	lhash_bmap_rec *pRec;
 14603  	lhpage *pPage;
 14604  	lhcell *pCell;
 14605  	pgno iBucket;
 14606  	sxu32 nHash;
 14607  	int rc;
 14608  	/* Acquire the first page (hash Header) so that everything gets loaded autmatically */
 14609  	rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0);
 14610  	if( rc != VEDIS_OK ){
 14611  		return rc;
 14612  	}
 14613  	/* Compute the hash of the key first */
 14614  	nHash = pEngine->xHash(pKey,nByte);
 14615  	/* Extract the logical (i.e. not real) page number */
 14616  	iBucket = nHash & (pEngine->nmax_split_nucket - 1);
 14617  	if( iBucket >= (pEngine->split_bucket + pEngine->max_split_bucket) ){
 14618  		/* Low mask */
 14619  		iBucket = nHash & (pEngine->max_split_bucket - 1);
 14620  	}
 14621  	/* Map the logical bucket number to real page number */
 14622  	pRec = lhMapFindBucket(pEngine,iBucket);
 14623  	if( pRec == 0 ){
 14624  		/* No such entry */
 14625  		return VEDIS_NOTFOUND;
 14626  	}
 14627  	/* Load the master page and it's slave page in-memory  */
 14628  	rc = lhLoadPage(pEngine,pRec->iReal,0,&pPage,0);
 14629  	if( rc != VEDIS_OK ){
 14630  		/* IO error, unlikely scenario */
 14631  		return rc;
 14632  	}
 14633  	/* Lookup for the cell */
 14634  	pCell = lhFindCell(pPage,pKey,nByte,nHash);
 14635  	if( pCell == 0 ){
 14636  		/* No such entry */
 14637  		return VEDIS_NOTFOUND;
 14638  	}
 14639  	if( ppCell ){
 14640  		*ppCell = pCell;
 14641  	}
 14642  	return VEDIS_OK;
 14643  }
 14644  /*
 14645   * Acquire a new page either from the free list or ask the pager
 14646   * for a new one.
 14647   */
 14648  static int lhAcquirePage(lhash_kv_engine *pEngine,vedis_page **ppOut)
 14649  {
 14650  	vedis_page *pPage;
 14651  	int rc;
 14652  	if( pEngine->nFreeList != 0 ){
 14653  		/* Acquire one from the free list */
 14654  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pEngine->nFreeList,&pPage);
 14655  		if( rc == VEDIS_OK ){
 14656  			/* Point to the next free page */
 14657  			SyBigEndianUnpack64(pPage->zData,&pEngine->nFreeList);
 14658  			/* Update the database header */
 14659  			rc = pEngine->pIo->xWrite(pEngine->pHeader);
 14660  			if( rc != VEDIS_OK ){
 14661  				return rc;
 14662  			}
 14663  			SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/],pEngine->nFreeList);
 14664  			/* Tell the pager do not journal this page */
 14665  			pEngine->pIo->xDontJournal(pPage);
 14666  			/* Return to the caller */
 14667  			*ppOut = pPage;
 14668  			/* All done */
 14669  			return VEDIS_OK;
 14670  		}
 14671  	}
 14672  	/* Acquire a new page */
 14673  	rc = pEngine->pIo->xNew(pEngine->pIo->pHandle,&pPage);
 14674  	if( rc != VEDIS_OK ){
 14675  		return rc;
 14676  	}
 14677  	/* Point to the target page */
 14678  	*ppOut = pPage;
 14679  	return VEDIS_OK;
 14680  }
 14681  /*
 14682   * Write a bucket map record to disk.
 14683   */
 14684  static int lhMapWriteRecord(lhash_kv_engine *pEngine,pgno iLogic,pgno iReal)
 14685  {
 14686  	lhash_bmap_page *pMap = &pEngine->sPageMap;
 14687  	vedis_page *pPage = 0;
 14688  	int rc;
 14689  	if( pMap->iPtr > (pEngine->iPageSize - 16) /* 8 byte logical bucket number + 8 byte real bucket number */ ){
 14690  		vedis_page *pOld;
 14691  		/* Point to the old page */
 14692  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pMap->iNum,&pOld);
 14693  		if( rc != VEDIS_OK ){
 14694  			return rc;
 14695  		}
 14696  		/* Acquire a new page */
 14697  		rc = lhAcquirePage(pEngine,&pPage);
 14698  		if( rc != VEDIS_OK ){
 14699  			return rc;
 14700  		}
 14701  		/* Reflect the change  */
 14702  		pMap->iNext = 0;
 14703  		pMap->iNum = pPage->pgno;
 14704  		pMap->nRec = 0;
 14705  		pMap->iPtr = 8/* Next page number */+4/* Total records in the map*/;
 14706  		/* Link this page */
 14707  		rc = pEngine->pIo->xWrite(pOld);
 14708  		if( rc != VEDIS_OK ){
 14709  			return rc;
 14710  		}
 14711  		if( pOld->pgno == pEngine->pHeader->pgno ){
 14712  			/* First page (Hash header) */
 14713  			SyBigEndianPack64(&pOld->zData[4/*magic*/+4/*hash*/+8/* Free page */+8/*current split bucket*/+8/*Maximum split bucket*/],pPage->pgno);
 14714  		}else{
 14715  			/* Link the new page */
 14716  			SyBigEndianPack64(pOld->zData,pPage->pgno);
 14717  			/* Unref */
 14718  			pEngine->pIo->xPageUnref(pOld);
 14719  		}
 14720  		/* Assume the last bucket map page */
 14721  		rc = pEngine->pIo->xWrite(pPage);
 14722  		if( rc != VEDIS_OK ){
 14723  			return rc;
 14724  		}
 14725  		SyBigEndianPack64(pPage->zData,0); /* Next bucket map page on the list */
 14726  	}
 14727  	if( pPage == 0){
 14728  		/* Point to the current map page */
 14729  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pMap->iNum,&pPage);
 14730  		if( rc != VEDIS_OK ){
 14731  			return rc;
 14732  		}
 14733  	}
 14734  	/* Make page writable */
 14735  	rc = pEngine->pIo->xWrite(pPage);
 14736  	if( rc != VEDIS_OK ){
 14737  		return rc;
 14738  	}
 14739  	/* Write the data */
 14740  	SyBigEndianPack64(&pPage->zData[pMap->iPtr],iLogic);
 14741  	pMap->iPtr += 8;
 14742  	SyBigEndianPack64(&pPage->zData[pMap->iPtr],iReal);
 14743  	pMap->iPtr += 8;
 14744  	/* Install the bucket map */
 14745  	rc = lhMapInstallBucket(pEngine,iLogic,iReal);
 14746  	if( rc == VEDIS_OK ){
 14747  		/* Total number of records */
 14748  		pMap->nRec++;
 14749  		if( pPage->pgno == pEngine->pHeader->pgno ){
 14750  			/* Page one: Always writable */
 14751  			SyBigEndianPack32(
 14752  				&pPage->zData[4/*magic*/+4/*hash*/+8/* Free page */+8/*current split bucket*/+8/*Maximum split bucket*/+8/*Next map page*/],
 14753  				pMap->nRec);
 14754  		}else{
 14755  			/* Make page writable */
 14756  			rc = pEngine->pIo->xWrite(pPage);
 14757  			if( rc != VEDIS_OK ){
 14758  				return rc;
 14759  			}
 14760  			SyBigEndianPack32(&pPage->zData[8],pMap->nRec);
 14761  		}
 14762  	}
 14763  	return rc;
 14764  }
 14765  /*
 14766   * Defragment a page.
 14767   */
 14768  static int lhPageDefragment(lhpage *pPage)
 14769  {
 14770  	lhash_kv_engine *pEngine = pPage->pHash;
 14771  	unsigned char *zTmp,*zPtr,*zEnd,*zPayload;
 14772  	lhcell *pCell;
 14773  	/* Get a temporary page from the pager. This opertaion never fail */
 14774  	zTmp = pEngine->pIo->xTmpPage(pEngine->pIo->pHandle);
 14775  	/* Move the target cells to the begining */
 14776  	pCell = pPage->pList;
 14777  	/* Write the slave page number */
 14778  	SyBigEndianPack64(&zTmp[2/*Offset of the first cell */+2/*Offset of the first free block */],pPage->sHdr.iSlave);
 14779  	zPtr = &zTmp[L_HASH_PAGE_HDR_SZ]; /* Offset to start writing from */
 14780  	zEnd = &zTmp[pEngine->iPageSize];
 14781  	pPage->sHdr.iOfft = 0; /* Offset of the first cell */
 14782  	for(;;){
 14783  		if( pCell == 0 ){
 14784  			/* No more cells */
 14785  			break;
 14786  		}
 14787  		if( pCell->pPage->pRaw->pgno == pPage->pRaw->pgno ){
 14788  			/* Cell payload if locally stored */
 14789  			zPayload = 0;
 14790  			if( pCell->iOvfl == 0 ){
 14791  				zPayload = &pCell->pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ];
 14792  			}
 14793  			/* Move the cell */
 14794  			pCell->iNext = pPage->sHdr.iOfft;
 14795  			pCell->iStart = (sxu16)(zPtr - zTmp); /* Offset where this cell start */
 14796  			pPage->sHdr.iOfft = pCell->iStart;
 14797  			/* Write the cell header */
 14798  			/* 4 byte hash number */
 14799  			SyBigEndianPack32(zPtr,pCell->nHash);
 14800  			zPtr += 4;
 14801  			/* 4 byte ley length */
 14802  			SyBigEndianPack32(zPtr,pCell->nKey);
 14803  			zPtr += 4;
 14804  			/* 8 byte data length */
 14805  			SyBigEndianPack64(zPtr,pCell->nData);
 14806  			zPtr += 8;
 14807  			/* 2 byte offset of the next cell */
 14808  			SyBigEndianPack16(zPtr,pCell->iNext);
 14809  			zPtr += 2;
 14810  			/* 8 byte overflow page number */
 14811  			SyBigEndianPack64(zPtr,pCell->iOvfl);
 14812  			zPtr += 8;
 14813  			if( zPayload ){
 14814  				/* Local payload */
 14815  				SyMemcpy((const void *)zPayload,zPtr,(sxu32)(pCell->nKey + pCell->nData));
 14816  				zPtr += pCell->nKey + pCell->nData;
 14817  			}
 14818  			if( zPtr >= zEnd ){
 14819  				/* Can't happen */
 14820  				break;
 14821  			}
 14822  		}
 14823  		/* Point to the next page */
 14824  		pCell = pCell->pNext;
 14825  	}
 14826  	/* Mark the free block */
 14827  	pPage->nFree = (sxu16)(zEnd - zPtr); /* Block length */
 14828  	if( pPage->nFree > 3 ){
 14829  		pPage->sHdr.iFree = (sxu16)(zPtr - zTmp); /* Offset of the free block */
 14830  		/* Mark the block */
 14831  		SyBigEndianPack16(zPtr,0); /* Offset of the next free block */
 14832  		SyBigEndianPack16(&zPtr[2],pPage->nFree); /* Block length */
 14833  	}else{
 14834  		/* Block of length less than 4 bytes are simply discarded */
 14835  		pPage->nFree = 0;
 14836  		pPage->sHdr.iFree = 0;
 14837  	}
 14838  	/* Reflect the change */
 14839  	SyBigEndianPack16(zTmp,pPage->sHdr.iOfft);     /* Offset of the first cell */
 14840  	SyBigEndianPack16(&zTmp[2],pPage->sHdr.iFree); /* Offset of the first free block */
 14841  	SyMemcpy((const void *)zTmp,pPage->pRaw->zData,pEngine->iPageSize);
 14842  	/* All done */
 14843  	return VEDIS_OK;
 14844  }
 14845  /*
 14846  ** Allocate nByte bytes of space on a page.
 14847  **
 14848  ** Return the index into pPage->pRaw->zData[] of the first byte of
 14849  ** the new allocation. Or return 0 if there is not enough free
 14850  ** space on the page to satisfy the allocation request.
 14851  **
 14852  ** If the page contains nBytes of free space but does not contain
 14853  ** nBytes of contiguous free space, then this routine automatically
 14854  ** calls defragementPage() to consolidate all free space before 
 14855  ** allocating the new chunk.
 14856  */
 14857  static int lhAllocateSpace(lhpage *pPage,sxu64 nAmount,sxu16 *pOfft)
 14858  {
 14859  	const unsigned char *zEnd,*zPtr;
 14860  	sxu16 iNext,iBlksz,nByte;
 14861  	unsigned char *zPrev;
 14862  	int rc;
 14863  	if( (sxu64)pPage->nFree < nAmount ){
 14864  		/* Don't bother looking for a free chunk */
 14865  		return VEDIS_FULL;
 14866  	}
 14867  	if( pPage->nCell < 10 && ((int)nAmount >= (pPage->pHash->iPageSize / 2)) ){
 14868  		/* Big chunk need an overflow page for its data */
 14869  		return VEDIS_FULL;
 14870  	}
 14871  	zPtr = &pPage->pRaw->zData[pPage->sHdr.iFree];
 14872  	zEnd = &pPage->pRaw->zData[pPage->pHash->iPageSize];
 14873  	nByte = (sxu16)nAmount;
 14874  	zPrev = 0;
 14875  	iBlksz = 0; /* cc warning */
 14876  	/* Perform the lookup */
 14877  	for(;;){
 14878  		if( zPtr >= zEnd ){
 14879  			return VEDIS_FULL;
 14880  		}
 14881  		/* Offset of the next free block */
 14882  		SyBigEndianUnpack16(zPtr,&iNext);
 14883  		/* Block size */
 14884  		SyBigEndianUnpack16(&zPtr[2],&iBlksz);
 14885  		if( iBlksz >= nByte ){
 14886  			/* Got one */
 14887  			break;
 14888  		}
 14889  		zPrev = (unsigned char *)zPtr;
 14890  		if( iNext == 0 ){
 14891  			/* No more free blocks, defragment the page */
 14892  			rc = lhPageDefragment(pPage);
 14893  			if( rc == VEDIS_OK && pPage->nFree >= nByte) {
 14894  				/* Free blocks are merged together */
 14895  				iNext = 0;
 14896  				zPtr = &pPage->pRaw->zData[pPage->sHdr.iFree];
 14897  				iBlksz = pPage->nFree;
 14898  				zPrev = 0;
 14899  				break;
 14900  			}else{
 14901  				return VEDIS_FULL;
 14902  			}
 14903  		}
 14904  		/* Point to the next free block */
 14905  		zPtr = &pPage->pRaw->zData[iNext];
 14906  	}
 14907  	/* Acquire writer lock on this page */
 14908  	rc = pPage->pHash->pIo->xWrite(pPage->pRaw);
 14909  	if( rc != VEDIS_OK ){
 14910  		return rc;
 14911  	}
 14912  	/* Save block offset */
 14913  	*pOfft = (sxu16)(zPtr - pPage->pRaw->zData);
 14914  	/* Fix pointers */
 14915  	if( iBlksz >= nByte && (iBlksz - nByte) > 3 ){
 14916  		unsigned char *zBlock = &pPage->pRaw->zData[(*pOfft) + nByte];
 14917  		/* Create a new block */
 14918  		zPtr = zBlock;
 14919  		SyBigEndianPack16(zBlock,iNext); /* Offset of the next block */
 14920  		SyBigEndianPack16(&zBlock[2],iBlksz-nByte); /* Block size*/
 14921  		/* Offset of the new block */
 14922  		iNext = (sxu16)(zPtr - pPage->pRaw->zData);
 14923  	}
 14924  	/* Fix offsets */
 14925  	if( zPrev ){
 14926  		SyBigEndianPack16(zPrev,iNext);
 14927  	}else{
 14928  		/* First block */
 14929  		pPage->sHdr.iFree = iNext;
 14930  		/* Reflect on the page header */
 14931  		SyBigEndianPack16(&pPage->pRaw->zData[2/* Offset of the first cell1*/],iNext);
 14932  	}
 14933  	/* All done */
 14934  	pPage->nFree -= nByte;
 14935  	return VEDIS_OK;
 14936  }
 14937  /*
 14938   * Write the cell header into the corresponding offset.
 14939   */
 14940  static int lhCellWriteHeader(lhcell *pCell)
 14941  {
 14942  	lhpage *pPage = pCell->pPage;
 14943  	unsigned char *zRaw = pPage->pRaw->zData;
 14944  	/* Seek to the desired location */
 14945  	zRaw += pCell->iStart;
 14946  	/* 4 byte hash number */
 14947  	SyBigEndianPack32(zRaw,pCell->nHash);
 14948  	zRaw += 4;
 14949  	/* 4 byte key length */
 14950  	SyBigEndianPack32(zRaw,pCell->nKey);
 14951  	zRaw += 4;
 14952  	/* 8 byte data length */
 14953  	SyBigEndianPack64(zRaw,pCell->nData);
 14954  	zRaw += 8;
 14955  	/* 2 byte offset of the next cell */
 14956  	pCell->iNext = pPage->sHdr.iOfft;
 14957  	SyBigEndianPack16(zRaw,pCell->iNext);
 14958  	zRaw += 2;
 14959  	/* 8 byte overflow page number */
 14960  	SyBigEndianPack64(zRaw,pCell->iOvfl);
 14961  	/* Update the page header */
 14962  	pPage->sHdr.iOfft = pCell->iStart;
 14963  	/* pEngine->pIo->xWrite() has been successfully called on this page */
 14964  	SyBigEndianPack16(pPage->pRaw->zData,pCell->iStart);
 14965  	/* All done */
 14966  	return VEDIS_OK;
 14967  }
 14968  /*
 14969   * Write local payload.
 14970   */
 14971  static int lhCellWriteLocalPayload(lhcell *pCell,
 14972  	const void *pKey,sxu32 nKeylen,
 14973  	const void *pData,vedis_int64 nDatalen
 14974  	)
 14975  {
 14976  	/* A writer lock have been acquired on this page */
 14977  	lhpage *pPage = pCell->pPage;
 14978  	unsigned char *zRaw = pPage->pRaw->zData;
 14979  	/* Seek to the desired location */
 14980  	zRaw += pCell->iStart + L_HASH_CELL_SZ;
 14981  	/* Write the key */
 14982  	SyMemcpy(pKey,(void *)zRaw,nKeylen);
 14983  	zRaw += nKeylen;
 14984  	if( nDatalen > 0 ){
 14985  		/* Write the Data */
 14986  		SyMemcpy(pData,(void *)zRaw,(sxu32)nDatalen);
 14987  	}
 14988  	return VEDIS_OK;
 14989  }
 14990  /*
 14991   * Allocate as much overflow page we need to store the cell payload.
 14992   */
 14993  static int lhCellWriteOvflPayload(lhcell *pCell,const void *pKey,sxu32 nKeylen,...)
 14994  {
 14995  	lhpage *pPage = pCell->pPage;
 14996  	lhash_kv_engine *pEngine = pPage->pHash;
 14997  	vedis_page *pOvfl,*pFirst,*pNew;
 14998  	const unsigned char *zPtr,*zEnd;
 14999  	unsigned char *zRaw,*zRawEnd;
 15000  	sxu32 nAvail;
 15001  	va_list ap;
 15002  	int rc;
 15003  	/* Acquire a new overflow page */
 15004  	rc = lhAcquirePage(pEngine,&pOvfl);
 15005  	if( rc != VEDIS_OK ){
 15006  		return rc;
 15007  	}
 15008  	/* Acquire a writer lock */
 15009  	rc = pEngine->pIo->xWrite(pOvfl);
 15010  	if( rc != VEDIS_OK ){
 15011  		return rc;
 15012  	}
 15013  	pFirst = pOvfl;
 15014  	/* Link */
 15015  	pCell->iOvfl = pOvfl->pgno;
 15016  	/* Update the cell header */
 15017  	SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4/*Hash*/ + 4/*Key*/ + 8/*Data*/ + 2 /*Next cell*/],pCell->iOvfl);
 15018  	/* Start the write process */
 15019  	zPtr = (const unsigned char *)pKey;
 15020  	zEnd = &zPtr[nKeylen];
 15021  	SyBigEndianPack64(pOvfl->zData,0); /* Next overflow page on the chain */
 15022  	zRaw = &pOvfl->zData[8/* Next ovfl page*/ + 8 /* Data page */ + 2 /* Data offset*/];
 15023  	zRawEnd = &pOvfl->zData[pEngine->iPageSize];
 15024  	pNew = pOvfl;
 15025  	/* Write the key */
 15026  	for(;;){
 15027  		if( zPtr >= zEnd ){
 15028  			break;
 15029  		}
 15030  		if( zRaw >= zRawEnd ){
 15031  			/* Acquire a new page */
 15032  			rc = lhAcquirePage(pEngine,&pNew);
 15033  			if( rc != VEDIS_OK ){
 15034  				return rc;
 15035  			}
 15036  			rc = pEngine->pIo->xWrite(pNew);
 15037  			if( rc != VEDIS_OK ){
 15038  				return rc;
 15039  			}
 15040  			/* Link */
 15041  			SyBigEndianPack64(pOvfl->zData,pNew->pgno);
 15042  			pEngine->pIo->xPageUnref(pOvfl);
 15043  			SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */
 15044  			pOvfl = pNew;
 15045  			zRaw = &pNew->zData[8];
 15046  			zRawEnd = &pNew->zData[pEngine->iPageSize];
 15047  		}
 15048  		nAvail = (sxu32)(zRawEnd-zRaw);
 15049  		nKeylen = (sxu32)(zEnd-zPtr);
 15050  		if( nKeylen > nAvail ){
 15051  			nKeylen = nAvail;
 15052  		}
 15053  		SyMemcpy((const void *)zPtr,(void *)zRaw,nKeylen);
 15054  		/* Synchronize pointers */
 15055  		zPtr += nKeylen;
 15056  		zRaw += nKeylen;
 15057  	}
 15058  	rc = VEDIS_OK;
 15059  	va_start(ap,nKeylen);
 15060  	pCell->iDataPage = pNew->pgno;
 15061  	pCell->iDataOfft = (sxu16)(zRaw-pNew->zData);
 15062  	/* Write the data page and its offset */
 15063  	SyBigEndianPack64(&pFirst->zData[8/*Next ovfl*/],pCell->iDataPage);
 15064  	SyBigEndianPack16(&pFirst->zData[8/*Next ovfl*/+8/*Data page*/],pCell->iDataOfft);
 15065  	/* Write data */
 15066  	for(;;){
 15067  		const void *pData;
 15068  		sxu32 nDatalen;
 15069  		sxu64 nData;
 15070  		pData = va_arg(ap,const void *);
 15071  		nData = va_arg(ap,sxu64);
 15072  		if( pData == 0 ){
 15073  			/* No more chunks */
 15074  			break;
 15075  		}
 15076  		/* Write this chunk */
 15077  		zPtr = (const unsigned char *)pData;
 15078  		zEnd = &zPtr[nData];
 15079  		for(;;){
 15080  			if( zPtr >= zEnd ){
 15081  				break;
 15082  			}
 15083  			if( zRaw >= zRawEnd ){
 15084  				/* Acquire a new page */
 15085  				rc = lhAcquirePage(pEngine,&pNew);
 15086  				if( rc != VEDIS_OK ){
 15087  					va_end(ap);
 15088  					return rc;
 15089  				}
 15090  				rc = pEngine->pIo->xWrite(pNew);
 15091  				if( rc != VEDIS_OK ){
 15092  					va_end(ap);
 15093  					return rc;
 15094  				}
 15095  				/* Link */
 15096  				SyBigEndianPack64(pOvfl->zData,pNew->pgno);
 15097  				pEngine->pIo->xPageUnref(pOvfl);
 15098  				SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */
 15099  				pOvfl = pNew;
 15100  				zRaw = &pNew->zData[8];
 15101  				zRawEnd = &pNew->zData[pEngine->iPageSize];
 15102  			}
 15103  			nAvail = (sxu32)(zRawEnd-zRaw);
 15104  			nDatalen = (sxu32)(zEnd-zPtr);
 15105  			if( nDatalen > nAvail ){
 15106  				nDatalen = nAvail;
 15107  			}
 15108  			SyMemcpy((const void *)zPtr,(void *)zRaw,nDatalen);
 15109  			/* Synchronize pointers */
 15110  			zPtr += nDatalen;
 15111  			zRaw += nDatalen;
 15112  		}
 15113  	}
 15114  	/* Unref the overflow page */
 15115  	pEngine->pIo->xPageUnref(pOvfl);
 15116  	va_end(ap);
 15117  	return VEDIS_OK;
 15118  }
 15119  /*
 15120   * Restore a page to the free list.
 15121   */
 15122  static int lhRestorePage(lhash_kv_engine *pEngine,vedis_page *pPage)
 15123  {
 15124  	int rc;
 15125  	rc = pEngine->pIo->xWrite(pEngine->pHeader);
 15126  	if( rc != VEDIS_OK ){
 15127  		return rc;
 15128  	}
 15129  	rc = pEngine->pIo->xWrite(pPage);
 15130  	if( rc != VEDIS_OK ){
 15131  		return rc;
 15132  	}
 15133  	/* Link to the list of free page */
 15134  	SyBigEndianPack64(pPage->zData,pEngine->nFreeList);
 15135  	pEngine->nFreeList = pPage->pgno;
 15136  	SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/],pEngine->nFreeList);
 15137  	/* All done */
 15138  	return VEDIS_OK;
 15139  }
 15140  /*
 15141   * Restore cell space and mark it as a free block.
 15142   */
 15143  static int lhRestoreSpace(lhpage *pPage,sxu16 iOfft,sxu16 nByte)
 15144  {
 15145  	unsigned char *zRaw;
 15146  	if( nByte < 4 ){
 15147  		/* At least 4 bytes of freespace must form a valid block */
 15148  		return VEDIS_OK;
 15149  	}
 15150  	/* pEngine->pIo->xWrite() has been successfully called on this page */
 15151  	zRaw = &pPage->pRaw->zData[iOfft];
 15152  	/* Mark as a free block */
 15153  	SyBigEndianPack16(zRaw,pPage->sHdr.iFree); /* Offset of the next free block */
 15154  	zRaw += 2;
 15155  	SyBigEndianPack16(zRaw,nByte);
 15156  	/* Link */
 15157  	SyBigEndianPack16(&pPage->pRaw->zData[2/* offset of the first cell */],iOfft);
 15158  	pPage->sHdr.iFree = iOfft;
 15159  	pPage->nFree += nByte;
 15160  	return VEDIS_OK;
 15161  }
 15162  /* Forward declaration */
 15163  static lhcell * lhFindSibeling(lhcell *pCell);
 15164  /*
 15165   * Unlink a cell.
 15166   */
 15167  static int lhUnlinkCell(lhcell *pCell)
 15168  {
 15169  	lhash_kv_engine *pEngine = pCell->pPage->pHash;
 15170  	lhpage *pPage = pCell->pPage;
 15171  	sxu16 nByte = L_HASH_CELL_SZ;
 15172  	lhcell *pPrev;
 15173  	int rc;
 15174  	rc = pEngine->pIo->xWrite(pPage->pRaw);
 15175  	if( rc != VEDIS_OK ){
 15176  		return rc;
 15177  	}
 15178  	/* Bring the link */
 15179  	pPrev = lhFindSibeling(pCell);
 15180  	if( pPrev ){
 15181  		pPrev->iNext = pCell->iNext;
 15182  		/* Fix offsets in the page header */
 15183  		SyBigEndianPack16(&pPage->pRaw->zData[pPrev->iStart + 4/*Hash*/+4/*Key*/+8/*Data*/],pCell->iNext);
 15184  	}else{
 15185  		/* First entry on this page (either master or slave) */
 15186  		pPage->sHdr.iOfft = pCell->iNext;
 15187  		/* Update the page header */
 15188  		SyBigEndianPack16(pPage->pRaw->zData,pCell->iNext);
 15189  	}
 15190  	/* Restore cell space */
 15191  	if( pCell->iOvfl == 0 ){
 15192  		nByte += (sxu16)(pCell->nData + pCell->nKey);
 15193  	}
 15194  	lhRestoreSpace(pPage,pCell->iStart,nByte);
 15195  	/* Discard the cell from the in-memory hashtable */
 15196  	lhCellDiscard(pCell);
 15197  	return VEDIS_OK;
 15198  }
 15199  /*
 15200   * Remove a cell and its paylod (key + data).
 15201   */
 15202  static int lhRecordRemove(lhcell *pCell)
 15203  {
 15204  	lhash_kv_engine *pEngine = pCell->pPage->pHash;
 15205  	int rc;
 15206  	if( pCell->iOvfl > 0){
 15207  		/* Discard overflow pages */
 15208  		vedis_page *pOvfl;
 15209  		pgno iNext = pCell->iOvfl;
 15210  		for(;;){
 15211  			/* Point to the overflow page */
 15212  			rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iNext,&pOvfl);
 15213  			if( rc != VEDIS_OK ){
 15214  				return rc;
 15215  			}
 15216  			/* Next page on the chain */
 15217  			SyBigEndianUnpack64(pOvfl->zData,&iNext);
 15218  			/* Restore the page to the free list */
 15219  			rc = lhRestorePage(pEngine,pOvfl);
 15220  			if( rc != VEDIS_OK ){
 15221  				return rc;
 15222  			}
 15223  			/* Unref */
 15224  			pEngine->pIo->xPageUnref(pOvfl);
 15225  			if( iNext == 0 ){
 15226  				break;
 15227  			}
 15228  		}
 15229  	}
 15230  	/* Unlink the cell */
 15231  	rc = lhUnlinkCell(pCell);
 15232  	return rc;
 15233  }
 15234  /*
 15235   * Find cell sibeling.
 15236   */
 15237  static lhcell * lhFindSibeling(lhcell *pCell)
 15238  {
 15239  	lhpage *pPage = pCell->pPage->pMaster;
 15240  	lhcell *pEntry;
 15241  	pEntry = pPage->pFirst; 
 15242  	while( pEntry ){
 15243  		if( pEntry->pPage == pCell->pPage && pEntry->iNext == pCell->iStart ){
 15244  			/* Sibeling found */
 15245  			return pEntry;
 15246  		}
 15247  		/* Point to the previous entry */
 15248  		pEntry = pEntry->pPrev; 
 15249  	}
 15250  	/* Last inserted cell */
 15251  	return 0;
 15252  }
 15253  /*
 15254   * Move a cell to a new location with its new data.
 15255   */
 15256  static int lhMoveLocalCell(
 15257  	lhcell *pCell,
 15258  	sxu16 iOfft,
 15259  	const void *pData,
 15260  	vedis_int64 nData
 15261  	)
 15262  {
 15263  	sxu16 iKeyOfft = pCell->iStart + L_HASH_CELL_SZ;
 15264  	lhpage *pPage = pCell->pPage;
 15265  	lhcell *pSibeling;
 15266  	pSibeling = lhFindSibeling(pCell);
 15267  	if( pSibeling ){
 15268  		/* Fix link */
 15269  		SyBigEndianPack16(&pPage->pRaw->zData[pSibeling->iStart + 4/*Hash*/+4/*Key*/+8/*Data*/],pCell->iNext);
 15270  		pSibeling->iNext = pCell->iNext;
 15271  	}else{
 15272  		/* First cell, update page header only */
 15273  		SyBigEndianPack16(pPage->pRaw->zData,pCell->iNext);
 15274  		pPage->sHdr.iOfft = pCell->iNext;
 15275  	}
 15276  	/* Set the new offset */
 15277  	pCell->iStart = iOfft;
 15278  	pCell->nData = (sxu64)nData;
 15279  	/* Write the cell payload */
 15280  	lhCellWriteLocalPayload(pCell,(const void *)&pPage->pRaw->zData[iKeyOfft],pCell->nKey,pData,nData);
 15281  	/* Finally write the cell header */
 15282  	lhCellWriteHeader(pCell);
 15283  	/* All done */
 15284  	return VEDIS_OK;
 15285  }
 15286  /*
 15287   * Overwrite an existing record.
 15288   */
 15289  static int lhRecordOverwrite(
 15290  	lhcell *pCell,
 15291  	const void *pData,vedis_int64 nByte
 15292  	)
 15293  {
 15294  	lhash_kv_engine *pEngine = pCell->pPage->pHash;
 15295  	unsigned char *zRaw,*zRawEnd,*zPayload;
 15296  	const unsigned char *zPtr,*zEnd;
 15297  	vedis_page *pOvfl,*pOld,*pNew;
 15298  	lhpage *pPage = pCell->pPage;
 15299  	sxu32 nAvail;
 15300  	pgno iOvfl;
 15301  	int rc;
 15302  	/* Acquire a writer lock on this page */
 15303  	rc = pEngine->pIo->xWrite(pPage->pRaw);
 15304  	if( rc != VEDIS_OK ){
 15305  		return rc;
 15306  	}
 15307  	if( pCell->iOvfl == 0 ){
 15308  		/* Local payload, try to deal with the free space issues */
 15309  		zPayload = &pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ + pCell->nKey];
 15310  		if( pCell->nData == (sxu64)nByte ){
 15311  			/* Best scenario, simply a memcpy operation */
 15312  			SyMemcpy(pData,(void *)zPayload,(sxu32)nByte);
 15313  		}else if( (sxu64)nByte < pCell->nData ){
 15314  			/* Shorter data, not so ugly */
 15315  			SyMemcpy(pData,(void *)zPayload,(sxu32)nByte);
 15316  			/* Update the cell header */
 15317  			SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],nByte);
 15318  			/* Restore freespace */
 15319  			lhRestoreSpace(pPage,(sxu16)(pCell->iStart + L_HASH_CELL_SZ + pCell->nKey + nByte),(sxu16)(pCell->nData - nByte));
 15320  			/* New data size */
 15321  			pCell->nData = (sxu64)nByte;
 15322  		}else{
 15323  			sxu16 iOfft = 0; /* cc warning */
 15324  			/* Check if another chunk is available for this cell */
 15325  			rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ + pCell->nKey + nByte,&iOfft);
 15326  			if( rc != VEDIS_OK ){
 15327  				/* Transfer the payload to an overflow page */
 15328  				rc = lhCellWriteOvflPayload(pCell,&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ],pCell->nKey,pData,nByte,(const void *)0);
 15329  				if( rc != VEDIS_OK ){
 15330  					return rc;
 15331  				}
 15332  				/* Update the cell header */
 15333  				SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],(sxu64)nByte);
 15334  				/* Restore freespace */
 15335  				lhRestoreSpace(pPage,(sxu16)(pCell->iStart + L_HASH_CELL_SZ),(sxu16)(pCell->nKey + pCell->nData));
 15336  				/* New data size */
 15337  				pCell->nData = (sxu64)nByte;
 15338  			}else{
 15339  				sxu16 iOldOfft = pCell->iStart;
 15340  				sxu32 iOld = (sxu32)pCell->nData;
 15341  				/* Space is available, transfer the cell */
 15342  				lhMoveLocalCell(pCell,iOfft,pData,nByte);
 15343  				/* Restore cell space */
 15344  				lhRestoreSpace(pPage,iOldOfft,(sxu16)(L_HASH_CELL_SZ + pCell->nKey + iOld));
 15345  			}
 15346  		}
 15347  		return VEDIS_OK;
 15348  	}
 15349  	/* Point to the overflow page */
 15350  	rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pCell->iDataPage,&pOvfl);
 15351  	if( rc != VEDIS_OK ){
 15352  		return rc;
 15353  	}
 15354  	/* Relase all old overflow pages first */
 15355  	SyBigEndianUnpack64(pOvfl->zData,&iOvfl);
 15356  	pOld = pOvfl;
 15357  	for(;;){
 15358  		if( iOvfl == 0 ){
 15359  			/* No more overflow pages on the chain */
 15360  			break;
 15361  		}
 15362  		/* Point to the target page */
 15363  		if( VEDIS_OK != pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pOld) ){
 15364  			/* Not so fatal if something goes wrong here */
 15365  			break;
 15366  		}
 15367  		/* Next overflow page to be released */
 15368  		SyBigEndianUnpack64(pOld->zData,&iOvfl);
 15369  		if( pOld != pOvfl ){ /* xx: chm is maniac */
 15370  			/* Restore the page to the free list */
 15371  			lhRestorePage(pEngine,pOld);
 15372  			/* Unref */
 15373  			pEngine->pIo->xPageUnref(pOld);
 15374  		}
 15375  	}
 15376  	/* Point to the data offset */
 15377  	zRaw = &pOvfl->zData[pCell->iDataOfft];
 15378  	zRawEnd = &pOvfl->zData[pEngine->iPageSize];
 15379  	/* The data to be stored */
 15380  	zPtr = (const unsigned char *)pData;
 15381  	zEnd = &zPtr[nByte];
 15382  	/* Start the overwrite process */
 15383  	/* Acquire a writer lock */
 15384  	rc = pEngine->pIo->xWrite(pOvfl);
 15385  	if( rc != VEDIS_OK ){
 15386  		return rc;
 15387  	}
 15388  	SyBigEndianPack64(pOvfl->zData,0);
 15389  	for(;;){
 15390  		sxu32 nLen;
 15391  		if( zPtr >= zEnd ){
 15392  			break;
 15393  		}
 15394  		if( zRaw >= zRawEnd ){
 15395  			/* Acquire a new page */
 15396  			rc = lhAcquirePage(pEngine,&pNew);
 15397  			if( rc != VEDIS_OK ){
 15398  				return rc;
 15399  			}
 15400  			rc = pEngine->pIo->xWrite(pNew);
 15401  			if( rc != VEDIS_OK ){
 15402  				return rc;
 15403  			}
 15404  			/* Link */
 15405  			SyBigEndianPack64(pOvfl->zData,pNew->pgno);
 15406  			pEngine->pIo->xPageUnref(pOvfl);
 15407  			SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */
 15408  			pOvfl = pNew;
 15409  			zRaw = &pNew->zData[8];
 15410  			zRawEnd = &pNew->zData[pEngine->iPageSize];
 15411  		}
 15412  		nAvail = (sxu32)(zRawEnd-zRaw);
 15413  		nLen = (sxu32)(zEnd-zPtr);
 15414  		if( nLen > nAvail ){
 15415  			nLen = nAvail;
 15416  		}
 15417  		SyMemcpy((const void *)zPtr,(void *)zRaw,nLen);
 15418  		/* Synchronize pointers */
 15419  		zPtr += nLen;
 15420  		zRaw += nLen;
 15421  	}
 15422  	/* Unref the last overflow page */
 15423  	pEngine->pIo->xPageUnref(pOvfl);
 15424  	/* Finally, update the cell header */
 15425  	pCell->nData = (sxu64)nByte;
 15426  	SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],pCell->nData);
 15427  	/* All done */
 15428  	return VEDIS_OK;
 15429  }
 15430  /*
 15431   * Append data to an existing record.
 15432   */
 15433  static int lhRecordAppend(
 15434  	lhcell *pCell,
 15435  	const void *pData,vedis_int64 nByte
 15436  	)
 15437  {
 15438  	lhash_kv_engine *pEngine = pCell->pPage->pHash;
 15439  	const unsigned char *zPtr,*zEnd;
 15440  	lhpage *pPage = pCell->pPage;
 15441  	unsigned char *zRaw,*zRawEnd;
 15442  	vedis_page *pOvfl,*pNew;
 15443  	sxu64 nDatalen;
 15444  	sxu32 nAvail;
 15445  	pgno iOvfl;
 15446  	int rc;
 15447  	if( pCell->nData + nByte < pCell->nData ){
 15448  		/* Overflow */
 15449  		pEngine->pIo->xErr(pEngine->pIo->pHandle,"Append operation will cause data overflow");
 15450  		return VEDIS_LIMIT;
 15451  	}
 15452  	/* Acquire a writer lock on this page */
 15453  	rc = pEngine->pIo->xWrite(pPage->pRaw);
 15454  	if( rc != VEDIS_OK ){
 15455  		return rc;
 15456  	}
 15457  	if( pCell->iOvfl == 0 ){
 15458  		sxu16 iOfft = 0; /* cc warning */
 15459  		/* Local payload, check for a bigger place */
 15460  		rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ + pCell->nKey + pCell->nData + nByte,&iOfft);
 15461  		if( rc != VEDIS_OK ){
 15462  			/* Transfer the payload to an overflow page */
 15463  			rc = lhCellWriteOvflPayload(pCell,
 15464  				&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ],pCell->nKey,
 15465  				(const void *)&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ + pCell->nKey],pCell->nData,
 15466  				pData,nByte,
 15467  				(const void *)0
 15468  				);
 15469  			if( rc != VEDIS_OK ){
 15470  				return rc;
 15471  			}
 15472  			/* Update the cell header */
 15473  			SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],pCell->nData + nByte);
 15474  			/* Restore freespace */
 15475  			lhRestoreSpace(pPage,(sxu16)(pCell->iStart + L_HASH_CELL_SZ),(sxu16)(pCell->nKey + pCell->nData));
 15476  			/* New data size */
 15477  			pCell->nData += nByte;
 15478  		}else{
 15479  			sxu16 iOldOfft = pCell->iStart;
 15480  			sxu32 iOld = (sxu32)pCell->nData;
 15481  			SyBlob sWorker;
 15482  			SyBlobInit(&sWorker,&pEngine->sAllocator);
 15483  			/* Copy the old data */
 15484  			rc = SyBlobAppend(&sWorker,(const void *)&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ + pCell->nKey],(sxu32)pCell->nData);
 15485  			if( rc == SXRET_OK ){
 15486  				/* Append the new data */
 15487  				rc = SyBlobAppend(&sWorker,pData,(sxu32)nByte);
 15488  			}
 15489  			if( rc != VEDIS_OK ){
 15490  				SyBlobRelease(&sWorker);
 15491  				return rc;
 15492  			}
 15493  			/* Space is available, transfer the cell */
 15494  			lhMoveLocalCell(pCell,iOfft,SyBlobData(&sWorker),(vedis_int64)SyBlobLength(&sWorker));
 15495  			/* Restore cell space */
 15496  			lhRestoreSpace(pPage,iOldOfft,(sxu16)(L_HASH_CELL_SZ + pCell->nKey + iOld));
 15497  			/* All done */
 15498  			SyBlobRelease(&sWorker);
 15499  		}
 15500  		return VEDIS_OK;
 15501  	}
 15502  	/* Point to the overflow page which hold the data */
 15503  	rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pCell->iDataPage,&pOvfl);
 15504  	if( rc != VEDIS_OK ){
 15505  		return rc;
 15506  	}
 15507  	/* Next overflow page in the chain */
 15508  	SyBigEndianUnpack64(pOvfl->zData,&iOvfl);
 15509  	/* Point to the end of the chunk */
 15510  	zRaw = &pOvfl->zData[pCell->iDataOfft];
 15511  	zRawEnd = &pOvfl->zData[pEngine->iPageSize];
 15512  	nDatalen = pCell->nData;
 15513  	nAvail = (sxu32)(zRawEnd - zRaw);
 15514  	for(;;){
 15515  		if( zRaw >= zRawEnd ){
 15516  			if( iOvfl == 0 ){
 15517  				/* Cant happen */
 15518  				pEngine->pIo->xErr(pEngine->pIo->pHandle,"Corrupt overflow page");
 15519  				return VEDIS_CORRUPT;
 15520  			}
 15521  			rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pNew);
 15522  			if( rc != VEDIS_OK ){
 15523  				return rc;
 15524  			}
 15525  			/* Next overflow page on the chain */
 15526  			SyBigEndianUnpack64(pNew->zData,&iOvfl);
 15527  			/* Unref the previous overflow page */
 15528  			pEngine->pIo->xPageUnref(pOvfl);
 15529  			/* Point to the new chunk */
 15530  			zRaw = &pNew->zData[8];
 15531  			zRawEnd = &pNew->zData[pCell->pPage->pHash->iPageSize];
 15532  			nAvail = L_HASH_OVERFLOW_SIZE(pCell->pPage->pHash->iPageSize);
 15533  			pOvfl = pNew;
 15534  		}
 15535  		if( (sxu64)nAvail > nDatalen ){
 15536  			zRaw += nDatalen;
 15537  			break;
 15538  		}else{
 15539  			nDatalen -= nAvail;
 15540  		}
 15541  		zRaw += nAvail;
 15542  	}
 15543  	/* Start the append process */
 15544  	zPtr = (const unsigned char *)pData;
 15545  	zEnd = &zPtr[nByte];
 15546  	/* Acquire a writer lock */
 15547  	rc = pEngine->pIo->xWrite(pOvfl);
 15548  	if( rc != VEDIS_OK ){
 15549  		return rc;
 15550  	}
 15551  	for(;;){
 15552  		sxu32 nLen;
 15553  		if( zPtr >= zEnd ){
 15554  			break;
 15555  		}
 15556  		if( zRaw >= zRawEnd ){
 15557  			/* Acquire a new page */
 15558  			rc = lhAcquirePage(pEngine,&pNew);
 15559  			if( rc != VEDIS_OK ){
 15560  				return rc;
 15561  			}
 15562  			rc = pEngine->pIo->xWrite(pNew);
 15563  			if( rc != VEDIS_OK ){
 15564  				return rc;
 15565  			}
 15566  			/* Link */
 15567  			SyBigEndianPack64(pOvfl->zData,pNew->pgno);
 15568  			pEngine->pIo->xPageUnref(pOvfl);
 15569  			SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */
 15570  			pOvfl = pNew;
 15571  			zRaw = &pNew->zData[8];
 15572  			zRawEnd = &pNew->zData[pEngine->iPageSize];
 15573  		}
 15574  		nAvail = (sxu32)(zRawEnd-zRaw);
 15575  		nLen = (sxu32)(zEnd-zPtr);
 15576  		if( nLen > nAvail ){
 15577  			nLen = nAvail;
 15578  		}
 15579  		SyMemcpy((const void *)zPtr,(void *)zRaw,nLen);
 15580  		/* Synchronize pointers */
 15581  		zPtr += nLen;
 15582  		zRaw += nLen;
 15583  	}
 15584  	/* Unref the last overflow page */
 15585  	pEngine->pIo->xPageUnref(pOvfl);
 15586  	/* Finally, update the cell header */
 15587  	pCell->nData += nByte;
 15588  	SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],pCell->nData);
 15589  	/* All done */
 15590  	return VEDIS_OK;
 15591  }
 15592  /*
 15593   * A write privilege have been acquired on this page.
 15594   * Mark it as an empty page (No cells).
 15595   */
 15596  static int lhSetEmptyPage(lhpage *pPage)
 15597  {
 15598  	unsigned char *zRaw = pPage->pRaw->zData;
 15599  	lhphdr *pHeader = &pPage->sHdr;
 15600  	sxu16 nByte;
 15601  	int rc;
 15602  	/* Acquire a writer lock */
 15603  	rc = pPage->pHash->pIo->xWrite(pPage->pRaw);
 15604  	if( rc != VEDIS_OK ){
 15605  		return rc;
 15606  	}
 15607  	/* Offset of the first cell */
 15608  	SyBigEndianPack16(zRaw,0);
 15609  	zRaw += 2;
 15610  	/* Offset of the first free block */
 15611  	pHeader->iFree = L_HASH_PAGE_HDR_SZ;
 15612  	SyBigEndianPack16(zRaw,L_HASH_PAGE_HDR_SZ);
 15613  	zRaw += 2;
 15614  	/* Slave page number */
 15615  	SyBigEndianPack64(zRaw,0);
 15616  	zRaw += 8;
 15617  	/* Fill the free block */
 15618  	SyBigEndianPack16(zRaw,0); /* Offset of the next free block */
 15619  	zRaw += 2;
 15620  	nByte = (sxu16)L_HASH_MX_FREE_SPACE(pPage->pHash->iPageSize);
 15621  	SyBigEndianPack16(zRaw,nByte);
 15622  	pPage->nFree = nByte;
 15623  	/* Do not add this page to the hot dirty list */
 15624  	pPage->pHash->pIo->xDontMkHot(pPage->pRaw);
 15625  	return VEDIS_OK;
 15626  }
 15627  /* Forward declaration */
 15628  static int lhSlaveStore(
 15629  	lhpage *pPage,
 15630  	const void *pKey,sxu32 nKeyLen,
 15631  	const void *pData,vedis_int64 nDataLen,
 15632  	sxu32 nHash
 15633  	);
 15634  /*
 15635   * Store a cell and its payload in a given page.
 15636   */
 15637  static int lhStoreCell(
 15638  	lhpage *pPage, /* Target page */
 15639  	const void *pKey,sxu32 nKeyLen, /* Payload: Key */
 15640  	const void *pData,vedis_int64 nDataLen, /* Payload: Data */
 15641  	sxu32 nHash, /* Hash of the key */
 15642  	int auto_append /* Auto append a slave page if full */
 15643  	)
 15644  {
 15645  	lhash_kv_engine *pEngine = pPage->pHash;
 15646  	int iNeedOvfl = 0; /* Need overflow page for this cell and its payload*/
 15647  	lhcell *pCell;
 15648  	sxu16 nOfft;
 15649  	int rc;
 15650  	/* Acquire a writer lock on this page first */
 15651  	rc = pEngine->pIo->xWrite(pPage->pRaw);
 15652  	if( rc != VEDIS_OK ){
 15653  		return rc;
 15654  	}
 15655  	/* Check for a free block  */
 15656  	rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ+nKeyLen+nDataLen,&nOfft);
 15657  	if( rc != VEDIS_OK ){
 15658  		/* Check for a free block to hold a single cell only (without payload) */
 15659  		rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ,&nOfft);
 15660  		if( rc != VEDIS_OK ){
 15661  			if( !auto_append ){
 15662  				/* A split must be done */
 15663  				return VEDIS_FULL;
 15664  			}else{
 15665  				/* Store this record in a slave page */
 15666  				rc = lhSlaveStore(pPage,pKey,nKeyLen,pData,nDataLen,nHash);
 15667  				return rc;
 15668  			}
 15669  		}
 15670  		iNeedOvfl = 1;
 15671  	}
 15672  	/* Allocate a new cell instance */
 15673  	pCell = lhNewCell(pEngine,pPage);
 15674  	if( pCell == 0 ){
 15675  		pEngine->pIo->xErr(pEngine->pIo->pHandle,"KV store is running out of memory");
 15676  		return VEDIS_NOMEM;
 15677  	}
 15678  	/* Fill-in the structure */
 15679  	pCell->iStart = nOfft;
 15680  	pCell->nKey = nKeyLen;
 15681  	pCell->nData = (sxu64)nDataLen;
 15682  	pCell->nHash = nHash;
 15683  	if( nKeyLen < 262144 /* 256 KB */ ){
 15684  		/* Keep the key in-memory for fast lookup */
 15685  		SyBlobAppend(&pCell->sKey,pKey,nKeyLen);
 15686  	}
 15687  	/* Link the cell */
 15688  	rc = lhInstallCell(pCell);
 15689  	if( rc != VEDIS_OK ){
 15690  		return rc;
 15691  	}
 15692  	/* Write the payload */
 15693  	if( iNeedOvfl ){
 15694  		rc = lhCellWriteOvflPayload(pCell,pKey,nKeyLen,pData,nDataLen,(const void *)0);
 15695  		if( rc != VEDIS_OK ){
 15696  			lhCellDiscard(pCell);
 15697  			return rc;
 15698  		}
 15699  	}else{
 15700  		lhCellWriteLocalPayload(pCell,pKey,nKeyLen,pData,nDataLen);
 15701  	}
 15702  	/* Finally, Write the cell header */
 15703  	lhCellWriteHeader(pCell);
 15704  	/* All done */
 15705  	return VEDIS_OK;
 15706  }
 15707  /*
 15708   * Find a slave page capable of hosting the given amount.
 15709   */
 15710  static int lhFindSlavePage(lhpage *pPage,sxu64 nAmount,sxu16 *pOfft,lhpage **ppSlave)
 15711  {
 15712  	lhash_kv_engine *pEngine = pPage->pHash;
 15713  	lhpage *pMaster = pPage->pMaster;
 15714  	lhpage *pSlave = pMaster->pSlave;
 15715  	vedis_page *pRaw;
 15716  	lhpage *pNew;
 15717  	sxu16 iOfft;
 15718  	sxi32 i;
 15719  	int rc;
 15720  	/* Look for an already attached slave page */
 15721  	for( i = 0 ; i < pMaster->iSlave ; ++i ){
 15722  		/* Find a free chunk big enough */
 15723  		rc = lhAllocateSpace(pSlave,L_HASH_CELL_SZ+nAmount,&iOfft);
 15724  		if( rc != VEDIS_OK ){
 15725  			/* A space for cell header only */
 15726  			rc = lhAllocateSpace(pSlave,L_HASH_CELL_SZ,&iOfft);
 15727  		}
 15728  		if( rc == VEDIS_OK ){
 15729  			/* All done */
 15730  			if( pOfft ){
 15731  				*pOfft = iOfft;
 15732  			}
 15733  			*ppSlave = pSlave;
 15734  			return VEDIS_OK;
 15735  		}
 15736  		/* Point to the next slave page */
 15737  		pSlave = pSlave->pNextSlave;
 15738  	}
 15739  	/* Acquire a new slave page */
 15740  	rc = lhAcquirePage(pEngine,&pRaw);
 15741  	if( rc != VEDIS_OK ){
 15742  		return rc;
 15743  	}
 15744  	/* Last slave page */
 15745  	pSlave = pMaster->pSlave;
 15746  	if( pSlave == 0 ){
 15747  		/* First slave page */
 15748  		pSlave = pMaster;
 15749  	}
 15750  	/* Initialize the page */
 15751  	pNew = lhNewPage(pEngine,pRaw,pMaster);
 15752  	if( pNew == 0 ){
 15753  		return VEDIS_NOMEM;
 15754  	}
 15755  	/* Mark as an empty page */
 15756  	rc = lhSetEmptyPage(pNew);
 15757  	if( rc != VEDIS_OK ){
 15758  		goto fail;
 15759  	}
 15760  	if( pOfft ){
 15761  		/* Look for a free block */
 15762  		if( VEDIS_OK != lhAllocateSpace(pNew,L_HASH_CELL_SZ+nAmount,&iOfft) ){
 15763  			/* Cell header only */
 15764  			lhAllocateSpace(pNew,L_HASH_CELL_SZ,&iOfft); /* Never fail */
 15765  		}	
 15766  		*pOfft = iOfft;
 15767  	}
 15768  	/* Link this page to the previous slave page */
 15769  	rc = pEngine->pIo->xWrite(pSlave->pRaw);
 15770  	if( rc != VEDIS_OK ){
 15771  		goto fail;
 15772  	}
 15773  	/* Reflect in the page header */
 15774  	SyBigEndianPack64(&pSlave->pRaw->zData[2/*Cell offset*/+2/*Free block offset*/],pRaw->pgno);
 15775  	pSlave->sHdr.iSlave = pRaw->pgno;
 15776  	/* All done */
 15777  	*ppSlave = pNew;
 15778  	return VEDIS_OK;
 15779  fail:
 15780  	pEngine->pIo->xPageUnref(pNew->pRaw); /* pNew will be released in this call */
 15781  	return rc;
 15782  
 15783  }
 15784  /*
 15785   * Perform a store operation in a slave page.
 15786   */
 15787  static int lhSlaveStore(
 15788  	lhpage *pPage, /* Master page */
 15789  	const void *pKey,sxu32 nKeyLen, /* Payload: key */
 15790  	const void *pData,vedis_int64 nDataLen, /* Payload: data */
 15791  	sxu32 nHash /* Hash of the key */
 15792  	)
 15793  {
 15794  	lhpage *pSlave;
 15795  	int rc;
 15796  	/* Find a slave page */
 15797  	rc = lhFindSlavePage(pPage,nKeyLen + nDataLen,0,&pSlave);
 15798  	if( rc != VEDIS_OK ){
 15799  		return rc;
 15800  	}
 15801  	/* Perform the insertion in the slave page */
 15802  	rc = lhStoreCell(pSlave,pKey,nKeyLen,pData,nDataLen,nHash,1);
 15803  	return rc;
 15804  }
 15805  /*
 15806   * Transfer a cell to a new page (either a master or slave).
 15807   */
 15808  static int lhTransferCell(lhcell *pTarget,lhpage *pPage)
 15809  {
 15810  	lhcell *pCell;
 15811  	sxu16 nOfft;
 15812  	int rc;
 15813  	/* Check for a free block to hold a single cell only */
 15814  	rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ,&nOfft);
 15815  	if( rc != VEDIS_OK ){
 15816  		/* Store in a slave page */
 15817  		rc = lhFindSlavePage(pPage,L_HASH_CELL_SZ,&nOfft,&pPage);
 15818  		if( rc != VEDIS_OK ){
 15819  			return rc;
 15820  		}
 15821  	}
 15822  	/* Allocate a new cell instance */
 15823  	pCell = lhNewCell(pPage->pHash,pPage);
 15824  	if( pCell == 0 ){
 15825  		return VEDIS_NOMEM;
 15826  	}
 15827  	/* Fill-in the structure */
 15828  	pCell->iStart = nOfft;
 15829  	pCell->nData  = pTarget->nData;
 15830  	pCell->nKey   = pTarget->nKey;
 15831  	pCell->iOvfl  = pTarget->iOvfl;
 15832  	pCell->iDataOfft = pTarget->iDataOfft;
 15833  	pCell->iDataPage = pTarget->iDataPage;
 15834  	pCell->nHash = pTarget->nHash;
 15835  	SyBlobDup(&pTarget->sKey,&pCell->sKey);
 15836  	/* Link the cell */
 15837  	rc = lhInstallCell(pCell);
 15838  	if( rc != VEDIS_OK ){
 15839  		return rc;
 15840  	}
 15841  	/* Finally, Write the cell header */
 15842  	lhCellWriteHeader(pCell);
 15843  	/* All done */
 15844  	return VEDIS_OK;
 15845  }
 15846  /*
 15847   * Perform a page split.
 15848   */
 15849  static int lhPageSplit(
 15850  	lhpage *pOld,      /* Page to be split */
 15851  	lhpage *pNew,      /* New page */
 15852  	pgno split_bucket, /* Current split bucket */
 15853  	pgno high_mask     /* High mask (Max split bucket - 1) */
 15854  	)
 15855  {
 15856  	lhcell *pCell,*pNext;
 15857  	SyBlob sWorker;
 15858  	pgno iBucket;
 15859  	int rc; 
 15860  	SyBlobInit(&sWorker,&pOld->pHash->sAllocator);
 15861  	/* Perform the split */
 15862  	pCell = pOld->pList;
 15863  	for( ;; ){
 15864  		if( pCell == 0 ){
 15865  			/* No more cells */
 15866  			break;
 15867  		}
 15868  		/* Obtain the new logical bucket */
 15869  		iBucket = pCell->nHash & high_mask;
 15870  		pNext =  pCell->pNext;
 15871  		if( iBucket != split_bucket){
 15872  			rc = VEDIS_OK;
 15873  			if( pCell->iOvfl ){
 15874  				/* Transfer the cell only */
 15875  				rc = lhTransferCell(pCell,pNew);
 15876  			}else{
 15877  				/* Transfer the cell and its payload */
 15878  				SyBlobReset(&sWorker);
 15879  				if( SyBlobLength(&pCell->sKey) < 1 ){
 15880  					/* Consume the key */
 15881  					rc = lhConsumeCellkey(pCell,vedisDataConsumer,&pCell->sKey,0);
 15882  					if( rc != VEDIS_OK ){
 15883  						goto fail;
 15884  					}
 15885  				}
 15886  				/* Consume the data (Very small data < 65k) */
 15887  				rc = lhConsumeCellData(pCell,vedisDataConsumer,&sWorker);
 15888  				if( rc != VEDIS_OK ){
 15889  					goto fail;
 15890  				}
 15891  				/* Perform the transfer */
 15892  				rc = lhStoreCell(
 15893  					pNew,
 15894  					SyBlobData(&pCell->sKey),(int)SyBlobLength(&pCell->sKey),
 15895  					SyBlobData(&sWorker),SyBlobLength(&sWorker),
 15896  					pCell->nHash,
 15897  					1
 15898  					);
 15899  			}
 15900  			if( rc != VEDIS_OK ){
 15901  				goto fail;
 15902  			}
 15903  			/* Discard the cell from the old page */
 15904  			lhUnlinkCell(pCell);
 15905  		}
 15906  		/* Point to the next cell */
 15907  		pCell = pNext;
 15908  	}
 15909  	/* All done */
 15910  	rc = VEDIS_OK;
 15911  fail:
 15912  	SyBlobRelease(&sWorker);
 15913  	return rc;
 15914  }
 15915  /*
 15916   * Perform the infamous linear hash split operation.
 15917   */
 15918  static int lhSplit(lhpage *pTarget,int *pRetry)
 15919  {
 15920  	lhash_kv_engine *pEngine = pTarget->pHash;
 15921  	lhash_bmap_rec *pRec;
 15922  	lhpage *pOld,*pNew;
 15923  	vedis_page *pRaw;
 15924  	int rc;
 15925  	/* Get the real page number of the bucket to split */
 15926  	pRec = lhMapFindBucket(pEngine,pEngine->split_bucket);
 15927  	if( pRec == 0 ){
 15928  		/* Can't happen */
 15929  		return VEDIS_CORRUPT;
 15930  	}
 15931  	/* Load the page to be split */
 15932  	rc = lhLoadPage(pEngine,pRec->iReal,0,&pOld,0);
 15933  	if( rc != VEDIS_OK ){
 15934  		return rc;
 15935  	}
 15936  	/* Request a new page */
 15937  	rc = lhAcquirePage(pEngine,&pRaw);
 15938  	if( rc != VEDIS_OK ){
 15939  		return rc;
 15940  	}
 15941  	/* Initialize the page */
 15942  	pNew = lhNewPage(pEngine,pRaw,0);
 15943  	if( pNew == 0 ){
 15944  		return VEDIS_NOMEM;
 15945  	}
 15946  	/* Mark as an empty page */
 15947  	rc = lhSetEmptyPage(pNew);
 15948  	if( rc != VEDIS_OK ){
 15949  		goto fail;
 15950  	}
 15951  	/* Install and write the logical map record */
 15952  	rc = lhMapWriteRecord(pEngine,
 15953  		pEngine->split_bucket + pEngine->max_split_bucket,
 15954  		pRaw->pgno
 15955  		);
 15956  	if( rc != VEDIS_OK ){
 15957  		goto fail;
 15958  	}
 15959  	if( pTarget->pRaw->pgno == pOld->pRaw->pgno ){
 15960  		*pRetry = 1;
 15961  	}
 15962  	/* Perform the split */
 15963  	rc = lhPageSplit(pOld,pNew,pEngine->split_bucket,pEngine->nmax_split_nucket - 1);
 15964  	if( rc != VEDIS_OK ){
 15965  		goto fail;
 15966  	}
 15967  	/* Update the database header */
 15968  	pEngine->split_bucket++;
 15969  	/* Acquire a writer lock on the first page */
 15970  	rc = pEngine->pIo->xWrite(pEngine->pHeader);
 15971  	if( rc != VEDIS_OK ){
 15972  		return rc;
 15973  	}
 15974  	if( pEngine->split_bucket >= pEngine->max_split_bucket ){
 15975  		/* Increment the generation number */
 15976  		pEngine->split_bucket = 0;
 15977  		pEngine->max_split_bucket = pEngine->nmax_split_nucket;
 15978  		pEngine->nmax_split_nucket <<= 1;
 15979  		if( !pEngine->nmax_split_nucket ){
 15980  			/* If this happen to your installation, please tell us <chm@symisc.net> */
 15981  			pEngine->pIo->xErr(pEngine->pIo->pHandle,"Database page (64-bit integer) limit reached");
 15982  			return VEDIS_LIMIT;
 15983  		}
 15984  		/* Reflect in the page header */
 15985  		SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/+8/*Free list*/],pEngine->split_bucket);
 15986  		SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/+8/*Free list*/+8/*Split bucket*/],pEngine->max_split_bucket);
 15987  	}else{
 15988  		/* Modify only the split bucket */
 15989  		SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/+8/*Free list*/],pEngine->split_bucket);
 15990  	}
 15991  	/* All done */
 15992  	return VEDIS_OK;
 15993  fail:
 15994  	pEngine->pIo->xPageUnref(pNew->pRaw);
 15995  	return rc;
 15996  }
 15997  /*
 15998   * Store a record in the target page.
 15999   */
 16000  static int lhRecordInstall(
 16001  	  lhpage *pPage, /* Target page */
 16002  	  sxu32 nHash,   /* Hash of the key */
 16003  	  const void *pKey,sxu32 nKeyLen,          /* Payload: Key */
 16004  	  const void *pData,vedis_int64 nDataLen /* Payload: Data */
 16005  	  )
 16006  {
 16007  	int rc;
 16008  	rc = lhStoreCell(pPage,pKey,nKeyLen,pData,nDataLen,nHash,0);
 16009  	if( rc == VEDIS_FULL ){
 16010  		int do_retry = 0;
 16011  		/* Split */
 16012  		rc = lhSplit(pPage,&do_retry);
 16013  		if( rc == VEDIS_OK ){
 16014  			if( do_retry ){
 16015  				/* Re-calculate logical bucket number */
 16016  				return SXERR_RETRY;
 16017  			}
 16018  			/* Perform the store */
 16019  			rc = lhStoreCell(pPage,pKey,nKeyLen,pData,nDataLen,nHash,1);
 16020  		}
 16021  	}
 16022  	return rc;
 16023  }
 16024  /*
 16025   * Insert a record (Either overwrite or append operation) in our database.
 16026   */
 16027  static int lh_record_insert(
 16028  	  vedis_kv_engine *pKv,         /* KV store */
 16029  	  const void *pKey,sxu32 nKeyLen, /* Payload: Key */
 16030  	  const void *pData,vedis_int64 nDataLen, /* Payload: data */
 16031  	  int is_append /* True for an append operation */
 16032  	  )
 16033  {
 16034  	lhash_kv_engine *pEngine = (lhash_kv_engine *)pKv;
 16035  	lhash_bmap_rec *pRec;
 16036  	vedis_page *pRaw;
 16037  	lhpage *pPage;
 16038  	lhcell *pCell;
 16039  	pgno iBucket;
 16040  	sxu32 nHash;
 16041  	int iCnt;
 16042  	int rc;
 16043  
 16044  	/* Acquire the first page (DB hash Header) so that everything gets loaded autmatically */
 16045  	rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0);
 16046  	if( rc != VEDIS_OK ){
 16047  		return rc;
 16048  	}
 16049  	iCnt = 0;
 16050  	/* Compute the hash of the key first */
 16051  	nHash = pEngine->xHash(pKey,(sxu32)nKeyLen);
 16052  retry:
 16053  	/* Extract the logical bucket number */
 16054  	iBucket = nHash & (pEngine->nmax_split_nucket - 1);
 16055  	if( iBucket >= pEngine->split_bucket + pEngine->max_split_bucket ){
 16056  		/* Low mask */
 16057  		iBucket = nHash & (pEngine->max_split_bucket - 1);
 16058  	}
 16059  	/* Map the logical bucket number to real page number */
 16060  	pRec = lhMapFindBucket(pEngine,iBucket);
 16061  	if( pRec == 0 ){
 16062  		/* Request a new page */
 16063  		rc = lhAcquirePage(pEngine,&pRaw);
 16064  		if( rc != VEDIS_OK ){
 16065  			return rc;
 16066  		}
 16067  		/* Initialize the page */
 16068  		pPage = lhNewPage(pEngine,pRaw,0);
 16069  		if( pPage == 0 ){
 16070  			return VEDIS_NOMEM;
 16071  		}
 16072  		/* Mark as an empty page */
 16073  		rc = lhSetEmptyPage(pPage);
 16074  		if( rc != VEDIS_OK ){
 16075  			pEngine->pIo->xPageUnref(pRaw); /* pPage will be released during this call */
 16076  			return rc;
 16077  		}
 16078  		/* Store the cell */
 16079  		rc = lhStoreCell(pPage,pKey,nKeyLen,pData,nDataLen,nHash,1);
 16080  		if( rc == VEDIS_OK ){
 16081  			/* Install and write the logical map record */
 16082  			rc = lhMapWriteRecord(pEngine,iBucket,pRaw->pgno);
 16083  		}
 16084  		pEngine->pIo->xPageUnref(pRaw);
 16085  		return rc;
 16086  	}else{
 16087  		/* Load the page */
 16088  		rc = lhLoadPage(pEngine,pRec->iReal,0,&pPage,0);
 16089  		if( rc != VEDIS_OK ){
 16090  			/* IO error, unlikely scenario */
 16091  			return rc;
 16092  		}
 16093  		/* Do not add this page to the hot dirty list */
 16094  		pEngine->pIo->xDontMkHot(pPage->pRaw);
 16095  		/* Lookup for the cell */
 16096  		pCell = lhFindCell(pPage,pKey,(sxu32)nKeyLen,nHash);
 16097  		if( pCell == 0 ){
 16098  			/* Create the record */
 16099  			rc = lhRecordInstall(pPage,nHash,pKey,nKeyLen,pData,nDataLen);
 16100  			if( rc == SXERR_RETRY && iCnt++ < 2 ){
 16101  				rc = VEDIS_OK;
 16102  				goto retry;
 16103  			}
 16104  		}else{
 16105  			if( is_append ){
 16106  				/* Append operation */
 16107  				rc = lhRecordAppend(pCell,pData,nDataLen);
 16108  			}else{
 16109  				/* Overwrite old value */
 16110  				rc = lhRecordOverwrite(pCell,pData,nDataLen);
 16111  			}
 16112  		}
 16113  		pEngine->pIo->xPageUnref(pPage->pRaw);
 16114  	}
 16115  	return rc;
 16116  }
 16117  /*
 16118   * Replace method.
 16119   */
 16120  static int lhash_kv_replace(
 16121  	  vedis_kv_engine *pKv,
 16122  	  const void *pKey,int nKeyLen,
 16123  	  const void *pData,vedis_int64 nDataLen
 16124  	  )
 16125  {
 16126  	int rc;
 16127  	rc = lh_record_insert(pKv,pKey,(sxu32)nKeyLen,pData,nDataLen,0);
 16128  	return rc;
 16129  }
 16130  /*
 16131   * Append method.
 16132   */
 16133  static int lhash_kv_append(
 16134  	  vedis_kv_engine *pKv,
 16135  	  const void *pKey,int nKeyLen,
 16136  	  const void *pData,vedis_int64 nDataLen
 16137  	  )
 16138  {
 16139  	int rc;
 16140  	rc = lh_record_insert(pKv,pKey,(sxu32)nKeyLen,pData,nDataLen,1);
 16141  	return rc;
 16142  }
 16143  /*
 16144   * Write the hash header (Page one).
 16145   */
 16146  static int lhash_write_header(lhash_kv_engine *pEngine,vedis_page *pHeader)
 16147  {
 16148  	unsigned char *zRaw = pHeader->zData;
 16149  	lhash_bmap_page *pMap;
 16150  
 16151  	pEngine->pHeader = pHeader;
 16152  	/* 4 byte magic number */
 16153  	SyBigEndianPack32(zRaw,pEngine->nMagic);
 16154  	zRaw += 4;
 16155  	/* 4 byte hash value to identify a valid hash function */
 16156  	SyBigEndianPack32(zRaw,pEngine->xHash(L_HASH_WORD,sizeof(L_HASH_WORD)-1));
 16157  	zRaw += 4;
 16158  	/* List of free pages: Empty */
 16159  	SyBigEndianPack64(zRaw,0);
 16160  	zRaw += 8;
 16161  	/* Current split bucket */
 16162  	SyBigEndianPack64(zRaw,pEngine->split_bucket);
 16163  	zRaw += 8;
 16164  	/* Maximum split bucket */
 16165  	SyBigEndianPack64(zRaw,pEngine->max_split_bucket);
 16166  	zRaw += 8;
 16167  	/* Initialiaze the bucket map */
 16168  	pMap = &pEngine->sPageMap;
 16169  	/* Fill in the structure */
 16170  	pMap->iNum = pHeader->pgno;
 16171  	/* Next page in the bucket map */
 16172  	SyBigEndianPack64(zRaw,0);
 16173  	zRaw += 8;
 16174  	/* Total number of records in the bucket map */
 16175  	SyBigEndianPack32(zRaw,0);
 16176  	zRaw += 4;
 16177  	pMap->iPtr = (sxu16)(zRaw - pHeader->zData);
 16178  	/* All done */
 16179  	return VEDIS_OK;
 16180   }
 16181  /*
 16182   * Exported: xOpen() method.
 16183   */
 16184  static int lhash_kv_open(vedis_kv_engine *pEngine,pgno dbSize)
 16185  {
 16186  	lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine;
 16187  	vedis_page *pHeader;
 16188  	int rc;
 16189  	if( dbSize < 1 ){
 16190  		/* A new database, create the header */
 16191  		rc = pEngine->pIo->xNew(pEngine->pIo->pHandle,&pHeader);
 16192  		if( rc != VEDIS_OK ){
 16193  			return rc;
 16194  		}
 16195  		/* Acquire a writer lock */
 16196  		rc = pEngine->pIo->xWrite(pHeader);
 16197  		if( rc != VEDIS_OK ){
 16198  			return rc;
 16199  		}
 16200  		/* Write the hash header */
 16201  		rc = lhash_write_header(pHash,pHeader);
 16202  		if( rc != VEDIS_OK ){
 16203  			return rc;
 16204  		}
 16205  	}else{
 16206  		/* Acquire the page one of the database */
 16207  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,&pHeader);
 16208  		if( rc != VEDIS_OK ){
 16209  			return rc;
 16210  		}
 16211  		/* Read the database header */
 16212  		rc = lhash_read_header(pHash,pHeader);
 16213  		if( rc != VEDIS_OK ){
 16214  			return rc;
 16215  		}
 16216  	}
 16217  	return VEDIS_OK;
 16218  }
 16219  /*
 16220   * Release a master or slave page. (xUnpin callback).
 16221   */
 16222  static void lhash_page_release(void *pUserData)
 16223  {
 16224  	lhpage *pPage = (lhpage *)pUserData;
 16225  	lhash_kv_engine *pEngine = pPage->pHash;
 16226  	lhcell *pNext,*pCell = pPage->pList;
 16227  	vedis_page *pRaw = pPage->pRaw;
 16228  	sxu32 n;
 16229  	/* Drop in-memory cells */
 16230  	for( n = 0 ; n < pPage->nCell ; ++n ){
 16231  		pNext = pCell->pNext;
 16232  		SyBlobRelease(&pCell->sKey);
 16233  		/* Release the cell instance */
 16234  		SyMemBackendPoolFree(&pEngine->sAllocator,(void *)pCell);
 16235  		/* Point to the next entry */
 16236  		pCell = pNext;
 16237  	}
 16238  	if( pPage->apCell ){
 16239  		/* Release the cell table */
 16240  		SyMemBackendFree(&pEngine->sAllocator,(void *)pPage->apCell);
 16241  	}
 16242  	/* Finally, release the whole page */
 16243  	SyMemBackendPoolFree(&pEngine->sAllocator,pPage);
 16244  	pRaw->pUserData = 0;
 16245  }
 16246  /*
 16247   * Default hash function (DJB).
 16248   */
 16249  static sxu32 lhash_bin_hash(const void *pSrc,sxu32 nLen)
 16250  {
 16251  	register unsigned char *zIn = (unsigned char *)pSrc;
 16252  	unsigned char *zEnd;
 16253  	sxu32 nH = 5381;
 16254  	if( nLen > 2048 /* 2K */ ){
 16255  		nLen = 2048;
 16256  	}
 16257  	zEnd = &zIn[nLen];
 16258  	for(;;){
 16259  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16260  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16261  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16262  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16263  	}	
 16264  	return nH;
 16265  }
 16266  /*
 16267   * Exported: xInit() method.
 16268   * Initialize the Key value storage engine.
 16269   */
 16270  static int lhash_kv_init(vedis_kv_engine *pEngine,int iPageSize)
 16271  {
 16272  	lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine;
 16273  	int rc;
 16274  
 16275  	/* This structure is always zeroed, go to the initialization directly */
 16276  	SyMemBackendInitFromParent(&pHash->sAllocator,vedisExportMemBackend());
 16277  #if defined(VEDIS_ENABLE_THREADS)
 16278  	/* Already protected by the upper layers */
 16279  	SyMemBackendDisbaleMutexing(&pHash->sAllocator);
 16280  #endif
 16281  	pHash->iPageSize = iPageSize;
 16282  	/* Default hash function */
 16283  	pHash->xHash = lhash_bin_hash;
 16284  	/* Default comparison function */
 16285  	pHash->xCmp = SyMemcmp;
 16286  	/* Allocate a new record map */
 16287  	pHash->nBuckSize = 32;
 16288  	pHash->apMap = (lhash_bmap_rec **)SyMemBackendAlloc(&pHash->sAllocator,pHash->nBuckSize *sizeof(lhash_bmap_rec *));
 16289  	if( pHash->apMap == 0 ){
 16290  		rc = VEDIS_NOMEM;
 16291  		goto err;
 16292  	}
 16293  	/* Zero the table */
 16294  	SyZero(pHash->apMap,pHash->nBuckSize * sizeof(lhash_bmap_rec *));
 16295  	/* Linear hashing components */
 16296  	pHash->split_bucket = 0; /* Logical not real bucket number */
 16297  	pHash->max_split_bucket = 1;
 16298  	pHash->nmax_split_nucket = 2;
 16299  	pHash->nMagic = L_HASH_MAGIC;
 16300  	/* Install the cache unpin and reload callbacks */
 16301  	pHash->pIo->xSetUnpin(pHash->pIo->pHandle,lhash_page_release);
 16302  	pHash->pIo->xSetReload(pHash->pIo->pHandle,lhash_page_release);
 16303  	return VEDIS_OK;
 16304  err:
 16305  	SyMemBackendRelease(&pHash->sAllocator);
 16306  	return rc;
 16307  }
 16308  /*
 16309   * Exported: xRelease() method.
 16310   * Release the Key value storage engine.
 16311   */
 16312  static void lhash_kv_release(vedis_kv_engine *pEngine)
 16313  {
 16314  	lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine;
 16315  	/* Release the private memory backend */
 16316  	SyMemBackendRelease(&pHash->sAllocator);
 16317  }
 16318  /*
 16319   *  Exported: xConfig() method.
 16320   *  Configure the linear hash KV store.
 16321   */
 16322  static int lhash_kv_config(vedis_kv_engine *pEngine,int op,va_list ap)
 16323  {
 16324  	lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine;
 16325  	int rc = VEDIS_OK;
 16326  	switch(op){
 16327  	case VEDIS_KV_CONFIG_HASH_FUNC: {
 16328  		/* Default hash function */
 16329  		if( pHash->nBuckRec > 0 ){
 16330  			/* Locked operation */
 16331  			rc = VEDIS_LOCKED;
 16332  		}else{
 16333  			ProcHash xHash = va_arg(ap,ProcHash);
 16334  			if( xHash ){
 16335  				pHash->xHash = xHash;
 16336  			}
 16337  		}
 16338  		break;
 16339  									  }
 16340  	case VEDIS_KV_CONFIG_CMP_FUNC: {
 16341  		/* Default comparison function */
 16342  		ProcCmp xCmp = va_arg(ap,ProcCmp);
 16343  		if( xCmp ){
 16344  			pHash->xCmp  = xCmp;
 16345  		}
 16346  		break;
 16347  									 }
 16348  	default:
 16349  		/* Unknown OP */
 16350  		rc = VEDIS_UNKNOWN;
 16351  		break;
 16352  	}
 16353  	return rc;
 16354  }
 16355  /*
 16356   * Each public cursor is identified by an instance of this structure.
 16357   */
 16358  typedef struct lhash_kv_cursor lhash_kv_cursor;
 16359  struct lhash_kv_cursor
 16360  {
 16361  	vedis_kv_engine *pStore; /* Must be first */
 16362  	/* Private fields */
 16363  	int iState;           /* Current state of the cursor */
 16364  	int is_first;         /* True to read the database header */
 16365  	lhcell *pCell;        /* Current cell we are processing */
 16366  	vedis_page *pRaw;   /* Raw disk page */
 16367  	lhash_bmap_rec *pRec; /* Logical to real bucket map */
 16368  };
 16369  /* 
 16370   * Possible state of the cursor
 16371   */
 16372  #define L_HASH_CURSOR_STATE_NEXT_PAGE 1 /* Next page in the list */
 16373  #define L_HASH_CURSOR_STATE_CELL      2 /* Processing Cell */
 16374  #define L_HASH_CURSOR_STATE_DONE      3 /* Cursor does not point to anything */
 16375  /*
 16376   * Initialize the cursor.
 16377   */
 16378  static void lhInitCursor(vedis_kv_cursor *pPtr)
 16379  {
 16380  	 lhash_kv_engine *pEngine = (lhash_kv_engine *)pPtr->pStore;
 16381  	 lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr;
 16382  	 /* Init */
 16383  	 pCur->iState = L_HASH_CURSOR_STATE_NEXT_PAGE;
 16384  	 pCur->pCell = 0;
 16385  	 pCur->pRec = pEngine->pFirst;
 16386  	 pCur->pRaw = 0;
 16387  	 pCur->is_first = 1;
 16388  }
 16389  /*
 16390   * Point to the next page on the database.
 16391   */
 16392  static int lhCursorNextPage(lhash_kv_cursor *pPtr)
 16393  {
 16394  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr;
 16395  	lhash_bmap_rec *pRec;
 16396  	lhpage *pPage;
 16397  	int rc;
 16398  	for(;;){
 16399  		pRec = pCur->pRec;
 16400  		if( pRec == 0 ){
 16401  			pCur->iState = L_HASH_CURSOR_STATE_DONE;
 16402  			return VEDIS_DONE;
 16403  		}
 16404  		if( pPtr->iState == L_HASH_CURSOR_STATE_CELL && pPtr->pRaw ){
 16405  			/* Unref this page */
 16406  			pCur->pStore->pIo->xPageUnref(pPtr->pRaw);
 16407  			pPtr->pRaw = 0;
 16408  		}
 16409  		/* Advance the map cursor */
 16410  		pCur->pRec = pRec->pPrev; /* Not a bug, reverse link */
 16411  		/* Load the next page on the list */
 16412  		rc = lhLoadPage((lhash_kv_engine *)pCur->pStore,pRec->iReal,0,&pPage,0);
 16413  		if( rc != VEDIS_OK ){
 16414  			return rc;
 16415  		}
 16416  		if( pPage->pList ){
 16417  			/* Reflect the change */
 16418  			pCur->pCell = pPage->pList;
 16419  			pCur->iState = L_HASH_CURSOR_STATE_CELL;
 16420  			pCur->pRaw = pPage->pRaw;
 16421  			break;
 16422  		}
 16423  		/* Empty page, discard this page and continue */
 16424  		pPage->pHash->pIo->xPageUnref(pPage->pRaw);
 16425  	}
 16426  	return VEDIS_OK;
 16427  }
 16428  /*
 16429   * Point to the previous page on the database.
 16430   */
 16431  static int lhCursorPrevPage(lhash_kv_cursor *pPtr)
 16432  {
 16433  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr;
 16434  	lhash_bmap_rec *pRec;
 16435  	lhpage *pPage;
 16436  	int rc;
 16437  	for(;;){
 16438  		pRec = pCur->pRec;
 16439  		if( pRec == 0 ){
 16440  			pCur->iState = L_HASH_CURSOR_STATE_DONE;
 16441  			return VEDIS_DONE;
 16442  		}
 16443  		if( pPtr->iState == L_HASH_CURSOR_STATE_CELL && pPtr->pRaw ){
 16444  			/* Unref this page */
 16445  			pCur->pStore->pIo->xPageUnref(pPtr->pRaw);
 16446  			pPtr->pRaw = 0;
 16447  		}
 16448  		/* Advance the map cursor */
 16449  		pCur->pRec = pRec->pNext; /* Not a bug, reverse link */
 16450  		/* Load the previous page on the list */
 16451  		rc = lhLoadPage((lhash_kv_engine *)pCur->pStore,pRec->iReal,0,&pPage,0);
 16452  		if( rc != VEDIS_OK ){
 16453  			return rc;
 16454  		}
 16455  		if( pPage->pFirst ){
 16456  			/* Reflect the change */
 16457  			pCur->pCell = pPage->pFirst;
 16458  			pCur->iState = L_HASH_CURSOR_STATE_CELL;
 16459  			pCur->pRaw = pPage->pRaw;
 16460  			break;
 16461  		}
 16462  		/* Discard this page and continue */
 16463  		pPage->pHash->pIo->xPageUnref(pPage->pRaw);
 16464  	}
 16465  	return VEDIS_OK;
 16466  }
 16467  /*
 16468   * Is a valid cursor.
 16469   */
 16470  static int lhCursorValid(vedis_kv_cursor *pPtr)
 16471  {
 16472  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr;
 16473  	return (pCur->iState == L_HASH_CURSOR_STATE_CELL) && pCur->pCell;
 16474  }
 16475  /*
 16476   * Point to the first record.
 16477   */
 16478  static int lhCursorFirst(vedis_kv_cursor *pCursor)
 16479  {
 16480  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16481  	lhash_kv_engine *pEngine = (lhash_kv_engine *)pCursor->pStore;
 16482  	int rc;
 16483  	if( pCur->is_first ){
 16484  		/* Read the database header first */
 16485  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0);
 16486  		if( rc != VEDIS_OK ){
 16487  			return rc;
 16488  		}
 16489  		pCur->is_first = 0;
 16490  	}
 16491  	/* Point to the first map record */
 16492  	pCur->pRec = pEngine->pFirst;
 16493  	/* Load the cells */
 16494  	rc = lhCursorNextPage(pCur);
 16495  	return rc;
 16496  }
 16497  /*
 16498   * Point to the last record.
 16499   */
 16500  static int lhCursorLast(vedis_kv_cursor *pCursor)
 16501  {
 16502  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16503  	lhash_kv_engine *pEngine = (lhash_kv_engine *)pCursor->pStore;
 16504  	int rc;
 16505  	if( pCur->is_first ){
 16506  		/* Read the database header first */
 16507  		rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0);
 16508  		if( rc != VEDIS_OK ){
 16509  			return rc;
 16510  		}
 16511  		pCur->is_first = 0;
 16512  	}
 16513  	/* Point to the last map record */
 16514  	pCur->pRec = pEngine->pList;
 16515  	/* Load the cells */
 16516  	rc = lhCursorPrevPage(pCur);
 16517  	return rc;
 16518  }
 16519  /*
 16520   * Reset the cursor.
 16521   */
 16522  static void lhCursorReset(vedis_kv_cursor *pCursor)
 16523  {
 16524  	lhCursorFirst(pCursor);
 16525  }
 16526  /*
 16527   * Point to the next record.
 16528   */
 16529  static int lhCursorNext(vedis_kv_cursor *pCursor)
 16530  {
 16531  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16532  	lhcell *pCell;
 16533  	int rc;
 16534  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16535  		/* Load the cells of the next page  */
 16536  		rc = lhCursorNextPage(pCur);
 16537  		return rc;
 16538  	}
 16539  	pCell = pCur->pCell;
 16540  	pCur->pCell = pCell->pNext;
 16541  	if( pCur->pCell == 0 ){
 16542  		/* Load the cells of the next page  */
 16543  		rc = lhCursorNextPage(pCur);
 16544  		return rc;
 16545  	}
 16546  	return VEDIS_OK;
 16547  }
 16548  /*
 16549   * Point to the previous record.
 16550   */
 16551  static int lhCursorPrev(vedis_kv_cursor *pCursor)
 16552  {
 16553  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16554  	lhcell *pCell;
 16555  	int rc;
 16556  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16557  		/* Load the cells of the previous page  */
 16558  		rc = lhCursorPrevPage(pCur);
 16559  		return rc;
 16560  	}
 16561  	pCell = pCur->pCell;
 16562  	pCur->pCell = pCell->pPrev;
 16563  	if( pCur->pCell == 0 ){
 16564  		/* Load the cells of the previous page  */
 16565  		rc = lhCursorPrevPage(pCur);
 16566  		return rc;
 16567  	}
 16568  	return VEDIS_OK;
 16569  }
 16570  /*
 16571   * Return key length.
 16572   */
 16573  static int lhCursorKeyLength(vedis_kv_cursor *pCursor,int *pLen)
 16574  {
 16575  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16576  	lhcell *pCell;
 16577  	
 16578  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16579  		/* Invalid state */
 16580  		return VEDIS_INVALID;
 16581  	}
 16582  	/* Point to the target cell */
 16583  	pCell = pCur->pCell;
 16584  	/* Return key length */
 16585  	*pLen = (int)pCell->nKey;
 16586  	return VEDIS_OK;
 16587  }
 16588  /*
 16589   * Return data length.
 16590   */
 16591  static int lhCursorDataLength(vedis_kv_cursor *pCursor,vedis_int64 *pLen)
 16592  {
 16593  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16594  	lhcell *pCell;
 16595  	
 16596  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16597  		/* Invalid state */
 16598  		return VEDIS_INVALID;
 16599  	}
 16600  	/* Point to the target cell */
 16601  	pCell = pCur->pCell;
 16602  	/* Return data length */
 16603  	*pLen = (vedis_int64)pCell->nData;
 16604  	return VEDIS_OK;
 16605  }
 16606  /*
 16607   * Consume the key.
 16608   */
 16609  static int lhCursorKey(vedis_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 16610  {
 16611  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16612  	lhcell *pCell;
 16613  	int rc;
 16614  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16615  		/* Invalid state */
 16616  		return VEDIS_INVALID;
 16617  	}
 16618  	/* Point to the target cell */
 16619  	pCell = pCur->pCell;
 16620  	if( SyBlobLength(&pCell->sKey) > 0 ){
 16621  		/* Consume the key directly */
 16622  		rc = xConsumer(SyBlobData(&pCell->sKey),SyBlobLength(&pCell->sKey),pUserData);
 16623  	}else{
 16624  		/* Very large key */
 16625  		rc = lhConsumeCellkey(pCell,xConsumer,pUserData,0);
 16626  	}
 16627  	return rc;
 16628  }
 16629  /*
 16630   * Consume the data.
 16631   */
 16632  static int lhCursorData(vedis_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 16633  {
 16634  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16635  	lhcell *pCell;
 16636  	int rc;
 16637  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16638  		/* Invalid state */
 16639  		return VEDIS_INVALID;
 16640  	}
 16641  	/* Point to the target cell */
 16642  	pCell = pCur->pCell;
 16643  	/* Consume the data */
 16644  	rc = lhConsumeCellData(pCell,xConsumer,pUserData);
 16645  	return rc;
 16646  }
 16647  /*
 16648   * Find a partiuclar record.
 16649   */
 16650  static int lhCursorSeek(vedis_kv_cursor *pCursor,const void *pKey,int nByte,int iPos)
 16651  {
 16652  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16653  	int rc;
 16654  	/* Perform a lookup */
 16655  	rc = lhRecordLookup((lhash_kv_engine *)pCur->pStore,pKey,nByte,&pCur->pCell);
 16656  	if( rc != VEDIS_OK ){
 16657  		SXUNUSED(iPos);
 16658  		pCur->pCell = 0;
 16659  		pCur->iState = L_HASH_CURSOR_STATE_DONE;
 16660  		return rc;
 16661  	}
 16662  	pCur->iState = L_HASH_CURSOR_STATE_CELL;
 16663  	return VEDIS_OK;
 16664  }
 16665  /*
 16666   * Remove a particular record.
 16667   */
 16668  static int lhCursorDelete(vedis_kv_cursor *pCursor)
 16669  {
 16670  	lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor;
 16671  	lhcell *pCell;
 16672  	int rc;
 16673  	if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){
 16674  		/* Invalid state */
 16675  		return VEDIS_INVALID;
 16676  	}
 16677  	/* Point to the target cell  */
 16678  	pCell = pCur->pCell;
 16679  	/* Point to the next entry */
 16680  	pCur->pCell = pCell->pNext;
 16681  	/* Perform the deletion */
 16682  	rc = lhRecordRemove(pCell);
 16683  	return rc;
 16684  }
 16685  /*
 16686   * Export the linear-hash storage engine.
 16687   */
 16688  VEDIS_PRIVATE const vedis_kv_methods * vedisExportDiskKvStorage(void)
 16689  {
 16690  	static const vedis_kv_methods sDiskStore = {
 16691  		"hash",                     /* zName */
 16692  		sizeof(lhash_kv_engine),    /* szKv */
 16693  		sizeof(lhash_kv_cursor),    /* szCursor */
 16694  		1,                          /* iVersion */
 16695  		lhash_kv_init,              /* xInit */
 16696  		lhash_kv_release,           /* xRelease */
 16697  		lhash_kv_config,            /* xConfig */
 16698  		lhash_kv_open,              /* xOpen */
 16699  		lhash_kv_replace,           /* xReplace */
 16700  		lhash_kv_append,            /* xAppend */
 16701  		lhInitCursor,               /* xCursorInit */
 16702  		lhCursorSeek,               /* xSeek */
 16703  		lhCursorFirst,              /* xFirst */
 16704  		lhCursorLast,               /* xLast */
 16705  		lhCursorValid,              /* xValid */
 16706  		lhCursorNext,               /* xNext */
 16707  		lhCursorPrev,               /* xPrev */
 16708  		lhCursorDelete,             /* xDelete */
 16709  		lhCursorKeyLength,          /* xKeyLength */
 16710  		lhCursorKey,                /* xKey */
 16711  		lhCursorDataLength,         /* xDataLength */
 16712  		lhCursorData,               /* xData */
 16713  		lhCursorReset,              /* xReset */
 16714  		0                           /* xRelease */                        
 16715  	};
 16716  	return &sDiskStore;
 16717  }
 16718  /*
 16719   * ----------------------------------------------------------
 16720   * File: json.c
 16721   * MD5: a4aef01e657e37d9ace4729b9205976c
 16722   * ----------------------------------------------------------
 16723   */
 16724  /*
 16725   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
 16726   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
 16727   * Version 1.2.6
 16728   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 16729   * please contact Symisc Systems via:
 16730   *       legal@symisc.net
 16731   *       licensing@symisc.net
 16732   *       contact@symisc.net
 16733   * or visit:
 16734   *      http://vedis.symisc.net/
 16735   */
 16736   /* $SymiscID: json.c v1.0 FreeBSD 2012-12-16 00:28 stable <chm@symisc.net> $ */
 16737  #ifndef VEDIS_AMALGAMATION
 16738  #include "vedisInt.h"
 16739  #endif
 16740  /* This file deals with JSON serialization, decoding and stuff like that. */
 16741  /*
 16742   * Section: 
 16743   *  JSON encoding/decoding routines.
 16744   * Authors:
 16745   *  Symisc Systems, devel@symisc.net.
 16746   *  Copyright (C) Symisc Systems, http://vedis.symisc.net
 16747   * Status:
 16748   *    Devel.
 16749   */
 16750  /* Forward reference */
 16751  static int VmJsonArrayEncode(vedis_value *pValue, void *pUserData);
 16752  /* 
 16753   * JSON encoder state is stored in an instance 
 16754   * of the following structure.
 16755   */
 16756  typedef struct json_private_data json_private_data;
 16757  struct json_private_data
 16758  {
 16759  	SyBlob *pOut;      /* Output consumer buffer */
 16760  	int isFirst;       /* True if first encoded entry */
 16761  	int iFlags;        /* JSON encoding flags */
 16762  	int nRecCount;     /* Recursion count */
 16763  };
 16764  /*
 16765   * Returns the JSON representation of a value.In other word perform a JSON encoding operation.
 16766   * According to wikipedia
 16767   * JSON's basic types are:
 16768   *   Number (double precision floating-point format in JavaScript, generally depends on implementation)
 16769   *   String (double-quoted Unicode, with backslash escaping)
 16770   *   Boolean (true or false)
 16771   *   Array (an ordered sequence of values, comma-separated and enclosed in square brackets; the values
 16772   *    do not need to be of the same type)
 16773   *   Object (an unordered collection of key:value pairs with the ':' character separating the key 
 16774   *     and the value, comma-separated and enclosed in curly braces; the keys must be strings and should
 16775   *     be distinct from each other)
 16776   *   null (empty)
 16777   * Non-significant white space may be added freely around the "structural characters"
 16778   * (i.e. the brackets "[{]}", colon ":" and comma ",").
 16779   */
 16780  static sxi32 VmJsonEncode(
 16781  	vedis_value *pIn,          /* Encode this value */
 16782  	json_private_data *pData /* Context data */
 16783  	){
 16784  		SyBlob *pOut = pData->pOut;
 16785  		int nByte;
 16786  		if( vedis_value_is_null(pIn) ){
 16787  			/* null */
 16788  			SyBlobAppend(pOut, "null", sizeof("null")-1);
 16789  		}else if( vedis_value_is_bool(pIn) ){
 16790  			int iBool = vedis_value_to_bool(pIn);
 16791  			sxu32 iLen;
 16792  			/* true/false */
 16793  			iLen = iBool ? sizeof("true") : sizeof("false");
 16794  			SyBlobAppend(pOut, iBool ? "true" : "false", iLen-1);
 16795  		}else if(  vedis_value_is_numeric(pIn) && !vedis_value_is_string(pIn) ){
 16796  			const char *zNum;
 16797  			/* Get a string representation of the number */
 16798  			zNum = vedis_value_to_string(pIn, &nByte);
 16799  			SyBlobAppend(pOut,zNum,nByte);
 16800  		}else if( vedis_value_is_string(pIn) ){
 16801  				const char *zIn, *zEnd;
 16802  				int c;
 16803  				/* Encode the string */
 16804  				zIn = vedis_value_to_string(pIn, &nByte);
 16805  				zEnd = &zIn[nByte];
 16806  				/* Append the double quote */
 16807  				SyBlobAppend(pOut,"\"", sizeof(char));
 16808  				for(;;){
 16809  					if( zIn >= zEnd ){
 16810  						/* No more input to process */
 16811  						break;
 16812  					}
 16813  					c = zIn[0];
 16814  					/* Advance the stream cursor */
 16815  					zIn++;
 16816  					if( c == '"' || c == '\\' ){
 16817  						/* Unescape the character */
 16818  						SyBlobAppend(pOut,"\\", sizeof(char));
 16819  					}
 16820  					/* Append character verbatim */
 16821  					SyBlobAppend(pOut,(const char *)&c,sizeof(char));
 16822  				}
 16823  				/* Append the double quote */
 16824  				SyBlobAppend(pOut,"\"",sizeof(char));
 16825  		}else if( vedis_value_is_array(pIn) ){
 16826  			/* Encode the array/object */
 16827  			pData->isFirst = 1;
 16828  			/* Append the square bracket or curly braces */
 16829  			SyBlobAppend(pOut,"[",sizeof(char));
 16830  			/* Iterate over array entries */
 16831  			vedis_array_walk(pIn, VmJsonArrayEncode, pData);
 16832  			/* Append the closing square bracket or curly braces */
 16833  			SyBlobAppend(pOut,"]",sizeof(char));
 16834  		}else{
 16835  			/* Can't happen */
 16836  			SyBlobAppend(pOut,"null",sizeof("null")-1);
 16837  		}
 16838  		/* All done */
 16839  		return VEDIS_OK;
 16840  }
 16841  /*
 16842   * The following walker callback is invoked each time we need
 16843   * to encode an array to JSON.
 16844   */
 16845  static int VmJsonArrayEncode(vedis_value *pValue, void *pUserData)
 16846  {
 16847  	json_private_data *pJson = (json_private_data *)pUserData;
 16848  	if( pJson->nRecCount > 31 ){
 16849  		/* Recursion limit reached, return immediately */
 16850  		return VEDIS_OK;
 16851  	}
 16852  	if( !pJson->isFirst ){
 16853  		/* Append the colon first */
 16854  		SyBlobAppend(pJson->pOut,",",(int)sizeof(char));
 16855  	}
 16856  	/* Encode the value */
 16857  	pJson->nRecCount++;
 16858  	VmJsonEncode(pValue, pJson);
 16859  	pJson->nRecCount--;
 16860  	pJson->isFirst = 0;
 16861  	return VEDIS_OK;
 16862  }
 16863  #if 0
 16864  /*
 16865   * The following walker callback is invoked each time we need to encode
 16866   * a object instance [i.e: Object in the VEDIS jargon] to JSON.
 16867   */
 16868  static int VmJsonObjectEncode(vedis_value *pKey,vedis_value *pValue,void *pUserData)
 16869  {
 16870  	json_private_data *pJson = (json_private_data *)pUserData;
 16871  	const char *zKey;
 16872  	int nByte;
 16873  	if( pJson->nRecCount > 31 ){
 16874  		/* Recursion limit reached, return immediately */
 16875  		return VEDIS_OK;
 16876  	}
 16877  	if( !pJson->isFirst ){
 16878  		/* Append the colon first */
 16879  		SyBlobAppend(pJson->pOut,",",sizeof(char));
 16880  	}
 16881  	/* Extract a string representation of the key */
 16882  	zKey = vedis_value_to_string(pKey, &nByte);
 16883  	/* Append the key and the double colon */
 16884  	if( nByte > 0 ){
 16885  		SyBlobAppend(pJson->pOut,"\"",sizeof(char));
 16886  		SyBlobAppend(pJson->pOut,zKey,(sxu32)nByte);
 16887  		SyBlobAppend(pJson->pOut,"\"",sizeof(char));
 16888  	}else{
 16889  		/* Can't happen */
 16890  		SyBlobAppend(pJson->pOut,"null",sizeof("null")-1);
 16891  	}
 16892  	SyBlobAppend(pJson->pOut,":",sizeof(char));
 16893  	/* Encode the value */
 16894  	pJson->nRecCount++;
 16895  	VmJsonEncode(pValue, pJson);
 16896  	pJson->nRecCount--;
 16897  	pJson->isFirst = 0;
 16898  	return VEDIS_OK;
 16899  }
 16900  #endif
 16901  /*
 16902   *  Returns a string containing the JSON representation of value. 
 16903   *  In other words, perform the serialization of the given JSON object.
 16904   */
 16905  VEDIS_PRIVATE int vedisJsonSerialize(vedis_value *pValue,SyBlob *pOut)
 16906  {
 16907  	json_private_data sJson;
 16908  	/* Prepare the JSON data */
 16909  	sJson.nRecCount = 0;
 16910  	sJson.pOut = pOut;
 16911  	sJson.isFirst = 1;
 16912  	sJson.iFlags = 0;
 16913  	/* Perform the encoding operation */
 16914  	VmJsonEncode(pValue, &sJson);
 16915  	/* All done */
 16916  	return VEDIS_OK;
 16917  }
 16918  /*
 16919   * ----------------------------------------------------------
 16920   * File: hashmap.c
 16921   * MD5: 8b3d7bf394c07e7c5442c871607e1f96
 16922   * ----------------------------------------------------------
 16923   */
 16924  /*
 16925   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
 16926   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
 16927   * Version 1.2.6
 16928   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 16929   * please contact Symisc Systems via:
 16930   *       legal@symisc.net
 16931   *       licensing@symisc.net
 16932   *       contact@symisc.net
 16933   * or visit:
 16934   *      http://vedis.symisc.net/
 16935   */
 16936  /* $SymiscID: hashmap.c v1.2 FreeBSD 2013-07-20 06:09 stable <chm@symisc.net> $ */
 16937  #ifndef VEDIS_AMALGAMATION
 16938  #include "vedisInt.h"
 16939  #endif
 16940  /*
 16941   * Each hashmap entry [i.e: array(4, 5, 6)] is recorded in an instance
 16942   * of the following structure.
 16943   */
 16944  struct vedis_hashmap_node
 16945  {
 16946  	vedis_hashmap *pMap;     /* Hashmap that own this instance */
 16947  	sxi32 iType;           /* Node type */
 16948  	union{
 16949  		sxi64 iKey;        /* Int key */
 16950  		SyBlob sKey;       /* Blob key */
 16951  	}xKey;
 16952  	sxi32 iFlags;          /* Control flags */
 16953  	sxu32 nHash;           /* Key hash value */
 16954  	vedis_value sValue;    /* Node value */
 16955  	vedis_hashmap_node *pNext, *pPrev;               /* Link to other entries [i.e: linear traversal] */
 16956  	vedis_hashmap_node *pNextCollide, *pPrevCollide; /* Collision chain */
 16957  };
 16958  /* 
 16959   * Each active hashmap is represented by an instance of the following structure.
 16960   */
 16961  struct vedis_hashmap
 16962  {
 16963  	vedis  *pStore;                  /* Store that own this instance */
 16964  	vedis_hashmap_node **apBucket;  /* Hash bucket */
 16965  	vedis_hashmap_node *pFirst;     /* First inserted entry */
 16966  	vedis_hashmap_node *pLast;      /* Last inserted entry */
 16967  	vedis_hashmap_node *pCur;       /* Current entry */
 16968  	sxu32 nSize;                  /* Bucket size */
 16969  	sxu32 nEntry;                 /* Total number of inserted entries */
 16970  	sxu32 (*xIntHash)(sxi64);     /* Hash function for int_keys */
 16971  	sxu32 (*xBlobHash)(const void *, sxu32); /* Hash function for blob_keys */
 16972  	sxi32 iFlags;                 /* Hashmap control flags */
 16973  	sxi64 iNextIdx;               /* Next available automatically assigned index */
 16974  	sxi32 iRef;                   /* Reference count */
 16975  };
 16976  /* Allowed node types */
 16977  #define HASHMAP_INT_NODE   1  /* Node with an int [i.e: 64-bit integer] key */
 16978  #define HASHMAP_BLOB_NODE  2  /* Node with a string/BLOB key */
 16979  /*
 16980   * Default hash function for int [i.e; 64-bit integer] keys.
 16981   */
 16982  static sxu32 IntHash(sxi64 iKey)
 16983  {
 16984  	return (sxu32)(iKey ^ (iKey << 8) ^ (iKey >> 8));
 16985  }
 16986  /*
 16987   * Default hash function for string/BLOB keys.
 16988   */
 16989  static sxu32 BinHash(const void *pSrc, sxu32 nLen)
 16990  {
 16991  	register unsigned char *zIn = (unsigned char *)pSrc;
 16992  	unsigned char *zEnd;
 16993  	sxu32 nH = 5381;
 16994  	zEnd = &zIn[nLen];
 16995  	for(;;){
 16996  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16997  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16998  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 16999  		if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
 17000  	}	
 17001  	return nH;
 17002  }
 17003  /*
 17004   * Return the total number of entries in a given hashmap.
 17005   */
 17006  VEDIS_PRIVATE sxu32 vedisHashmapCount(vedis_hashmap *pMap)
 17007  {
 17008  	return pMap->nEntry;
 17009  }
 17010  /*
 17011   * Allocate a new hashmap node with a 64-bit integer key.
 17012   * If something goes wrong [i.e: out of memory], this function return NULL.
 17013   * Otherwise a fresh [vedis_hashmap_node] instance is returned.
 17014   */
 17015  static vedis_hashmap_node * HashmapNewIntNode(vedis_hashmap *pMap, sxi64 iKey, sxu32 nHash,vedis_value *pValue)
 17016  {
 17017  	vedis_hashmap_node *pNode;
 17018  	/* Allocate a new node */
 17019  	pNode = (vedis_hashmap_node *)SyMemBackendPoolAlloc(&pMap->pStore->sMem, sizeof(vedis_hashmap_node));
 17020  	if( pNode == 0 ){
 17021  		return 0;
 17022  	}
 17023  	/* Zero the stucture */
 17024  	SyZero(pNode, sizeof(vedis_hashmap_node));
 17025  	/* Fill in the structure */
 17026  	pNode->pMap  = &(*pMap);
 17027  	pNode->iType = HASHMAP_INT_NODE;
 17028  	pNode->nHash = nHash;
 17029  	pNode->xKey.iKey = iKey;
 17030  	/* Duplicate the value */
 17031  	vedisMemObjInit(pMap->pStore,&pNode->sValue);
 17032  	if( pValue ){
 17033  		vedisMemObjStore(pValue,&pNode->sValue);
 17034  	}
 17035  	return pNode;
 17036  }
 17037  /*
 17038   * Allocate a new hashmap node with a BLOB key.
 17039   * If something goes wrong [i.e: out of memory], this function return NULL.
 17040   * Otherwise a fresh [vedis_hashmap_node] instance is returned.
 17041   */
 17042  static vedis_hashmap_node * HashmapNewBlobNode(vedis_hashmap *pMap, const void *pKey, sxu32 nKeyLen, sxu32 nHash,vedis_value *pValue)
 17043  {
 17044  	vedis_hashmap_node *pNode;
 17045  	/* Allocate a new node */
 17046  	pNode = (vedis_hashmap_node *)SyMemBackendPoolAlloc(&pMap->pStore->sMem, sizeof(vedis_hashmap_node));
 17047  	if( pNode == 0 ){
 17048  		return 0;
 17049  	}
 17050  	/* Zero the stucture */
 17051  	SyZero(pNode, sizeof(vedis_hashmap_node));
 17052  	/* Fill in the structure */
 17053  	pNode->pMap  = &(*pMap);
 17054  	pNode->iType = HASHMAP_BLOB_NODE;
 17055  	pNode->nHash = nHash;
 17056  	SyBlobInit(&pNode->xKey.sKey, &pMap->pStore->sMem);
 17057  	SyBlobAppend(&pNode->xKey.sKey, pKey, nKeyLen);
 17058  	/* Duplicate the value */
 17059  	vedisMemObjInit(pMap->pStore,&pNode->sValue);
 17060  	if( pValue ){
 17061  		vedisMemObjStore(pValue,&pNode->sValue);
 17062  	}
 17063  	return pNode;
 17064  }
 17065  /*
 17066   * link a hashmap node to the given bucket index (last argument to this function).
 17067   */
 17068  static void HashmapNodeLink(vedis_hashmap *pMap, vedis_hashmap_node *pNode, sxu32 nBucketIdx)
 17069  {
 17070  	/* Link */
 17071  	if( pMap->apBucket[nBucketIdx] != 0 ){
 17072  		pNode->pNextCollide = pMap->apBucket[nBucketIdx];
 17073  		pMap->apBucket[nBucketIdx]->pPrevCollide = pNode;
 17074  	}
 17075  	pMap->apBucket[nBucketIdx] = pNode;
 17076  	/* Link to the map list */
 17077  	if( pMap->pFirst == 0 ){
 17078  		pMap->pFirst = pMap->pLast = pNode;
 17079  		/* Point to the first inserted node */
 17080  		pMap->pCur = pNode;
 17081  	}else{
 17082  		MACRO_LD_PUSH(pMap->pLast, pNode);
 17083  	}
 17084  	++pMap->nEntry;
 17085  }
 17086  #define HASHMAP_FILL_FACTOR 3
 17087  /*
 17088   * Grow the hash-table and rehash all entries.
 17089   */
 17090  static sxi32 HashmapGrowBucket(vedis_hashmap *pMap)
 17091  {
 17092  	if( pMap->nEntry >= pMap->nSize * HASHMAP_FILL_FACTOR ){
 17093  		vedis_hashmap_node **apOld = pMap->apBucket;
 17094  		vedis_hashmap_node *pEntry, **apNew;
 17095  		sxu32 nNew = pMap->nSize << 1;
 17096  		sxu32 nBucket;
 17097  		sxu32 n;
 17098  		if( nNew < 1 ){
 17099  			nNew = 16;
 17100  		}
 17101  		/* Allocate a new bucket */
 17102  		apNew = (vedis_hashmap_node **)SyMemBackendAlloc(&pMap->pStore->sMem, nNew * sizeof(vedis_hashmap_node *));
 17103  		if( apNew == 0 ){
 17104  			if( pMap->nSize < 1 ){
 17105  				return SXERR_MEM; /* Fatal */
 17106  			}
 17107  			/* Not so fatal here, simply a performance hit */
 17108  			return SXRET_OK;
 17109  		}
 17110  		/* Zero the table */
 17111  		SyZero((void *)apNew, nNew * sizeof(vedis_hashmap_node *));
 17112  		/* Reflect the change */
 17113  		pMap->apBucket = apNew;
 17114  		pMap->nSize = nNew;
 17115  		if( apOld == 0 ){
 17116  			/* First allocated table [i.e: no entry], return immediately */
 17117  			return SXRET_OK;
 17118  		}
 17119  		/* Rehash old entries */
 17120  		pEntry = pMap->pFirst;
 17121  		n = 0;
 17122  		for( ;; ){
 17123  			if( n >= pMap->nEntry ){
 17124  				break;
 17125  			}
 17126  			/* Clear the old collision link */
 17127  			pEntry->pNextCollide = pEntry->pPrevCollide = 0;
 17128  			/* Link to the new bucket */
 17129  			nBucket = pEntry->nHash & (nNew - 1);
 17130  			if( pMap->apBucket[nBucket] != 0 ){
 17131  				pEntry->pNextCollide = pMap->apBucket[nBucket];
 17132  				pMap->apBucket[nBucket]->pPrevCollide = pEntry;
 17133  			}
 17134  			pMap->apBucket[nBucket] = pEntry;
 17135  			/* Point to the next entry */
 17136  			pEntry = pEntry->pPrev; /* Reverse link */
 17137  			n++;
 17138  		}
 17139  		/* Free the old table */
 17140  		SyMemBackendFree(&pMap->pStore->sMem, (void *)apOld);
 17141  	}
 17142  	return SXRET_OK;
 17143  }
 17144  /*
 17145   * Insert a 64-bit integer key and it's associated value (if any) in the given
 17146   * hashmap.
 17147   */
 17148  static sxi32 HashmapInsertIntKey(vedis_hashmap *pMap,sxi64 iKey,vedis_value *pValue)
 17149  {
 17150  	vedis_hashmap_node *pNode;
 17151  	sxu32 nHash;
 17152  	sxi32 rc;
 17153  	
 17154  	/* Hash the key */
 17155  	nHash = pMap->xIntHash(iKey);
 17156  	/* Allocate a new int node */
 17157  	pNode = HashmapNewIntNode(&(*pMap), iKey, nHash, pValue);
 17158  	if( pNode == 0 ){
 17159  		return SXERR_MEM;
 17160  	}
 17161  	/* Make sure the bucket is big enough to hold the new entry */
 17162  	rc = HashmapGrowBucket(&(*pMap));
 17163  	if( rc != SXRET_OK ){
 17164  		SyMemBackendPoolFree(&pMap->pStore->sMem, pNode);
 17165  		return rc;
 17166  	}
 17167  	/* Perform the insertion */
 17168  	HashmapNodeLink(&(*pMap), pNode, nHash & (pMap->nSize - 1));
 17169  	/* All done */
 17170  	return SXRET_OK;
 17171  }
 17172  /*
 17173   * Insert a BLOB key and it's associated value (if any) in the given
 17174   * hashmap.
 17175   */
 17176  static sxi32 HashmapInsertBlobKey(vedis_hashmap *pMap,const void *pKey,sxu32 nKeyLen,vedis_value *pValue)
 17177  {
 17178  	vedis_hashmap_node *pNode;
 17179  	sxu32 nHash;
 17180  	sxi32 rc;
 17181  	
 17182  	/* Hash the key */
 17183  	nHash = pMap->xBlobHash(pKey, nKeyLen);
 17184  	/* Allocate a new blob node */
 17185  	pNode = HashmapNewBlobNode(&(*pMap), pKey, nKeyLen, nHash,pValue);
 17186  	if( pNode == 0 ){
 17187  		return SXERR_MEM;
 17188  	}
 17189  	/* Make sure the bucket is big enough to hold the new entry */
 17190  	rc = HashmapGrowBucket(&(*pMap));
 17191  	if( rc != SXRET_OK ){
 17192  		SyMemBackendPoolFree(&pMap->pStore->sMem, pNode);
 17193  		return rc;
 17194  	}
 17195  	/* Perform the insertion */
 17196  	HashmapNodeLink(&(*pMap), pNode, nHash & (pMap->nSize - 1));
 17197  	/* All done */
 17198  	return SXRET_OK;
 17199  }
 17200  /*
 17201   * Check if a given 64-bit integer key exists in the given hashmap.
 17202   * Write a pointer to the target node on success. Otherwise
 17203   * SXERR_NOTFOUND is returned on failure.
 17204   */
 17205  static sxi32 HashmapLookupIntKey(
 17206  	vedis_hashmap *pMap,         /* Target hashmap */
 17207  	sxi64 iKey,                /* lookup key */
 17208  	vedis_hashmap_node **ppNode  /* OUT: target node on success */
 17209  	)
 17210  {
 17211  	vedis_hashmap_node *pNode;
 17212  	sxu32 nHash;
 17213  	if( pMap->nEntry < 1 ){
 17214  		/* Don't bother hashing, there is no entry anyway */
 17215  		return SXERR_NOTFOUND;
 17216  	}
 17217  	/* Hash the key first */
 17218  	nHash = pMap->xIntHash(iKey);
 17219  	/* Point to the appropriate bucket */
 17220  	pNode = pMap->apBucket[nHash & (pMap->nSize - 1)];
 17221  	/* Perform the lookup */
 17222  	for(;;){
 17223  		if( pNode == 0 ){
 17224  			break;
 17225  		}
 17226  		if( pNode->iType == HASHMAP_INT_NODE
 17227  			&& pNode->nHash == nHash
 17228  			&& pNode->xKey.iKey == iKey ){
 17229  				/* Node found */
 17230  				if( ppNode ){
 17231  					*ppNode = pNode;
 17232  				}
 17233  				return SXRET_OK;
 17234  		}
 17235  		/* Follow the collision link */
 17236  		pNode = pNode->pNextCollide;
 17237  	}
 17238  	/* No such entry */
 17239  	return SXERR_NOTFOUND;
 17240  }
 17241  /*
 17242   * Check if a given BLOB key exists in the given hashmap.
 17243   * Write a pointer to the target node on success. Otherwise
 17244   * SXERR_NOTFOUND is returned on failure.
 17245   */
 17246  static sxi32 HashmapLookupBlobKey(
 17247  	vedis_hashmap *pMap,          /* Target hashmap */
 17248  	const void *pKey,           /* Lookup key */
 17249  	sxu32 nKeyLen,              /* Key length in bytes */
 17250  	vedis_hashmap_node **ppNode   /* OUT: target node on success */
 17251  	)
 17252  {
 17253  	vedis_hashmap_node *pNode;
 17254  	sxu32 nHash;
 17255  	if( pMap->nEntry < 1 ){
 17256  		/* Don't bother hashing, there is no entry anyway */
 17257  		return SXERR_NOTFOUND;
 17258  	}
 17259  	/* Hash the key first */
 17260  	nHash = pMap->xBlobHash(pKey, nKeyLen);
 17261  	/* Point to the appropriate bucket */
 17262  	pNode = pMap->apBucket[nHash & (pMap->nSize - 1)];
 17263  	/* Perform the lookup */
 17264  	for(;;){
 17265  		if( pNode == 0 ){
 17266  			break;
 17267  		}
 17268  		if( pNode->iType == HASHMAP_BLOB_NODE 
 17269  			&& pNode->nHash == nHash
 17270  			&& SyBlobLength(&pNode->xKey.sKey) == nKeyLen 
 17271  			&& SyMemcmp(SyBlobData(&pNode->xKey.sKey), pKey, nKeyLen) == 0 ){
 17272  				/* Node found */
 17273  				if( ppNode ){
 17274  					*ppNode = pNode;
 17275  				}
 17276  				return SXRET_OK;
 17277  		}
 17278  		/* Follow the collision link */
 17279  		pNode = pNode->pNextCollide;
 17280  	}
 17281  	/* No such entry */
 17282  	return SXERR_NOTFOUND;
 17283  }
 17284  /*
 17285   * Check if a given key exists in the given hashmap.
 17286   * Write a pointer to the target node on success.
 17287   * Otherwise SXERR_NOTFOUND is returned on failure.
 17288   */
 17289  static sxi32 HashmapLookup(
 17290  	vedis_hashmap *pMap,          /* Target hashmap */
 17291  	vedis_value *pKey,            /* Lookup key */
 17292  	vedis_hashmap_node **ppNode   /* OUT: target node on success */
 17293  	)
 17294  {
 17295  	vedis_hashmap_node *pNode = 0; /* cc -O6 warning */
 17296  	sxi32 rc;
 17297  	if( pKey->iFlags & (MEMOBJ_STRING|MEMOBJ_HASHMAP) ){
 17298  		if( (pKey->iFlags & MEMOBJ_STRING) == 0 ){
 17299  			/* Force a string cast */
 17300  			vedisMemObjToString(&(*pKey));
 17301  		}
 17302  		if( SyBlobLength(&pKey->sBlob) > 0 ){
 17303  			/* Perform a blob lookup */
 17304  			rc = HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &pNode);
 17305  			goto result;
 17306  		}
 17307  	}
 17308  	/* Perform an int lookup */
 17309  	if((pKey->iFlags & MEMOBJ_INT) == 0 ){
 17310  		/* Force an integer cast */
 17311  		vedisMemObjToInteger(pKey);
 17312  	}
 17313  	/* Perform an int lookup */
 17314  	rc = HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode);
 17315  result:
 17316  	if( rc == SXRET_OK ){
 17317  		/* Node found */
 17318  		if( ppNode ){
 17319  			*ppNode = pNode;
 17320  		}
 17321  		return SXRET_OK;
 17322  	}
 17323  	/* No such entry */
 17324  	return SXERR_NOTFOUND;
 17325  }
 17326  /*
 17327   * Check if the given BLOB key looks like a decimal number. 
 17328   * Retrurn TRUE on success.FALSE otherwise.
 17329   */
 17330  static int HashmapIsIntKey(SyBlob *pKey)
 17331  {
 17332  	const char *zIn  = (const char *)SyBlobData(pKey);
 17333  	const char *zEnd = &zIn[SyBlobLength(pKey)];
 17334  	if( (int)(zEnd-zIn) > 1 && zIn[0] == '0' ){
 17335  		/* Octal not decimal number */
 17336  		return FALSE;
 17337  	}
 17338  	if( (zIn[0] == '-' || zIn[0] == '+') && &zIn[1] < zEnd ){
 17339  		zIn++;
 17340  	}
 17341  	for(;;){
 17342  		if( zIn >= zEnd ){
 17343  			return TRUE;
 17344  		}
 17345  		if( (unsigned char)zIn[0] >= 0xc0 /* UTF-8 stream */  || !SyisDigit(zIn[0]) ){
 17346  			break;
 17347  		}
 17348  		zIn++;
 17349  	}
 17350  	/* Key does not look like a decimal number */
 17351  	return FALSE;
 17352  }
 17353  /*
 17354   * Insert a given key and it's associated value (if any) in the given
 17355   * hashmap.
 17356   * If a node with the given key already exists in the database
 17357   * then this function overwrite the old value.
 17358   */
 17359  static sxi32 HashmapInsert(
 17360  	vedis_hashmap *pMap, /* Target hashmap */
 17361  	vedis_value *pKey,   /* Lookup key  */
 17362  	vedis_value *pVal    /* Node value */
 17363  	)
 17364  {
 17365  	vedis_hashmap_node *pNode = 0;
 17366  	sxi32 rc = SXRET_OK;
 17367  	
 17368  	if( pKey && (pKey->iFlags & (MEMOBJ_STRING|MEMOBJ_HASHMAP)) ){
 17369  		if( (pKey->iFlags & MEMOBJ_STRING) == 0 ){
 17370  			/* Force a string cast */
 17371  			vedisMemObjToString(&(*pKey));
 17372  		}
 17373  		if( SyBlobLength(&pKey->sBlob) < 1 || HashmapIsIntKey(&pKey->sBlob) ){
 17374  			if(SyBlobLength(&pKey->sBlob) < 1){
 17375  				/* Automatic index assign */
 17376  				pKey = 0;
 17377  			}
 17378  			goto IntKey;
 17379  		}
 17380  		if( SXRET_OK == HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), 
 17381  			SyBlobLength(&pKey->sBlob), &pNode) ){
 17382  				/* Overwrite the old value */
 17383  				if( pVal ){
 17384  					vedisMemObjStore(pVal,&pNode->sValue);
 17385  				}else{
 17386  					/* Nullify the entry */
 17387  					vedisMemObjToNull(&pNode->sValue);
 17388  				}
 17389  				return SXRET_OK;
 17390  		}
 17391  		/* Perform a blob-key insertion */
 17392  		rc = HashmapInsertBlobKey(&(*pMap),SyBlobData(&pKey->sBlob),SyBlobLength(&pKey->sBlob),&(*pVal));
 17393  		return rc;
 17394  	}
 17395  IntKey:
 17396  	if( pKey ){
 17397  		if((pKey->iFlags & MEMOBJ_INT) == 0 ){
 17398  			/* Force an integer cast */
 17399  			vedisMemObjToInteger(pKey);
 17400  		}
 17401  		if( SXRET_OK == HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode) ){
 17402  			/* Overwrite the old value */
 17403  			if( pVal ){
 17404  				vedisMemObjStore(pVal,&pNode->sValue);
 17405  			}else{
 17406  				/* Nullify the entry */
 17407  				vedisMemObjToNull(&pNode->sValue);
 17408  			}
 17409  			return SXRET_OK;
 17410  		}
 17411  		/* Perform a 64-bit-int-key insertion */
 17412  		rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal));
 17413  		if( rc == SXRET_OK ){
 17414  			if( pKey->x.iVal >= pMap->iNextIdx ){
 17415  				/* Increment the automatic index */ 
 17416  				pMap->iNextIdx = pKey->x.iVal + 1;
 17417  				/* Make sure the automatic index is not reserved */
 17418  				while( SXRET_OK == HashmapLookupIntKey(&(*pMap), pMap->iNextIdx, 0) ){
 17419  					pMap->iNextIdx++;
 17420  				}
 17421  			}
 17422  		}
 17423  	}else{
 17424  		/* Assign an automatic index */
 17425  		rc = HashmapInsertIntKey(&(*pMap),pMap->iNextIdx,&(*pVal));
 17426  		if( rc == SXRET_OK ){
 17427  			++pMap->iNextIdx;
 17428  		}
 17429  	}
 17430  	/* Insertion result */
 17431  	return rc;
 17432  }
 17433  /*
 17434   * Allocate a new hashmap.
 17435   * Return a pointer to the freshly allocated hashmap on success.NULL otherwise.
 17436   */
 17437  VEDIS_PRIVATE vedis_hashmap * vedisNewHashmap(
 17438  	vedis *pStore,             /* Engine that trigger the hashmap creation */
 17439  	sxu32 (*xIntHash)(sxi64), /* Hash function for int keys.NULL otherwise*/
 17440  	sxu32 (*xBlobHash)(const void *, sxu32) /* Hash function for BLOB keys.NULL otherwise */
 17441  	)
 17442  {
 17443  	vedis_hashmap *pMap;
 17444  	/* Allocate a new instance */
 17445  	pMap = (vedis_hashmap *)SyMemBackendPoolAlloc(&pStore->sMem, sizeof(vedis_hashmap));
 17446  	if( pMap == 0 ){
 17447  		return 0;
 17448  	}
 17449  	/* Zero the structure */
 17450  	SyZero(pMap, sizeof(vedis_hashmap));
 17451  	/* Fill in the structure */
 17452  	pMap->pStore = &(*pStore);
 17453  	pMap->iRef = 1;
 17454  	/* pMap->iFlags = 0; */
 17455  	/* Default hash functions */
 17456  	pMap->xIntHash  = xIntHash ? xIntHash : IntHash;
 17457  	pMap->xBlobHash = xBlobHash ? xBlobHash : BinHash;
 17458  	return pMap;
 17459  }
 17460  /*
 17461   * Increment the reference count of a given hashmap.
 17462   */
 17463  VEDIS_PRIVATE void vedisHashmapRef(vedis_hashmap *pMap)
 17464  {
 17465  	pMap->iRef++;
 17466  }
 17467  /*
 17468   * Release a hashmap.
 17469   */
 17470  static sxi32 vedisHashmapRelease(vedis_hashmap *pMap)
 17471  {
 17472  	vedis_hashmap_node *pEntry, *pNext;
 17473  	vedis *pStore = pMap->pStore;
 17474  	sxu32 n;
 17475  	/* Start the release process */
 17476  	n = 0;
 17477  	pEntry = pMap->pFirst;
 17478  	for(;;){
 17479  		if( n >= pMap->nEntry ){
 17480  			break;
 17481  		}
 17482  		pNext = pEntry->pPrev; /* Reverse link */
 17483  		/* Release the vedis_value */
 17484  		vedisMemObjRelease(&pEntry->sValue);
 17485  		/* Release the node */
 17486  		if( pEntry->iType == HASHMAP_BLOB_NODE ){
 17487  			SyBlobRelease(&pEntry->xKey.sKey);
 17488  		}
 17489  		SyMemBackendPoolFree(&pStore->sMem, pEntry);
 17490  		/* Point to the next entry */
 17491  		pEntry = pNext;
 17492  		n++;
 17493  	}
 17494  	if( pMap->nEntry > 0 ){
 17495  		/* Release the hash bucket */
 17496  		SyMemBackendFree(&pStore->sMem, pMap->apBucket);
 17497  	}
 17498  	/* Free the whole instance */
 17499  	SyMemBackendPoolFree(&pStore->sMem, pMap);
 17500  	return SXRET_OK;
 17501  }
 17502  /*
 17503   * Decrement the reference count of a given hashmap.
 17504   * If the count reaches zero which mean no more variables
 17505   * are pointing to this hashmap, then release the whole instance.
 17506   */
 17507  VEDIS_PRIVATE void vedisHashmapUnref(vedis_hashmap *pMap)
 17508  {
 17509  	pMap->iRef--;
 17510  	if( pMap->iRef < 1 ){
 17511  		vedisHashmapRelease(pMap);
 17512  	}
 17513  }
 17514  VEDIS_PRIVATE vedis * vedisHashmapGetEngine(vedis_hashmap *pMap)
 17515  {
 17516  	return pMap->pStore;
 17517  }
 17518  /*
 17519   * Check if a given key exists in the given hashmap.
 17520   * Write a pointer to the target node on success.
 17521   * Otherwise SXERR_NOTFOUND is returned on failure.
 17522   */
 17523  VEDIS_PRIVATE sxi32 vedisHashmapLookup(
 17524  	vedis_hashmap *pMap,        /* Target hashmap */
 17525  	vedis_value *pKey,          /* Lookup key */
 17526  	vedis_value **ppOut /* OUT: Target node on success */
 17527  	)
 17528  {
 17529  	vedis_hashmap_node *pNode;
 17530  	sxi32 rc;
 17531  	if( pMap->nEntry < 1 ){
 17532  		/* TICKET 1433-25: Don't bother hashing, the hashmap is empty anyway.
 17533  		 */
 17534  		return SXERR_NOTFOUND;
 17535  	}
 17536  	rc = HashmapLookup(&(*pMap), &(*pKey),&pNode);
 17537  	if( rc != SXRET_OK ){
 17538  		return rc;
 17539  	}
 17540  	if( ppOut ){
 17541  		/* Point to the node value */
 17542  		*ppOut = &pNode->sValue;
 17543  	}
 17544  	return VEDIS_OK;
 17545  }
 17546  /*
 17547   * Insert a given key and it's associated value (if any) in the given
 17548   * hashmap.
 17549   * If a node with the given key already exists in the database
 17550   * then this function overwrite the old value.
 17551   */
 17552  VEDIS_PRIVATE sxi32 vedisHashmapInsert(
 17553  	vedis_hashmap *pMap, /* Target hashmap */
 17554  	vedis_value *pKey,   /* Lookup key */
 17555  	vedis_value *pVal    /* Node value.NULL otherwise */
 17556  	)
 17557  {
 17558  	sxi32 rc;
 17559  	rc = HashmapInsert(&(*pMap), &(*pKey), &(*pVal));
 17560  	return rc;
 17561  }
 17562  /*
 17563   * Iterate throw hashmap entries and invoke the given callback [i.e: xWalk()] for each 
 17564   * retrieved entry.
 17565   * If the callback wishes to abort processing [i.e: it's invocation] it must return
 17566   * a value different from VEDIS_OK.
 17567   * Refer to [vedis_array_walk()] for more information.
 17568   */
 17569  VEDIS_PRIVATE sxi32 vedisHashmapWalk(
 17570  	vedis_hashmap *pMap, /* Target hashmap */
 17571  	int (*xWalk)(vedis_value *, void *), /* Walker callback */
 17572  	void *pUserData /* Last argument to xWalk() */
 17573  	)
 17574  {
 17575  	vedis_hashmap_node *pEntry;
 17576  	sxi32 rc;
 17577  	sxu32 n;
 17578  	/* Initialize walker parameter */
 17579  	rc = SXRET_OK;
 17580  	n = pMap->nEntry;
 17581  	pEntry = pMap->pFirst;
 17582  	/* Start the iteration process */
 17583  	for(;;){
 17584  		if( n < 1 ){
 17585  			break;
 17586  		}
 17587  		/* Invoke the user callback */
 17588  		rc = xWalk(&pEntry->sValue,pUserData);
 17589  		if( rc != VEDIS_OK ){
 17590  			/* Callback request an operation abort */
 17591  			return SXERR_ABORT;
 17592  		}
 17593  		/* Point to the next entry */
 17594  		pEntry = pEntry->pPrev; /* Reverse link */
 17595  		n--;
 17596  	}
 17597  	/* All done */
 17598  	return SXRET_OK;
 17599  }
 17600  /*
 17601   * Reset the node cursor of a given hashmap.
 17602   */
 17603  VEDIS_PRIVATE void vedisHashmapResetLoopCursor(vedis_hashmap *pMap)
 17604  {
 17605  	/* Reset the loop cursor */
 17606  	pMap->pCur = pMap->pFirst;
 17607  }
 17608  /*
 17609   * Return a pointer to the node currently pointed by the node cursor.
 17610   * If the cursor reaches the end of the list, then this function
 17611   * return NULL.
 17612   * Note that the node cursor is automatically advanced by this function.
 17613   */
 17614  VEDIS_PRIVATE vedis_value * vedisHashmapGetNextEntry(vedis_hashmap *pMap)
 17615  {
 17616  	vedis_hashmap_node *pCur = pMap->pCur;
 17617  	if( pCur == 0 ){
 17618  		/* End of the list, return null */
 17619  		return 0;
 17620  	}
 17621  	/* Advance the node cursor */
 17622  	pMap->pCur = pCur->pPrev; /* Reverse link */
 17623  	/* Entry value */
 17624  	return &pCur->sValue;
 17625  }
 17626  /*
 17627   * ----------------------------------------------------------
 17628   * File: cmd.c
 17629   * MD5: 9f423624c51655b52e412da8cc3bb222
 17630   * ----------------------------------------------------------
 17631   */
 17632  /*
 17633   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
 17634   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
 17635   * Version 1.2.6
 17636   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 17637   * please contact Symisc Systems via:
 17638   *       legal@symisc.net
 17639   *       licensing@symisc.net
 17640   *       contact@symisc.net
 17641   * or visit:
 17642   *      http://vedis.symisc.net/
 17643   */
 17644  /* $SymiscID: cmd.c v1.2 FreeBSD 2013-07-10 04:45 stable <chm@symisc.net> $ */
 17645  #ifndef VEDIS_AMALGAMATION
 17646  #include "vedisInt.h"
 17647  #endif
 17648  /* Implementation of the vedis commands  */
 17649  /*
 17650   *  Command: DEL key [key ...]
 17651   * Description:
 17652   *   Removes the specified keys. A key is ignored if it does not exist.
 17653   * Return:
 17654   * Integer: The number of keys that were removed.
 17655   */
 17656  static int vedis_cmd_del(vedis_context *pCtx,int argc,vedis_value **argv)
 17657  {
 17658  	int nDel = 0; 
 17659  	int rc;
 17660  	int i;
 17661  	/* Delete the given keys */
 17662  	for( i = 0 ; i < argc; ++i ){
 17663  		const char *zValue;
 17664  		int nByte;
 17665  		/* String representation of the key */
 17666  		zValue = vedis_value_to_string(argv[i],&nByte);
 17667  		/* Delete the key */
 17668  		rc = vedis_context_kv_delete(pCtx,(const void *)zValue,nByte);
 17669  		if( rc == VEDIS_OK ){
 17670  			nDel++;
 17671  		}
 17672  	}
 17673  	/* Total number of removed keys */
 17674  	vedis_result_int(pCtx,nDel);
 17675  	return VEDIS_OK;
 17676  }
 17677  /*
 17678   *  Command:  EXISTS key
 17679   * Description:
 17680   *   Check key existance.
 17681   * Return:
 17682   *   bool: TRUE if key exists. FALSE otherwise.
 17683   */
 17684  static int vedis_cmd_exists(vedis_context *pCtx,int argc,vedis_value **argv)
 17685  {
 17686  	int rc = VEDIS_NOTFOUND;
 17687  	if( argc > 0 ){
 17688  		const char *zKey;
 17689  		int nByte;
 17690  		/* Target key */
 17691  		zKey = vedis_value_to_string(argv[0],&nByte);
 17692  		/* Fetch */
 17693  		rc = vedis_context_kv_fetch_callback(pCtx,zKey,nByte,0,0);
 17694  	}
 17695  	/* Result */
 17696  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 17697  	return VEDIS_OK;
 17698  }
 17699  /*
 17700   *  Command:   APPEND key value
 17701   * Description:
 17702   *   If key already exists and is a string, this command appends the value
 17703   *   at the end of the string. If key does not exist it is created and set 
 17704   *   as an empty string, so APPEND will be similar to SET in this special case.
 17705   * Return:
 17706   *   Integer: the length of the string after the append operation.
 17707   */
 17708  static int vedis_cmd_append(vedis_context *pCtx,int argc,vedis_value **argv)
 17709  {
 17710  	const char *zKey,*zValue;
 17711  	vedis_int64 nTot;
 17712  	int nKey,nByte;
 17713  	int rc;
 17714  	if( argc < 2 ){
 17715  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 17716  		/* Return 0 */
 17717  		vedis_result_int(pCtx,0);
 17718  		return VEDIS_OK;
 17719  	}
 17720  	/* Target key */
 17721  	zKey  = vedis_value_to_string(argv[0],&nKey);
 17722  	zValue = vedis_value_to_string(argv[1],&nByte);
 17723  	if( nByte > 0 ){
 17724  		/* Append */
 17725  		rc = vedis_context_kv_append(pCtx,zKey,nKey,zValue,nByte);
 17726  		if( rc != VEDIS_OK ){
 17727  			vedis_result_int(pCtx,0);
 17728  			return VEDIS_ABORT;
 17729  		}
 17730  	}
 17731  	/* New length */
 17732  	nTot = nByte;
 17733  	vedis_context_kv_fetch(pCtx,zKey,nKey,0,&nTot);
 17734  	vedis_result_int64(pCtx,nTot);
 17735  	return VEDIS_OK;
 17736  }
 17737  /*
 17738   *  Command:   STRLEN key
 17739   * Description:
 17740   *   Returns the length of the string value stored at key. An error is returned when key
 17741   *   holds a non-string value.
 17742   * Return:
 17743   *   Integer: The length of the string at key, or 0 when key does not exist.
 17744   */
 17745  static int vedis_cmd_strlen(vedis_context *pCtx,int argc,vedis_value **argv)
 17746  {
 17747  	vedis_int64 nByte = 0;
 17748  	if( argc > 0 ){
 17749  		const char *zKey;
 17750  		int nKey;
 17751  		/* Target key */
 17752  		zKey  = vedis_value_to_string(argv[0],&nKey);
 17753  		vedis_context_kv_fetch(pCtx,zKey,nKey,0,&nByte);
 17754  	}
 17755  	vedis_result_int64(pCtx,nByte);
 17756  	return VEDIS_OK;
 17757  }
 17758  /*
 17759   * Fetch Key value from the underlying database.
 17760   */
 17761  static int vedisFetchValue(vedis_context *pCtx,vedis_value *pArg,SyBlob *pOut)
 17762  {
 17763  	const char *zKey;
 17764  	int nByte;
 17765  	int rc;
 17766  	/* Target key */
 17767  	zKey = vedis_value_to_string(pArg,&nByte);
 17768  	/* Fetch the value */
 17769  	rc = vedis_context_kv_fetch_callback(pCtx,zKey,nByte,pOut ? vedisDataConsumer : 0,pOut);
 17770  	return rc;
 17771  }
 17772  /*
 17773   *  Command:   GET key
 17774   * Description:
 17775   *   Get the value of key. If the key does not exist the special value nil is returned.
 17776   * Return:
 17777   *   the value of key, or nil when key does not exist.
 17778   */
 17779  static int vedis_cmd_get(vedis_context *pCtx,int argc,vedis_value **argv)
 17780  {
 17781  	int rc;
 17782  	if( argc <  1 ){
 17783  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 17784  		/* return null */
 17785  		vedis_result_null(pCtx);
 17786  		return VEDIS_OK;
 17787  	}
 17788  	/* Fetch the record */
 17789  	rc = vedisFetchValue(pCtx,argv[0],VedisContextResultBuffer(pCtx));
 17790  	if( rc == VEDIS_OK ){
 17791  		vedis_result_string(pCtx,0,0);
 17792  	}else{
 17793  		/* No such record */
 17794  		vedis_result_null(pCtx);
 17795  	}
 17796  	return VEDIS_OK;
 17797  }
 17798  /*
 17799   *  Command:   COPY old_key new_key
 17800   * Description:
 17801   *   Copy key values.
 17802   * Return:
 17803   *   Boolean: TRUE on success. FALSE otherwise.
 17804   */
 17805  static int vedis_cmd_copy(vedis_context *pCtx,int argc,vedis_value **argv)
 17806  {
 17807  	const char *zNew;
 17808  	SyBlob *pWorker;
 17809  	int nByte,rc;
 17810  	if( argc <  2 ){
 17811  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing old_key/new_key pair");
 17812  		/* return null */
 17813  		vedis_result_null(pCtx);
 17814  		return VEDIS_OK;
 17815  	}
 17816  	pWorker = VedisContextWorkingBuffer(pCtx);
 17817  	SyBlobReset(pWorker);
 17818  	/* Fetch the record */
 17819  	rc = vedisFetchValue(pCtx,argv[0],pWorker);
 17820  	if( rc != VEDIS_OK ){
 17821  		/* No such record, return FALSE */
 17822  		vedis_result_bool(pCtx,0);
 17823  	}
 17824  	/* Duplicate the record */
 17825  	zNew = vedis_value_to_string(argv[1],&nByte);
 17826  	rc = vedis_context_kv_store(pCtx,zNew,nByte,SyBlobData(pWorker),(vedis_int64)SyBlobLength(pWorker));
 17827  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 17828  	return VEDIS_OK;
 17829  }
 17830  /*
 17831   *  Command:   MOVE old_key new_key
 17832   * Description:
 17833   *   Move key values.
 17834   * Return:
 17835   *   Boolean: TRUE on success. FALSE otherwise.
 17836   */
 17837  static int vedis_cmd_move(vedis_context *pCtx,int argc,vedis_value **argv)
 17838  {
 17839  	const char *zNew;
 17840  	SyBlob *pWorker;
 17841  	int nByte,rc;
 17842  	if( argc <  2 ){
 17843  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing old_key/new_key pair");
 17844  		/* return null */
 17845  		vedis_result_null(pCtx);
 17846  		return VEDIS_OK;
 17847  	}
 17848  	pWorker = VedisContextWorkingBuffer(pCtx);
 17849  	SyBlobReset(pWorker);
 17850  	/* Fetch the record */
 17851  	rc = vedisFetchValue(pCtx,argv[0],pWorker);
 17852  	if( rc != VEDIS_OK ){
 17853  		/* No such record, return FALSE */
 17854  		vedis_result_bool(pCtx,0);
 17855  	}
 17856  	/* Duplicate the record */
 17857  	zNew = vedis_value_to_string(argv[1],&nByte);
 17858  	rc = vedis_context_kv_store(pCtx,zNew,nByte,SyBlobData(pWorker),(vedis_int64)SyBlobLength(pWorker));
 17859  	if( rc == VEDIS_OK ){
 17860  		const char *zOld;
 17861  		/* Discard the old record */
 17862  		zOld = vedis_value_to_string(argv[0],&nByte);
 17863  		rc = vedis_context_kv_delete(pCtx,zOld,nByte);
 17864  	}
 17865  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 17866  	return VEDIS_OK;
 17867  }
 17868  /*
 17869   *  Command:   MGET key [key ...]
 17870   * Description:
 17871   *   Returns the values of all specified keys. For every key that
 17872   *   does not hold a string value or does not exist, the special value
 17873   *   nil is returned. Because of this, the operation never fails.
 17874   * Return:
 17875   *   Array: Multiple values.
 17876   */
 17877  static int vedis_cmd_mget(vedis_context *pCtx,int argc,vedis_value **argv)
 17878  {
 17879  	vedis_value *pArray,*pScalar;
 17880  	SyBlob *pWorker;
 17881  	int i,rc;
 17882  	if( argc <  1 ){
 17883  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 17884  		/* return null */
 17885  		vedis_result_null(pCtx);
 17886  		return VEDIS_OK;
 17887  	}
 17888  	/* Allocate a new array and a working buffer */
 17889  	pArray = vedis_context_new_array(pCtx);
 17890  	pScalar = vedis_context_new_scalar(pCtx);
 17891  	if( pArray == 0 || pScalar == 0){
 17892  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 17893  		/* return null */
 17894  		vedis_result_null(pCtx);
 17895  		/* pScalar and pArray will be automaticallay desotroyed */
 17896  		return VEDIS_OK;
 17897  	}
 17898  	vedis_value_string(pScalar,0,0);
 17899  	pWorker = vedisObjectValueBlob(pScalar);
 17900  	for( i = 0 ; i < argc; ++i ){
 17901  		/* Fetch the record */
 17902  		SyBlobReset(pWorker);
 17903  		rc = vedisFetchValue(pCtx,argv[i],pWorker);
 17904  		/* Populate our array */
 17905  		vedis_array_insert(pArray,rc == VEDIS_OK ? pScalar /* Will make its own copy */ : 0 /* null */);
 17906  	}
 17907  	/* Return our array */
 17908  	vedis_result_value(pCtx,pArray);
 17909  	vedis_context_release_value(pCtx,pScalar);
 17910  	return VEDIS_OK;
 17911  }
 17912  static int VedisStoreValue(vedis_context *pCtx,vedis_value *pKey,vedis_value *pData)
 17913  {
 17914  	const char *zKey,*zData;
 17915  	int nKey,nData;
 17916  	int rc;
 17917  	/* Extract the key and data */
 17918  	zKey  = vedis_value_to_string(pKey,&nKey);
 17919  	zData = vedis_value_to_string(pData,&nData);
 17920  	/* Perform the store operation */
 17921  	rc = vedis_context_kv_store(pCtx,zKey,nKey,zData,(vedis_int64)nData);
 17922  	return rc;
 17923  }
 17924  /*
 17925   *  Command:   SET key value
 17926   * Description:
 17927   *   Set key to hold the string value. If key already holds a value, it is overwritten,
 17928   *   regardless of its type. Any previous time to live associated with the key is
 17929   *   discarded on successful SET operation.
 17930   * Return:
 17931   *   bool: TRUE on success, FALSE otherwise.
 17932   */
 17933  static int vedis_cmd_set(vedis_context *pCtx,int argc,vedis_value **argv)
 17934  {
 17935  	int rc;
 17936  	if( argc <  2 ){
 17937  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 17938  		/* return false */
 17939  		vedis_result_bool(pCtx,0);
 17940  		return VEDIS_OK;
 17941  	}
 17942  	/* Perform the store operation */
 17943  	rc = VedisStoreValue(pCtx,argv[0],argv[1]);
 17944  	/* Store result */
 17945  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 17946  	return VEDIS_OK;
 17947  }
 17948  /*
 17949   *  Command:  SETNX key value
 17950   * Description:
 17951   *   Set key to hold string value if key does not exist. In that case, it is equal to SET.
 17952   *   When key already holds a value, no operation is performed. SETNX is short for
 17953   *  "SET if N ot e X ists".
 17954   * Return:
 17955   *   bool: TRUE on success, FALSE otherwise.
 17956   */
 17957  static int vedis_cmd_setnx(vedis_context *pCtx,int argc,vedis_value **argv)
 17958  {
 17959  	int rc;
 17960  	if( argc <  2 ){
 17961  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 17962  		/* return false */
 17963  		vedis_result_bool(pCtx,0);
 17964  		return VEDIS_OK;
 17965  	}
 17966  	/* Fetch the key */
 17967  	rc = vedisFetchValue(pCtx,argv[0],0);
 17968  	if( rc == VEDIS_OK ){
 17969  		/* Key exists, return FALSE */
 17970  		vedis_result_bool(pCtx,0);
 17971  		return VEDIS_OK;
 17972  	}
 17973  	/* Perform the store operation */
 17974  	rc = VedisStoreValue(pCtx,argv[0],argv[1]);
 17975  	/* Store result */
 17976  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 17977  	return VEDIS_OK;
 17978  }
 17979  /*
 17980   *  Command:   MSET key value [key value]
 17981   * Description:
 17982   *   Sets the given keys to their respective values. MSET replaces existing values
 17983   *   with new values, just as regular SET. See MSETNX if you don't want to overwrite
 17984   *   existing values.
 17985   *   MSET is atomic, so all given keys are set at once. It is not possible for clients
 17986   *   to see that some of the keys were updated while others are unchanged.
 17987   * Return:
 17988   *   bool: TRUE on success, FALSE otherwise.
 17989   */
 17990  static int vedis_cmd_mset(vedis_context *pCtx,int argc,vedis_value **argv)
 17991  {
 17992  	int i,rc = VEDIS_OK;
 17993  	if( argc <  2 ){
 17994  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 17995  		/* return false */
 17996  		vedis_result_bool(pCtx,0);
 17997  		return VEDIS_OK;
 17998  	}
 17999  	for( i = 0 ; i + 1 < argc ; i += 2 ){
 18000  		/* Perform the store operation */
 18001  		rc = VedisStoreValue(pCtx,argv[i],argv[i + 1]);
 18002  		if( rc != VEDIS_OK ){
 18003  			break;
 18004  		}
 18005  	}
 18006  	/* Store result */
 18007  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 18008  	return VEDIS_OK;
 18009  }
 18010  /*
 18011   *  Command:   MSETNX key value [key value]
 18012   * Description:
 18013   *   Sets the given keys to their respective values. MSETNX replaces existing values
 18014   *   with new values only if the key does not exits, just as regular SETNX. 
 18015   *   MSET is atomic, so all given keys are set at once. It is not possible for clients
 18016   *   to see that some of the keys were updated while others are unchanged.
 18017   * Return:
 18018   *   bool: TRUE on success, FALSE otherwise.
 18019   */
 18020  static int vedis_cmd_msetnx(vedis_context *pCtx,int argc,vedis_value **argv)
 18021  {
 18022  	int i,rc = VEDIS_OK;
 18023  	if( argc <  2 ){
 18024  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 18025  		/* return false */
 18026  		vedis_result_bool(pCtx,0);
 18027  		return VEDIS_OK;
 18028  	}
 18029  	for( i = 0 ; i + 1 < argc ; i += 2 ){
 18030  		/* Fetch the key first */
 18031  		rc = vedisFetchValue(pCtx,argv[i],0);
 18032  		if( rc == VEDIS_OK ){
 18033  			/* Key exists, ignore */
 18034  			continue;
 18035  		}
 18036  		/* Perform the store operation */
 18037  		rc = VedisStoreValue(pCtx,argv[i],argv[i + 1]);
 18038  		if( rc != VEDIS_OK ){
 18039  			break;
 18040  		}
 18041  	}
 18042  	/* Store result */
 18043  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 18044  	return VEDIS_OK;
 18045  }
 18046  /*
 18047   *  Command:    GETSET key value
 18048   * Description:
 18049   *   Atomically sets key to value and returns the old value stored at key.
 18050   *   Returns an error when key exists but does not hold a string value.
 18051   * Return:
 18052   *   the old value stored at key, or nil when key does not exist.
 18053   */
 18054  static int vedis_cmd_getset(vedis_context *pCtx,int argc,vedis_value **argv)
 18055  {
 18056  	SyBlob *pWorker;
 18057  	int rc;
 18058  	if( argc <  2 ){
 18059  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 18060  		/* return null */
 18061  		vedis_result_null(pCtx);
 18062  		return VEDIS_OK;
 18063  	}
 18064  	/* Working buffer */
 18065  	pWorker = VedisContextWorkingBuffer(pCtx);
 18066  	SyBlobReset(pWorker);
 18067  	/* Fetch the key first */
 18068  	rc = vedisFetchValue(pCtx,argv[0],pWorker);
 18069  	if( rc != VEDIS_OK ){
 18070  		/* Key does not exists, return null */
 18071  		vedis_result_null(pCtx);
 18072  	}else{
 18073  		/* old value */
 18074  		vedis_result_string(pCtx,(const char *)SyBlobData(pWorker),(int)SyBlobLength(pWorker));
 18075  	}
 18076  	/* Perform the store operation */
 18077  	VedisStoreValue(pCtx,argv[0],argv[1]);	
 18078  	return VEDIS_OK;
 18079  }
 18080  /*
 18081   * Increment/Decrement a vedis record. 
 18082   */
 18083  static int vedisValueIncrementBy(vedis_context *pCtx,vedis_value *pKey,int nIncrement,int decr_op)
 18084  {
 18085  	vedis_int64 iVal = 0;
 18086  	vedis_value *pScalar;
 18087  	SyBlob *pWorker;
 18088  	int rc;
 18089  	pWorker = VedisContextWorkingBuffer(pCtx);
 18090  	SyBlobReset(pWorker);
 18091  	/* Fetch the value */
 18092  	rc = vedisFetchValue(pCtx,pKey,pWorker);
 18093  	if( rc == VEDIS_OK && SyBlobLength(pWorker) > 0 ){
 18094  		/* Cast to an integer */
 18095  		SyStrToInt64((const char *)SyBlobData(pWorker),SyBlobLength(pWorker),(void *)&iVal,0);
 18096  	}
 18097  	if( decr_op ){
 18098  		/* Decrement the number */
 18099  		iVal -= nIncrement;
 18100  	}else{
 18101  		/* Increment the number */
 18102  		iVal += nIncrement;
 18103  	}
 18104  	/* Store the result */
 18105  	vedis_result_int64(pCtx,iVal);
 18106  	/* Update the database */
 18107  	pScalar = vedis_context_new_scalar(pCtx);
 18108  	if( pScalar ==  0 ){
 18109  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 18110  		rc = VEDIS_NOMEM;
 18111  	}else{
 18112  		vedis_value_int64(pScalar,iVal);
 18113  		/* Update the database */
 18114  		rc = VedisStoreValue(pCtx,pKey,pScalar);
 18115  		/* cleanup */
 18116  		vedis_context_release_value(pCtx,pScalar);
 18117  	}
 18118  	return rc;
 18119  }
 18120  /*
 18121   *  Command:     INCR key
 18122   * Description:
 18123   *   Increments the number stored at key by one. If the key does not exist,
 18124   *   it is set to 0 before performing the operation. An error is returned if
 18125   *   the key contains a value of the wrong type or contains a string that can
 18126   *   not be represented as integer. This operation is limited to 64 bit signed integers.
 18127   * Return:
 18128   *   the value of key after the increment
 18129   */
 18130  static int vedis_cmd_incr(vedis_context *pCtx,int argc,vedis_value **argv)
 18131  {
 18132  	int rc;
 18133  	if( argc <  1 ){
 18134  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18135  		/* return 0 */
 18136  		vedis_result_int(pCtx,0);
 18137  		return VEDIS_OK;
 18138  	}
 18139  	/* Increment */
 18140  	rc = vedisValueIncrementBy(pCtx,argv[0],1,0);
 18141  	return rc;
 18142  }
 18143  /*
 18144   *  Command:     DECR key
 18145   * Description:
 18146   *   Decrement the number stored at key by one. If the key does not exist,
 18147   *   it is set to 0 before performing the operation. An error is returned if
 18148   *   the key contains a value of the wrong type or contains a string that can
 18149   *   not be represented as integer. This operation is limited to 64 bit signed integers.
 18150   * Return:
 18151   *   the value of key after the decrement
 18152   */
 18153  static int vedis_cmd_decr(vedis_context *pCtx,int argc,vedis_value **argv)
 18154  {
 18155  	int rc;
 18156  	if( argc <  1 ){
 18157  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18158  		/* return 0 */
 18159  		vedis_result_int(pCtx,0);
 18160  		return VEDIS_OK;
 18161  	}
 18162  	/* decrement */
 18163  	rc = vedisValueIncrementBy(pCtx,argv[0],1,1);
 18164  	return rc;
 18165  }
 18166  /*
 18167   *  Command:   INCRBY key increment 
 18168   * Description:
 18169   *   Increments the number stored at key by increment. If the key does not exist, it
 18170   *   is set to 0 before performing the operation. An error is returned if the key
 18171   *   contains a value of the wrong type or contains a string that can not be represented
 18172   *   as integer. This operation is limited to 64 bit signed integers.
 18173   * Return:
 18174   *   the value of key after the increment
 18175   */
 18176  static int vedis_cmd_incrby(vedis_context *pCtx,int argc,vedis_value **argv)
 18177  {
 18178  	int iIncr;
 18179  	int rc;
 18180  	if( argc <  2 ){
 18181  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/increment");
 18182  		/* return 0 */
 18183  		vedis_result_int(pCtx,0);
 18184  		return VEDIS_OK;
 18185  	}
 18186  	/* Number to increment by */
 18187  	iIncr = vedis_value_to_int(argv[1]);
 18188  	/* Increment */
 18189  	rc = vedisValueIncrementBy(pCtx,argv[0],iIncr,0);
 18190  	return rc;
 18191  }
 18192  /*
 18193   *  Command:   DECRBY key increment 
 18194   * Description:
 18195   *   Decrements the number stored at key by decrement. If the key does not exist, it
 18196   *   is set to 0 before performing the operation. An error is returned if the key
 18197   *   contains a value of the wrong type or contains a string that can not be represented
 18198   *   as integer. This operation is limited to 64 bit signed integers.
 18199   * Return:
 18200   *   the value of key after the decrement
 18201   */
 18202  static int vedis_cmd_decrby(vedis_context *pCtx,int argc,vedis_value **argv)
 18203  {
 18204  	int iDecr;
 18205  	int rc;
 18206  	if( argc <  2 ){
 18207  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/decrement");
 18208  		/* return 0 */
 18209  		vedis_result_int(pCtx,0);
 18210  		return VEDIS_OK;
 18211  	}
 18212  	/* Number to decrement by */
 18213  	iDecr = vedis_value_to_int(argv[1]);
 18214  	/* Increment */
 18215  	rc = vedisValueIncrementBy(pCtx,argv[0],iDecr,1);
 18216  	return rc;
 18217  }
 18218  /*
 18219   * Fetch a key from the given vedis Table.
 18220   */
 18221  static vedis_table_entry * vedisGetEntryFromTable(vedis_context *pCtx,vedis_value *pTable,vedis_value *pKey)
 18222  {
 18223  	vedis *pVedis = (vedis *)vedis_context_user_data(pCtx);
 18224  	vedis_table_entry *pEntry;
 18225  	vedis_table *pHash;
 18226  	/* Fetch the table first */
 18227  	pHash = vedisFetchTable(pVedis,pTable,0,VEDIS_TABLE_HASH);
 18228  	if( pHash == 0 ){
 18229  		/* No such table */
 18230  		return 0;
 18231  	}
 18232  	/* Try to fetch the field */
 18233  	pEntry = vedisTableGetRecord(pHash,pKey);
 18234  	return pEntry;
 18235  }
 18236  #define VEDIS_ENTRY_BLOB(ENTRY) (ENTRY->iType == VEDIS_TABLE_ENTRY_BLOB_NODE)
 18237  static void vedisEntryKey(vedis_table_entry *pEntry,SyString *pOut)
 18238  {
 18239  	SyStringInitFromBuf(pOut,SyBlobData(&pEntry->xKey.sKey),SyBlobLength(&pEntry->xKey.sKey));
 18240  }
 18241  /*
 18242   *  Command:    HGET key field 
 18243   * Description:
 18244   *   Returns the value associated with field in the hash stored at key.
 18245   * Return:
 18246   *   the value associated with field, or nil when field is not present in the hash
 18247   *   or key does not exist.
 18248   */
 18249  static int vedis_cmd_hget(vedis_context *pCtx,int argc,vedis_value **argv)
 18250  {
 18251  	vedis_table_entry *pEntry;
 18252  	if( argc <  2 ){
 18253  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/field pair");
 18254  		/* return null */
 18255  		vedis_result_null(pCtx);
 18256  		return VEDIS_OK;
 18257  	}
 18258  	/* Go fetch */
 18259  	pEntry = vedisGetEntryFromTable(pCtx,argv[0],argv[1]);
 18260  	if( pEntry == 0 ){
 18261  		/* return null */
 18262  		vedis_result_null(pCtx);
 18263  		return VEDIS_OK;
 18264  	}
 18265  	/* Return the payload */
 18266  	vedis_result_string(pCtx,(const char *)SyBlobData(&pEntry->sData),(int)SyBlobLength(&pEntry->sData));
 18267  	return VEDIS_OK;
 18268  }
 18269  /*
 18270   *  Command:     HMGET key field [field ...]  
 18271   * Description:
 18272   *   Returns the values associated with the specified fields in the hash stored at key.
 18273   *   For every field that does not exist in the hash, a nil value is returned.
 18274   *   Because a non-existing keys are treated as empty hashes, running HMGET against
 18275   *   a non-existing key will return a list of nil values.
 18276   * Return:
 18277   *   array of values associated with the given fields, in the same order as they are requested.
 18278   */
 18279  static int vedis_cmd_hmget(vedis_context *pCtx,int argc,vedis_value **argv)
 18280  {
 18281  	vedis_value *pScalar,*pArray;
 18282  	vedis_table_entry *pEntry;
 18283  	vedis_table *pHash;
 18284  	int i;
 18285  	if( argc <  2 ){
 18286  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/field pair");
 18287  		/* return null */
 18288  		vedis_result_null(pCtx);
 18289  		return VEDIS_OK;
 18290  	}
 18291  	/* Fetch the table  */
 18292  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_HASH);
 18293  	if( pHash == 0 ){
 18294  		/* No such table, return null */
 18295  		vedis_result_null(pCtx);
 18296  		return VEDIS_OK;
 18297  	}
 18298  	/* Allocate a new scalar and array */
 18299  	pScalar = vedis_context_new_scalar(pCtx);
 18300  	pArray = vedis_context_new_array(pCtx);
 18301  	if( pScalar == 0 || pArray == 0 ){
 18302  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 18303  		/* return null */
 18304  		vedis_result_null(pCtx);
 18305  		return VEDIS_OK;
 18306  	}
 18307  	/* Perform the requested operation */
 18308  	for( i = 1 ; i < argc ; ++i ){
 18309  		/* Fetch the record */
 18310  		pEntry = vedisTableGetRecord(pHash,argv[i]);
 18311  		if( pEntry == 0 ){
 18312  			/* Insert null */
 18313  			vedis_value_null(pScalar);
 18314  		}else{
 18315  			/* Populate the scalar with the data */
 18316  			vedis_value_reset_string_cursor(pScalar);
 18317  			vedis_value_string(pScalar,(const char *)SyBlobData(&pEntry->sData),(int)SyBlobLength(&pEntry->sData));
 18318  		}
 18319  		/* Perform the insertion */
 18320  		vedis_array_insert(pArray,pScalar); /* Will make its own copy */
 18321  	}
 18322  	/* Return our array */
 18323  	vedis_result_value(pCtx,pArray);
 18324  	vedis_context_release_value(pCtx,pScalar);
 18325  	/* pArray will be automatically destroyed */
 18326  	return VEDIS_OK;
 18327  }
 18328  /*
 18329   *  Command:      HKEYS key  
 18330   * Description:
 18331   *   Returns all field names in the hash stored at key.
 18332   * Return:
 18333   *   array of fields in the hash, or null on failure.
 18334   */
 18335  static int vedis_cmd_hkeys(vedis_context *pCtx,int argc,vedis_value **argv)
 18336  {
 18337  	vedis_value *pScalar,*pArray;
 18338  	vedis_table_entry *pEntry;
 18339  	vedis_table *pHash;
 18340  	
 18341  	if( argc <  1 ){
 18342  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18343  		/* return null */
 18344  		vedis_result_null(pCtx);
 18345  		return VEDIS_OK;
 18346  	}
 18347  	/* Fetch the table  */
 18348  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_HASH);
 18349  	if( pHash == 0 ){
 18350  		/* No such table, return null */
 18351  		vedis_result_null(pCtx);
 18352  		return VEDIS_OK;
 18353  	}
 18354  	/* Allocate a new scalar and array */
 18355  	pScalar = vedis_context_new_scalar(pCtx);
 18356  	pArray = vedis_context_new_array(pCtx);
 18357  	if( pScalar == 0 || pArray == 0 ){
 18358  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 18359  		/* return null */
 18360  		vedis_result_null(pCtx);
 18361  		return VEDIS_OK;
 18362  	}
 18363  	/* Perform the requested operation */
 18364  	vedisTableReset(pHash);
 18365  	while( (pEntry = vedisTableNextEntry(pHash)) != 0 ){
 18366  		if( VEDIS_ENTRY_BLOB(pEntry) ){
 18367  			SyString sKey;
 18368  			vedisEntryKey(pEntry,&sKey);
 18369  			/* Populate the scalar with the data */
 18370  			vedis_value_reset_string_cursor(pScalar);
 18371  			vedis_value_string(pScalar,sKey.zString,(int)sKey.nByte);
 18372  			/* Perform the insertion */
 18373  			vedis_array_insert(pArray,pScalar); /* Will make its own copy */
 18374  		}
 18375  	}
 18376  	/* Return our array */
 18377  	vedis_result_value(pCtx,pArray);
 18378  	vedis_context_release_value(pCtx,pScalar);
 18379  	/* pArray will be automatically destroyed */
 18380  	return VEDIS_OK;
 18381  }
 18382  /*
 18383   *  Command:       HVALS key  
 18384   * Description:
 18385   *   Returns all values in the hash stored at key.
 18386   * Return:
 18387   *   array of values in the hash, or an empty list when key does not exist.
 18388   */
 18389  static int vedis_cmd_hvals(vedis_context *pCtx,int argc,vedis_value **argv)
 18390  {
 18391  	vedis_value *pScalar,*pArray;
 18392  	vedis_table_entry *pEntry;
 18393  	vedis_table *pHash;
 18394  	
 18395  	if( argc <  1 ){
 18396  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18397  		/* return null */
 18398  		vedis_result_null(pCtx);
 18399  		return VEDIS_OK;
 18400  	}
 18401  	/* Fetch the table  */
 18402  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_HASH);
 18403  	if( pHash == 0 ){
 18404  		/* No such table, return null */
 18405  		vedis_result_null(pCtx);
 18406  		return VEDIS_OK;
 18407  	}
 18408  	/* Allocate a new scalar and array */
 18409  	pScalar = vedis_context_new_scalar(pCtx);
 18410  	pArray = vedis_context_new_array(pCtx);
 18411  	if( pScalar == 0 || pArray == 0 ){
 18412  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 18413  		/* return null */
 18414  		vedis_result_null(pCtx);
 18415  		return VEDIS_OK;
 18416  	}
 18417  	/* Perform the requested operation */
 18418  	vedisTableReset(pHash);
 18419  	while( (pEntry = vedisTableNextEntry(pHash)) != 0 ){
 18420  		/* Populate the scalar with the data */
 18421  		vedis_value_reset_string_cursor(pScalar);
 18422  		vedis_value_string(pScalar,(const char *)SyBlobData(&pEntry->sData),(int)SyBlobLength(&pEntry->sData));		
 18423  		/* Perform the insertion */
 18424  		vedis_array_insert(pArray,pScalar); /* Will make its own copy */
 18425  	}
 18426  	/* Return our array */
 18427  	vedis_result_value(pCtx,pArray);
 18428  	vedis_context_release_value(pCtx,pScalar);
 18429  	/* pArray will be automatically destroyed */
 18430  	return VEDIS_OK;
 18431  }
 18432  /*
 18433   *  Command:      HGETALL key 
 18434   * Description:
 18435   *   Returns all fields and values of the hash stored at key. In the returned value,
 18436   *   every field name is followed by its value, so the length of the reply is twice
 18437   *   the size of the hash.
 18438   * Return:
 18439   *   array of fields and their values stored in the hash, or an empty list when key does not exist.
 18440   */
 18441  static int vedis_cmd_hgetall(vedis_context *pCtx,int argc,vedis_value **argv)
 18442  {
 18443  	vedis_value *pScalar,*pArray;
 18444  	vedis_table_entry *pEntry;
 18445  	vedis_table *pHash;
 18446  	if( argc <  1 ){
 18447  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18448  		/* return null */
 18449  		vedis_result_null(pCtx);
 18450  		return VEDIS_OK;
 18451  	}
 18452  	/* Fetch the table  */
 18453  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_HASH);
 18454  	if( pHash == 0 ){
 18455  		/* No such table, return null */
 18456  		vedis_result_null(pCtx);
 18457  		return VEDIS_OK;
 18458  	}
 18459  	/* Allocate a new scalar and array */
 18460  	pScalar = vedis_context_new_scalar(pCtx);
 18461  	pArray = vedis_context_new_array(pCtx);
 18462  	if( pScalar == 0 || pArray == 0 ){
 18463  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 18464  		/* return null */
 18465  		vedis_result_null(pCtx);
 18466  		return VEDIS_OK;
 18467  	}
 18468  	/* Perform the requested operation */
 18469  	vedisTableReset(pHash);
 18470  	while( (pEntry = vedisTableNextEntry(pHash)) != 0 ){
 18471  		if( VEDIS_ENTRY_BLOB(pEntry) ){
 18472  			SyString sKey;
 18473  			vedisEntryKey(pEntry,&sKey);
 18474  			/* Populate the scalar with the key */
 18475  			vedis_value_reset_string_cursor(pScalar);
 18476  			vedis_value_string(pScalar,sKey.zString,(int)sKey.nByte);
 18477  			/* Insert the key */
 18478  			vedis_array_insert(pArray,pScalar); /* Will make its own copy of pScalar */
 18479  			/* Populate the scalar with the data */
 18480  			vedis_value_reset_string_cursor(pScalar);
 18481  			vedis_value_string(pScalar,(const char *)SyBlobData(&pEntry->sData),(int)SyBlobLength(&pEntry->sData));
 18482  			/* Perform the insertion */
 18483  			vedis_array_insert(pArray,pScalar); /* Will make its own copy */
 18484  		}
 18485  	}
 18486  	/* Return our array */
 18487  	vedis_result_value(pCtx,pArray);
 18488  	vedis_context_release_value(pCtx,pScalar);
 18489  	/* pArray will be automatically destroyed */
 18490  	return VEDIS_OK;
 18491  }
 18492  /*
 18493   *  Command:    HEXISTS key field 
 18494   * Description:
 18495   *   Returns if field is an existing field in the hash stored at key.
 18496   * Return:
 18497   *   boolean: TRUE on success, FALSE otherwise.
 18498   */
 18499  static int vedis_cmd_hexists(vedis_context *pCtx,int argc,vedis_value **argv)
 18500  {
 18501  	vedis_table_entry *pEntry;
 18502  	if( argc <  2 ){
 18503  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/field pair");
 18504  		/* return false */
 18505  		vedis_result_bool(pCtx,0);
 18506  		return VEDIS_OK;
 18507  	}
 18508  	/* Go fetch */
 18509  	pEntry = vedisGetEntryFromTable(pCtx,argv[0],argv[1]);
 18510  	if( pEntry == 0 ){
 18511  		/* return false */
 18512  		vedis_result_bool(pCtx,0);
 18513  		return VEDIS_OK;
 18514  	}
 18515  	/* Return true */
 18516  	vedis_result_bool(pCtx,1);
 18517  	return VEDIS_OK;
 18518  }
 18519  /*
 18520   *  Command:     HDEL key field [field ...] 
 18521   * Description:
 18522   *   Removes the specified fields from the hash stored at key. Specified fields
 18523   *   that do not exist within this hash are ignored. If key does not exist, it is treated
 18524   *   as an empty hash and this command returns 0.
 18525   * Return:
 18526   *   integer: Total number of fields removed.
 18527   */
 18528  static int vedis_cmd_hdel(vedis_context *pCtx,int argc,vedis_value **argv)
 18529  {
 18530  	vedis_table *pHash;
 18531  	int nDel = 0;
 18532  	int i,rc;
 18533  	if( argc <  2 ){
 18534  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/field pair");
 18535  		/* return 0 */
 18536  		vedis_result_int(pCtx,0);
 18537  		return VEDIS_OK;
 18538  	}
 18539  	/* Fetch the table  */
 18540  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_HASH);
 18541  	if( pHash == 0 ){
 18542  		/* No such table, return zero */
 18543  		vedis_result_int(pCtx,0);
 18544  		return VEDIS_OK;
 18545  	}
 18546  	/* Perform the deletion */
 18547  	for( i = 1 ; i < argc ; ++i ){
 18548  		rc = vedisTableDeleteRecord(pHash,argv[i]);
 18549  		if( rc == VEDIS_OK ){
 18550  			nDel++;
 18551  		}
 18552  	}
 18553  	/* Total number of deleted records */
 18554  	vedis_result_int(pCtx,nDel);
 18555  	return VEDIS_OK;
 18556  }
 18557  /*
 18558   *  Command:     HLEN key 
 18559   * Description:
 18560   *   Returns the number of fields contained in the hash stored at key.
 18561   * Return:
 18562   *    number of fields in the hash, or 0 when key does not exist.
 18563   */
 18564  static int vedis_cmd_hlen(vedis_context *pCtx,int argc,vedis_value **argv)
 18565  {
 18566  	vedis_table *pHash;
 18567  	if( argc <  1 ){
 18568  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18569  		/* return 0 */
 18570  		vedis_result_int(pCtx,0);
 18571  		return VEDIS_OK;
 18572  	}
 18573  	/* Fetch the table  */
 18574  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_HASH);
 18575  	if( pHash == 0 ){
 18576  		/* No such table, return zero */
 18577  		vedis_result_int(pCtx,0);
 18578  		return VEDIS_OK;
 18579  	}
 18580  	vedis_result_int(pCtx,(int)vedisTableLength(pHash));
 18581  	return VEDIS_OK;
 18582  }
 18583  /*
 18584   *  Command:     HSET key field value  
 18585   * Description:
 18586   *   Sets field in the hash stored at key to value. If key does not exist, a new key holding
 18587   *   a hash is created. If field already exists in the hash, it is overwritten.
 18588   * Return:
 18589   *   boolean: TRUE on success. FALSE on failure.
 18590   */
 18591  static int vedis_cmd_hset(vedis_context *pCtx,int argc,vedis_value **argv)
 18592  {
 18593  	vedis *pVedis = (vedis *)vedis_context_user_data(pCtx);
 18594  	vedis_table *pHash;
 18595  	int rc;
 18596  
 18597  	if( argc < 3 ){
 18598  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key field/value pair");
 18599  		/* return false */
 18600  		vedis_result_bool(pCtx,0);
 18601  		return VEDIS_OK;
 18602  	}
 18603  	/* Fetch the table first */
 18604  	pHash = vedisFetchTable(pVedis,argv[0],1,VEDIS_TABLE_HASH);
 18605  	if( pHash == 0 ){
 18606  		/* No such table, return FALSE */
 18607  		vedis_result_bool(pCtx,0);
 18608  		return VEDIS_OK;
 18609  	}
 18610  	/* Perform the insertion  */
 18611  	rc = vedisTableInsertRecord(pHash,argv[1],argv[2]);
 18612  	/* Insertion result */
 18613  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 18614  	return VEDIS_OK;
 18615  }
 18616  /*
 18617   *  Command:      HMSET key field value [field value ...]  
 18618   * Description:
 18619   *   Sets the specified fields to their respective values in the hash stored at key.
 18620   *   This command overwrites any existing fields in the hash. If key does not exist,
 18621   *   a new key holding a hash is created.
 18622   * Return:
 18623   *   Integer: Total number of inserted fields.
 18624   */
 18625  static int vedis_cmd_hmset(vedis_context *pCtx,int argc,vedis_value **argv)
 18626  {
 18627  	vedis_table *pHash;
 18628  	int i,rc,cnt = 0;
 18629  	if( argc < 3 ){
 18630  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key field/value pair");
 18631  		/* return false */
 18632  		vedis_result_bool(pCtx,0);
 18633  		return VEDIS_OK;
 18634  	}
 18635  	pHash = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],1,VEDIS_TABLE_HASH);
 18636  	if( pHash == 0 ){
 18637  		/* return false */
 18638  		vedis_result_bool(pCtx,0);
 18639  		return VEDIS_OK;
 18640  	}
 18641  	rc = VEDIS_OK;
 18642  	for( i = 1 ; i + 1 < argc ; i += 2 ){
 18643  		rc = vedisTableInsertRecord(pHash,argv[i],argv[i+1]);
 18644  		if( rc == VEDIS_OK ){
 18645  			cnt++;
 18646  		}
 18647  	}
 18648  	/* Insertion result */
 18649  	vedis_result_int(pCtx,cnt);
 18650  	return VEDIS_OK;
 18651  }
 18652  /*
 18653   *  Command:      HSETNX key field value   
 18654   * Description:
 18655   *   Sets field in the hash stored at key to value, only if field does not yet exist.
 18656   *   If key does not exist, a new key holding a hash is created. If field already exists,
 18657   *   this operation has no effect.
 18658   * Return:
 18659   *   boolean: TRUE on success. FALSE on failure.
 18660   */
 18661  static int vedis_cmd_hsetnx(vedis_context *pCtx,int argc,vedis_value **argv)
 18662  {
 18663  	vedis *pVedis = (vedis *)vedis_context_user_data(pCtx);
 18664  	vedis_table_entry *pEntry;
 18665  	vedis_table *pHash;
 18666  	int rc;
 18667  	
 18668  	if( argc < 3 ){
 18669  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key field/value pair");
 18670  		/* return false */
 18671  		vedis_result_bool(pCtx,0);
 18672  		return VEDIS_OK;
 18673  	}
 18674  	/* Fetch the table first */
 18675  	pHash = vedisFetchTable(pVedis,argv[0],1,VEDIS_TABLE_HASH);
 18676  	if( pHash == 0 ){
 18677  		/* No such table, return FALSE */
 18678  		vedis_result_bool(pCtx,0);
 18679  		return VEDIS_OK;
 18680  	}
 18681  	/* Fetch the record */
 18682  	pEntry = vedisTableGetRecord(pHash,argv[1]);
 18683  	if( pEntry ){
 18684  		/* Record exists, return FALSE */
 18685  		vedis_result_bool(pCtx,0);
 18686  		return VEDIS_OK;
 18687  	}
 18688  	/* Safely, erform the insertion  */
 18689  	rc = vedisTableInsertRecord(pHash,argv[1],argv[2]);
 18690  	/* Insertion result */
 18691  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 18692  	return VEDIS_OK;
 18693  }
 18694  /*
 18695   *  Command:     TABLE_LIST  
 18696   * Description:
 18697   *   Return a array holding the list of loaded vedis tables (i.e. Hashes, Sets, List) in memory.
 18698   * Return:
 18699   *   array of loaded tables.
 18700   */
 18701  static int vedis_cmd_table_list(vedis_context *pCtx,int argc,vedis_value **argv)
 18702  {
 18703  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 18704  	vedis_value *pScalar,*pArray;
 18705  	vedis_table *pEntry;
 18706  	sxu32 n;
 18707  	/* Allocate a new scalar and array */
 18708  	pScalar = vedis_context_new_scalar(pCtx);
 18709  	pArray = vedis_context_new_array(pCtx);
 18710  	if( pScalar == 0 || pArray == 0 ){
 18711  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 18712  		/* return null */
 18713  		vedis_result_null(pCtx);
 18714  		SXUNUSED(argc); /* cc warning */
 18715  		SXUNUSED(argv);
 18716  		return VEDIS_OK;
 18717  	}
 18718  	/* Point to the first entry */
 18719  	pEntry = pStore->pTableList;
 18720  	for( n = 0 ; n < pStore->nTable ; ++n ){
 18721  		SyString *pName = vedisTableName(pEntry);
 18722  		/* Populate the scalar with the data */
 18723  		vedis_value_reset_string_cursor(pScalar);
 18724  		vedis_value_string(pScalar,pName->zString,(int)pName->nByte);
 18725  		/* Perform the insertion */
 18726  		vedis_array_insert(pArray,pScalar); /* Will make its own copy */
 18727  		/* Point to the next loaded table */
 18728  		pEntry = vedisTableChain(pEntry);
 18729  	}
 18730  	/* Return our array */
 18731  	vedis_result_value(pCtx,pArray);
 18732  	vedis_context_release_value(pCtx,pScalar);
 18733  	/* pArray will be automatically destroyed */
 18734  	return VEDIS_OK;
 18735  }
 18736  /*
 18737   *  Command:    SADD key member [member ...]  
 18738   * Description:
 18739   *   Add the specified members to the set stored at key. Specified members that
 18740   *   are already a member of this set are ignored. If key does not exist, a new
 18741   *   set is created before adding the specified members. An error is returned when
 18742   *   the value stored at key is not a set.
 18743   * Return:
 18744   *   Intger: number of item succesfully stored.
 18745   */
 18746  static int vedis_cmd_sadd(vedis_context *pCtx,int argc,vedis_value **argv)
 18747  {
 18748  	vedis *pVedis = (vedis *)vedis_context_user_data(pCtx);
 18749  	vedis_table *pSet;
 18750  	int nStore = 0;
 18751  	int i,rc;
 18752  	
 18753  	if( argc < 2 ){
 18754  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/member pair");
 18755  		/* return zero */
 18756  		vedis_result_int(pCtx,0);
 18757  		return VEDIS_OK;
 18758  	}
 18759  	/* Fetch the table first */
 18760  	pSet = vedisFetchTable(pVedis,argv[0],1,VEDIS_TABLE_SET);
 18761  	if( pSet == 0 ){
 18762  		/* No such table, return zero */
 18763  		vedis_result_int(pCtx,0);
 18764  		return VEDIS_OK;
 18765  	}
 18766  	/* Perform the insertion  */
 18767  	for( i = 1 ; i < argc ; ++i ){
 18768  		rc = vedisTableInsertRecord(pSet,argv[i],0/* No data */);
 18769  		if( rc == VEDIS_OK ){
 18770  			nStore++;
 18771  		}
 18772  	}
 18773  	/* Total number of items stored  */
 18774  	vedis_result_int(pCtx,nStore);
 18775  	return VEDIS_OK;
 18776  }
 18777  /*
 18778   *  Command:    SCARD key 
 18779   * Description:
 18780   *   Returns the set cardinality (number of elements) of the set stored at key.
 18781   * Return:
 18782   *    number of fields in the set, or 0 when key does not exist.
 18783   */
 18784  static int vedis_cmd_scard(vedis_context *pCtx,int argc,vedis_value **argv)
 18785  {
 18786  	vedis_table *pSet;
 18787  	if( argc <  1 ){
 18788  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18789  		/* return 0 */
 18790  		vedis_result_int(pCtx,0);
 18791  		return VEDIS_OK;
 18792  	}
 18793  	/* Fetch the table  */
 18794  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 18795  	if( pSet == 0 ){
 18796  		/* No such table, return zero */
 18797  		vedis_result_int(pCtx,0);
 18798  		return VEDIS_OK;
 18799  	}
 18800  	vedis_result_int(pCtx,(int)vedisTableLength(pSet));
 18801  	return VEDIS_OK;
 18802  }
 18803  /*
 18804   *  Command:    SISMEMBER key member 
 18805   * Description:
 18806   *   Returns if member is a member of the set stored at key.
 18807   * Return:
 18808   *   boolean: TRUE on success, FALSE otherwise.
 18809   */
 18810  static int vedis_cmd_sismember(vedis_context *pCtx,int argc,vedis_value **argv)
 18811  {
 18812  	vedis_table_entry *pEntry;
 18813  	vedis_table *pSet;
 18814  	if( argc <  2 ){
 18815  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/member pair");
 18816  		/* return false */
 18817  		vedis_result_bool(pCtx,0);
 18818  		return VEDIS_OK;
 18819  	}
 18820  	/* Fetch the table first */
 18821  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 18822  	if( pSet == 0 ){
 18823  		/* No such table */
 18824  		vedis_result_null(pCtx);
 18825  		return VEDIS_OK;
 18826  	}
 18827  	/* Go fetch */
 18828  	pEntry = vedisTableGetRecord(pSet,argv[1]);
 18829  	if( pEntry == 0 ){
 18830  		/* return false */
 18831  		vedis_result_bool(pCtx,0);
 18832  		return VEDIS_OK;
 18833  	}
 18834  	/* Return true */
 18835  	vedis_result_bool(pCtx,1);
 18836  	return VEDIS_OK;
 18837  }
 18838  /*
 18839   *  Command:   SPOP key 
 18840   * Description:
 18841   *   Removes and returns the last record from the set value stored at key.
 18842   * Return:
 18843   *   the removed element, or nil when key does not exist or is empty.
 18844   */
 18845  static int vedis_cmd_spop(vedis_context *pCtx,int argc,vedis_value **argv)
 18846  {
 18847  	vedis_table_entry *pEntry;
 18848  	vedis_table *pSet;
 18849  	if( argc < 1 ){
 18850  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18851  		/* return null */
 18852  		vedis_result_null(pCtx);
 18853  		return VEDIS_OK;
 18854  	}
 18855  	/* Fetch the table first */
 18856  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 18857  	if( pSet == 0 ){
 18858  		/* No such table */
 18859  		vedis_result_null(pCtx);
 18860  		return VEDIS_OK;
 18861  	}
 18862  	/* Extract the last entry */
 18863  	pEntry = vedisTableLastEntry(pSet);
 18864  	if( pEntry == 0 ){
 18865  		/* Empty table, return null */
 18866  		vedis_result_null(pCtx);
 18867  		return VEDIS_OK;
 18868  	}
 18869  	if ( VEDIS_ENTRY_BLOB(pEntry) ){
 18870  		SyString sKey;
 18871  		vedisEntryKey(pEntry,&sKey);
 18872  		/* Return its key */
 18873  		vedis_result_string(pCtx,sKey.zString,(int)sKey.nByte);
 18874  	}
 18875  	/* Discard this element */
 18876  	VedisRemoveTableEntry(pSet,pEntry);
 18877  	return VEDIS_OK;
 18878  }
 18879  /*
 18880   *  Command:   SPEEK key 
 18881   * Description:
 18882   *   Returns the last record from the set value stored at key.
 18883   * Return:
 18884   *   the last element, or nil when key does not exist.
 18885   */
 18886  static int vedis_cmd_speek(vedis_context *pCtx,int argc,vedis_value **argv)
 18887  {
 18888  	vedis_table_entry *pEntry;
 18889  	vedis_table *pSet;
 18890  	if( argc < 1 ){
 18891  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18892  		/* return null */
 18893  		vedis_result_null(pCtx);
 18894  		return VEDIS_OK;
 18895  	}
 18896  	/* Fetch the table first */
 18897  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 18898  	if( pSet == 0 ){
 18899  		/* No such table */
 18900  		vedis_result_null(pCtx);
 18901  		return VEDIS_OK;
 18902  	}
 18903  	/* Extract the last entry */
 18904  	pEntry = vedisTableLastEntry(pSet);
 18905  	if( pEntry == 0 ){
 18906  		/* Empty table, return null */
 18907  		vedis_result_null(pCtx);
 18908  		return VEDIS_OK;
 18909  	}
 18910  	if ( VEDIS_ENTRY_BLOB(pEntry) ){
 18911  		SyString sKey;
 18912  		vedisEntryKey(pEntry,&sKey);
 18913  		/* Return its key */
 18914  		vedis_result_string(pCtx,sKey.zString,(int)sKey.nByte);
 18915  	}
 18916  	return VEDIS_OK;
 18917  }
 18918  /*
 18919   *  Command:   STOP key 
 18920   * Description:
 18921   *   Returns the first record from the set value stored at key.
 18922   * Return:
 18923   *   the last element, or nil when key does not exist.
 18924   */
 18925  static int vedis_cmd_stop(vedis_context *pCtx,int argc,vedis_value **argv)
 18926  {
 18927  	vedis_table_entry *pEntry;
 18928  	vedis_table *pSet;
 18929  	if( argc < 1 ){
 18930  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 18931  		/* return null */
 18932  		vedis_result_null(pCtx);
 18933  		return VEDIS_OK;
 18934  	}
 18935  	/* Fetch the table first */
 18936  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 18937  	if( pSet == 0 ){
 18938  		/* No such table */
 18939  		vedis_result_null(pCtx);
 18940  		return VEDIS_OK;
 18941  	}
 18942  	/* Extract the first entry */
 18943  	pEntry = vedisTableFirstEntry(pSet);
 18944  	if( pEntry == 0 ){
 18945  		/* Empty table, return null */
 18946  		vedis_result_null(pCtx);
 18947  		return VEDIS_OK;
 18948  	}
 18949  	if ( VEDIS_ENTRY_BLOB(pEntry) ){
 18950  		SyString sKey;
 18951  		vedisEntryKey(pEntry,&sKey);
 18952  		/* Return its key */
 18953  		vedis_result_string(pCtx,sKey.zString,(int)sKey.nByte);
 18954  	}
 18955  	return VEDIS_OK;
 18956  }
 18957  /*
 18958   *  Command:     SREM key member [member ...]  
 18959   * Description:
 18960   *   Remove the specified members from the set stored at key.
 18961   *   Specified members that are not a member of this set are ignored.
 18962   *   If key does not exist, it is treated as an empty set and this command returns 0.
 18963   * Return:
 18964   *   Integer: the number of members that were removed from the set, not including non existing members.
 18965   */
 18966  static int vedis_cmd_srem(vedis_context *pCtx,int argc,vedis_value **argv)
 18967  {
 18968  	vedis_table *pSet;
 18969  	int nDel = 0;
 18970  	int i,rc;
 18971  	if( argc <  2 ){
 18972  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/member pair");
 18973  		/* return 0 */
 18974  		vedis_result_int(pCtx,0);
 18975  		return VEDIS_OK;
 18976  	}
 18977  	/* Fetch the table  */
 18978  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 18979  	if( pSet == 0 ){
 18980  		/* No such table, return zero */
 18981  		vedis_result_int(pCtx,0);
 18982  		return VEDIS_OK;
 18983  	}
 18984  	/* Perform the deletion */
 18985  	for( i = 1 ; i < argc ; ++i ){
 18986  		rc = vedisTableDeleteRecord(pSet,argv[i]);
 18987  		if( rc == VEDIS_OK ){
 18988  			nDel++;
 18989  		}
 18990  	}
 18991  	/* Total number of deleted records */
 18992  	vedis_result_int(pCtx,nDel);
 18993  	return VEDIS_OK;
 18994  }
 18995  /*
 18996   *  Command:    SMEMBERS key  
 18997   * Description:
 18998   *   Returns all the members of the set value stored at key.
 18999   * Return:
 19000   *   array of all elements of the set.
 19001   */
 19002  static int vedis_cmd_smembers(vedis_context *pCtx,int argc,vedis_value **argv)
 19003  {
 19004  	vedis_value *pScalar,*pArray;
 19005  	vedis_table_entry *pEntry;
 19006  	vedis_table *pSet;
 19007  	
 19008  	if( argc <  1 ){
 19009  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 19010  		/* return null */
 19011  		vedis_result_null(pCtx);
 19012  		return VEDIS_OK;
 19013  	}
 19014  	/* Fetch the table  */
 19015  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 19016  	if( pSet == 0 ){
 19017  		/* No such table, return null */
 19018  		vedis_result_null(pCtx);
 19019  		return VEDIS_OK;
 19020  	}
 19021  	/* Allocate a new scalar and array */
 19022  	pScalar = vedis_context_new_scalar(pCtx);
 19023  	pArray = vedis_context_new_array(pCtx);
 19024  	if( pScalar == 0 || pArray == 0 ){
 19025  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 19026  		/* return null */
 19027  		vedis_result_null(pCtx);
 19028  		return VEDIS_OK;
 19029  	}
 19030  	/* Perform the requested operation */
 19031  	vedisTableReset(pSet);
 19032  	while( (pEntry = vedisTableNextEntry(pSet)) != 0 ){
 19033  		if( VEDIS_ENTRY_BLOB(pEntry) ){
 19034  			SyString sKey;
 19035  			vedisEntryKey(pEntry,&sKey);
 19036  			/* Populate the scalar with the key */
 19037  			vedis_value_reset_string_cursor(pScalar);
 19038  			vedis_value_string(pScalar,sKey.zString,(int)sKey.nByte);
 19039  			/* Insert the key */
 19040  			vedis_array_insert(pArray,pScalar); /* Will make its own copy of pScalar */
 19041  		}
 19042  	}
 19043  	/* Return our array */
 19044  	vedis_result_value(pCtx,pArray);
 19045  	vedis_context_release_value(pCtx,pScalar);
 19046  	/* pArray will be automatically destroyed */
 19047  	return VEDIS_OK;
 19048  }
 19049  /*
 19050   *  Command:    SDIFF key [key ...] 
 19051   * Description:
 19052   *   Returns the members of the set resulting from the difference between the first set
 19053   *   and all the successive sets.
 19054   * Return:
 19055   *   array of Keys that do not exist are considered to be empty sets.
 19056   */
 19057  static int vedis_cmd_sdiff(vedis_context *pCtx,int argc,vedis_value **argv)
 19058  {
 19059  	vedis_value *pScalar,*pArray;
 19060  	vedis_table_entry *pEntry;
 19061  	vedis_table *pSrc;
 19062  	int i;
 19063  	if( argc <  1 ){
 19064  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 19065  		/* return null */
 19066  		vedis_result_null(pCtx);
 19067  		return VEDIS_OK;
 19068  	}
 19069  	/* Fetch the table  */
 19070  	pSrc = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 19071  	if( pSrc == 0 ){
 19072  		/* No such table, return null */
 19073  		vedis_result_null(pCtx);
 19074  		return VEDIS_OK;
 19075  	}
 19076  	/* Allocate a new scalar and array */
 19077  	pScalar = vedis_context_new_scalar(pCtx);
 19078  	pArray = vedis_context_new_array(pCtx);
 19079  	if( pScalar == 0 || pArray == 0 ){
 19080  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 19081  		/* return null */
 19082  		vedis_result_null(pCtx);
 19083  		return VEDIS_OK;
 19084  	}
 19085  	/* Perform the requested operation */
 19086  	vedisTableReset(pSrc);
 19087  	while( (pEntry = vedisTableNextEntry(pSrc)) != 0 ){
 19088  		if( VEDIS_ENTRY_BLOB(pEntry) ){
 19089  			SyString sKey;
 19090  			vedisEntryKey(pEntry,&sKey);
 19091  			/* Populate the scalar with the key */
 19092  			vedis_value_reset_string_cursor(pScalar);
 19093  			vedis_value_string(pScalar,sKey.zString,(int)sKey.nByte);
 19094  			/* Perform the diff */
 19095  			for( i = 1 ; i < argc ; ++i ){
 19096  				vedis_table *pTarget = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[i],0,VEDIS_TABLE_SET);
 19097  				vedis_table_entry *pEntry;
 19098  				if( pTarget == 0 ){
 19099  					/* No such set */
 19100  					continue;
 19101  				}
 19102  				/* Perform the lokup */
 19103  				pEntry = vedisTableGetRecord(pTarget,pScalar);
 19104  				if( pEntry ){
 19105  					/* Entry found */
 19106  					break;
 19107  				}
 19108  			}
 19109  			if( i >= argc ){
 19110  				/* Perform the insertion */
 19111  				vedis_array_insert(pArray,pScalar);
 19112  			}
 19113  
 19114  		}
 19115  	}
 19116  	/* Return our array */
 19117  	vedis_result_value(pCtx,pArray);
 19118  	vedis_context_release_value(pCtx,pScalar);
 19119  	/* pArray will be automatically destroyed */
 19120  	return VEDIS_OK;
 19121  }
 19122  /*
 19123   *  Command:    SINTER key [key ...] 
 19124   * Description:
 19125   *   Returns the members of the set resulting from the intersection of all the given sets.
 19126   * Return:
 19127   *   array of Keys that do not exist are considered to be empty sets.
 19128   */
 19129  static int vedis_cmd_sinter(vedis_context *pCtx,int argc,vedis_value **argv)
 19130  {
 19131  	vedis_value *pScalar,*pArray;
 19132  	vedis_table_entry *pEntry;
 19133  	vedis_table *pSrc;
 19134  	int i;
 19135  	if( argc <  1 ){
 19136  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 19137  		/* return null */
 19138  		vedis_result_null(pCtx);
 19139  		return VEDIS_OK;
 19140  	}
 19141  	/* Fetch the table  */
 19142  	pSrc = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 19143  	if( pSrc == 0 ){
 19144  		/* No such table, return null */
 19145  		vedis_result_null(pCtx);
 19146  		return VEDIS_OK;
 19147  	}
 19148  	/* Allocate a new scalar and array */
 19149  	pScalar = vedis_context_new_scalar(pCtx);
 19150  	pArray = vedis_context_new_array(pCtx);
 19151  	if( pScalar == 0 || pArray == 0 ){
 19152  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 19153  		/* return null */
 19154  		vedis_result_null(pCtx);
 19155  		return VEDIS_OK;
 19156  	}
 19157  	/* Perform the requested operation */
 19158  	vedisTableReset(pSrc);
 19159  	while( (pEntry = vedisTableNextEntry(pSrc)) != 0 ){
 19160  		if( VEDIS_ENTRY_BLOB(pEntry) ){
 19161  			SyString sKey;
 19162  			vedisEntryKey(pEntry,&sKey);
 19163  			/* Populate the scalar with the key */
 19164  			vedis_value_reset_string_cursor(pScalar);
 19165  			vedis_value_string(pScalar,sKey.zString,(int)sKey.nByte);
 19166  			/* Perform the intersection */
 19167  			for( i = 1 ; i < argc ; ++i ){
 19168  				vedis_table *pTarget = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[i],0,VEDIS_TABLE_SET);
 19169  				vedis_table_entry *pEntry;
 19170  				if( pTarget == 0 ){
 19171  					/* No such set */
 19172  					continue;
 19173  				}
 19174  				/* Perform the lokup */
 19175  				pEntry = vedisTableGetRecord(pTarget,pScalar);
 19176  				if( !pEntry ){
 19177  					/* no such entry */
 19178  					break;
 19179  				}
 19180  			}
 19181  			if( i >= argc ){
 19182  				/* Perform the insertion */
 19183  				vedis_array_insert(pArray,pScalar);
 19184  			}
 19185  
 19186  		}
 19187  	}
 19188  	/* Return our array */
 19189  	vedis_result_value(pCtx,pArray);
 19190  	vedis_context_release_value(pCtx,pScalar);
 19191  	/* pArray will be automatically destroyed */
 19192  	return VEDIS_OK;
 19193  }
 19194  /*
 19195   *  Command:     SLEN key 
 19196   * Description:
 19197   *   Returns the number of fields contained in the set stored at key.
 19198   * Return:
 19199   *    number of fields in the set, or 0 when key does not exist.
 19200   */
 19201  static int vedis_cmd_slen(vedis_context *pCtx,int argc,vedis_value **argv)
 19202  {
 19203  	vedis_table *pSet;
 19204  	if( argc <  1 ){
 19205  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 19206  		/* return 0 */
 19207  		vedis_result_int(pCtx,0);
 19208  		return VEDIS_OK;
 19209  	}
 19210  	/* Fetch the table  */
 19211  	pSet = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_SET);
 19212  	if( pSet == 0 ){
 19213  		/* No such table, return zero */
 19214  		vedis_result_int(pCtx,0);
 19215  		return VEDIS_OK;
 19216  	}
 19217  	vedis_result_int(pCtx,(int)vedisTableLength(pSet));
 19218  	return VEDIS_OK;
 19219  }
 19220  /*
 19221   *  Command:   LINDEX key index  
 19222   * Description:
 19223   *   Returns the element at index index in the list stored at key.
 19224   *   The index is zero-based, so 0 means the first element, 1 the second
 19225   *   element and so on. Negative indices can be used to designate elements
 19226   *   starting at the tail of the list. Here, -1 means the last element, -2 means
 19227   *   the penultimate and so forth.
 19228   *   When the value at key is not a list, an error is returned.
 19229   * Return:
 19230   *   the requested element, or nil when index is out of range.
 19231   */
 19232  static int vedis_cmd_lindex(vedis_context *pCtx,int argc,vedis_value **argv)
 19233  {
 19234  	vedis_table_entry *pEntry;
 19235  	vedis_table *pList;
 19236  	sxu32 nReal;
 19237  	int iIndex;
 19238  	
 19239  	if( argc <  2 ){
 19240  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/index pair");
 19241  		/* return null */
 19242  		vedis_result_null(pCtx);
 19243  		return VEDIS_OK;
 19244  	}
 19245  	/* Fetch the table  */
 19246  	pList = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_LIST);
 19247  	if( pList == 0 ){
 19248  		/* No such table, return null */
 19249  		vedis_result_null(pCtx);
 19250  		return VEDIS_OK;
 19251  	}
 19252  	/* Index */
 19253  	iIndex = vedis_value_to_int(argv[1]);
 19254  	if( iIndex < 0 ){
 19255  		iIndex = -iIndex;
 19256  		nReal = vedisTableLength(pList) - iIndex;
 19257  	}else{
 19258  		nReal = (sxu32)iIndex;
 19259  	}
 19260  	/* Go fetch */
 19261  	pEntry = vedisTableGetRecordByIndex(pList,nReal); /* This will handle out of range indexes */
 19262  	if( pEntry == 0 ){
 19263  		/* return null */
 19264  		vedis_result_null(pCtx);
 19265  		return VEDIS_OK;
 19266  	}
 19267  	/* Return data */
 19268  	vedis_result_string(pCtx,(const char *)SyBlobData(&pEntry->sData),(int)SyBlobLength(&pEntry->sData));
 19269  	return VEDIS_OK;
 19270  }
 19271  /*
 19272   *  Command:    LLEN key  
 19273   * Description:
 19274   *   Returns the number of fields contained in the list stored at key.
 19275   * Return:
 19276   *    number of fields in the list, or 0 when key does not exist.
 19277   */
 19278  static int vedis_cmd_llen(vedis_context *pCtx,int argc,vedis_value **argv)
 19279  {
 19280  	vedis_table *pList;
 19281  	if( argc <  1 ){
 19282  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 19283  		/* return 0 */
 19284  		vedis_result_int(pCtx,0);
 19285  		return VEDIS_OK;
 19286  	}
 19287  	/* Fetch the table  */
 19288  	pList = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_LIST);
 19289  	if( pList == 0 ){
 19290  		/* No such table, return zero */
 19291  		vedis_result_int(pCtx,0);
 19292  		return VEDIS_OK;
 19293  	}
 19294  	vedis_result_int(pCtx,(int)vedisTableLength(pList));
 19295  	return VEDIS_OK;
 19296  }
 19297  /*
 19298   *  Command:    LPOP key  
 19299   * Description:
 19300   *   Removes and returns the first element of the list stored at key.
 19301   * Return:
 19302   *    the value of the first element, or nil when key does not exist.
 19303   */
 19304  static int vedis_cmd_lpop(vedis_context *pCtx,int argc,vedis_value **argv)
 19305  {
 19306  	vedis_table_entry *pEntry;
 19307  	vedis_table *pList;
 19308  	if( argc <  1 ){
 19309  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key");
 19310  		/* return null */
 19311  		vedis_result_null(pCtx);
 19312  		return VEDIS_OK;
 19313  	}
 19314  	/* Fetch the table  */
 19315  	pList = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],0,VEDIS_TABLE_LIST);
 19316  	if( pList == 0 ){
 19317  		/* No such table, return zero */
 19318  		vedis_result_null(pCtx);
 19319  		return VEDIS_OK;
 19320  	}
 19321  	/* Point to the first element */
 19322  	pEntry = vedisTableFirstEntry(pList);
 19323  	if( pEntry == 0 ){
 19324  		/* No such entry */
 19325  		vedis_result_null(pCtx);
 19326  		return VEDIS_OK;
 19327  	}
 19328  	vedis_result_string(pCtx,(const char *)SyBlobData(&pEntry->sData),(int)SyBlobLength(&pEntry->sData));
 19329  	/* Discard item */
 19330  	VedisRemoveTableEntry(pList,pEntry);
 19331  	return VEDIS_OK;
 19332  }
 19333  /*
 19334   *  Command:   LPUSH key value [value ...]  
 19335   * Description:
 19336   *   Insert all the specified values at the head of the list stored at key. If key does
 19337   *   not exist, it is created as empty list before performing the push operations.
 19338   *   It is possible to push multiple elements using a single command call just specifying
 19339   *   multiple arguments at the end of the command. Elements are inserted one after the other
 19340   *   to the head of the list, from the leftmost element to the rightmost element.
 19341   *   So for instance the command LPUSH mylist a b c will result into a list containing
 19342   *  c as first element, b as second element and a as third element.
 19343   * Return:
 19344   *    the length of the list after the push operations.
 19345   */
 19346  static int vedis_cmd_lpush(vedis_context *pCtx,int argc,vedis_value **argv)
 19347  {
 19348  	vedis_table *pList;
 19349  	int i;
 19350  	if( argc <  2 ){
 19351  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Missing key/value pair");
 19352  		/* return 0 */
 19353  		vedis_result_int(pCtx,0);
 19354  		return VEDIS_OK;
 19355  	}
 19356  	/* Fetch the table  */
 19357  	pList = vedisFetchTable((vedis *)vedis_context_user_data(pCtx),argv[0],1,VEDIS_TABLE_LIST);
 19358  	if( pList == 0 ){
 19359  		/* No such table, return zero */
 19360  		vedis_result_int(pCtx,0);
 19361  		return VEDIS_OK;
 19362  	}
 19363  	/* Perform the insertion */
 19364  	for( i = 1 ; i < argc; ++i ){
 19365  		vedisTableInsertRecord(pList,0/*Assign an automatic key*/,argv[i]);
 19366  	}
 19367  	/* Total number of inserted elements */
 19368  	vedis_result_int(pCtx,(int)vedisTableLength(pList));
 19369  	return VEDIS_OK;
 19370  }
 19371  /*
 19372   *  Command: RAND [min] [max]
 19373   * Description:
 19374   *  Generate a random (unsigned 32-bit) integer.
 19375   * Parameter
 19376   *  min
 19377   *    The lowest value to return (default: 0)
 19378   *  max
 19379   *   The highest value to return (default: GETRANDMAX)
 19380   * Return
 19381   *   Unsigned integer: A pseudo random value between min (or 0) and max (or GETRANDMAX, inclusive).
 19382   */
 19383  static int vedis_cmd_rand(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19384  {
 19385  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 19386  	sxu32 iNum;
 19387  	/* Generate the random number */
 19388  	iNum = vedisPagerRandomNum(pStore->pPager);
 19389  	if( nArg > 1 ){
 19390  		sxu32 iMin, iMax;
 19391  		iMin = (sxu32)vedis_value_to_int(apArg[0]);
 19392  		iMax = (sxu32)vedis_value_to_int(apArg[1]);
 19393  		if( iMin < iMax ){
 19394  			sxu32 iDiv = iMax+1-iMin;
 19395  			if( iDiv > 0 ){
 19396  				iNum = (iNum % iDiv)+iMin;
 19397  			}
 19398  		}else if(iMax > 0 ){
 19399  			iNum %= iMax;
 19400  		}
 19401  	}
 19402  	/* Return the generated number */
 19403  	vedis_result_int64(pCtx, (vedis_int64)iNum);
 19404  	return VEDIS_OK;
 19405  }
 19406  /*
 19407   *  Command: GETRANDMAX
 19408   * Description:
 19409   *   Show largest possible random value
 19410   * Return
 19411   *  Unsigned Integer: The largest possible random value returned by rand() which is in
 19412   *  this implementation 0xFFFFFFFF.
 19413   */
 19414  static int vedis_cmd_getrandmax(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19415  {
 19416  	SXUNUSED(nArg); /* cc warning */
 19417  	SXUNUSED(apArg);
 19418  	vedis_result_int64(pCtx, SXU32_HIGH);
 19419  	return VEDIS_OK;
 19420  }
 19421  /*
 19422   *  Command: RANDSTR [len]
 19423   * Description:
 19424   *  Generate a random string (English alphabet).
 19425   * Parameter
 19426   *  len
 19427   *    Length of the desired string (default: 16, Min: 1, Max: 1024)
 19428   * Return
 19429   *   String: A pseudo random string.
 19430   */
 19431  static int vedis_cmd_rand_str(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19432  {
 19433  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 19434  	char zString[1024];
 19435  	int iLen = 0x10;
 19436  	if( nArg > 0 ){
 19437  		/* Get the desired length */
 19438  		iLen = vedis_value_to_int(apArg[0]);
 19439  		if( iLen < 1 || iLen > 1024 ){
 19440  			/* Default length */
 19441  			iLen = 0x10;
 19442  		}
 19443  	}
 19444  	/* Generate the random string */
 19445  	vedisPagerRandomString(pStore->pPager, zString, iLen);
 19446  	/* Return the generated string */
 19447  	vedis_result_string(pCtx, zString, iLen); /* Will make it's own copy */
 19448  	return VEDIS_OK;
 19449  }
 19450  /*
 19451   * Output consumer callback for the standard Symisc routines.
 19452   * [i.e: SyBase64Encode(), SyBase64Decode(), SyUriEncode(), ...].
 19453   */
 19454  static int base64Consumer(const void *pData, unsigned int nLen, void *pUserData)
 19455  {
 19456  	/* Store in the call context result buffer */
 19457  	vedis_result_string((vedis_context *)pUserData, (const char *)pData, (int)nLen);
 19458  	return SXRET_OK;
 19459  }
 19460  /*
 19461   *  Command: BASE64 data
 19462   * Description:
 19463   *  Encode data with MIME base64
 19464   * Parameter
 19465   *  data
 19466   *    Data to encode
 19467   * Return
 19468   *  String: MIME base64 encoded input on sucess. False otherwise.
 19469   */
 19470  static int vedis_cmd_base64_encode(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19471  {
 19472  	const char *zIn;
 19473  	int nLen;
 19474  	if( nArg < 1 ){
 19475  		/* Missing arguments, return FALSE */
 19476  		vedis_result_bool(pCtx, 0);
 19477  		return VEDIS_OK;
 19478  	}
 19479  	/* Extract the input string */
 19480  	zIn = vedis_value_to_string(apArg[0], &nLen);
 19481  	if( nLen < 1 ){
 19482  		/* Nothing to process, return FALSE */
 19483  		vedis_result_bool(pCtx, 0);
 19484  		return VEDIS_OK;
 19485  	}
 19486  	/* Perform the BASE64 encoding */
 19487  	SyBase64Encode(zIn, (sxu32)nLen, base64Consumer, pCtx);
 19488  	return VEDIS_OK;
 19489  }
 19490  /*
 19491   * Command: BASE64_DEC
 19492   *  Decode MIME base64 based input
 19493   * Parameter
 19494   *  data
 19495   *    Encoded data.
 19496   * Return
 19497   *  String: Returns the original data or FALSE on failure.
 19498   */
 19499  static int vedis_cmd_base64_decode(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19500  {
 19501  	const char *zIn;
 19502  	int nLen;
 19503  	if( nArg < 1 ){
 19504  		/* Missing arguments, return FALSE */
 19505  		vedis_result_bool(pCtx, 0);
 19506  		return VEDIS_OK;
 19507  	}
 19508  	/* Extract the input string */
 19509  	zIn = vedis_value_to_string(apArg[0], &nLen);
 19510  	if( nLen < 1 ){
 19511  		/* Nothing to process, return FALSE */
 19512  		vedis_result_bool(pCtx, 0);
 19513  		return VEDIS_OK;
 19514  	}
 19515  	/* Perform the BASE64 decoding */
 19516  	SyBase64Decode(zIn, (sxu32)nLen, base64Consumer, pCtx);
 19517  	return VEDIS_OK;
 19518  }
 19519  /*
 19520   * Command: SOUNDEX string
 19521   *  Calculate the soundex key of a string.
 19522   * Parameters
 19523   *  string
 19524   *   The input string.
 19525   * Return
 19526   *  String: Returns the soundex key as a string.
 19527   * Note:
 19528   *  This implementation is based on the one found in the SQLite3
 19529   * source tree.
 19530   */
 19531  static int vedis_cmd_soundex(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19532  {
 19533  	const unsigned char *zIn;
 19534  	char zResult[8];
 19535  	int i, j;
 19536  	static const unsigned char iCode[] = {
 19537  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 19538  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 19539  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 19540  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
 19541  		0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 
 19542  		1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, 
 19543  		0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 
 19544  		1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, 
 19545  	};
 19546  	if( nArg < 1 ){
 19547  		/* Missing arguments, return the empty string */
 19548  		vedis_result_string(pCtx, "", 0);
 19549  		return VEDIS_OK;
 19550  	}
 19551  	zIn = (unsigned char *)vedis_value_to_string(apArg[0], 0);
 19552  	for(i=0; zIn[i] && zIn[i] < 0xc0 && !SyisAlpha(zIn[i]); i++){}
 19553  	if( zIn[i] ){
 19554  		unsigned char prevcode = iCode[zIn[i]&0x7f];
 19555  		zResult[0] = (char)SyToUpper(zIn[i]);
 19556  		for(j=1; j<4 && zIn[i]; i++){
 19557  			int code = iCode[zIn[i]&0x7f];
 19558  			if( code>0 ){
 19559  				if( code!=prevcode ){
 19560  					prevcode = (unsigned char)code;
 19561  					zResult[j++] = (char)code + '0';
 19562  				}
 19563  			}else{
 19564  				prevcode = 0;
 19565  			}
 19566  		}
 19567  		while( j<4 ){
 19568  			zResult[j++] = '0';
 19569  		}
 19570  		vedis_result_string(pCtx, zResult, 4);
 19571  	}else{
 19572  	  vedis_result_string(pCtx, "?000", 4);
 19573  	}
 19574  	return VEDIS_OK;
 19575  }
 19576  /*
 19577   * Command: SIZE_FMT int_size
 19578   *  Return a smart string represenation of the given size [i.e: 64-bit integer]
 19579   *  Example:
 19580   *     size_format(1*1024*1024*1024);// 1GB
 19581   *     size_format(512*1024*1024); // 512 MB
 19582   *     size_format(file_size(/path/to/my/file_8192)); //8KB
 19583   * Parameter
 19584   *  size
 19585   *    Entity size in bytes.
 19586   * Return
 19587   *   String: Formatted string representation of the given size.
 19588   */
 19589  static int vedis_cmd_size_format(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19590  {
 19591  	/*Kilo*/ /*Mega*/ /*Giga*/ /*Tera*/ /*Peta*/ /*Exa*/ /*Zeta*/
 19592  	static const char zUnit[] = {"KMGTPEZ"};
 19593  	sxi32 nRest, i_32;
 19594  	vedis_int64 iSize;
 19595  	int c = -1; /* index in zUnit[] */
 19596  
 19597  	if( nArg < 1 ){
 19598  		/* Missing argument, return the empty string */
 19599  		vedis_result_string(pCtx, "", 0);
 19600  		return VEDIS_OK;
 19601  	}
 19602  	/* Extract the given size */
 19603  	iSize = vedis_value_to_int64(apArg[0]);
 19604  	if( iSize < 100 /* Bytes */ ){
 19605  		/* Don't bother formatting, return immediately */
 19606  		vedis_result_string(pCtx, "0.1 KB", (int)sizeof("0.1 KB")-1);
 19607  		return VEDIS_OK;
 19608  	}
 19609  	for(;;){
 19610  		nRest = (sxi32)(iSize & 0x3FF); 
 19611  		iSize >>= 10;
 19612  		c++;
 19613  		if( (iSize & (~0 ^ 1023)) == 0 ){
 19614  			break;
 19615  		}
 19616  	}
 19617  	nRest /= 100;
 19618  	if( nRest > 9 ){
 19619  		nRest = 9;
 19620  	}
 19621  	if( iSize > 999 ){
 19622  		c++;
 19623  		nRest = 9;
 19624  		iSize = 0;
 19625  	}
 19626  	i_32 = (sxi32)iSize;
 19627  	/* Format */
 19628  	vedis_result_string_format(pCtx, "%d.%d %cB", i_32, nRest, zUnit[c]);
 19629  	return VEDIS_OK;
 19630  }
 19631  #ifdef VEDIS_ENABLE_HASH_CMD
 19632  /*
 19633   * Binary to hex consumer callback.
 19634   * This callback is the default consumer used by the hash functions
 19635   * [i.e: md5(), sha1(), ... ] defined below.
 19636   */
 19637  static int HashConsumer(const void *pData, unsigned int nLen, void *pUserData)
 19638  {
 19639  	/* Append hex chunk verbatim */
 19640  	vedis_result_string((vedis_context *)pUserData, (const char *)pData, (int)nLen);
 19641  	return SXRET_OK;
 19642  }
 19643  /*
 19644   * Command:  MD5 string
 19645   *   Calculate the md5 hash of a string.
 19646   * Parameter
 19647   *  string
 19648   *   Input string
 19649   * Return
 19650   *  String: MD5 Hash as a 32-character hexadecimal string.
 19651   */
 19652  static int vedis_cmd_md5(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19653  {
 19654  	unsigned char zDigest[16];
 19655  	const void *pIn;
 19656  	int nLen;
 19657  	if( nArg < 1 ){
 19658  		/* Missing arguments, return the empty string */
 19659  		vedis_result_string(pCtx, "", 0);
 19660  		return VEDIS_OK;
 19661  	}
 19662  	/* Extract the input string */
 19663  	pIn = (const void *)vedis_value_to_string(apArg[0], &nLen);
 19664  	if( nLen < 1 ){
 19665  		/* Empty string */
 19666  		vedis_result_string(pCtx, "", 0);
 19667  		return VEDIS_OK;
 19668  	}
 19669  	/* Compute the MD5 digest */
 19670  	SyMD5Compute(pIn, (sxu32)nLen, zDigest);
 19671  	/* Perform a binary to hex conversion */
 19672  	SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), HashConsumer, pCtx);
 19673  	return VEDIS_OK;
 19674  }
 19675  /*
 19676   * Command: SHA1 string 
 19677   *   Calculate the sha1 hash of a string.
 19678   * Parameter
 19679   *  string
 19680   *   Input string
 19681   * Return
 19682   *  String: SHA1 Hash as a 40-character hexadecimal string.
 19683   */
 19684  static int vedis_cmd_sha1(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19685  {
 19686  	unsigned char zDigest[20];
 19687  	const void *pIn;
 19688  	int nLen;
 19689  	if( nArg < 1 ){
 19690  		/* Missing arguments, return the empty string */
 19691  		vedis_result_string(pCtx, "", 0);
 19692  		return VEDIS_OK;
 19693  	}
 19694  	/* Extract the input string */
 19695  	pIn = (const void *)vedis_value_to_string(apArg[0], &nLen);
 19696  	if( nLen < 1 ){
 19697  		/* Empty string */
 19698  		vedis_result_string(pCtx, "", 0);
 19699  		return VEDIS_OK;
 19700  	}
 19701  	/* Compute the SHA1 digest */
 19702  	SySha1Compute(pIn, (sxu32)nLen, zDigest);
 19703  	/* Perform a binary to hex conversion */
 19704  	SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), HashConsumer, pCtx);
 19705  	return VEDIS_OK;
 19706  }
 19707  /*
 19708   * Command: CRC32 string
 19709   *   Calculates the crc32 polynomial of a strin.
 19710   * Parameter
 19711   *  $str
 19712   *   Input string
 19713   * Return
 19714   *  64-bit Integer: CRC32 checksum of the given input (64-bit integer).
 19715   */
 19716  static int vedis_cmd_crc32(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19717  {
 19718  	const void *pIn;
 19719  	sxu32 nCRC;
 19720  	int nLen;
 19721  	if( nArg < 1 ){
 19722  		/* Missing arguments, return 0 */
 19723  		vedis_result_int(pCtx, 0);
 19724  		return VEDIS_OK;
 19725  	}
 19726  	/* Extract the input string */
 19727  	pIn = (const void *)vedis_value_to_string(apArg[0], &nLen);
 19728  	if( nLen < 1 ){
 19729  		/* Empty string */
 19730  		vedis_result_int(pCtx, 0);
 19731  		return VEDIS_OK;
 19732  	}
 19733  	/* Calculate the sum */
 19734  	nCRC = SyCrc32(pIn, (sxu32)nLen);
 19735  	/* Return the CRC32 as 64-bit integer */
 19736  	vedis_result_int64(pCtx, (vedis_int64)nCRC^ 0xFFFFFFFF);
 19737  	return VEDIS_OK;
 19738  }
 19739  #endif /* VEDIS_ENABLE_HASH_CMD */
 19740  /*
 19741   * Parse a CSV string and invoke the supplied callback for each processed xhunk.
 19742   */
 19743  static sxi32 vedisProcessCsv(
 19744  	const char *zInput, /* Raw input */
 19745  	int nByte,  /* Input length */
 19746  	int delim,  /* Delimiter */
 19747  	int encl,   /* Enclosure */
 19748  	int escape,  /* Escape character */
 19749  	sxi32 (*xConsumer)(const char *, int, void *), /* User callback */
 19750  	void *pUserData /* Last argument to xConsumer() */
 19751  	)
 19752  {
 19753  	const char *zEnd = &zInput[nByte];
 19754  	const char *zIn = zInput;
 19755  	const char *zPtr;
 19756  	int isEnc;
 19757  	/* Start processing */
 19758  	for(;;){
 19759  		if( zIn >= zEnd ){
 19760  			/* No more input to process */
 19761  			break;
 19762  		}
 19763  		isEnc = 0;
 19764  		zPtr = zIn;
 19765  		/* Find the first delimiter */
 19766  		while( zIn < zEnd ){
 19767  			if( zIn[0] == delim && !isEnc){
 19768  				/* Delimiter found, break imediately */
 19769  				break;
 19770  			}else if( zIn[0] == encl ){
 19771  				/* Inside enclosure? */
 19772  				isEnc = !isEnc;
 19773  			}else if( zIn[0] == escape ){
 19774  				/* Escape sequence */
 19775  				zIn++;
 19776  			}
 19777  			/* Advance the cursor */
 19778  			zIn++;
 19779  		}
 19780  		if( zIn > zPtr ){
 19781  			int nByte = (int)(zIn-zPtr);
 19782  			sxi32 rc;
 19783  			/* Invoke the supllied callback */
 19784  			if( zPtr[0] == encl ){
 19785  				zPtr++;
 19786  				nByte-=2;
 19787  			}
 19788  			if( nByte > 0 ){
 19789  				rc = xConsumer(zPtr, nByte, pUserData);
 19790  				if( rc == SXERR_ABORT ){
 19791  					/* User callback request an operation abort */
 19792  					break;
 19793  				}
 19794  			}
 19795  		}
 19796  		/* Ignore trailing delimiter */
 19797  		while( zIn < zEnd && zIn[0] == delim ){
 19798  			zIn++;
 19799  		}
 19800  	}
 19801  	return SXRET_OK;
 19802  }
 19803  /*
 19804   * Default consumer callback for the CSV parsing routine defined above.
 19805   * All the processed input is insereted into an array passed as the last
 19806   * argument to this callback.
 19807   */
 19808  static sxi32 vedisCsvConsumer(const char *zToken, int nTokenLen, void *pUserData)
 19809  {
 19810  	vedis_value *pArray = (vedis_value *)pUserData;
 19811  	vedis_value sEntry;
 19812  	SyString sToken;
 19813  	/* Insert the token in the given array */
 19814  	SyStringInitFromBuf(&sToken, zToken, nTokenLen);
 19815  	/* Remove trailing and leading white spcaces and null bytes */
 19816  	SyStringFullTrimSafe(&sToken);
 19817  	if( sToken.nByte < 1){
 19818  		return SXRET_OK;
 19819  	}
 19820  	vedisMemObjInitFromString(vedisHashmapGetEngine((vedis_hashmap *)pArray->x.pOther), &sEntry, &sToken);
 19821  	vedis_array_insert(pArray, &sEntry);
 19822  	vedisMemObjRelease(&sEntry);
 19823  	return SXRET_OK;
 19824  }
 19825  /*
 19826   * Command: GETCSV input
 19827   *  Parse a CSV string into a array.
 19828   * Parameters
 19829   *  $input
 19830   *   The string to parse.
 19831   *  $delimiter
 19832   *   Set the field delimiter (one character only).
 19833   *  $enclosure
 19834   *   Set the field enclosure character (one character only).
 19835   *  $escape
 19836   *   Set the escape character (one character only). Defaults as a backslash (\)
 19837   * Return
 19838   *  Array: An indexed array containing the CSV fields or NULL on failure.
 19839   */
 19840  static int vedis_cmd_str_getcsv(vedis_context *pCtx, int nArg, vedis_value **apArg)
 19841  {
 19842  	const char *zInput, *zPtr;
 19843  	vedis_value *pArray;
 19844  	int delim  = ',';   /* Delimiter */
 19845  	int encl   = '"' ;  /* Enclosure */
 19846  	int escape = '\\';  /* Escape character */
 19847  	int nLen;
 19848  	if( nArg < 1 || !vedis_value_is_string(apArg[0]) ){
 19849  		/* Missing/Invalid arguments, return NULL */
 19850  		vedis_result_null(pCtx);
 19851  		return VEDIS_OK;
 19852  	}
 19853  	/* Extract the raw input */
 19854  	zInput = vedis_value_to_string(apArg[0], &nLen);
 19855  	if( nArg > 1 ){
 19856  		int i;
 19857  		if( vedis_value_is_string(apArg[1]) ){
 19858  			/* Extract the delimiter */
 19859  			zPtr = vedis_value_to_string(apArg[1], &i);
 19860  			if( i > 0 ){
 19861  				delim = zPtr[0];
 19862  			}
 19863  		}
 19864  		if( nArg > 2 ){
 19865  			if( vedis_value_is_string(apArg[2]) ){
 19866  				/* Extract the enclosure */
 19867  				zPtr = vedis_value_to_string(apArg[2], &i);
 19868  				if( i > 0 ){
 19869  					encl = zPtr[0];
 19870  				}
 19871  			}
 19872  			if( nArg > 3 ){
 19873  				if( vedis_value_is_string(apArg[3]) ){
 19874  					/* Extract the escape character */
 19875  					zPtr = vedis_value_to_string(apArg[3], &i);
 19876  					if( i > 0 ){
 19877  						escape = zPtr[0];
 19878  					}
 19879  				}
 19880  			}
 19881  		}
 19882  	}
 19883  	/* Create our array */
 19884  	pArray = vedis_context_new_array(pCtx);
 19885  	if( pArray == 0 ){
 19886  		vedis_context_throw_error(pCtx, VEDIS_CTX_ERR, "VEDIS is running out of memory");
 19887  		vedis_result_null(pCtx);
 19888  		return VEDIS_OK;
 19889  	}
 19890  	/* Parse the raw input */
 19891  	vedisProcessCsv(zInput, nLen, delim, encl, escape, vedisCsvConsumer, pArray);
 19892  	/* Return the freshly created array */
 19893  	vedis_result_value(pCtx, pArray);
 19894  	return VEDIS_OK;
 19895  }
 19896  /*
 19897   * Extract a tag name from a raw HTML input and insert it in the given
 19898   * container.
 19899   * Refer to [strip_tags()].
 19900   */
 19901  static sxi32 AddTag(SySet *pSet, const char *zTag, int nByte)
 19902  {
 19903  	const char *zEnd = &zTag[nByte];
 19904  	const char *zPtr;
 19905  	SyString sEntry;
 19906  	/* Strip tags */
 19907  	for(;;){
 19908  		while( zTag < zEnd && (zTag[0] == '<' || zTag[0] == '/' || zTag[0] == '?'
 19909  			|| zTag[0] == '!' || zTag[0] == '-' || ((unsigned char)zTag[0] < 0xc0 && SyisSpace(zTag[0]))) ){
 19910  				zTag++;
 19911  		}
 19912  		if( zTag >= zEnd ){
 19913  			break;
 19914  		}
 19915  		zPtr = zTag;
 19916  		/* Delimit the tag */
 19917  		while(zTag < zEnd ){
 19918  			if( (unsigned char)zTag[0] >= 0xc0 ){
 19919  				/* UTF-8 stream */
 19920  				zTag++;
 19921  				SX_JMP_UTF8(zTag, zEnd);
 19922  			}else if( !SyisAlphaNum(zTag[0]) ){
 19923  				break;
 19924  			}else{
 19925  				zTag++;
 19926  			}
 19927  		}
 19928  		if( zTag > zPtr ){
 19929  			/* Perform the insertion */
 19930  			SyStringInitFromBuf(&sEntry, zPtr, (int)(zTag-zPtr));
 19931  			SyStringFullTrim(&sEntry);
 19932  			SySetPut(pSet, (const void *)&sEntry);
 19933  		}
 19934  		/* Jump the trailing '>' */
 19935  		zTag++;
 19936  	}
 19937  	return SXRET_OK;
 19938  }
 19939  /*
 19940   * Check if the given HTML tag name is present in the given container.
 19941   * Return SXRET_OK if present.SXERR_NOTFOUND otherwise.
 19942   * Refer to [strip_tags()].
 19943   */
 19944  static sxi32 FindTag(SySet *pSet, const char *zTag, int nByte)
 19945  {
 19946  	if( SySetUsed(pSet) > 0 ){
 19947  		const char *zCur, *zEnd = &zTag[nByte];
 19948  		SyString sTag;
 19949  		while( zTag < zEnd &&  (zTag[0] == '<' || zTag[0] == '/' || zTag[0] == '?' ||
 19950  			((unsigned char)zTag[0] < 0xc0 && SyisSpace(zTag[0]))) ){
 19951  			zTag++;
 19952  		}
 19953  		/* Delimit the tag */
 19954  		zCur = zTag;
 19955  		while(zTag < zEnd ){
 19956  			if( (unsigned char)zTag[0] >= 0xc0 ){
 19957  				/* UTF-8 stream */
 19958  				zTag++;
 19959  				SX_JMP_UTF8(zTag, zEnd);
 19960  			}else if( !SyisAlphaNum(zTag[0]) ){
 19961  				break;
 19962  			}else{
 19963  				zTag++;
 19964  			}
 19965  		}
 19966  		SyStringInitFromBuf(&sTag, zCur, zTag-zCur);
 19967  		/* Trim leading white spaces and null bytes */
 19968  		SyStringLeftTrimSafe(&sTag);
 19969  		if( sTag.nByte > 0 ){
 19970  			SyString *aEntry, *pEntry;
 19971  			sxi32 rc;
 19972  			sxu32 n;
 19973  			/* Perform the lookup */
 19974  			aEntry = (SyString *)SySetBasePtr(pSet);
 19975  			for( n = 0 ; n < SySetUsed(pSet) ; ++n ){
 19976  				pEntry = &aEntry[n];
 19977  				/* Do the comparison */
 19978  				rc = SyStringCmp(pEntry, &sTag, SyStrnicmp);
 19979  				if( !rc ){
 19980  					return SXRET_OK;
 19981  				}
 19982  			}
 19983  		}
 19984  	}
 19985  	/* No such tag */
 19986  	return SXERR_NOTFOUND;
 19987  }
 19988  /*
 19989   * This function tries to return a string [i.e: in the call context result buffer]
 19990   * with all NUL bytes, HTML and VEDIS tags stripped from a given string.
 19991   * Refer to [strip_tags()].
 19992   */
 19993  static sxi32 vedisStripTagsFromString(vedis_context *pCtx, const char *zIn, int nByte, const char *zTaglist, int nTaglen)
 19994  {
 19995  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 19996  	const char *zEnd = &zIn[nByte];
 19997  	const char *zPtr, *zTag;
 19998  	SySet sSet;
 19999  	/* initialize the set of allowed tags */
 20000  	SySetInit(&sSet, &pStore->sMem, sizeof(SyString));
 20001  	if( nTaglen > 0 ){
 20002  		/* Set of allowed tags */
 20003  		AddTag(&sSet, zTaglist, nTaglen);
 20004  	}
 20005  	/* Set the empty string */
 20006  	vedis_result_string(pCtx, "", 0);
 20007  	/* Start processing */
 20008  	for(;;){
 20009  		if(zIn >= zEnd){
 20010  			/* No more input to process */
 20011  			break;
 20012  		}
 20013  		zPtr = zIn;
 20014  		/* Find a tag */
 20015  		while( zIn < zEnd && zIn[0] != '<' && zIn[0] != 0 /* NUL byte */ ){
 20016  			zIn++;
 20017  		}
 20018  		if( zIn > zPtr ){
 20019  			/* Consume raw input */
 20020  			vedis_result_string(pCtx, zPtr, (int)(zIn-zPtr));
 20021  		}
 20022  		/* Ignore trailing null bytes */
 20023  		while( zIn < zEnd && zIn[0] == 0 ){
 20024  			zIn++;
 20025  		}
 20026  		if(zIn >= zEnd){
 20027  			/* No more input to process */
 20028  			break;
 20029  		}
 20030  		if( zIn[0] == '<' ){
 20031  			sxi32 rc;
 20032  			zTag = zIn++;
 20033  			/* Delimit the tag */
 20034  			while( zIn < zEnd && zIn[0] != '>' ){
 20035  				zIn++;
 20036  			}
 20037  			if( zIn < zEnd ){
 20038  				zIn++; /* Ignore the trailing closing tag */
 20039  			}
 20040  			/* Query the set */
 20041  			rc = FindTag(&sSet, zTag, (int)(zIn-zTag));
 20042  			if( rc == SXRET_OK ){
 20043  				/* Keep the tag */
 20044  				vedis_result_string(pCtx, zTag, (int)(zIn-zTag));
 20045  			}
 20046  		}
 20047  	}
 20048  	/* Cleanup */
 20049  	SySetRelease(&sSet);
 20050  	return SXRET_OK;
 20051  }
 20052  /*
 20053   * Command: STRIP_TAG string [allowable_tags]
 20054   *   Strip HTML tags from a string.
 20055   * Parameters
 20056   * str
 20057   *  The input string.
 20058   * allowable_tags
 20059   *  You can use the optional second parameter to specify tags which should not be stripped. 
 20060   * Return
 20061   *  String: Returns the stripped string.
 20062   */
 20063  static int vedis_cmd_strip_tags(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20064  {
 20065  	const char *zTaglist = 0;
 20066  	const char *zString;
 20067  	int nTaglen = 0;
 20068  	int nLen;
 20069  	if( nArg < 1 || !vedis_value_is_string(apArg[0]) ){
 20070  		/* Missing/Invalid arguments, return the empty string */
 20071  		vedis_result_string(pCtx, "", 0);
 20072  		return VEDIS_OK;
 20073  	}
 20074  	/* Point to the raw string */
 20075  	zString = vedis_value_to_string(apArg[0], &nLen);
 20076  	if( nArg > 1 && vedis_value_is_string(apArg[1]) ){
 20077  		/* Allowed tag */
 20078  		zTaglist = vedis_value_to_string(apArg[1], &nTaglen);
 20079  	}
 20080  	/* Process input */
 20081  	vedisStripTagsFromString(pCtx, zString, nLen, zTaglist, nTaglen);
 20082  	return VEDIS_OK;
 20083  }
 20084  /*
 20085   * Command:  STR_SPLIT string, [$split_length = 1 ]
 20086   *  Split a string into an indexed array.
 20087   * Parameters
 20088   * $str
 20089   *  The input string.
 20090   * $split_length
 20091   *  Maximum length of the chunk.
 20092   * Return
 20093   *  Array: If the optional split_length parameter is specified, the returned array
 20094   *  will be broken down into chunks with each being split_length in length, otherwise
 20095   *  each chunk will be one character in length. FALSE is returned if split_length is less than 1.
 20096   *  If the split_length length exceeds the length of string, the entire string is returned 
 20097   *  as the first (and only) array element.
 20098   */
 20099  static int vedis_cmd_str_split(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20100  {
 20101  	const char *zString, *zEnd;
 20102  	vedis_value *pArray, *pValue;
 20103  	int split_len;
 20104  	int nLen;
 20105  	if( nArg < 1 ){
 20106  		/* Missing arguments, return FALSE */
 20107  		vedis_result_bool(pCtx, 0);
 20108  		return VEDIS_OK;
 20109  	}
 20110  	/* Point to the target string */
 20111  	zString = vedis_value_to_string(apArg[0], &nLen);
 20112  	if( nLen < 1 ){
 20113  		/* Nothing to process, return FALSE */
 20114  		vedis_result_bool(pCtx, 0);
 20115  		return VEDIS_OK;
 20116  	}
 20117  	split_len = (int)sizeof(char);
 20118  	if( nArg > 1 ){
 20119  		/* Split length */
 20120  		split_len = vedis_value_to_int(apArg[1]);
 20121  		if( split_len < 1 ){
 20122  			/* Invalid length, return FALSE */
 20123  			vedis_result_bool(pCtx, 0);
 20124  			return VEDIS_OK;
 20125  		}
 20126  		if( split_len > nLen ){
 20127  			split_len = nLen;
 20128  		}
 20129  	}
 20130  	/* Create the array and the scalar value */
 20131  	pArray = vedis_context_new_array(pCtx);
 20132  	/*Chunk value */
 20133  	pValue = vedis_context_new_scalar(pCtx);
 20134  	if( pValue == 0 || pArray == 0 ){
 20135  		/* Return FALSE */
 20136  		vedis_result_bool(pCtx, 0);
 20137  		return VEDIS_OK;
 20138  	}
 20139  	/* Point to the end of the string */
 20140  	zEnd = &zString[nLen];
 20141  	/* Perform the requested operation */
 20142  	for(;;){
 20143  		int nMax;
 20144  		if( zString >= zEnd ){
 20145  			/* No more input to process */
 20146  			break;
 20147  		}
 20148  		nMax = (int)(zEnd-zString);
 20149  		if( nMax < split_len ){
 20150  			split_len = nMax;
 20151  		}
 20152  		/* Copy the current chunk */
 20153  		vedis_value_string(pValue, zString, split_len);
 20154  		/* Insert it */
 20155  		vedis_array_insert(pArray, pValue); /* Will make it's own copy */
 20156  		/* reset the string cursor */
 20157  		vedis_value_reset_string_cursor(pValue);
 20158  		/* Update position */
 20159  		zString += split_len;
 20160  	}
 20161  	/* 
 20162  	 * Return the array.
 20163  	 * Don't worry about freeing memory, everything will be automatically released
 20164  	 * upon we return from this function.
 20165  	 */
 20166  	vedis_result_value(pCtx, pArray);
 20167  	return VEDIS_OK;
 20168  }
 20169  #ifdef __WINNT__
 20170  #include <Windows.h>
 20171  #else
 20172  #include <time.h>
 20173  #endif
 20174  /*
 20175   *  Command: TIME
 20176   *   Expand the current time (GMT).
 20177   * Return:
 20178   *  String: Formatted time (HH:MM:SS)
 20179   */
 20180  static int vedis_cmd_time(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20181  {
 20182  	Sytm sTm;
 20183  #ifdef __WINNT__
 20184  	SYSTEMTIME sOS;
 20185  	GetSystemTime(&sOS);
 20186  	SYSTEMTIME_TO_SYTM(&sOS, &sTm);
 20187  #else
 20188  	struct tm *pTm;
 20189  	time_t t;
 20190  	time(&t);
 20191  	pTm = gmtime(&t);
 20192  	STRUCT_TM_TO_SYTM(pTm, &sTm);
 20193  #endif
 20194  	SXUNUSED(nArg); /* cc warning */
 20195  	SXUNUSED(apArg);
 20196  	/* Expand */
 20197  	vedis_result_string_format(pCtx, "%02d:%02d:%02d", sTm.tm_hour, sTm.tm_min, sTm.tm_sec);
 20198  	return VEDIS_OK;
 20199  }
 20200  /*
 20201   *  Command: DATE
 20202   *   Expand the current date in the ISO-8601 format
 20203   * Return:
 20204   *  String: ISO-8601 date format.
 20205   */
 20206  static int vedis_cmd_date(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20207  {
 20208  	Sytm sTm;
 20209  #ifdef __WINNT__
 20210  	SYSTEMTIME sOS;
 20211  	GetSystemTime(&sOS);
 20212  	SYSTEMTIME_TO_SYTM(&sOS, &sTm);
 20213  #else
 20214  	struct tm *pTm;
 20215  	time_t t;
 20216  	time(&t);
 20217  	pTm = gmtime(&t);
 20218  	STRUCT_TM_TO_SYTM(pTm, &sTm);
 20219  #endif
 20220  	SXUNUSED(nArg); /* cc warning */
 20221  	SXUNUSED(apArg);
 20222  	/* Expand */
 20223  	vedis_result_string_format(pCtx, "%04d-%02d-%02d", sTm.tm_year, sTm.tm_mon+1, sTm.tm_mday);
 20224  	return VEDIS_OK;
 20225  }
 20226  #if defined(__UNIXES__)
 20227  #include <sys/utsname.h>
 20228  #endif
 20229  /*
 20230   *  Command: OS
 20231   *   Expand the name of the host Operating System
 20232   * Return:
 20233   *  String: OS name.
 20234   */
 20235  static int vedis_cmd_os(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20236  {
 20237  #if defined(__WINNT__)
 20238  	const char *zName = "Microsoft Windows";
 20239  	OSVERSIONINFOW sVer;
 20240  	sVer.dwOSVersionInfoSize = sizeof(sVer);
 20241  	if( TRUE != GetVersionExW(&sVer)){
 20242  		vedis_result_string(pCtx, zName, -1);
 20243  		return VEDIS_OK;
 20244  	}
 20245  	if( sVer.dwPlatformId == VER_PLATFORM_WIN32_NT ){
 20246  		if( sVer.dwMajorVersion <= 4 ){
 20247  			zName = "Microsoft Windows NT";
 20248  		}else if( sVer.dwMajorVersion == 5 ){
 20249  			switch(sVer.dwMinorVersion){
 20250  				case 0:	zName = "Microsoft Windows 2000"; break;
 20251  				case 1: zName = "Microsoft Windows XP";   break;
 20252  				case 2: zName = "Microsoft Windows Server 2003"; break;
 20253  			}
 20254  		}else if( sVer.dwMajorVersion == 6){
 20255  				switch(sVer.dwMinorVersion){
 20256  					case 0: zName = "Microsoft Windows Vista"; break;
 20257  					case 1: zName = "Microsoft Windows 7"; break;
 20258  					case 2: zName = "Microsoft Windows 8"; break;
 20259  					default: break;
 20260  				}
 20261  		}
 20262  	}
 20263  	vedis_result_string_format(pCtx, "%s localhost %u.%u build %u x86", 
 20264  			zName, 
 20265  			sVer.dwMajorVersion, sVer.dwMinorVersion, sVer.dwBuildNumber
 20266  			);
 20267  #elif defined(__UNIXES__)
 20268  	struct utsname sInfo;
 20269  	if( uname(&sInfo) != 0 ){
 20270  		vedis_result_string(pCtx, "Unix", (int)sizeof("Unix")-1);
 20271  	}else{
 20272  		vedis_result_string(pCtx, sInfo.sysname, -1);
 20273  	}
 20274  #else
 20275  	vedis_result_string(pCtx,"Host OS", (int)sizeof("Host OS")-1);
 20276  #endif
 20277  	SXUNUSED(nArg); /* cc warning */
 20278  	SXUNUSED(apArg);
 20279  	return VEDIS_OK;
 20280  }
 20281  /*
 20282   *  Command: VEDIS
 20283   *   Expand the vedis signature and copyright notice.
 20284   * Return:
 20285   *  String: Vedis signature and copyright notice.
 20286   */
 20287  static int vedis_cmd_credits(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20288  {
 20289  	SXUNUSED(nArg); /* cc warning */
 20290  	SXUNUSED(apArg);
 20291  	/* Expand */
 20292  	vedis_result_string(pCtx,VEDIS_SIG " " VEDIS_COPYRIGHT,-1);
 20293  	return VEDIS_OK;
 20294  }
 20295  /*
 20296   *  Command: ECHO,PRINT
 20297   *   Return the given argument.
 20298   * Return:
 20299   *  String: Given argument.
 20300   */
 20301  static int vedis_cmd_echo(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20302  {
 20303  	if( nArg > 0 ){
 20304  		/* Expand */
 20305  		vedis_result_value(pCtx,apArg[0]);
 20306  	}
 20307  	return VEDIS_OK;
 20308  }
 20309  /*
 20310   *  Command: ABORT
 20311   *   Throw an error message and abort execution.
 20312   * Return:
 20313   *  nil
 20314   */
 20315  static int vedis_cmd_abort(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20316  {
 20317  	vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"User request an operation abort");
 20318  	SXUNUSED(nArg); /* cc wanring */
 20319  	SXUNUSED(apArg);
 20320  	return VEDIS_ABORT; /* Abort execution */
 20321  }
 20322  /*
 20323   *  Command: CMD_LIST
 20324   *   Return an indexed array holding the list of installed vedis commands.
 20325   * Return:
 20326   *  Array: Array of installed vedis commands.
 20327   */
 20328  static int vedis_cmd_c_list(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20329  {
 20330  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 20331  	vedis_value *pArray,*pScalar;
 20332  	vedis_cmd *pCmd;
 20333  	sxu32 n;
 20334  	
 20335  	/* Allocate a new scalar and array */
 20336  	pScalar = vedis_context_new_scalar(pCtx);
 20337  	pArray = vedis_context_new_array(pCtx);
 20338  	if( pScalar == 0 || pArray == 0 ){
 20339  		vedis_context_throw_error(pCtx,VEDIS_CTX_ERR,"Out of memory");
 20340  		/* return null */
 20341  		vedis_result_null(pCtx);
 20342  		SXUNUSED(nArg); /* cc warning */
 20343  		SXUNUSED(apArg);
 20344  		return VEDIS_OK;
 20345  	}
 20346  	pCmd = pStore->pList;
 20347  	for( n = 0 ; n < pStore->nCmd; ++n ){
 20348  		vedis_value_reset_string_cursor(pScalar);
 20349  		/* Copy the command name */
 20350  		vedis_value_string(pScalar,SyStringData(&pCmd->sName),(int)SyStringLength(&pCmd->sName));
 20351  		/* Perform the insertion */
 20352  		vedis_array_insert(pArray,pScalar);
 20353  		/* Point to the next entry */
 20354  		pCmd = pCmd->pNext;
 20355  	}
 20356  	/* Return our array */
 20357  	vedis_result_value(pCtx,pArray);
 20358  	/* pScalar will be automatically destroyed */
 20359  	return VEDIS_OK;
 20360  }
 20361  /*
 20362   *  Command: COMMIT
 20363   *   Commit an active write transaction.
 20364   * Return:
 20365   *  Boolean: TRUE on success. FALSE otherwise.
 20366   */
 20367  static int vedis_cmd_commit(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20368  {
 20369  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 20370  	int rc;
 20371  	SXUNUSED(nArg); /*cc warning */
 20372  	SXUNUSED(apArg);
 20373  	rc = vedisPagerCommit(pStore->pPager);
 20374  	/* Result */
 20375  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 20376  	return VEDIS_OK;
 20377  }
 20378  /*
 20379   *  Command: ROLLBACK
 20380   *   Rollback an active write transaction.
 20381   * Return:
 20382   *  Boolean: TRUE on success. FALSE otherwise.
 20383   */
 20384  static int vedis_cmd_rollback(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20385  {
 20386  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 20387  	int rc;
 20388  	SXUNUSED(nArg); /*cc warning */
 20389  	SXUNUSED(apArg);
 20390  	rc = vedisPagerRollback(pStore->pPager,TRUE);
 20391  	/* Result */
 20392  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 20393  	return VEDIS_OK;
 20394  }
 20395  /*
 20396   *  Command: BEGIN
 20397   *   Start a write transaction.
 20398   * Return:
 20399   *  Boolean: TRUE on success. FALSE otherwise.
 20400   */
 20401  static int vedis_cmd_begin(vedis_context *pCtx, int nArg, vedis_value **apArg)
 20402  {
 20403  	vedis *pStore = (vedis *)vedis_context_user_data(pCtx);
 20404  	int rc;
 20405  	SXUNUSED(nArg); /*cc warning */
 20406  	SXUNUSED(apArg);
 20407  	rc = vedisPagerBegin(pStore->pPager);
 20408  	/* Result */
 20409  	vedis_result_bool(pCtx,rc == VEDIS_OK);
 20410  	return VEDIS_OK;
 20411  }
 20412  /*
 20413   * Register the built-in Vedis command defined above.
 20414   */
 20415  VEDIS_PRIVATE int vedisRegisterBuiltinCommands(vedis *pVedis)
 20416  {
 20417  	static const struct vedis_built_command {
 20418  		const char *zName; /* Command name */
 20419  		ProcVedisCmd xCmd; /* Implementation of the command */
 20420  	}aCmd[] = {
 20421  		{ "DEL",       vedis_cmd_del },
 20422  		{ "REMOVE",    vedis_cmd_del },
 20423  		{ "EXISTS",    vedis_cmd_exists },
 20424  		{ "APPEND",    vedis_cmd_append },
 20425  		{ "STRLEN",    vedis_cmd_strlen },
 20426  		{ "GET",       vedis_cmd_get    },
 20427  		{ "COPY",      vedis_cmd_copy   },
 20428  		{ "MOVE",      vedis_cmd_move   },
 20429  		{ "MGET",      vedis_cmd_mget   },
 20430  		{ "SET",       vedis_cmd_set    },
 20431  		{ "SETNX",     vedis_cmd_setnx  },
 20432  		{ "MSET",      vedis_cmd_mset   },
 20433  		{ "MSETNX",    vedis_cmd_msetnx },
 20434  		{ "GETSET",    vedis_cmd_getset },
 20435  		{ "INCR",      vedis_cmd_incr   },
 20436  		{ "DECR",      vedis_cmd_decr   },
 20437  		{ "INCRBY",    vedis_cmd_incrby },
 20438  		{ "DECRBY",    vedis_cmd_decrby },
 20439  		{ "HGET",      vedis_cmd_hget   },
 20440  		{ "HEXISTS",   vedis_cmd_hexists},
 20441  		{ "HDEL",      vedis_cmd_hdel   },
 20442  		{ "HLEN",      vedis_cmd_hlen   },
 20443  		{ "HMGET",     vedis_cmd_hmget  },
 20444  		{ "HKEYS",     vedis_cmd_hkeys  },
 20445  		{ "HVALS",     vedis_cmd_hvals  }, 
 20446  		{ "HGETALL",   vedis_cmd_hgetall },
 20447  		{ "HSET",      vedis_cmd_hset   },
 20448  		{ "HMSET",     vedis_cmd_hmset  },
 20449  		{ "HSETNX",    vedis_cmd_hsetnx },
 20450  		{ "SADD",      vedis_cmd_sadd   },
 20451  		{ "SCARD",     vedis_cmd_scard  },
 20452  		{ "SISMEMBER", vedis_cmd_sismember },
 20453  		{ "SPOP",      vedis_cmd_spop   },
 20454  		{ "SPEEK",     vedis_cmd_speek  },
 20455  		{ "STOP",      vedis_cmd_stop   },
 20456  		{ "SREM",      vedis_cmd_srem   },
 20457  		{ "SMEMBERS",  vedis_cmd_smembers },
 20458  		{ "SDIFF",     vedis_cmd_sdiff  },
 20459  		{ "SINTER",    vedis_cmd_sinter },
 20460  		{ "SLEN",      vedis_cmd_slen   },
 20461  		{ "LINDEX",    vedis_cmd_lindex },
 20462  		{ "LLEN",      vedis_cmd_llen   },
 20463  		{ "LPOP",      vedis_cmd_lpop   },
 20464  		{ "LPUSH",     vedis_cmd_lpush  },
 20465  		{ "RAND",      vedis_cmd_rand   },
 20466  		{ "GETRANDMAX", vedis_cmd_getrandmax },
 20467  		{ "RANDSTR",    vedis_cmd_rand_str },
 20468  		{ "BASE64",     vedis_cmd_base64_encode },
 20469  		{ "BASE64_DEC", vedis_cmd_base64_decode },
 20470  		{ "SOUNDEX",    vedis_cmd_soundex  },
 20471  		{ "SIZE_FMT",   vedis_cmd_size_format },
 20472  #ifdef VEDIS_ENABLE_HASH_CMD
 20473  		{ "MD5",        vedis_cmd_md5 },
 20474  		{ "SHA1",       vedis_cmd_sha1 },
 20475  		{ "CRC32",      vedis_cmd_crc32 },
 20476  #endif /* VEDIS_ENABLE_HASH_CMD */
 20477  		{ "GETCSV",     vedis_cmd_str_getcsv },
 20478  		{ "STRIP_TAG",  vedis_cmd_strip_tags },
 20479  		{ "STR_SPLIT",  vedis_cmd_str_split  },
 20480  		{ "TIME",       vedis_cmd_time       },
 20481  		{ "DATE",       vedis_cmd_date       },
 20482  		{ "OS",         vedis_cmd_os         },
 20483  		{ "ECHO",       vedis_cmd_echo       },
 20484  		{ "PRINT",      vedis_cmd_echo       },
 20485  		{ "ABORT",      vedis_cmd_abort      },
 20486  		{ "CMD_LIST",   vedis_cmd_c_list     },
 20487  		{ "TABLE_LIST", vedis_cmd_table_list },
 20488  		{ "VEDIS",      vedis_cmd_credits    },
 20489  		{ "COMMIT",     vedis_cmd_commit     },
 20490  		{ "ROLLBACK",   vedis_cmd_rollback   },
 20491  		{ "BEGIN",      vedis_cmd_begin      },
 20492  	};
 20493  	int rc = VEDIS_OK;
 20494  	sxu32 n;
 20495  	for( n = 0 ; n < SX_ARRAYSIZE(aCmd); ++n ){
 20496  		/* Create the command */
 20497  		rc = vedis_register_command(pVedis,aCmd[n].zName,aCmd[n].xCmd,pVedis);
 20498  	}
 20499  	return rc;
 20500  }
 20501  /*
 20502   * ----------------------------------------------------------
 20503   * File: bitvec.c
 20504   * MD5: dfd57c382edf589956568a2527d13e36
 20505   * ----------------------------------------------------------
 20506   */
 20507  /*
 20508   * Symisc Vedis: An Embeddable NoSQL (Post Modern) Database Engine.
 20509   * Copyright (C) 2012-2013, Symisc Systems http://vedis.org/
 20510   * Version 1.1.6
 20511   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 20512   * please contact Symisc Systems via:
 20513   *       legal@symisc.net
 20514   *       licensing@symisc.net
 20515   *       contact@symisc.net
 20516   * or visit:
 20517   *      http://vedis.org/licensing.html
 20518   */
 20519   /* $SymiscID: bitvec.c v1.0 Win7 2013-02-27 15:16 stable <chm@symisc.net> $ */
 20520  #ifndef VEDIS_AMALGAMATION
 20521  #include "vedisInt.h"
 20522  #endif
 20523  
 20524  /** This file implements an object that represents a dynmaic
 20525  ** bitmap.
 20526  **
 20527  ** A bitmap is used to record which pages of a database file have been
 20528  ** journalled during a transaction, or which pages have the "dont-write"
 20529  ** property.  Usually only a few pages are meet either condition.
 20530  ** So the bitmap is usually sparse and has low cardinality.
 20531  */
 20532  /*
 20533   * Actually, this is not a bitmap but a simple hashtable where page 
 20534   * number (64-bit unsigned integers) are used as the lookup keys.
 20535   */
 20536  typedef struct bitvec_rec bitvec_rec;
 20537  struct bitvec_rec
 20538  {
 20539  	pgno iPage;                  /* Page number */
 20540  	bitvec_rec *pNext,*pNextCol; /* Collison link */
 20541  };
 20542  struct Bitvec
 20543  {
 20544  	SyMemBackend *pAlloc; /* Memory allocator */
 20545  	sxu32 nRec;           /* Total number of records */
 20546  	sxu32 nSize;          /* Table size */
 20547  	bitvec_rec **apRec;   /* Record table */
 20548  	bitvec_rec *pList;    /* List of records */
 20549  };
 20550  /* 
 20551   * Allocate a new bitvec instance.
 20552  */
 20553  VEDIS_PRIVATE Bitvec * vedisBitvecCreate(SyMemBackend *pAlloc,pgno iSize)
 20554  {
 20555  	bitvec_rec **apNew;
 20556  	Bitvec *p;
 20557  	
 20558  	p = (Bitvec *)SyMemBackendAlloc(pAlloc,sizeof(*p) );
 20559  	if( p == 0 ){
 20560  		SXUNUSED(iSize); /* cc warning */
 20561  		return 0;
 20562  	}
 20563  	/* Zero the structure */
 20564  	SyZero(p,sizeof(Bitvec));
 20565  	/* Allocate a new table */
 20566  	p->nSize = 64; /* Must be a power of two */
 20567  	apNew = (bitvec_rec **)SyMemBackendAlloc(pAlloc,p->nSize * sizeof(bitvec_rec *));
 20568  	if( apNew == 0 ){
 20569  		SyMemBackendFree(pAlloc,p);
 20570  		return 0;
 20571  	}
 20572  	/* Zero the new table */
 20573  	SyZero((void *)apNew,p->nSize * sizeof(bitvec_rec *));
 20574  	/* Fill-in */
 20575  	p->apRec = apNew;
 20576  	p->pAlloc = pAlloc;
 20577  	return p;
 20578  }
 20579  /*
 20580   * Check if the given page number is already installed in the table.
 20581   * Return true if installed. False otherwise.
 20582   */
 20583  VEDIS_PRIVATE int vedisBitvecTest(Bitvec *p,pgno i)
 20584  {  
 20585  	bitvec_rec *pRec;
 20586  	/* Point to the desired bucket */
 20587  	pRec = p->apRec[i & (p->nSize - 1)];
 20588  	for(;;){
 20589  		if( pRec == 0 ){ break; }
 20590  		if( pRec->iPage == i ){
 20591  			/* Page found */
 20592  			return 1;
 20593  		}
 20594  		/* Point to the next entry */
 20595  		pRec = pRec->pNextCol;
 20596  
 20597  		if( pRec == 0 ){ break; }
 20598  		if( pRec->iPage == i ){
 20599  			/* Page found */
 20600  			return 1;
 20601  		}
 20602  		/* Point to the next entry */
 20603  		pRec = pRec->pNextCol;
 20604  
 20605  
 20606  		if( pRec == 0 ){ break; }
 20607  		if( pRec->iPage == i ){
 20608  			/* Page found */
 20609  			return 1;
 20610  		}
 20611  		/* Point to the next entry */
 20612  		pRec = pRec->pNextCol;
 20613  
 20614  
 20615  		if( pRec == 0 ){ break; }
 20616  		if( pRec->iPage == i ){
 20617  			/* Page found */
 20618  			return 1;
 20619  		}
 20620  		/* Point to the next entry */
 20621  		pRec = pRec->pNextCol;
 20622  	}
 20623  	/* No such entry */
 20624  	return 0;
 20625  }
 20626  /*
 20627   * Install a given page number in our bitmap (Actually, our hashtable).
 20628   */
 20629  VEDIS_PRIVATE int vedisBitvecSet(Bitvec *p,pgno i)
 20630  {
 20631  	bitvec_rec *pRec;
 20632  	sxi32 iBuck;
 20633  	/* Allocate a new instance */
 20634  	pRec = (bitvec_rec *)SyMemBackendPoolAlloc(p->pAlloc,sizeof(bitvec_rec));
 20635  	if( pRec == 0 ){
 20636  		return VEDIS_NOMEM;
 20637  	}
 20638  	/* Zero the structure */
 20639  	SyZero(pRec,sizeof(bitvec_rec));
 20640  	/* Fill-in */
 20641  	pRec->iPage = i;
 20642  	iBuck = i & (p->nSize - 1);
 20643  	pRec->pNextCol = p->apRec[iBuck];
 20644  	p->apRec[iBuck] = pRec;
 20645  	pRec->pNext = p->pList;
 20646  	p->pList = pRec;
 20647  	p->nRec++;
 20648  	if( p->nRec >= (p->nSize * 3) && p->nRec < 100000 ){
 20649  		/* Grow the hashtable */
 20650  		sxu32 nNewSize = p->nSize << 1;
 20651  		bitvec_rec *pEntry,**apNew;
 20652  		sxu32 n;
 20653  		apNew = (bitvec_rec **)SyMemBackendAlloc(p->pAlloc, nNewSize * sizeof(bitvec_rec *));
 20654  		if( apNew ){
 20655  			sxu32 iBucket;
 20656  			/* Zero the new table */
 20657  			SyZero((void *)apNew, nNewSize * sizeof(bitvec_rec *));
 20658  			/* Rehash all entries */
 20659  			n = 0;
 20660  			pEntry = p->pList;
 20661  			for(;;){
 20662  				/* Loop one */
 20663  				if( n >= p->nRec ){
 20664  					break;
 20665  				}
 20666  				pEntry->pNextCol = 0;
 20667  				/* Install in the new bucket */
 20668  				iBucket = pEntry->iPage & (nNewSize - 1);
 20669  				pEntry->pNextCol = apNew[iBucket];
 20670  				apNew[iBucket] = pEntry;
 20671  				/* Point to the next entry */
 20672  				pEntry = pEntry->pNext;
 20673  				n++;
 20674  			}
 20675  			/* Release the old table and reflect the change */
 20676  			SyMemBackendFree(p->pAlloc,(void *)p->apRec);
 20677  			p->apRec = apNew;
 20678  			p->nSize  = nNewSize;
 20679  		}
 20680  	}
 20681  	return VEDIS_OK;
 20682  }
 20683  /*
 20684   * Destroy a bitvec instance. Reclaim all memory used.
 20685   */
 20686  VEDIS_PRIVATE void vedisBitvecDestroy(Bitvec *p)
 20687  {
 20688  	bitvec_rec *pNext,*pRec = p->pList;
 20689  	SyMemBackend *pAlloc = p->pAlloc;
 20690  	
 20691  	for(;;){
 20692  		if( p->nRec < 1 ){
 20693  			break;
 20694  		}
 20695  		pNext = pRec->pNext;
 20696  		SyMemBackendPoolFree(pAlloc,(void *)pRec);
 20697  		pRec = pNext;
 20698  		p->nRec--;
 20699  
 20700  		if( p->nRec < 1 ){
 20701  			break;
 20702  		}
 20703  		pNext = pRec->pNext;
 20704  		SyMemBackendPoolFree(pAlloc,(void *)pRec);
 20705  		pRec = pNext;
 20706  		p->nRec--;
 20707  
 20708  
 20709  		if( p->nRec < 1 ){
 20710  			break;
 20711  		}
 20712  		pNext = pRec->pNext;
 20713  		SyMemBackendPoolFree(pAlloc,(void *)pRec);
 20714  		pRec = pNext;
 20715  		p->nRec--;
 20716  
 20717  
 20718  		if( p->nRec < 1 ){
 20719  			break;
 20720  		}
 20721  		pNext = pRec->pNext;
 20722  		SyMemBackendPoolFree(pAlloc,(void *)pRec);
 20723  		pRec = pNext;
 20724  		p->nRec--;
 20725  	}
 20726  	SyMemBackendFree(pAlloc,(void *)p->apRec);
 20727  	SyMemBackendFree(pAlloc,p);
 20728  }
 20729  /*
 20730   * ----------------------------------------------------------
 20731   * File: api.c
 20732   * MD5: 8fb4f708f4ac6f1e2b766bbdc73137f1
 20733   * ----------------------------------------------------------
 20734   */
 20735  /*
 20736   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
 20737   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
 20738   * Version 1.2.6
 20739   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 20740   * please contact Symisc Systems via:
 20741   *       legal@symisc.net
 20742   *       licensing@symisc.net
 20743   *       contact@symisc.net
 20744   * or visit:
 20745   *      http://vedis.symisc.net/
 20746   */ 
 20747  /* $SymiscID: api.c v2.0 FreeBSD 2012-11-08 23:07 stable <chm@symisc.net> $ */
 20748  #ifndef VEDIS_AMALGAMATION
 20749  #include "vedisInt.h"
 20750  #endif
 20751  /* This file implement the public interfaces presented to host-applications.
 20752   * Routines in other files are for internal use by Vedis and should not be
 20753   * accessed by users of the library.
 20754   */
 20755  #define VEDIS_DB_MISUSE(DB) (DB == 0 || DB->nMagic != VEDIS_DB_MAGIC)
 20756  /* If another thread have released a working instance, the following macros
 20757   * evaluates to true. These macros are only used when the library
 20758   * is built with threading support enabled.
 20759   */
 20760  #define VEDIS_THRD_DB_RELEASE(DB) (DB->nMagic != VEDIS_DB_MAGIC)
 20761  /* IMPLEMENTATION: vedis@embedded@symisc 115-04-1213 */
 20762  /*
 20763   * All global variables are collected in the structure named "sVedisMPGlobal".
 20764   * That way it is clear in the code when we are using static variable because
 20765   * its name start with sVedisMPGlobal.
 20766   */
 20767  static struct vedisGlobal_Data
 20768  {
 20769  	SyMemBackend sAllocator;                /* Global low level memory allocator */
 20770  #if defined(VEDIS_ENABLE_THREADS)
 20771  	const SyMutexMethods *pMutexMethods;   /* Mutex methods */
 20772  	SyMutex *pMutex;                       /* Global mutex */
 20773  	sxu32 nThreadingLevel;                 /* Threading level: 0 == Single threaded/1 == Multi-Threaded 
 20774  										    * The threading level can be set using the [vedis_lib_config()]
 20775  											* interface with a configuration verb set to
 20776  											* VEDIS_LIB_CONFIG_THREAD_LEVEL_SINGLE or 
 20777  											* VEDIS_LIB_CONFIG_THREAD_LEVEL_MULTI
 20778  											*/
 20779  #endif
 20780  	SySet kv_storage;                       /* Installed KV storage engines */
 20781  	int iPageSize;                          /* Default Page size */
 20782  	vedis_vfs *pVfs;                        /* Underlying virtual file system (Vfs) */
 20783  	sxi32 nStore;                           /* Total number of active Vedis engines */
 20784  	vedis *pStore;                          /* List of active engines */
 20785  	sxu32 nMagic;                           /* Sanity check against library misuse */
 20786  }sVedisMPGlobal = {
 20787  	{0, 0, 0, 0, 0, 0, 0, 0, {0}}, 
 20788  #if defined(VEDIS_ENABLE_THREADS)
 20789  	0, 
 20790  	0, 
 20791  	0, 
 20792  #endif
 20793  	{0, 0, 0, 0, 0, 0, 0 },
 20794  	VEDIS_DEFAULT_PAGE_SIZE,
 20795  	0, 
 20796  	0, 
 20797  	0, 
 20798  	0
 20799  };
 20800  #define VEDIS_LIB_MAGIC  0xAB1495DB
 20801  #define VEDIS_LIB_MISUSE (sVedisMPGlobal.nMagic != VEDIS_LIB_MAGIC)
 20802  /*
 20803   * Supported threading level.
 20804   * These options have meaning only when the library is compiled with multi-threading
 20805   * support. That is, the VEDIS_ENABLE_THREADS compile time directive must be defined
 20806   * when Vedis is built.
 20807   * VEDIS_THREAD_LEVEL_SINGLE:
 20808   *  In this mode, mutexing is disabled and the library can only be used by a single thread.
 20809   * VEDIS_THREAD_LEVEL_MULTI
 20810   *  In this mode, all mutexes including the recursive mutexes on [vedis] objects
 20811   *  are enabled so that the application is free to share the same engine
 20812   *  between different threads at the same time.
 20813   */
 20814  #define VEDIS_THREAD_LEVEL_SINGLE 1 
 20815  #define VEDIS_THREAD_LEVEL_MULTI  2
 20816  /*
 20817   * Find a Key Value storage engine from the set of installed engines.
 20818   * Return a pointer to the storage engine methods on success. NULL on failure.
 20819   */
 20820  VEDIS_PRIVATE vedis_kv_methods * vedisFindKVStore(
 20821  	const char *zName, /* Storage engine name [i.e. Hash, B+tree, LSM, etc.] */
 20822  	sxu32 nByte /* zName length */
 20823  	)
 20824  {
 20825  	vedis_kv_methods **apStore,*pEntry;
 20826  	sxu32 n,nMax;
 20827  	/* Point to the set of installed engines */
 20828  	apStore = (vedis_kv_methods **)SySetBasePtr(&sVedisMPGlobal.kv_storage);
 20829  	nMax = SySetUsed(&sVedisMPGlobal.kv_storage);
 20830  	for( n = 0 ; n < nMax; ++n ){
 20831  		pEntry = apStore[n];
 20832  		if( nByte == SyStrlen(pEntry->zName) && SyStrnicmp(pEntry->zName,zName,nByte) == 0 ){
 20833  			/* Storage engine found */
 20834  			return pEntry;
 20835  		}
 20836  	}
 20837  	/* No such entry, return NULL */
 20838  	return 0;
 20839  }
 20840  /*
 20841   * Configure the Vedis library.
 20842   * Return VEDIS_OK on success. Any other return value indicates failure.
 20843   * Refer to [vedis_lib_config()].
 20844   */
 20845  static sxi32 vedisCoreConfigure(sxi32 nOp, va_list ap)
 20846  {
 20847  	int rc = VEDIS_OK;
 20848  	switch(nOp){
 20849  	    case VEDIS_LIB_CONFIG_PAGE_SIZE: {
 20850  			/* Default page size: Must be a power of two */
 20851  			int iPage = va_arg(ap,int);
 20852  			if( iPage >= VEDIS_MIN_PAGE_SIZE && iPage <= VEDIS_MAX_PAGE_SIZE ){
 20853  				if( !(iPage & (iPage - 1)) ){
 20854  					sVedisMPGlobal.iPageSize = iPage;
 20855  				}else{
 20856  					/* Invalid page size */
 20857  					rc = VEDIS_INVALID;
 20858  				}
 20859  			}else{
 20860  				/* Invalid page size */
 20861  				rc = VEDIS_INVALID;
 20862  			}
 20863  			break;
 20864  										   }
 20865  	    case VEDIS_LIB_CONFIG_STORAGE_ENGINE: {
 20866  			/* Install a key value storage engine */
 20867  			vedis_kv_methods *pMethods = va_arg(ap,vedis_kv_methods *);
 20868  			/* Make sure we are delaing with a valid methods */
 20869  			if( pMethods == 0 || SX_EMPTY_STR(pMethods->zName) || pMethods->xSeek == 0 || pMethods->xData == 0
 20870  				|| pMethods->xKey == 0 || pMethods->xDataLength == 0 || pMethods->xKeyLength == 0 
 20871  				|| pMethods->szKv < (int)sizeof(vedis_kv_engine) ){
 20872  					rc = VEDIS_INVALID;
 20873  					break;
 20874  			}
 20875  			/* Install it */
 20876  			rc = SySetPut(&sVedisMPGlobal.kv_storage,(const void *)&pMethods);
 20877  			break;
 20878  												}
 20879  	    case VEDIS_LIB_CONFIG_VFS:{
 20880  			/* Install a virtual file system */
 20881  			vedis_vfs *pVfs = va_arg(ap,vedis_vfs *);
 20882  			if( pVfs ){
 20883  			 sVedisMPGlobal.pVfs = pVfs;
 20884  			}
 20885  			break;
 20886  								}
 20887  		case VEDIS_LIB_CONFIG_USER_MALLOC: {
 20888  			/* Use an alternative low-level memory allocation routines */
 20889  			const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *);
 20890  			/* Save the memory failure callback (if available) */
 20891  			ProcMemError xMemErr = sVedisMPGlobal.sAllocator.xMemError;
 20892  			void *pMemErr = sVedisMPGlobal.sAllocator.pUserData;
 20893  			if( pMethods == 0 ){
 20894  				/* Use the built-in memory allocation subsystem */
 20895  				rc = SyMemBackendInit(&sVedisMPGlobal.sAllocator, xMemErr, pMemErr);
 20896  			}else{
 20897  				rc = SyMemBackendInitFromOthers(&sVedisMPGlobal.sAllocator, pMethods, xMemErr, pMemErr);
 20898  			}
 20899  			break;
 20900  										  }
 20901  		case VEDIS_LIB_CONFIG_MEM_ERR_CALLBACK: {
 20902  			/* Memory failure callback */
 20903  			ProcMemError xMemErr = va_arg(ap, ProcMemError);
 20904  			void *pUserData = va_arg(ap, void *);
 20905  			sVedisMPGlobal.sAllocator.xMemError = xMemErr;
 20906  			sVedisMPGlobal.sAllocator.pUserData = pUserData;
 20907  			break;
 20908  												 }	  
 20909  		case VEDIS_LIB_CONFIG_USER_MUTEX: {
 20910  #if defined(VEDIS_ENABLE_THREADS)
 20911  			/* Use an alternative low-level mutex subsystem */
 20912  			const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *);
 20913  #if defined (UNTRUST)
 20914  			if( pMethods == 0 ){
 20915  				rc = VEDIS_CORRUPT;
 20916  			}
 20917  #endif
 20918  			/* Sanity check */
 20919  			if( pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0){
 20920  				/* At least three criticial callbacks xEnter(), xLeave() and xNew() must be supplied */
 20921  				rc = VEDIS_CORRUPT;
 20922  				break;
 20923  			}
 20924  			if( sVedisMPGlobal.pMutexMethods ){
 20925  				/* Overwrite the previous mutex subsystem */
 20926  				SyMutexRelease(sVedisMPGlobal.pMutexMethods, sVedisMPGlobal.pMutex);
 20927  				if( sVedisMPGlobal.pMutexMethods->xGlobalRelease ){
 20928  					sVedisMPGlobal.pMutexMethods->xGlobalRelease();
 20929  				}
 20930  				sVedisMPGlobal.pMutex = 0;
 20931  			}
 20932  			/* Initialize and install the new mutex subsystem */
 20933  			if( pMethods->xGlobalInit ){
 20934  				rc = pMethods->xGlobalInit();
 20935  				if ( rc != VEDIS_OK ){
 20936  					break;
 20937  				}
 20938  			}
 20939  			/* Create the global mutex */
 20940  			sVedisMPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
 20941  			if( sVedisMPGlobal.pMutex == 0 ){
 20942  				/*
 20943  				 * If the supplied mutex subsystem is so sick that we are unable to
 20944  				 * create a single mutex, there is no much we can do here.
 20945  				 */
 20946  				if( pMethods->xGlobalRelease ){
 20947  					pMethods->xGlobalRelease();
 20948  				}
 20949  				rc = VEDIS_CORRUPT;
 20950  				break;
 20951  			}
 20952  			sVedisMPGlobal.pMutexMethods = pMethods;			
 20953  			if( sVedisMPGlobal.nThreadingLevel == 0 ){
 20954  				/* Set a default threading level */
 20955  				sVedisMPGlobal.nThreadingLevel = VEDIS_THREAD_LEVEL_MULTI; 
 20956  			}
 20957  #endif
 20958  			break;
 20959  										   }
 20960  		case VEDIS_LIB_CONFIG_THREAD_LEVEL_SINGLE:
 20961  #if defined(VEDIS_ENABLE_THREADS)
 20962  			/* Single thread mode (Only one thread is allowed to play with the library) */
 20963  			sVedisMPGlobal.nThreadingLevel = VEDIS_THREAD_LEVEL_SINGLE;
 20964  #endif
 20965  			break;
 20966  		case VEDIS_LIB_CONFIG_THREAD_LEVEL_MULTI:
 20967  #if defined(VEDIS_ENABLE_THREADS)
 20968  			/* Multi-threading mode (library is thread safe and engines and virtual machines
 20969  			 * may be shared between multiple threads).
 20970  			 */
 20971  			sVedisMPGlobal.nThreadingLevel = VEDIS_THREAD_LEVEL_MULTI;
 20972  #endif
 20973  			break;
 20974  		default:
 20975  			/* Unknown configuration option */
 20976  			rc = VEDIS_CORRUPT;
 20977  			break;
 20978  	}
 20979  	return rc;
 20980  }
 20981  /*
 20982   * [CAPIREF: vedis_lib_config()]
 20983   * Please refer to the official documentation for function purpose and expected parameters.
 20984   */
 20985  int vedis_lib_config(int nConfigOp,...)
 20986  {
 20987  	va_list ap;
 20988  	int rc;
 20989  	if( sVedisMPGlobal.nMagic == VEDIS_LIB_MAGIC ){
 20990  		/* Library is already initialized, this operation is forbidden */
 20991  		return VEDIS_LOCKED;
 20992  	}
 20993  	va_start(ap,nConfigOp);
 20994  	rc = vedisCoreConfigure(nConfigOp,ap);
 20995  	va_end(ap);
 20996  	return rc;
 20997  }
 20998  /*
 20999   * Global library initialization
 21000   * Refer to [vedis_lib_init()]
 21001   * This routine must be called to initialize the memory allocation subsystem, the mutex 
 21002   * subsystem prior to doing any serious work with the library. The first thread to call
 21003   * this routine does the initialization process and set the magic number so no body later
 21004   * can re-initialize the library. If subsequent threads call this  routine before the first
 21005   * thread have finished the initialization process, then the subsequent threads must block 
 21006   * until the initialization process is done.
 21007   */
 21008  static sxi32 vedisCoreInitialize(void)
 21009  {
 21010  	const vedis_kv_methods *pMethods;
 21011  	const vedis_vfs *pVfs; /* Built-in vfs */
 21012  #if defined(VEDIS_ENABLE_THREADS)
 21013  	const SyMutexMethods *pMutexMethods = 0;
 21014  	SyMutex *pMaster = 0;
 21015  #endif
 21016  	int rc;
 21017  	/*
 21018  	 * If the library is already initialized, then a call to this routine
 21019  	 * is a no-op.
 21020  	 */
 21021  	if( sVedisMPGlobal.nMagic == VEDIS_LIB_MAGIC ){
 21022  		return VEDIS_OK; /* Already initialized */
 21023  	}
 21024  #if defined(VEDIS_ENABLE_THREADS)
 21025  	if( sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_SINGLE ){
 21026  		pMutexMethods = sVedisMPGlobal.pMutexMethods;
 21027  		if( pMutexMethods == 0 ){
 21028  			/* Use the built-in mutex subsystem */
 21029  			pMutexMethods = SyMutexExportMethods();
 21030  			if( pMutexMethods == 0 ){
 21031  				return VEDIS_CORRUPT; /* Can't happen */
 21032  			}
 21033  			/* Install the mutex subsystem */
 21034  			rc = vedis_lib_config(VEDIS_LIB_CONFIG_USER_MUTEX, pMutexMethods);
 21035  			if( rc != VEDIS_OK ){
 21036  				return rc;
 21037  			}
 21038  		}
 21039  		/* Obtain a static mutex so we can initialize the library without calling malloc() */
 21040  		pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1);
 21041  		if( pMaster == 0 ){
 21042  			return VEDIS_CORRUPT; /* Can't happen */
 21043  		}
 21044  	}
 21045  	/* Lock the master mutex */
 21046  	rc = VEDIS_OK;
 21047  	SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sVedisMPGlobal.nThreadingLevel == VEDIS_THREAD_LEVEL_SINGLE */
 21048  	if( sVedisMPGlobal.nMagic != VEDIS_LIB_MAGIC ){
 21049  #endif
 21050  		if( sVedisMPGlobal.sAllocator.pMethods == 0 ){
 21051  			/* Install a memory subsystem */
 21052  			rc = vedis_lib_config(VEDIS_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */
 21053  			if( rc != VEDIS_OK ){
 21054  				/* If we are unable to initialize the memory backend, there is no much we can do here.*/
 21055  				goto End;
 21056  			}
 21057  		}
 21058  #if defined(VEDIS_ENABLE_THREADS)
 21059  		if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE ){
 21060  			/* Protect the memory allocation subsystem */
 21061  			rc = SyMemBackendMakeThreadSafe(&sVedisMPGlobal.sAllocator, sVedisMPGlobal.pMutexMethods);
 21062  			if( rc != VEDIS_OK ){
 21063  				goto End;
 21064  			}
 21065  		}
 21066  #endif
 21067  		/* Point to the built-in vfs */
 21068  		pVfs = vedisExportBuiltinVfs();
 21069  		if( sVedisMPGlobal.pVfs == 0 ){
 21070  			/* Install it */
 21071  			vedis_lib_config(VEDIS_LIB_CONFIG_VFS, pVfs);
 21072  		}
 21073  		SySetInit(&sVedisMPGlobal.kv_storage,&sVedisMPGlobal.sAllocator,sizeof(vedis_kv_methods *));
 21074  		/* Install the built-in Key Value storage engines */
 21075  		pMethods = vedisExportMemKvStorage(); /* In-memory storage */
 21076  		vedis_lib_config(VEDIS_LIB_CONFIG_STORAGE_ENGINE,pMethods);
 21077  		/* Default disk key/value storage engine */
 21078  		pMethods = vedisExportDiskKvStorage(); /* Disk storage */
 21079  		vedis_lib_config(VEDIS_LIB_CONFIG_STORAGE_ENGINE,pMethods);
 21080  		/* Default page size */
 21081  		if( sVedisMPGlobal.iPageSize < VEDIS_MIN_PAGE_SIZE ){
 21082  			vedis_lib_config(VEDIS_LIB_CONFIG_PAGE_SIZE,VEDIS_DEFAULT_PAGE_SIZE);
 21083  		}
 21084  		/* Our library is initialized, set the magic number */
 21085  		sVedisMPGlobal.nMagic = VEDIS_LIB_MAGIC;
 21086  		rc = VEDIS_OK;
 21087  #if defined(VEDIS_ENABLE_THREADS)
 21088  	} /* sVedisMPGlobal.nMagic != VEDIS_LIB_MAGIC */
 21089  #endif
 21090  End:
 21091  #if defined(VEDIS_ENABLE_THREADS)
 21092  	/* Unlock the master mutex */
 21093  	SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sVedisMPGlobal.nThreadingLevel == VEDIS_THREAD_LEVEL_SINGLE */
 21094  #endif
 21095  	return rc;
 21096  }
 21097  /*
 21098   * Release a single instance of a Vedis engine.
 21099   */
 21100  static int vedisEngineRelease(vedis *pStore)
 21101  {
 21102  	int rc = VEDIS_OK;
 21103  	if( (pStore->iFlags & VEDIS_FL_DISABLE_AUTO_COMMIT) == 0 ){
 21104  		/* Commit any outstanding transaction */
 21105  		rc = vedisPagerCommit(pStore->pPager);
 21106  		if( rc != VEDIS_OK ){
 21107  			/* Rollback the transaction */
 21108  			rc = vedisPagerRollback(pStore->pPager,FALSE);
 21109  		}
 21110  	}else{
 21111  		/* Rollback any outstanding transaction */
 21112  		rc = vedisPagerRollback(pStore->pPager,FALSE);
 21113  	}
 21114  	/* Close the pager */
 21115  	vedisPagerClose(pStore->pPager);
 21116  	/* Set a dummy magic number */
 21117  	pStore->nMagic = 0x7250;
 21118  	/* Release the whole memory subsystem */
 21119  	SyMemBackendRelease(&pStore->sMem);
 21120  	/* Commit or rollback result */
 21121  	return rc;
 21122  }
 21123  /*
 21124   * Release all resources consumed by the library.
 21125   * Note: This call is not thread safe. Refer to [vedis_lib_shutdown()].
 21126   */
 21127  static void vedisCoreShutdown(void)
 21128  {
 21129  	vedis *pStore, *pNext;
 21130  	/* Release all active databases handles */
 21131  	pStore = sVedisMPGlobal.pStore;
 21132  	for(;;){
 21133  		if( sVedisMPGlobal.nStore < 1 ){
 21134  			break;
 21135  		}
 21136  		pNext = pStore->pNext;
 21137  		vedisEngineRelease(pStore); 
 21138  		pStore = pNext;
 21139  		sVedisMPGlobal.nStore--;
 21140  	}
 21141  	/* Release the storage methods container */
 21142  	SySetRelease(&sVedisMPGlobal.kv_storage);
 21143  #if defined(VEDIS_ENABLE_THREADS)
 21144  	/* Release the mutex subsystem */
 21145  	if( sVedisMPGlobal.pMutexMethods ){
 21146  		if( sVedisMPGlobal.pMutex ){
 21147  			SyMutexRelease(sVedisMPGlobal.pMutexMethods, sVedisMPGlobal.pMutex);
 21148  			sVedisMPGlobal.pMutex = 0;
 21149  		}
 21150  		if( sVedisMPGlobal.pMutexMethods->xGlobalRelease ){
 21151  			sVedisMPGlobal.pMutexMethods->xGlobalRelease();
 21152  		}
 21153  		sVedisMPGlobal.pMutexMethods = 0;
 21154  	}
 21155  	sVedisMPGlobal.nThreadingLevel = 0;
 21156  #endif
 21157  	if( sVedisMPGlobal.sAllocator.pMethods ){
 21158  		/* Release the memory backend */
 21159  		SyMemBackendRelease(&sVedisMPGlobal.sAllocator);
 21160  	}
 21161  	sVedisMPGlobal.nMagic = 0x1764;
 21162  }
 21163  /*
 21164   * [CAPIREF: vedis_lib_init()]
 21165   * Please refer to the official documentation for function purpose and expected parameters.
 21166   */
 21167  int vedis_lib_init(void)
 21168  {
 21169  	int rc;
 21170  	rc = vedisCoreInitialize();
 21171  	return rc;
 21172  }
 21173  /*
 21174   * [CAPIREF: vedis_lib_shutdown()]
 21175   * Please refer to the official documentation for function purpose and expected parameters.
 21176   */
 21177  int vedis_lib_shutdown(void)
 21178  {
 21179  	if( sVedisMPGlobal.nMagic != VEDIS_LIB_MAGIC ){
 21180  		/* Already shut */
 21181  		return VEDIS_OK;
 21182  	}
 21183  	vedisCoreShutdown();
 21184  	return VEDIS_OK;
 21185  }
 21186  /*
 21187   * [CAPIREF: vedis_lib_is_threadsafe()]
 21188   * Please refer to the official documentation for function purpose and expected parameters.
 21189   */
 21190  int vedis_lib_is_threadsafe(void)
 21191  {
 21192  	if( sVedisMPGlobal.nMagic != VEDIS_LIB_MAGIC ){
 21193  		return 0;
 21194  	}
 21195  #if defined(VEDIS_ENABLE_THREADS)
 21196  		if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE ){
 21197  			/* Muli-threading support is enabled */
 21198  			return 1;
 21199  		}else{
 21200  			/* Single-threading */
 21201  			return 0;
 21202  		}
 21203  #else
 21204  	return 0;
 21205  #endif
 21206  }
 21207  /*
 21208   *
 21209   * [CAPIREF: vedis_lib_version()]
 21210   * Please refer to the official documentation for function purpose and expected parameters.
 21211   */
 21212  const char * vedis_lib_version(void)
 21213  {
 21214  	return VEDIS_VERSION;
 21215  }
 21216  /*
 21217   *
 21218   * [CAPIREF: vedis_lib_signature()]
 21219   * Please refer to the official documentation for function purpose and expected parameters.
 21220   */
 21221  const char * vedis_lib_signature(void)
 21222  {
 21223  	return VEDIS_SIG;
 21224  }
 21225  /*
 21226   *
 21227   * [CAPIREF: vedis_lib_ident()]
 21228   * Please refer to the official documentation for function purpose and expected parameters.
 21229   */
 21230  const char * vedis_lib_ident(void)
 21231  {
 21232  	return VEDIS_IDENT;
 21233  }
 21234  /*
 21235   *
 21236   * [CAPIREF: vedis_lib_copyright()]
 21237   * Please refer to the official documentation for function purpose and expected parameters.
 21238   */
 21239  const char * vedis_lib_copyright(void)
 21240  {
 21241  	return VEDIS_COPYRIGHT;
 21242  }
 21243  /*
 21244   * Remove harmfull and/or stale flags passed to the [vedis_open()] interface.
 21245   */
 21246  static unsigned int vedisSanityzeFlag(unsigned int iFlags)
 21247  {
 21248  	iFlags &= ~VEDIS_OPEN_EXCLUSIVE; /* Reserved flag */
 21249  	if( !iFlags ){
 21250  		/* Default flags */
 21251  		iFlags |= VEDIS_OPEN_CREATE;
 21252  	}
 21253  	if( iFlags & VEDIS_OPEN_TEMP_DB ){
 21254  		/* Omit journaling for temporary database */
 21255  		iFlags |= VEDIS_OPEN_OMIT_JOURNALING|VEDIS_OPEN_CREATE;
 21256  	}
 21257  	if( (iFlags & (VEDIS_OPEN_READONLY|VEDIS_OPEN_READWRITE)) == 0 ){
 21258  		/* Auto-append the R+W flag */
 21259  		iFlags |= VEDIS_OPEN_READWRITE;
 21260  	}
 21261  	if( iFlags & VEDIS_OPEN_CREATE ){
 21262  		iFlags &= ~(VEDIS_OPEN_MMAP|VEDIS_OPEN_READONLY);
 21263  		/* Auto-append the R+W flag */
 21264  		iFlags |= VEDIS_OPEN_READWRITE;
 21265  	}else{
 21266  		if( iFlags & VEDIS_OPEN_READONLY ){
 21267  			iFlags &= ~VEDIS_OPEN_READWRITE;
 21268  		}else if( iFlags & VEDIS_OPEN_READWRITE ){
 21269  			iFlags &= ~VEDIS_OPEN_MMAP;
 21270  		}
 21271  	}
 21272  	return iFlags;
 21273  }
 21274  /*
 21275   * This routine does the work of initializing a engine on behalf
 21276   * of [vedis_open()].
 21277   */
 21278  static int vedisInitDatabase(
 21279  	vedis *pStore,            /* Database handle */
 21280  	SyMemBackend *pParent,   /* Master memory backend */
 21281  	const char *zFilename,   /* Target database */
 21282  	unsigned int iFlags      /* Open flags */
 21283  	)
 21284  {
 21285  	vedis_cmd **apTable;
 21286  	int rc;
 21287  	/* Initialiaze the memory subsystem */
 21288  	SyMemBackendInitFromParent(&pStore->sMem,pParent);
 21289  #if defined(VEDIS_ENABLE_THREADS)
 21290  	/* No need for internal mutexes */
 21291  	SyMemBackendDisbaleMutexing(&pStore->sMem);
 21292  #endif
 21293  	SyBlobInit(&pStore->sErr,&pStore->sMem);	
 21294  	/* Sanityze flags */
 21295  	iFlags = vedisSanityzeFlag(iFlags);
 21296  	/* Init the pager and the transaction manager */
 21297  	rc = vedisPagerOpen(sVedisMPGlobal.pVfs,pStore,zFilename,iFlags);
 21298  	if( rc != VEDIS_OK ){
 21299  		return rc;
 21300  	}
 21301  	/* Allocate the command table */
 21302  	apTable = (vedis_cmd **)SyMemBackendAlloc(&pStore->sMem,sizeof(vedis_cmd *) * 64);
 21303  	if( apTable == 0 ){
 21304  		return VEDIS_NOMEM;
 21305  	}
 21306  	/* Zero the table */
 21307  	SyZero((void *)apTable,sizeof(vedis_cmd *) * 64);
 21308  	pStore->apCmd = apTable;
 21309  	pStore->nSize = 64;
 21310  	/* Allocate table bucket */
 21311  	pStore->apTable = (vedis_table **)SyMemBackendAlloc(&pStore->sMem,sizeof(vedis_table *) * 32);
 21312  	if( pStore->apTable == 0 ){
 21313  		return VEDIS_NOMEM;
 21314  	}
 21315  	/* Zero the table */
 21316  	SyZero((void *)pStore->apTable,sizeof(vedis_table *) * 32);
 21317  	pStore->nTableSize = 32;
 21318  	/* Execution result */
 21319  	vedisMemObjInit(pStore,&pStore->sResult);
 21320  	return VEDIS_OK;
 21321  }
 21322  /*
 21323   * Return the default page size.
 21324   */
 21325  VEDIS_PRIVATE int vedisGetPageSize(void)
 21326  {
 21327  	int iSize =  sVedisMPGlobal.iPageSize;
 21328  	if( iSize < VEDIS_MIN_PAGE_SIZE || iSize > VEDIS_MAX_PAGE_SIZE ){
 21329  		iSize = VEDIS_DEFAULT_PAGE_SIZE;
 21330  	}
 21331  	return iSize;
 21332  }
 21333  /*
 21334   * Generate an error message.
 21335   */
 21336  VEDIS_PRIVATE int vedisGenError(vedis *pStore,const char *zErr)
 21337  {
 21338  	int rc;
 21339  	/* Append the error message */
 21340  	rc = SyBlobAppend(&pStore->sErr,(const void *)zErr,SyStrlen(zErr));
 21341  	/* Append a new line */
 21342  	SyBlobAppend(&pStore->sErr,(const void *)"\n",sizeof(char));
 21343  	return rc;
 21344  }
 21345  /*
 21346   * Generate an error message (Printf like).
 21347   */
 21348  VEDIS_PRIVATE int vedisGenErrorFormat(vedis *pStore,const char *zFmt,...)
 21349  {
 21350  	va_list ap;
 21351  	int rc;
 21352  	va_start(ap,zFmt);
 21353  	rc = SyBlobFormatAp(&pStore->sErr,zFmt,ap);
 21354  	va_end(ap);
 21355  	/* Append a new line */
 21356  	SyBlobAppend(&pStore->sErr,(const void *)"\n",sizeof(char));
 21357  	return rc;
 21358  }
 21359  /*
 21360   * Generate an error message (Out of memory).
 21361   */
 21362  VEDIS_PRIVATE int vedisGenOutofMem(vedis *pStore)
 21363  {
 21364  	int rc;
 21365  	rc = vedisGenError(pStore,"Vedis is running out of memory");
 21366  	return rc;
 21367  }
 21368  /*
 21369   * Configure a working Vedis instance.
 21370   */
 21371  static int vedisConfigure(vedis *pStore,int nOp,va_list ap)
 21372  {
 21373  	int rc = VEDIS_OK;
 21374  	switch(nOp){
 21375  	case VEDIS_CONFIG_MAX_PAGE_CACHE: {
 21376  		int max_page = va_arg(ap,int);
 21377  		/* Maximum number of page to cache (Simple hint). */
 21378  		rc = vedisPagerSetCachesize(pStore->pPager,max_page);
 21379  		break;
 21380  										}
 21381  	case VEDIS_CONFIG_ERR_LOG: {
 21382  		/* Database error log if any */
 21383  		const char **pzPtr = va_arg(ap, const char **);
 21384  		int *pLen = va_arg(ap, int *);
 21385  		if( pzPtr == 0 ){
 21386  			rc = VEDIS_CORRUPT;
 21387  			break;
 21388  		}
 21389  		/* NULL terminate the error-log buffer */
 21390  		SyBlobNullAppend(&pStore->sErr);
 21391  		/* Point to the error-log buffer */
 21392  		*pzPtr = (const char *)SyBlobData(&pStore->sErr);
 21393  		if( pLen ){
 21394  			if( SyBlobLength(&pStore->sErr) > 1 /* NULL '\0' terminator */ ){
 21395  				*pLen = (int)SyBlobLength(&pStore->sErr);
 21396  			}else{
 21397  				*pLen = 0;
 21398  			}
 21399  		}
 21400  		break;
 21401  								 }
 21402  	case VEDIS_CONFIG_DISABLE_AUTO_COMMIT:{
 21403  		/* Disable auto-commit */
 21404  		pStore->iFlags |= VEDIS_FL_DISABLE_AUTO_COMMIT;
 21405  		break;
 21406  											}
 21407  	case VEDIS_CONFIG_GET_KV_NAME: {
 21408  		/* Name of the underlying KV storage engine */
 21409  		const char **pzPtr = va_arg(ap,const char **);
 21410  		if( pzPtr ){
 21411  			vedis_kv_engine *pEngine;
 21412  			pEngine = vedisPagerGetKvEngine(pStore);
 21413  			/* Point to the name */
 21414  			*pzPtr = pEngine->pIo->pMethods->zName;
 21415  		}
 21416  		break;
 21417  									 }
 21418  	case VEDIS_CONFIG_DUP_EXEC_VALUE:{
 21419  		/* Duplicate execution value */
 21420  		vedis_value **ppOut = va_arg(ap,vedis_value **);
 21421  		if( ppOut ){
 21422  			vedis_value *pObj = vedisNewObjectValue(pStore,0);
 21423  			if( pObj == 0 ){
 21424  				*ppOut = 0;
 21425  				rc = VEDIS_NOMEM;
 21426  				break;
 21427  			}
 21428  			/* Duplicate */
 21429  			vedisMemObjStore(&pStore->sResult,pObj);
 21430  			*ppOut = pObj;
 21431  		}
 21432  		break;
 21433  									 }
 21434  	case VEDIS_CONFIG_RELEASE_DUP_VALUE: {
 21435  		/* Release a duplicated vedis_value */
 21436  		vedis_value *pIn = va_arg(ap,vedis_value *);
 21437  		if( pIn ){
 21438  			vedisObjectValueDestroy(pStore,pIn);
 21439  		}
 21440  		break;
 21441  										 }
 21442  	case VEDIS_CONFIG_OUTPUT_CONSUMER: {
 21443  		/* Output consumer callback */
 21444  		ProcCmdConsumer xCons = va_arg(ap,ProcCmdConsumer);
 21445  		void *pUserData = va_arg(ap,void *);
 21446  		pStore->xResultConsumer = xCons;
 21447  		pStore->pUserData = pUserData;
 21448  		break;
 21449  									   }
 21450  	default:
 21451  		/* Unknown configuration option */
 21452  		rc = VEDIS_UNKNOWN;
 21453  		break;
 21454  	}
 21455  	return rc;
 21456  }
 21457  /*
 21458   * Export the global (master) memory allocator to submodules.
 21459   */
 21460  VEDIS_PRIVATE const SyMemBackend * vedisExportMemBackend(void)
 21461  {
 21462  	return &sVedisMPGlobal.sAllocator;
 21463  }
 21464  /*
 21465   * Default data consumer callback. That is, all retrieved is redirected to this
 21466   * routine which store the output in an internal blob.
 21467   */
 21468  VEDIS_PRIVATE int vedisDataConsumer(
 21469  	const void *pOut,   /* Data to consume */
 21470  	unsigned int nLen,  /* Data length */
 21471  	void *pUserData     /* User private data */
 21472  	)
 21473  {
 21474  	 sxi32 rc;
 21475  	 /* Store the output in an internal BLOB */
 21476  	 rc = SyBlobAppend((SyBlob *)pUserData, pOut, nLen);
 21477  	 return rc;
 21478  }
 21479  /*
 21480   * Fetch an installed vedis command.
 21481   */
 21482  VEDIS_PRIVATE vedis_cmd * vedisFetchCommand(vedis *pVedis,SyString *pName)
 21483  {
 21484  	vedis_cmd *pCmd;
 21485  	sxu32 nH;
 21486  	if( pVedis->nCmd < 1 ){
 21487  		/* Don't bother hashing */
 21488  		return 0;
 21489  	}
 21490  	/* Hash the name */
 21491  	nH = SyBinHash(pName->zString,pName->nByte);
 21492  	/* Point to the corresponding bucket */
 21493  	pCmd = pVedis->apCmd[nH & (pVedis->nSize - 1)];
 21494  	/* Perform the lookup */
 21495  	for(;;){
 21496  		if( pCmd == 0 ){
 21497  			break;
 21498  		}
 21499  		if( pCmd->nHash == nH && SyStringCmp(&pCmd->sName,pName,SyMemcmp) == 0 ){
 21500  			/* Got command */
 21501  			return pCmd;
 21502  		}
 21503  		/* Point to the next item */
 21504  		pCmd = pCmd->pNextCol;
 21505  	}
 21506  	/* No such command */
 21507  	return 0;
 21508  }
 21509  /*
 21510   * Install a vedis command.
 21511   */
 21512  static int vedisInstallCommand(vedis *pVedis,const char *zName,ProcVedisCmd xCmd,void *pUserData)
 21513  {
 21514  	SyMemBackend *pAlloc = &sVedisMPGlobal.sAllocator;
 21515  	vedis_cmd *pCmd;
 21516  	SyString sName;
 21517  	sxu32 nBucket;
 21518  	char *zDup;
 21519  	sxu32 nLen;
 21520  	/* Check for an existing command with the same name */
 21521  	nLen = SyStrlen(zName);
 21522  	SyStringInitFromBuf(&sName,zName,nLen);
 21523  	pCmd = vedisFetchCommand(pVedis,&sName);
 21524  	if( pCmd ){
 21525  		/* Already installed */
 21526  		pCmd->xCmd = xCmd;
 21527  		pCmd->pUserData = pUserData;
 21528  		SySetReset(&pCmd->aAux);
 21529  		return VEDIS_OK;
 21530  	}
 21531  	/* Allocate a new instance */
 21532  	pCmd = (vedis_cmd *)SyMemBackendAlloc(pAlloc,sizeof(vedis_cmd)+nLen);
 21533  	if( pCmd == 0 ){
 21534  		return VEDIS_NOMEM;
 21535  	}
 21536  	/* Zero the structure */
 21537  	SyZero(pCmd,sizeof(vedis_cmd));
 21538  	/* Fill-in */
 21539  	SySetInit(&pCmd->aAux,&pVedis->sMem,sizeof(vedis_aux_data));
 21540  	pCmd->nHash = SyBinHash(zName,nLen);
 21541  	pCmd->xCmd = xCmd;
 21542  	pCmd->pUserData = pUserData;
 21543  	zDup = (char *)&pCmd[1];
 21544  	SyMemcpy(zName,zDup,nLen);
 21545  	SyStringInitFromBuf(&pCmd->sName,zDup,nLen);
 21546  	/* Install the command */
 21547  	MACRO_LD_PUSH(pVedis->pList,pCmd);
 21548  	pVedis->nCmd++;
 21549  	nBucket = pCmd->nHash & (pVedis->nSize - 1);
 21550  	pCmd->pNextCol = pVedis->apCmd[nBucket];
 21551  	if( pVedis->apCmd[nBucket] ){
 21552  		pVedis->apCmd[nBucket]->pPrevCol = pCmd;
 21553  	}
 21554  	pVedis->apCmd[nBucket] = pCmd;
 21555  	if( (pVedis->nCmd >= pVedis->nSize * 3) && pVedis->nCmd < 100000 ){
 21556  		/* Rehash */
 21557  		sxu32 nNewSize = pVedis->nSize << 1;
 21558  		vedis_cmd *pEntry;
 21559  		vedis_cmd **apNew;
 21560  		sxu32 n;
 21561  		/* Allocate a new larger table */
 21562  		apNew = (vedis_cmd **)SyMemBackendAlloc(&pVedis->sMem, nNewSize * sizeof(vedis_cmd *));
 21563  		if( apNew ){
 21564  			/* Zero the new table */
 21565  			SyZero((void *)apNew, nNewSize * sizeof(vedis_cmd *));
 21566  			/* Rehash all entries */
 21567  			n = 0;
 21568  			pEntry = pVedis->pList;
 21569  			for(;;){
 21570  				/* Loop one */
 21571  				if( n >= pVedis->nCmd ){
 21572  					break;
 21573  				}
 21574  				pEntry->pNextCol = pEntry->pPrevCol = 0;
 21575  				/* Install in the new bucket */
 21576  				nBucket = pEntry->nHash & (nNewSize - 1);
 21577  				pEntry->pNextCol = apNew[nBucket];
 21578  				if( apNew[nBucket] ){
 21579  					apNew[nBucket]->pPrevCol = pEntry;
 21580  				}
 21581  				apNew[nBucket] = pEntry;
 21582  				/* Point to the next entry */
 21583  				pEntry = pEntry->pNext;
 21584  				n++;
 21585  			}
 21586  			/* Release the old table and reflect the change */
 21587  			SyMemBackendFree(&pVedis->sMem,(void *)pVedis->apCmd);
 21588  			pVedis->apCmd = apNew;
 21589  			pVedis->nSize  = nNewSize;
 21590  		}
 21591  	}
 21592  	return VEDIS_OK;
 21593  }
 21594  /*
 21595   * Remove a vedis command.
 21596   */
 21597  static int vedisRemoveCommand(vedis *pVedis,const char *zCmd)
 21598  {
 21599  	vedis_cmd *pCmd;
 21600  	SyString sName;
 21601  	SyStringInitFromBuf(&sName,zCmd,SyStrlen(zCmd));
 21602  	/* Fetch the command first */
 21603  	pCmd = vedisFetchCommand(pVedis,&sName);
 21604  	if( pCmd == 0 ){
 21605  		/* No such command */
 21606  		return VEDIS_NOTFOUND;
 21607  	}
 21608  	/* Unlink */
 21609  	if( pCmd->pNextCol ){
 21610  		pCmd->pNextCol->pPrevCol = pCmd->pPrevCol;
 21611  	}
 21612  	if( pCmd->pPrevCol ){
 21613  		pCmd->pPrevCol->pNextCol = pCmd->pNextCol;
 21614  	}else{
 21615  		sxu32 nBucket;
 21616  		nBucket = pCmd->nHash & (pVedis->nSize - 1);
 21617  		pVedis->apCmd[nBucket] = pCmd->pNextCol;
 21618  	}
 21619  	MACRO_LD_REMOVE(pVedis->pList,pCmd);
 21620  	pVedis->nCmd--;
 21621  	/* Release */
 21622  	SyMemBackendFree(&sVedisMPGlobal.sAllocator,pCmd);
 21623  	return VEDIS_OK;
 21624  }
 21625  /*
 21626   * [CAPIREF: vedis_open()]
 21627   * Please refer to the official documentation for function purpose and expected parameters.
 21628   */
 21629  int vedis_open(vedis **ppStore,const char *zStorage)
 21630  {
 21631  	vedis *pHandle;
 21632  	int rc;
 21633  #if defined(UNTRUST)
 21634  	if( ppStore == 0 ){
 21635  		return VEDIS_CORRUPT;
 21636  	}
 21637  #endif
 21638  	*ppStore = 0;
 21639  	/* One-time automatic library initialization */
 21640  	rc = vedisCoreInitialize();
 21641  	if( rc != VEDIS_OK ){
 21642  		return rc;
 21643  	}
 21644  	/* Allocate a new engine instance */
 21645  	pHandle = (vedis *)SyMemBackendPoolAlloc(&sVedisMPGlobal.sAllocator, sizeof(vedis));
 21646  	if( pHandle == 0 ){
 21647  		return VEDIS_NOMEM;
 21648  	}
 21649  	/* Zero the structure */
 21650  	SyZero(pHandle,sizeof(vedis));
 21651  	/* Init the database */
 21652  	rc = vedisInitDatabase(pHandle,&sVedisMPGlobal.sAllocator,zStorage,0);
 21653  	if( rc != VEDIS_OK ){
 21654  		goto Release;
 21655  	}
 21656  	/* Set the magic number to identify a valid DB handle */
 21657  	 pHandle->nMagic = VEDIS_DB_MAGIC;
 21658  	 /* Register built-in vedis commands */
 21659  	vedisRegisterBuiltinCommands(pHandle);
 21660  	/* Install the commit callback */
 21661  	vedisPagerSetCommitCallback(pHandle->pPager,vedisOnCommit,pHandle);
 21662  #if defined(VEDIS_ENABLE_THREADS)
 21663  	if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE ){
 21664  		 /* Associate a recursive mutex with this instance */
 21665  		 pHandle->pMutex = SyMutexNew(sVedisMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
 21666  		 if( pHandle->pMutex == 0 ){
 21667  			 rc = VEDIS_NOMEM;
 21668  			 goto Release;
 21669  		 }
 21670  	 }
 21671  #endif
 21672  	/* Link to the list of active engines */
 21673  #if defined(VEDIS_ENABLE_THREADS)
 21674  	/* Enter the global mutex */
 21675  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, sVedisMPGlobal.pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel == VEDIS_THREAD_LEVEL_SINGLE */
 21676  #endif
 21677  	 MACRO_LD_PUSH(sVedisMPGlobal.pStore,pHandle);
 21678  	 sVedisMPGlobal.nStore++;
 21679  #if defined(VEDIS_ENABLE_THREADS)
 21680  	/* Leave the global mutex */
 21681  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods, sVedisMPGlobal.pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel == VEDIS_THREAD_LEVEL_SINGLE */
 21682  #endif
 21683  	/* Make the handle available to the caller */
 21684  	*ppStore = pHandle;
 21685  	return VEDIS_OK;
 21686  Release:
 21687  	SyMemBackendRelease(&pHandle->sMem);
 21688  	SyMemBackendPoolFree(&sVedisMPGlobal.sAllocator,pHandle);
 21689  	return rc;
 21690  }
 21691  /*
 21692   * [CAPIREF: vedis_config()]
 21693   * Please refer to the official documentation for function purpose and expected parameters.
 21694   */
 21695  int vedis_config(vedis *pStore,int nConfigOp,...)
 21696  {
 21697  	va_list ap;
 21698  	int rc;
 21699  	if( VEDIS_DB_MISUSE(pStore) ){
 21700  		return VEDIS_CORRUPT;
 21701  	}
 21702  #if defined(VEDIS_ENABLE_THREADS)
 21703  	 /* Acquire DB mutex */
 21704  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21705  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21706  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21707  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21708  	 }
 21709  #endif
 21710  	 va_start(ap, nConfigOp);
 21711  	 rc = vedisConfigure(&(*pStore),nConfigOp, ap);
 21712  	 va_end(ap);
 21713  #if defined(VEDIS_ENABLE_THREADS)
 21714  	 /* Leave DB mutex */
 21715  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21716  #endif
 21717  	return rc;
 21718  }
 21719  /*
 21720   * [CAPIREF: vedis_close()]
 21721   * Please refer to the official documentation for function purpose and expected parameters.
 21722   */
 21723  int vedis_close(vedis *pStore)
 21724  {
 21725  	int rc;
 21726  	if( VEDIS_DB_MISUSE(pStore) ){
 21727  		return VEDIS_CORRUPT;
 21728  	}
 21729  #if defined(VEDIS_ENABLE_THREADS)
 21730  	 /* Acquire DB mutex */
 21731  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21732  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21733  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21734  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21735  	 }
 21736  #endif
 21737  	/* Release the engine */
 21738  	rc = vedisEngineRelease(pStore);
 21739  #if defined(VEDIS_ENABLE_THREADS)
 21740  	 /* Leave DB mutex */
 21741  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21742  	 /* Release DB mutex */
 21743  	 SyMutexRelease(sVedisMPGlobal.pMutexMethods, pStore->pMutex) /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21744  #endif
 21745  #if defined(VEDIS_ENABLE_THREADS)
 21746  	/* Enter the global mutex */
 21747  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, sVedisMPGlobal.pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel == VEDIS_THREAD_LEVEL_SINGLE */
 21748  #endif
 21749  	/* Unlink from the list of active engines */
 21750  	 MACRO_LD_REMOVE(sVedisMPGlobal.pStore, pStore);
 21751  	sVedisMPGlobal.nStore--;
 21752  #if defined(VEDIS_ENABLE_THREADS)
 21753  	/* Leave the global mutex */
 21754  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods, sVedisMPGlobal.pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel == VEDIS_THREAD_LEVEL_SINGLE */
 21755  #endif
 21756  	/* Release the memory chunk allocated to this handle */
 21757  	SyMemBackendPoolFree(&sVedisMPGlobal.sAllocator,pStore);
 21758  	return rc;
 21759  }
 21760  /*
 21761   * [CAPIREF: vedis_exec()]
 21762   * Please refer to the official documentation for function purpose and expected parameters.
 21763   */
 21764  int vedis_exec(vedis *pStore,const char *zCmd,int nLen)
 21765  {
 21766  	int rc;
 21767  	if( VEDIS_DB_MISUSE(pStore) ){
 21768  		return VEDIS_CORRUPT;
 21769  	}
 21770  #if defined(VEDIS_ENABLE_THREADS)
 21771  	 /* Acquire DB mutex */
 21772  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21773  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21774  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21775  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21776  	 }
 21777  #endif
 21778  	 /* Tokenize, parse and execute */
 21779  	 rc = vedisProcessInput(pStore,zCmd,nLen < 0 ? /* Assume a null terminated string */ SyStrlen(zCmd) : (sxu32)nLen);
 21780  #if defined(VEDIS_ENABLE_THREADS)
 21781  	 /* Leave DB mutex */
 21782  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21783  #endif
 21784  	 /* Execution result */
 21785  	return rc;
 21786  }
 21787  /*
 21788   * [CAPIREF: vedis_exec_fmt()]
 21789   * Please refer to the official documentation for function purpose and expected parameters.
 21790   */
 21791  int vedis_exec_fmt(vedis *pStore,const char *zFmt,...)
 21792  {
 21793  	SyBlob sWorker;
 21794  	va_list ap;
 21795  	int rc;
 21796  #if defined(VEDIS_ENABLE_THREADS)
 21797  	 /* Acquire DB mutex */
 21798  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21799  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21800  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21801  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21802  	 }
 21803  #endif
 21804  	 SyBlobInit(&sWorker,&pStore->sMem);
 21805  	 va_start(ap,zFmt);
 21806  	 SyBlobFormatAp(&sWorker,zFmt,ap);
 21807  	 va_end(ap);
 21808  	 /* Execute */
 21809  	 rc = vedisProcessInput(pStore,(const char *)SyBlobData(&sWorker),SyBlobLength(&sWorker));
 21810  	 /* Cleanup */
 21811  	 SyBlobRelease(&sWorker);
 21812  #if defined(VEDIS_ENABLE_THREADS)
 21813  	 /* Leave DB mutex */
 21814  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21815  #endif
 21816  	 /* Execution result */
 21817  	return rc;
 21818  }
 21819  /*
 21820   * [CAPIREF: vedis_exec_result()]
 21821   * Please refer to the official documentation for function purpose and expected parameters.
 21822   */
 21823  int vedis_exec_result(vedis *pStore,vedis_value **ppOut)
 21824  {
 21825  	if( VEDIS_DB_MISUSE(pStore) ){
 21826  		return VEDIS_CORRUPT;
 21827  	}
 21828  #if defined(VEDIS_ENABLE_THREADS)
 21829  	 /* Acquire DB mutex */
 21830  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21831  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21832  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21833  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21834  	 }
 21835  #endif
 21836  	 if(ppOut ){
 21837  		 *ppOut = &pStore->sResult;
 21838  	 }
 21839  #if defined(VEDIS_ENABLE_THREADS)
 21840  	 /* Leave DB mutex */
 21841  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21842  #endif
 21843  	return VEDIS_OK;
 21844  }
 21845  /*
 21846   * [CAPIREF: vedis_register_command()]
 21847   * Please refer to the official documentation for function purpose and expected parameters.
 21848   */
 21849  int vedis_register_command(vedis *pStore,const char *zName,int (*xCmd)(vedis_context *,int,vedis_value **),void *pUserdata)
 21850  {
 21851  	int rc;
 21852  	if( VEDIS_DB_MISUSE(pStore) || xCmd == 0){
 21853  		return VEDIS_CORRUPT;
 21854  	}
 21855  #if defined(VEDIS_ENABLE_THREADS)
 21856  	 /* Acquire DB mutex */
 21857  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21858  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21859  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21860  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21861  	 }
 21862  #endif
 21863  	 /* Install the command */
 21864  	 rc = vedisInstallCommand(pStore,zName,xCmd,pUserdata);
 21865  #if defined(VEDIS_ENABLE_THREADS)
 21866  	 /* Leave DB mutex */
 21867  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21868  #endif
 21869  	return rc;
 21870  }
 21871  /*
 21872   * [CAPIREF: vedis_delete_command()]
 21873   * Please refer to the official documentation for function purpose and expected parameters.
 21874   */
 21875  int vedis_delete_command(vedis *pStore,const char *zName)
 21876  {
 21877  	int rc;
 21878  	if( VEDIS_DB_MISUSE(pStore) ){
 21879  		return VEDIS_CORRUPT;
 21880  	}
 21881  #if defined(VEDIS_ENABLE_THREADS)
 21882  	 /* Acquire DB mutex */
 21883  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21884  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 21885  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 21886  			 return VEDIS_ABORT; /* Another thread have released this instance */
 21887  	 }
 21888  #endif
 21889  	 /* Delete the command */
 21890  	 rc = vedisRemoveCommand(pStore,zName);
 21891  #if defined(VEDIS_ENABLE_THREADS)
 21892  	 /* Leave DB mutex */
 21893  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 21894  #endif
 21895  	return rc;
 21896  }
 21897  /*
 21898   * [CAPIREF: vedis_context_throw_error()]
 21899   * Please refer to the official documentation for function purpose and expected parameters.
 21900   */
 21901  int vedis_context_throw_error(vedis_context *pCtx, int iErr, const char *zErr)
 21902  {
 21903  	if( zErr ){
 21904  		SyBlob *pErr = &pCtx->pVedis->sErr;
 21905  		const char *zErrType = "-Error-";
 21906  		/* Severity */
 21907  		switch(iErr){
 21908  		case VEDIS_CTX_WARNING: zErrType = "-Warning-"; break;
 21909  		case VEDIS_CTX_NOTICE:  zErrType = "-Notice-";  break;
 21910  		default: break;
 21911  		}
 21912  		/* Generate the error message */
 21913  		SyBlobFormat(pErr,"%z: %s %s\n",&pCtx->pCmd->sName,zErrType,zErr);
 21914  	}
 21915  	return VEDIS_OK;
 21916  }
 21917  /*
 21918   * [CAPIREF: vedis_context_throw_error_format()]
 21919   * Please refer to the official documentation for function purpose and expected parameters.
 21920   */
 21921  int vedis_context_throw_error_format(vedis_context *pCtx, int iErr, const char *zFormat, ...)
 21922  {
 21923  	SyBlob *pErr = &pCtx->pVedis->sErr;
 21924  	const char *zErr = "-Error-";
 21925  	va_list ap;
 21926  	
 21927  	if( zFormat == 0){
 21928  		return VEDIS_OK;
 21929  	}
 21930  	/* Severity */
 21931  	switch(iErr){
 21932  	case VEDIS_CTX_WARNING: zErr = "-Warning-"; break;
 21933  	case VEDIS_CTX_NOTICE:  zErr = "-Notice-";  break;
 21934  	default: break;
 21935  	}
 21936  	/* Generate the error message */
 21937  	SyBlobFormat(pErr,"%z: %s",&pCtx->pCmd->sName,zErr);
 21938  	va_start(ap, zFormat);
 21939  	SyBlobFormatAp(pErr,zFormat,ap);
 21940  	va_end(ap);
 21941  	SyBlobAppend(pErr,(const void *)"\n",sizeof(char));
 21942  	return VEDIS_OK;
 21943  }
 21944  /*
 21945   * [CAPIREF: vedis_context_random_num()]
 21946   * Please refer to the official documentation for function purpose and expected parameters.
 21947   */
 21948  unsigned int vedis_context_random_num(vedis_context *pCtx)
 21949  {
 21950  	sxu32 n;
 21951  	n = vedisPagerRandomNum(pCtx->pVedis->pPager);
 21952  	return n;
 21953  }
 21954  /*
 21955   * [CAPIREF: vedis_context_random_string()]
 21956   * Please refer to the official documentation for function purpose and expected parameters.
 21957   */
 21958  int vedis_context_random_string(vedis_context *pCtx, char *zBuf, int nBuflen)
 21959  {
 21960  	if( nBuflen < 3 ){
 21961  		return VEDIS_CORRUPT;
 21962  	}
 21963  	vedisPagerRandomString(pCtx->pVedis->pPager, zBuf, nBuflen);
 21964  	return VEDIS_OK;
 21965  }
 21966  /*
 21967   * [CAPIREF: vedis_context_user_data()]
 21968   * Please refer to the official documentation for function purpose and expected parameters.
 21969   */
 21970  void * vedis_context_user_data(vedis_context *pCtx)
 21971  {
 21972  	return pCtx->pCmd->pUserData;
 21973  }
 21974  /*
 21975   * [CAPIREF: vedis_context_push_aux_data()]
 21976   * Please refer to the official documentation for function purpose and expected parameters.
 21977   */
 21978  int vedis_context_push_aux_data(vedis_context *pCtx, void *pUserData)
 21979  {
 21980  	vedis_aux_data sAux;
 21981  	int rc;
 21982  	sAux.pAuxData = pUserData;
 21983  	rc = SySetPut(&pCtx->pCmd->aAux, (const void *)&sAux);
 21984  	return rc;
 21985  }
 21986  /*
 21987   * [CAPIREF: vedis_context_peek_aux_data()]
 21988   * Please refer to the official documentation for function purpose and expected parameters.
 21989   */
 21990  void * vedis_context_peek_aux_data(vedis_context *pCtx)
 21991  {
 21992  	vedis_aux_data *pAux;
 21993  	pAux = (vedis_aux_data *)SySetPeek(&pCtx->pCmd->aAux);
 21994  	return pAux ? pAux->pAuxData : 0;
 21995  }
 21996  /*
 21997   * [CAPIREF: vedis_context_pop_aux_data()]
 21998   * Please refer to the official documentation for function purpose and expected parameters.
 21999   */
 22000  void * vedis_context_pop_aux_data(vedis_context *pCtx)
 22001  {
 22002  	vedis_aux_data *pAux;
 22003  	pAux = (vedis_aux_data *)SySetPop(&pCtx->pCmd->aAux);
 22004  	return pAux ? pAux->pAuxData : 0;
 22005  }
 22006  /*
 22007   * [CAPIREF: vedis_context_new_scalar()]
 22008   * Please refer to the official documentation for function purpose and expected parameters.
 22009   */
 22010  vedis_value * vedis_context_new_scalar(vedis_context *pCtx)
 22011  {
 22012  	vedis_value *pVal;
 22013  	pVal = vedisNewObjectValue(pCtx->pVedis,0);
 22014  	if( pVal ){
 22015  		/* Record value address so it can be freed automatically
 22016  		 * when the calling function returns. 
 22017  		 */
 22018  		SySetPut(&pCtx->sVar, (const void *)&pVal);
 22019  	}
 22020  	return pVal;
 22021  }
 22022  /*
 22023   * [CAPIREF: vedis_context_new_array()]
 22024   * Please refer to the official documentation for function purpose and expected parameters.
 22025   */
 22026  vedis_value * vedis_context_new_array(vedis_context *pCtx)
 22027  {
 22028  	vedis_value *pVal;
 22029  	pVal = vedisNewObjectArrayValue(pCtx->pVedis);
 22030  	if( pVal ){
 22031  		/* Record value address so it can be freed automatically
 22032  		 * when the calling function returns. 
 22033  		 */
 22034  		SySetPut(&pCtx->sVar, (const void *)&pVal);
 22035  	}
 22036  	return pVal;
 22037  }
 22038  /*
 22039   * [CAPIREF: vedis_context_release_value()]
 22040   * Please refer to the official documentation for function purpose and expected parameters.
 22041   */
 22042  void vedis_context_release_value(vedis_context *pCtx, vedis_value *pValue)
 22043  {
 22044  	if( pValue == 0 ){
 22045  		/* NULL value is a harmless operation */
 22046  		return;
 22047  	}
 22048  	if( SySetUsed(&pCtx->sVar) > 0 ){
 22049  		vedis_value **apObj = (vedis_value **)SySetBasePtr(&pCtx->sVar);
 22050  		sxu32 n;
 22051  		for( n = 0 ; n < SySetUsed(&pCtx->sVar) ; ++n ){
 22052  			if( apObj[n] == pValue ){
 22053  				vedisObjectValueDestroy(pCtx->pVedis,pValue);
 22054  				/* Mark as released */
 22055  				apObj[n] = 0;
 22056  				break;
 22057  			}
 22058  		}
 22059  	}
 22060  }
 22061  /*
 22062   * [CAPIREF: vedis_array_walk()]
 22063   * Please refer to the official documentation for function purpose and expected parameters.
 22064   */
 22065  int vedis_array_walk(vedis_value *pArray, int (*xWalk)(vedis_value *, void *), void *pUserData)
 22066  {
 22067  	int rc;
 22068  	if( xWalk == 0 ){
 22069  		return VEDIS_CORRUPT;
 22070  	}
 22071  	/* Make sure we are dealing with a valid hashmap */
 22072  	if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){
 22073  		return VEDIS_CORRUPT;
 22074  	}
 22075  	/* Start the walk process */
 22076  	rc = vedisHashmapWalk((vedis_hashmap *)pArray->x.pOther, xWalk, pUserData);
 22077  	return rc != VEDIS_OK ? VEDIS_ABORT /* User callback request an operation abort*/ : VEDIS_OK;
 22078  }
 22079  /*
 22080   * [CAPIREF: vedis_array_reset()]
 22081   * Please refer to the official documentation for function purpose and expected parameters.
 22082   */
 22083  int vedis_array_reset(vedis_value *pArray)
 22084  {
 22085  	/* Make sure we are dealing with a valid hashmap */
 22086  	if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){
 22087  		return 0;
 22088  	}
 22089  	vedisHashmapResetLoopCursor((vedis_hashmap *)pArray->x.pOther);
 22090  	return VEDIS_OK;
 22091  }
 22092  /*
 22093   * [CAPIREF: vedis_array_fetch()]
 22094   * Please refer to the official documentation for function purpose and expected parameters.
 22095   */
 22096  vedis_value * vedis_array_fetch(vedis_value *pArray,unsigned int index)
 22097  {
 22098  	vedis_value *pValue = 0; /* cc warning */
 22099  	vedis_hashmap *pMap;
 22100  	vedis_value skey;
 22101  	int rc;
 22102  	/* Make sure we are dealing with a valid hashmap */
 22103  	if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){
 22104  		return 0;
 22105  	}
 22106  	pMap = (vedis_hashmap *)pArray->x.pOther;
 22107  	/* Convert the key to a vedis_value  */
 22108  	vedisMemObjInitFromInt(vedisHashmapGetEngine(pMap),&skey,(vedis_int64)index);
 22109  	/* Perform the lookup */
 22110  	rc = vedisHashmapLookup(pMap,&skey,&pValue);
 22111  	vedisMemObjRelease(&skey);
 22112  	if( rc != VEDIS_OK ){
 22113  		/* No such entry */
 22114  		return 0;
 22115  	}
 22116  	return pValue;
 22117  }
 22118  /*
 22119   * [CAPIREF: vedis_array_insert()]
 22120   * Please refer to the official documentation for function purpose and expected parameters.
 22121   */
 22122  int vedis_array_insert(vedis_value *pArray,vedis_value *pValue)
 22123  {
 22124  	int rc;
 22125  	/* Make sure we are dealing with a valid hashmap */
 22126  	if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){
 22127  		return VEDIS_CORRUPT;
 22128  	}
 22129  	/* Perform the insertion */
 22130  	rc = vedisHashmapInsert((vedis_hashmap *)pArray->x.pOther, 0 /* Assign an automatic index */, &(*pValue));
 22131  	return rc;
 22132  }
 22133  /*
 22134   * [CAPIREF: vedis_array_next_elem()]
 22135   * Please refer to the official documentation for function purpose and expected parameters.
 22136   */
 22137  vedis_value * vedis_array_next_elem(vedis_value *pArray)
 22138  {
 22139  	vedis_value *pValue;
 22140  	/* Make sure we are dealing with a valid hashmap */
 22141  	if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){
 22142  		return 0;
 22143  	}
 22144  	/* Extract the current element */
 22145  	pValue = vedisHashmapGetNextEntry((vedis_hashmap *)pArray->x.pOther);
 22146  	return pValue;
 22147  }
 22148  /*
 22149   * [CAPIREF: vedis_array_count()]
 22150   * Please refer to the official documentation for function purpose and expected parameters.
 22151   */
 22152  unsigned int vedis_array_count(vedis_value *pArray)
 22153  {
 22154  	/* Make sure we are dealing with a valid hashmap */
 22155  	if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){
 22156  		return 0;
 22157  	}
 22158  	return vedisHashmapCount((vedis_hashmap *)pArray->x.pOther);
 22159  }
 22160  /*
 22161   * [CAPIREF: vedis_result_int()]
 22162   * Please refer to the official documentation for function purpose and expected parameters.
 22163   */
 22164  int vedis_result_int(vedis_context *pCtx, int iValue)
 22165  {
 22166  	return vedis_value_int(pCtx->pRet, iValue);
 22167  }
 22168  /*
 22169   * [CAPIREF: vedis_result_int64()]
 22170   * Please refer to the official documentation for function purpose and expected parameters.
 22171   */
 22172  int vedis_result_int64(vedis_context *pCtx, vedis_int64 iValue)
 22173  {
 22174  	return vedis_value_int64(pCtx->pRet, iValue);
 22175  }
 22176  /*
 22177   * [CAPIREF: vedis_result_bool()]
 22178   * Please refer to the official documentation for function purpose and expected parameters.
 22179   */
 22180  int vedis_result_bool(vedis_context *pCtx, int iBool)
 22181  {
 22182  	return vedis_value_bool(pCtx->pRet, iBool);
 22183  }
 22184  /*
 22185   * [CAPIREF: vedis_result_double()]
 22186   * Please refer to the official documentation for function purpose and expected parameters.
 22187   */
 22188  int vedis_result_double(vedis_context *pCtx, double Value)
 22189  {
 22190  	return vedis_value_double(pCtx->pRet, Value);
 22191  }
 22192  /*
 22193   * [CAPIREF: vedis_result_null()]
 22194   * Please refer to the official documentation for function purpose and expected parameters.
 22195   */
 22196  int vedis_result_null(vedis_context *pCtx)
 22197  {
 22198  	/* Invalidate any prior representation and set the NULL flag */
 22199  	vedisMemObjRelease(pCtx->pRet);
 22200  	return VEDIS_OK;
 22201  }
 22202  /*
 22203   * [CAPIREF: vedis_result_string()]
 22204   * Please refer to the official documentation for function purpose and expected parameters.
 22205   */
 22206  int vedis_result_string(vedis_context *pCtx, const char *zString, int nLen)
 22207  {
 22208  	return vedis_value_string(pCtx->pRet, zString, nLen);
 22209  }
 22210  /*
 22211   * [CAPIREF: vedis_result_string_format()]
 22212   * Please refer to the official documentation for function purpose and expected parameters.
 22213   */
 22214  int vedis_result_string_format(vedis_context *pCtx, const char *zFormat, ...)
 22215  {
 22216  	vedis_value *p;
 22217  	va_list ap;
 22218  	int rc;
 22219  	p = pCtx->pRet;
 22220  	if( (p->iFlags & MEMOBJ_STRING) == 0 ){
 22221  		/* Invalidate any prior representation */
 22222  		vedisMemObjRelease(p);
 22223  		MemObjSetType(p, MEMOBJ_STRING);
 22224  	}
 22225  	/* Format the given string */
 22226  	va_start(ap, zFormat);
 22227  	rc = SyBlobFormatAp(&p->sBlob, zFormat, ap);
 22228  	va_end(ap);
 22229  	return rc;
 22230  }
 22231  /*
 22232   * [CAPIREF: vedis_result_value()]
 22233   * Please refer to the official documentation for function purpose and expected parameters.
 22234   */
 22235  int vedis_result_value(vedis_context *pCtx, vedis_value *pValue)
 22236  {
 22237  	int rc = VEDIS_OK;
 22238  	if( pValue == 0 ){
 22239  		vedisMemObjRelease(pCtx->pRet);
 22240  	}else{
 22241  		rc = vedisMemObjStore(pValue, pCtx->pRet);
 22242  	}
 22243  	return rc;
 22244  }
 22245  /*
 22246   * [CAPIREF: vedis_value_to_int()]
 22247   * Please refer to the official documentation for function purpose and expected parameters.
 22248   */
 22249  int vedis_value_to_int(vedis_value *pValue)
 22250  {
 22251  	int rc;
 22252  	rc = vedisMemObjToInteger(pValue);
 22253  	if( rc != VEDIS_OK ){
 22254  		return 0;
 22255  	}
 22256  	return (int)pValue->x.iVal;
 22257  }
 22258  /*
 22259   * [CAPIREF: vedis_value_to_bool()]
 22260   * Please refer to the official documentation for function purpose and expected parameters.
 22261   */
 22262  int vedis_value_to_bool(vedis_value *pValue)
 22263  {
 22264  	int rc;
 22265  	rc = vedisMemObjToBool(pValue);
 22266  	if( rc != VEDIS_OK ){
 22267  		return 0;
 22268  	}
 22269  	return (int)pValue->x.iVal;
 22270  }
 22271  /*
 22272   * [CAPIREF: vedis_value_to_int64()]
 22273   * Please refer to the official documentation for function purpose and expected parameters.
 22274   */
 22275  vedis_int64 vedis_value_to_int64(vedis_value *pValue)
 22276  {
 22277  	int rc;
 22278  	rc = vedisMemObjToInteger(pValue);
 22279  	if( rc != VEDIS_OK ){
 22280  		return 0;
 22281  	}
 22282  	return pValue->x.iVal;
 22283  }
 22284  /*
 22285   * [CAPIREF: vedis_value_to_double()]
 22286   * Please refer to the official documentation for function purpose and expected parameters.
 22287   */
 22288  double vedis_value_to_double(vedis_value *pValue)
 22289  {
 22290  	int rc;
 22291  	rc = vedisMemObjToReal(pValue);
 22292  	if( rc != VEDIS_OK ){
 22293  		return (double)0;
 22294  	}
 22295  	return (double)pValue->x.rVal;
 22296  }
 22297  /*
 22298   * [CAPIREF: vedis_value_to_string()]
 22299   * Please refer to the official documentation for function purpose and expected parameters.
 22300   */
 22301  const char * vedis_value_to_string(vedis_value *pValue, int *pLen)
 22302  {
 22303  	vedisMemObjToString(pValue);
 22304  	if( SyBlobLength(&pValue->sBlob) > 0 ){
 22305  		SyBlobNullAppend(&pValue->sBlob);
 22306  		if( pLen ){
 22307  			*pLen = (int)SyBlobLength(&pValue->sBlob);
 22308  		}
 22309  		return (const char *)SyBlobData(&pValue->sBlob);
 22310  	}else{
 22311  		/* Return the empty string */
 22312  		if( pLen ){
 22313  			*pLen = 0;
 22314  		}
 22315  		return "";
 22316  	}
 22317  }
 22318  /*
 22319   * [CAPIREF: vedis_value_int()]
 22320   * Please refer to the official documentation for function purpose and expected parameters.
 22321   */
 22322  int vedis_value_int(vedis_value *pVal, int iValue)
 22323  {
 22324  	/* Invalidate any prior representation */
 22325  	vedisMemObjRelease(pVal);
 22326  	pVal->x.iVal = (vedis_int64)iValue;
 22327  	MemObjSetType(pVal, MEMOBJ_INT);
 22328  	return VEDIS_OK;
 22329  }
 22330  /*
 22331   * [CAPIREF: vedis_value_int64()]
 22332   * Please refer to the official documentation for function purpose and expected parameters.
 22333   */
 22334  int vedis_value_int64(vedis_value *pVal, vedis_int64 iValue)
 22335  {
 22336  	/* Invalidate any prior representation */
 22337  	vedisMemObjRelease(pVal);
 22338  	pVal->x.iVal = iValue;
 22339  	MemObjSetType(pVal, MEMOBJ_INT);
 22340  	return VEDIS_OK;
 22341  }
 22342  /*
 22343   * [CAPIREF: vedis_value_bool()]
 22344   * Please refer to the official documentation for function purpose and expected parameters.
 22345   */
 22346  int vedis_value_bool(vedis_value *pVal, int iBool)
 22347  {
 22348  	/* Invalidate any prior representation */
 22349  	vedisMemObjRelease(pVal);
 22350  	pVal->x.iVal = iBool ? 1 : 0;
 22351  	MemObjSetType(pVal, MEMOBJ_BOOL);
 22352  	return VEDIS_OK;
 22353  }
 22354  /*
 22355   * [CAPIREF: vedis_value_null()]
 22356   * Please refer to the official documentation for function purpose and expected parameters.
 22357   */
 22358  int vedis_value_null(vedis_value *pVal)
 22359  {
 22360  	/* Invalidate any prior representation and set the NULL flag */
 22361  	vedisMemObjRelease(pVal);
 22362  	return VEDIS_OK;
 22363  }
 22364  /*
 22365   * [CAPIREF: vedis_value_double()]
 22366   * Please refer to the official documentation for function purpose and expected parameters.
 22367   */
 22368  int vedis_value_double(vedis_value *pVal, double Value)
 22369  {
 22370  	/* Invalidate any prior representation */
 22371  	vedisMemObjRelease(pVal);
 22372  	pVal->x.rVal = (vedis_real)Value;
 22373  	MemObjSetType(pVal, MEMOBJ_REAL);
 22374  	/* Try to get an integer representation also */
 22375  	vedisMemObjTryInteger(pVal);
 22376  	return VEDIS_OK;
 22377  }
 22378  /*
 22379   * [CAPIREF: vedis_value_string()]
 22380   * Please refer to the official documentation for function purpose and expected parameters.
 22381   */
 22382  int vedis_value_string(vedis_value *pVal, const char *zString, int nLen)
 22383  {
 22384  	if((pVal->iFlags & MEMOBJ_STRING) == 0 ){
 22385  		/* Invalidate any prior representation */
 22386  		vedisMemObjRelease(pVal);
 22387  		MemObjSetType(pVal, MEMOBJ_STRING);
 22388  	}
 22389  	if( zString ){
 22390  		if( nLen < 0 ){
 22391  			/* Compute length automatically */
 22392  			nLen = (int)SyStrlen(zString);
 22393  		}
 22394  		SyBlobAppend(&pVal->sBlob, (const void *)zString, (sxu32)nLen);
 22395  	}
 22396  	return VEDIS_OK;
 22397  }
 22398  /*
 22399   * [CAPIREF: vedis_value_string_format()]
 22400   * Please refer to the official documentation for function purpose and expected parameters.
 22401   */
 22402  int vedis_value_string_format(vedis_value *pVal, const char *zFormat, ...)
 22403  {
 22404  	va_list ap;
 22405  	int rc;
 22406  	if((pVal->iFlags & MEMOBJ_STRING) == 0 ){
 22407  		/* Invalidate any prior representation */
 22408  		vedisMemObjRelease(pVal);
 22409  		MemObjSetType(pVal, MEMOBJ_STRING);
 22410  	}
 22411  	va_start(ap, zFormat);
 22412  	rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap);
 22413  	va_end(ap);
 22414  	return VEDIS_OK;
 22415  }
 22416  /*
 22417   * [CAPIREF: vedis_value_reset_string_cursor()]
 22418   * Please refer to the official documentation for function purpose and expected parameters.
 22419   */
 22420  int vedis_value_reset_string_cursor(vedis_value *pVal)
 22421  {
 22422  	/* Reset the string cursor */
 22423  	SyBlobReset(&pVal->sBlob);
 22424  	return VEDIS_OK;
 22425  }
 22426  /*
 22427   * [CAPIREF: vedis_value_release()]
 22428   * Please refer to the official documentation for function purpose and expected parameters.
 22429   */
 22430  int vedis_value_release(vedis_value *pVal)
 22431  {
 22432  	vedisMemObjRelease(pVal);
 22433  	return VEDIS_OK;
 22434  }
 22435  /*
 22436   * [CAPIREF: vedis_value_is_int()]
 22437   * Please refer to the official documentation for function purpose and expected parameters.
 22438   */
 22439  int vedis_value_is_int(vedis_value *pVal)
 22440  {
 22441  	return (pVal->iFlags & MEMOBJ_INT) ? TRUE : FALSE;
 22442  }
 22443  /*
 22444   * [CAPIREF: vedis_value_is_float()]
 22445   * Please refer to the official documentation for function purpose and expected parameters.
 22446   */
 22447  int vedis_value_is_float(vedis_value *pVal)
 22448  {
 22449  	return (pVal->iFlags & MEMOBJ_REAL) ? TRUE : FALSE;
 22450  }
 22451  /*
 22452   * [CAPIREF: vedis_value_is_bool()]
 22453   * Please refer to the official documentation for function purpose and expected parameters.
 22454   */
 22455  int vedis_value_is_bool(vedis_value *pVal)
 22456  {
 22457  	return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE;
 22458  }
 22459  /*
 22460   * [CAPIREF: vedis_value_is_string()]
 22461   * Please refer to the official documentation for function purpose and expected parameters.
 22462   */
 22463  int vedis_value_is_string(vedis_value *pVal)
 22464  {
 22465  	return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE;
 22466  }
 22467  /*
 22468   * [CAPIREF: vedis_value_is_null()]
 22469   * Please refer to the official documentation for function purpose and expected parameters.
 22470   */
 22471  int vedis_value_is_null(vedis_value *pVal)
 22472  {
 22473  	return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE;
 22474  }
 22475  /*
 22476   * [CAPIREF: vedis_value_is_numeric()]
 22477   * Please refer to the official documentation for function purpose and expected parameters.
 22478   */
 22479  int vedis_value_is_numeric(vedis_value *pVal)
 22480  {
 22481  	int rc;
 22482  	rc = vedisMemObjIsNumeric(pVal);
 22483  	return rc;
 22484  }
 22485  /*
 22486   * [CAPIREF: vedis_value_is_scalar()]
 22487   * Please refer to the official documentation for function purpose and expected parameters.
 22488   */
 22489  int vedis_value_is_scalar(vedis_value *pVal)
 22490  {
 22491  	return (pVal->iFlags & MEMOBJ_SCALAR) ? TRUE : FALSE;
 22492  }
 22493  /*
 22494   * [CAPIREF: vedis_value_is_json_array()]
 22495   * Please refer to the official documentation for function purpose and expected parameters.
 22496   */
 22497  int vedis_value_is_array(vedis_value *pVal)
 22498  {
 22499  	return (pVal->iFlags & MEMOBJ_HASHMAP) ? TRUE : FALSE;
 22500  }
 22501  /*
 22502   * Refer to [vedis_kv_store()].
 22503   */
 22504  static int vedisKvStore(vedis *pStore,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen)
 22505  {
 22506  	vedis_kv_engine *pEngine;
 22507  	int rc;
 22508  	/* Point to the underlying storage engine */
 22509  	 pEngine = vedisPagerGetKvEngine(pStore);
 22510  	 if( pEngine->pIo->pMethods->xReplace == 0 ){
 22511  		 /* Storage engine does not implement such method */
 22512  		 vedisGenError(pStore,"xReplace() method not implemented in the underlying storage engine");
 22513  		 rc = VEDIS_NOTIMPLEMENTED;
 22514  	 }else{
 22515  		 if( nKeyLen < 0 ){
 22516  			 /* Assume a null terminated string and compute its length */
 22517  			 nKeyLen = SyStrlen((const char *)pKey);
 22518  		 }
 22519  		 if( !nKeyLen ){
 22520  			 vedisGenError(pStore,"Empty key");
 22521  			 rc = VEDIS_EMPTY;
 22522  		 }else{
 22523  			 /* Perform the requested operation */
 22524  			 rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,pData,nDataLen);
 22525  		 }
 22526  	 }
 22527  	 return rc;
 22528  }
 22529  /*
 22530   * [CAPIREF: vedis_kv_store()]
 22531   * Please refer to the official documentation for function purpose and expected parameters.
 22532   */
 22533  int vedis_kv_store(vedis *pStore,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen)
 22534  {
 22535  	int rc;
 22536  	if( VEDIS_DB_MISUSE(pStore) ){
 22537  		return VEDIS_CORRUPT;
 22538  	}
 22539  #if defined(VEDIS_ENABLE_THREADS)
 22540  	 /* Acquire DB mutex */
 22541  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22542  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22543  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22544  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22545  	 }
 22546  #endif
 22547  	 rc = vedisKvStore(pStore,pKey,nKeyLen,pData,nDataLen);
 22548  #if defined(VEDIS_ENABLE_THREADS)
 22549  	 /* Leave DB mutex */
 22550  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22551  #endif
 22552  	return rc;
 22553  }
 22554  /*
 22555   * [CAPIREF: vedis_kv_store_fmt()]
 22556   * Please refer to the official documentation for function purpose and expected parameters.
 22557   */
 22558  int vedis_kv_store_fmt(vedis *pStore,const void *pKey,int nKeyLen,const char *zFormat,...)
 22559  {
 22560  	SyBlob sWorker; /* Working buffer */
 22561  	va_list ap;
 22562  	int rc;
 22563  	if( VEDIS_DB_MISUSE(pStore) ){
 22564  		return VEDIS_CORRUPT;
 22565  	}
 22566  #if defined(VEDIS_ENABLE_THREADS)
 22567  	 /* Acquire DB mutex */
 22568  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22569  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22570  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22571  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22572  	 }
 22573  #endif
 22574  	 SyBlobInit(&sWorker,&pStore->sMem);
 22575  	 /* Format the data */
 22576  	 va_start(ap,zFormat);
 22577  	 SyBlobFormatAp(&sWorker,zFormat,ap);
 22578  	 va_end(ap);
 22579  	 /* Perform the requested operation */
 22580  	 rc = vedisKvStore(pStore,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker));
 22581  	 /* Clean up */
 22582  	 SyBlobRelease(&sWorker);
 22583  #if defined(VEDIS_ENABLE_THREADS)
 22584  	 /* Leave DB mutex */
 22585  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22586  #endif
 22587  	return rc;
 22588  }
 22589  /*
 22590   * Refer to [vedis_kv_append()].
 22591   */
 22592  static int vedisKvAppend(vedis *pStore,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen)
 22593  {
 22594  	vedis_kv_engine *pEngine;
 22595  	int rc;
 22596  	/* Point to the underlying storage engine */
 22597  	 pEngine = vedisPagerGetKvEngine(pStore);
 22598  	 if( pEngine->pIo->pMethods->xAppend == 0 ){
 22599  		 /* Storage engine does not implement such method */
 22600  		 vedisGenError(pStore,"xAppend() method not implemented in the underlying storage engine");
 22601  		 rc = VEDIS_NOTIMPLEMENTED;
 22602  	 }else{
 22603  		 if( nKeyLen < 0 ){
 22604  			 /* Assume a null terminated string and compute its length */
 22605  			 nKeyLen = SyStrlen((const char *)pKey);
 22606  		 }
 22607  		 if( !nKeyLen ){
 22608  			 vedisGenError(pStore,"Empty key");
 22609  			 rc = VEDIS_EMPTY;
 22610  		 }else{
 22611  			 /* Perform the requested operation */
 22612  			 rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,pData,nDataLen);
 22613  		 }
 22614  	 }
 22615  	 return rc;
 22616  }
 22617  /*
 22618   * [CAPIREF: vedis_kv_append()]
 22619   * Please refer to the official documentation for function purpose and expected parameters.
 22620   */
 22621  int vedis_kv_append(vedis *pStore,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen)
 22622  {
 22623  	int rc;
 22624  	if( VEDIS_DB_MISUSE(pStore) ){
 22625  		return VEDIS_CORRUPT;
 22626  	}
 22627  #if defined(VEDIS_ENABLE_THREADS)
 22628  	 /* Acquire DB mutex */
 22629  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22630  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22631  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22632  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22633  	 }
 22634  #endif
 22635  	 rc = vedisKvAppend(pStore,pKey,nKeyLen,pData,nDataLen);
 22636  #if defined(VEDIS_ENABLE_THREADS)
 22637  	 /* Leave DB mutex */
 22638  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22639  #endif
 22640  	return rc;
 22641  }
 22642  /*
 22643   * [CAPIREF: vedis_kv_append_fmt()]
 22644   * Please refer to the official documentation for function purpose and expected parameters.
 22645   */
 22646  int vedis_kv_append_fmt(vedis *pStore,const void *pKey,int nKeyLen,const char *zFormat,...)
 22647  {
 22648  	SyBlob sWorker; /* Working buffer */
 22649  	va_list ap;
 22650  	int rc;
 22651  	if( VEDIS_DB_MISUSE(pStore) ){
 22652  		return VEDIS_CORRUPT;
 22653  	}
 22654  #if defined(VEDIS_ENABLE_THREADS)
 22655  	 /* Acquire DB mutex */
 22656  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22657  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22658  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22659  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22660  	 }
 22661  #endif
 22662  	 SyBlobInit(&sWorker,&pStore->sMem);
 22663  	 /* Format the data */
 22664  	 va_start(ap,zFormat);
 22665  	 SyBlobFormatAp(&sWorker,zFormat,ap);
 22666  	 va_end(ap);
 22667  	 /* Perform the requested operation */
 22668  	 rc = vedisKvAppend(pStore,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker));
 22669  	 /* Clean up */
 22670  	 SyBlobRelease(&sWorker);
 22671  #if defined(VEDIS_ENABLE_THREADS)
 22672  	 /* Leave DB mutex */
 22673  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22674  #endif
 22675  	return rc;
 22676  }
 22677  /*
 22678   * Refer to [vedis_kv_fetch()].
 22679   */
 22680  static int vedisKvFetch(vedis *pStore,const void *pKey,int nKeyLen,void *pBuf,vedis_int64 *pBufLen)
 22681  {
 22682  	vedis_kv_methods *pMethods;
 22683  	vedis_kv_engine *pEngine;
 22684  	vedis_kv_cursor *pCur;
 22685  	int rc;
 22686  	/* Point to the underlying storage engine */
 22687  	 pEngine = vedisPagerGetKvEngine(pStore);
 22688  	 pMethods = pEngine->pIo->pMethods;
 22689  	 pCur = pStore->pCursor;
 22690  	 if( nKeyLen < 0 ){
 22691  		 /* Assume a null terminated string and compute its length */
 22692  		 nKeyLen = SyStrlen((const char *)pKey);
 22693  	 }
 22694  	 if( !nKeyLen ){
 22695  		  vedisGenError(pStore,"Empty key");
 22696  		  rc = VEDIS_EMPTY;
 22697  	 }else{
 22698  		  /* Seek to the record position */
 22699  		  rc = pMethods->xSeek(pCur,pKey,nKeyLen,VEDIS_CURSOR_MATCH_EXACT);
 22700  	 }
 22701  	 if( rc == VEDIS_OK ){
 22702  		 if( pBuf == 0 ){
 22703  			 /* Data length only */
 22704  			 rc = pMethods->xDataLength(pCur,pBufLen);
 22705  		 }else{
 22706  			 SyBlob sBlob;
 22707  			 /* Initialize the data consumer */
 22708  			 SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)*pBufLen);
 22709  			 /* Consume the data */
 22710  			 rc = pMethods->xData(pCur,vedisDataConsumer,&sBlob);
 22711  			 /* Data length */
 22712  			 *pBufLen = (vedis_int64)SyBlobLength(&sBlob);
 22713  			 /* Cleanup */
 22714  			 SyBlobRelease(&sBlob);
 22715  		 }
 22716  	 }
 22717  	 return rc;
 22718  }
 22719  /*
 22720   * [CAPIREF: vedis_kv_fetch()]
 22721   * Please refer to the official documentation for function purpose and expected parameters.
 22722   */
 22723  int vedis_kv_fetch(vedis *pStore,const void *pKey,int nKeyLen,void *pBuf,vedis_int64 *pBufLen)
 22724  {
 22725  	int rc;
 22726  	if( VEDIS_DB_MISUSE(pStore) ){
 22727  		return VEDIS_CORRUPT;
 22728  	}
 22729  #if defined(VEDIS_ENABLE_THREADS)
 22730  	 /* Acquire DB mutex */
 22731  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22732  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22733  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22734  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22735  	 }
 22736  #endif
 22737  	 rc = vedisKvFetch(pStore,pKey,nKeyLen,pBuf,pBufLen);
 22738  #if defined(VEDIS_ENABLE_THREADS)
 22739  	 /* Leave DB mutex */
 22740  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22741  #endif
 22742  	return rc;
 22743  }
 22744  /*
 22745   * Refer to [vedis_kv_fetch_callback()].
 22746   */
 22747  VEDIS_PRIVATE int vedisKvFetchCallback(vedis *pStore,const void *pKey,int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 22748  {
 22749  	vedis_kv_methods *pMethods;
 22750  	vedis_kv_engine *pEngine;
 22751  	vedis_kv_cursor *pCur;
 22752  	int rc;
 22753  	/* Point to the underlying storage engine */
 22754  	 pEngine = vedisPagerGetKvEngine(pStore);
 22755  	 pMethods = pEngine->pIo->pMethods;
 22756  	 pCur = pStore->pCursor;
 22757  	 if( nKeyLen < 0 ){
 22758  		 /* Assume a null terminated string and compute its length */
 22759  		 nKeyLen = SyStrlen((const char *)pKey);
 22760  	 }
 22761  	 if( !nKeyLen ){
 22762  		 vedisGenError(pStore,"Empty key");
 22763  		 rc = VEDIS_EMPTY;
 22764  	 }else{
 22765  		 /* Seek to the record position */
 22766  		 rc = pMethods->xSeek(pCur,pKey,nKeyLen,VEDIS_CURSOR_MATCH_EXACT);
 22767  	 }
 22768  	 if( rc == VEDIS_OK && xConsumer ){
 22769  		 /* Consume the data directly */
 22770  		 rc = pMethods->xData(pCur,xConsumer,pUserData);	 
 22771  	 }
 22772  	return rc;
 22773  }
 22774  /*
 22775   * [CAPIREF: vedis_kv_fetch_callback()]
 22776   * Please refer to the official documentation for function purpose and expected parameters.
 22777   */
 22778  int vedis_kv_fetch_callback(vedis *pStore,const void *pKey,int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 22779  {
 22780  	int rc;
 22781  	if( VEDIS_DB_MISUSE(pStore) ){
 22782  		return VEDIS_CORRUPT;
 22783  	}
 22784  #if defined(VEDIS_ENABLE_THREADS)
 22785  	 /* Acquire DB mutex */
 22786  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22787  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22788  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22789  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22790  	 }
 22791  #endif
 22792  	 rc = vedisKvFetchCallback(pStore,pKey,nKeyLen,xConsumer,pUserData);
 22793  #if defined(VEDIS_ENABLE_THREADS)
 22794  	 /* Leave DB mutex */
 22795  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22796  #endif
 22797  	return rc;
 22798  }
 22799  /*
 22800   * Refer to [vedis_kv_delete()].
 22801   */
 22802  VEDIS_PRIVATE int vedisKvDelete(vedis *pStore,const void *pKey,int nKeyLen)
 22803  {
 22804  	vedis_kv_methods *pMethods;
 22805  	vedis_kv_engine *pEngine;
 22806  	vedis_kv_cursor *pCur;
 22807  	int rc;
 22808  	/* Point to the underlying storage engine */
 22809  	 pEngine = vedisPagerGetKvEngine(pStore);
 22810  	 pMethods = pEngine->pIo->pMethods;
 22811  	 pCur = pStore->pCursor;
 22812  	 if( pMethods->xDelete == 0 ){
 22813  		 /* Storage engine does not implement such method */
 22814  		 vedisGenError(pStore,"xDelete() method not implemented in the underlying storage engine");
 22815  		 rc = VEDIS_NOTIMPLEMENTED;
 22816  	 }else{
 22817  		 if( nKeyLen < 0 ){
 22818  			 /* Assume a null terminated string and compute its length */
 22819  			 nKeyLen = SyStrlen((const char *)pKey);
 22820  		 }
 22821  		 if( !nKeyLen ){
 22822  			 vedisGenError(pStore,"Empty key");
 22823  			 rc = VEDIS_EMPTY;
 22824  		 }else{
 22825  			 /* Seek to the record position */
 22826  			 rc = pMethods->xSeek(pCur,pKey,nKeyLen,VEDIS_CURSOR_MATCH_EXACT);
 22827  		 }
 22828  		 if( rc == VEDIS_OK ){
 22829  			 /* Exact match found, delete the entry */
 22830  			 rc = pMethods->xDelete(pCur);
 22831  		 }
 22832  	 }
 22833  	return rc;
 22834  }
 22835  /*
 22836   * [CAPIREF: vedis_kv_config()]
 22837   * Please refer to the official documentation for function purpose and expected parameters.
 22838   */
 22839  int vedis_kv_config(vedis *pStore,int iOp,...)
 22840  {
 22841  	vedis_kv_engine *pEngine;
 22842  	int rc;
 22843  	if( VEDIS_DB_MISUSE(pStore) ){
 22844  		return VEDIS_CORRUPT;
 22845  	}
 22846  #if defined(VEDIS_ENABLE_THREADS)
 22847  	 /* Acquire DB mutex */
 22848  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22849  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22850  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22851  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22852  	 }
 22853  #endif
 22854  	 /* Point to the underlying storage engine */
 22855  	 pEngine = vedisPagerGetKvEngine(pStore);
 22856  	 if( pEngine->pIo->pMethods->xConfig == 0 ){
 22857  		 /* Storage engine does not implements such method */
 22858  		 vedisGenError(pStore,"xConfig() method not implemented in the underlying storage engine");
 22859  		 rc = VEDIS_NOTIMPLEMENTED;
 22860  	 }else{
 22861  		 va_list ap;
 22862  		 /* Configure the storage engine */
 22863  		 va_start(ap,iOp);
 22864  		 rc = pEngine->pIo->pMethods->xConfig(pEngine,iOp,ap);
 22865  		 va_end(ap);
 22866  	 }
 22867  #if defined(VEDIS_ENABLE_THREADS)
 22868  	 /* Leave DB mutex */
 22869  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22870  #endif
 22871  	return rc;
 22872  }
 22873  /*
 22874   * [CAPIREF: vedis_kv_delete()]
 22875   * Please refer to the official documentation for function purpose and expected parameters.
 22876   */
 22877  int vedis_kv_delete(vedis *pStore,const void *pKey,int nKeyLen)
 22878  {
 22879  	int rc;
 22880  	if( VEDIS_DB_MISUSE(pStore) ){
 22881  		return VEDIS_CORRUPT;
 22882  	}
 22883  #if defined(VEDIS_ENABLE_THREADS)
 22884  	 /* Acquire DB mutex */
 22885  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22886  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 22887  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 22888  			 return VEDIS_ABORT; /* Another thread have released this instance */
 22889  	 }
 22890  #endif
 22891  	 rc = vedisKvDelete(pStore,pKey,nKeyLen);
 22892  #if defined(VEDIS_ENABLE_THREADS)
 22893  	 /* Leave DB mutex */
 22894  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 22895  #endif
 22896  	return rc;
 22897  }
 22898  /*
 22899   * [CAPIREF: vedis_context_kv_store()]
 22900   * Please refer to the official documentation for function purpose and expected parameters.
 22901   */
 22902  int vedis_context_kv_store(vedis_context *pCtx,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen)
 22903  {
 22904  	int rc;
 22905  	rc = vedisKvStore(pCtx->pVedis,pKey,nKeyLen,pData,nDataLen);
 22906  	return rc;
 22907  }
 22908  /*
 22909   * [CAPIREF: vedis_context_kv_append()]
 22910   * Please refer to the official documentation for function purpose and expected parameters.
 22911   */
 22912  int vedis_context_kv_append(vedis_context *pCtx,const void *pKey,int nKeyLen,const void *pData,vedis_int64 nDataLen)
 22913  {
 22914  	int rc;
 22915  	rc = vedisKvAppend(pCtx->pVedis,pKey,nKeyLen,pData,nDataLen);
 22916  	return rc;
 22917  }
 22918  /*
 22919   * [CAPIREF: vedis_context_kv_store_fmt()]
 22920   * Please refer to the official documentation for function purpose and expected parameters.
 22921   */
 22922  int vedis_context_kv_store_fmt(vedis_context *pCtx,const void *pKey,int nKeyLen,const char *zFormat,...)
 22923  {
 22924  	SyBlob sWorker; /* Working buffer */
 22925  	va_list ap;
 22926  	int rc;
 22927  	SyBlobInit(&sWorker,&pCtx->pVedis->sMem);
 22928  	/* Format the data */
 22929  	va_start(ap,zFormat);
 22930  	SyBlobFormatAp(&sWorker,zFormat,ap);
 22931  	va_end(ap);
 22932  	/* Perform the requested operation */
 22933  	rc = vedisKvStore(pCtx->pVedis,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker));
 22934  	/* Clean up */
 22935  	SyBlobRelease(&sWorker);
 22936  	return rc;
 22937  }
 22938  /*
 22939   * [CAPIREF: vedis_context_kv_append_fmt()]
 22940   * Please refer to the official documentation for function purpose and expected parameters.
 22941   */
 22942  int vedis_context_kv_append_fmt(vedis_context *pCtx,const void *pKey,int nKeyLen,const char *zFormat,...)
 22943  {
 22944  	SyBlob sWorker; /* Working buffer */
 22945  	va_list ap;
 22946  	int rc;
 22947  	SyBlobInit(&sWorker,&pCtx->pVedis->sMem);
 22948  	/* Format the data */
 22949  	va_start(ap,zFormat);
 22950  	SyBlobFormatAp(&sWorker,zFormat,ap);
 22951  	va_end(ap);
 22952  	/* Perform the requested operation */
 22953  	rc = vedisKvAppend(pCtx->pVedis,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker));
 22954  	/* Clean up */
 22955  	SyBlobRelease(&sWorker);
 22956  	return rc;
 22957  }
 22958  /*
 22959   * [CAPIREF: vedis_context_kv_fetch()]
 22960   * Please refer to the official documentation for function purpose and expected parameters.
 22961   */
 22962  int vedis_context_kv_fetch(vedis_context *pCtx,const void *pKey,int nKeyLen,void *pBuf,vedis_int64 /* in|out */*pBufLen)
 22963  {
 22964  	int rc;
 22965  	rc = vedisKvFetch(pCtx->pVedis,pKey,nKeyLen,pBuf,pBufLen);
 22966  	return rc;
 22967  }
 22968  /*
 22969   * [CAPIREF: vedis_context_kv_fetch_callback()]
 22970   * Please refer to the official documentation for function purpose and expected parameters.
 22971   */
 22972  int vedis_context_kv_fetch_callback(vedis_context *pCtx,const void *pKey,
 22973  	                    int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData)
 22974  {
 22975  	int rc;
 22976  	rc = vedisKvFetchCallback(pCtx->pVedis,pKey,nKeyLen,xConsumer,pUserData);
 22977  	return rc;
 22978  }
 22979  /*
 22980   * [CAPIREF: vedis_context_kv_delete()]
 22981   * Please refer to the official documentation for function purpose and expected parameters.
 22982   */
 22983  int vedis_context_kv_delete(vedis_context *pCtx,const void *pKey,int nKeyLen)
 22984  {
 22985  	int rc;
 22986  	rc = vedisKvDelete(pCtx->pVedis,pKey,nKeyLen);
 22987  	return rc;
 22988  }
 22989  /*
 22990   * [CAPIREF: vedis_begin()]
 22991   * Please refer to the official documentation for function purpose and expected parameters.
 22992   */
 22993  int vedis_begin(vedis *pStore)
 22994  {
 22995  	int rc;
 22996  	if( VEDIS_DB_MISUSE(pStore) ){
 22997  		return VEDIS_CORRUPT;
 22998  	}
 22999  #if defined(VEDIS_ENABLE_THREADS)
 23000  	 /* Acquire DB mutex */
 23001  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23002  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 23003  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 23004  			 return VEDIS_ABORT; /* Another thread have released this instance */
 23005  	 }
 23006  #endif
 23007  	 /* Begin the write transaction */
 23008  	 rc = vedisPagerBegin(pStore->pPager);
 23009  #if defined(VEDIS_ENABLE_THREADS)
 23010  	 /* Leave DB mutex */
 23011  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23012  #endif
 23013  	 return rc;
 23014  }
 23015  /*
 23016   * [CAPIREF: vedis_commit()]
 23017   * Please refer to the official documentation for function purpose and expected parameters.
 23018   */
 23019  int vedis_commit(vedis *pStore)
 23020  {
 23021  	int rc;
 23022  	if( VEDIS_DB_MISUSE(pStore) ){
 23023  		return VEDIS_CORRUPT;
 23024  	}
 23025  #if defined(VEDIS_ENABLE_THREADS)
 23026  	 /* Acquire DB mutex */
 23027  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23028  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 23029  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 23030  			 return VEDIS_ABORT; /* Another thread have released this instance */
 23031  	 }
 23032  #endif
 23033  	 /* Commit the transaction */
 23034  	 rc = vedisPagerCommit(pStore->pPager);
 23035  #if defined(VEDIS_ENABLE_THREADS)
 23036  	 /* Leave DB mutex */
 23037  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23038  #endif
 23039  	 return rc;
 23040  }
 23041  /*
 23042   * [CAPIREF: vedis_rollback()]
 23043   * Please refer to the official documentation for function purpose and expected parameters.
 23044   */
 23045  int vedis_rollback(vedis *pStore)
 23046  {
 23047  	int rc;
 23048  	if( VEDIS_DB_MISUSE(pStore) ){
 23049  		return VEDIS_CORRUPT;
 23050  	}
 23051  #if defined(VEDIS_ENABLE_THREADS)
 23052  	 /* Acquire DB mutex */
 23053  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23054  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 23055  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 23056  			 return VEDIS_ABORT; /* Another thread have released this instance */
 23057  	 }
 23058  #endif
 23059  	 /* Rollback the transaction */
 23060  	 rc = vedisPagerRollback(pStore->pPager,TRUE);
 23061  #if defined(VEDIS_ENABLE_THREADS)
 23062  	 /* Leave DB mutex */
 23063  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23064  #endif
 23065  	 return rc;
 23066  }
 23067  /*
 23068   * [CAPIREF: vedis_util_random_string()]
 23069   * Please refer to the official documentation for function purpose and expected parameters.
 23070   */
 23071   int vedis_util_random_string(vedis *pStore,char *zBuf,unsigned int buf_size)
 23072  {
 23073  	if( VEDIS_DB_MISUSE(pStore) ){
 23074  		return VEDIS_CORRUPT;
 23075  	}
 23076  	if( zBuf == 0 || buf_size < 3 ){
 23077  		/* Buffer must be long enough to hold three bytes */
 23078  		return VEDIS_INVALID;
 23079  	}
 23080  #if defined(VEDIS_ENABLE_THREADS)
 23081  	 /* Acquire DB mutex */
 23082  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23083  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 23084  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 23085  			 return VEDIS_ABORT; /* Another thread have released this instance */
 23086  	 }
 23087  #endif
 23088  	 /* Generate the random string */
 23089  	 vedisPagerRandomString(pStore->pPager,zBuf,buf_size);
 23090  #if defined(VEDIS_ENABLE_THREADS)
 23091  	 /* Leave DB mutex */
 23092  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23093  #endif
 23094  	 return VEDIS_OK;
 23095  }
 23096  /*
 23097   * [CAPIREF: vedis_util_random_num()]
 23098   * Please refer to the official documentation for function purpose and expected parameters.
 23099   */
 23100   unsigned int vedis_util_random_num(vedis *pStore)
 23101  {
 23102  	sxu32 iNum;
 23103  	if( VEDIS_DB_MISUSE(pStore) ){
 23104  		return 0;
 23105  	}
 23106  #if defined(VEDIS_ENABLE_THREADS)
 23107  	 /* Acquire DB mutex */
 23108  	 SyMutexEnter(sVedisMPGlobal.pMutexMethods, pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23109  	 if( sVedisMPGlobal.nThreadingLevel > VEDIS_THREAD_LEVEL_SINGLE && 
 23110  		 VEDIS_THRD_DB_RELEASE(pStore) ){
 23111  			 return 0; /* Another thread have released this instance */
 23112  	 }
 23113  #endif
 23114  	 /* Generate the random number */
 23115  	 iNum = vedisPagerRandomNum(pStore->pPager);
 23116  #if defined(VEDIS_ENABLE_THREADS)
 23117  	 /* Leave DB mutex */
 23118  	 SyMutexLeave(sVedisMPGlobal.pMutexMethods,pStore->pMutex); /* NO-OP if sVedisMPGlobal.nThreadingLevel != VEDIS_THREAD_LEVEL_MULTI */
 23119  #endif
 23120  	 return iNum;
 23121  }
 23122  /* END-OF-IMPLEMENTATION: vedis@embedded@symisc 34-09-46 */
 23123  /*
 23124   * Symisc Vedis: A Highly Efficient Embeddable Data Store Engine.
 23125   * Copyright (C) 2013, Symisc Systems http://vedis.symisc.net/
 23126   * Version 1.2.6
 23127   * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES
 23128   * please contact Symisc Systems via:
 23129   *       legal@symisc.net
 23130   *       licensing@symisc.net
 23131   *       contact@symisc.net
 23132   * or visit:
 23133   *      http://vedis.symisc.net/
 23134   */
 23135  /*
 23136   * Copyright (C) 2013 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine <chm@symisc.net>].
 23137   * All rights reserved.
 23138   *
 23139   * Redistribution and use in source and binary forms, with or without
 23140   * modification, are permitted provided that the following conditions
 23141   * are met:
 23142   * 1. Redistributions of source code must retain the above copyright
 23143   *    notice, this list of conditions and the following disclaimer.
 23144   * 2. Redistributions in binary form must reproduce the above copyright
 23145   *    notice, this list of conditions and the following disclaimer in the
 23146   *    documentation and/or other materials provided with the distribution.
 23147   * 3. Redistributions in any form must be accompanied by information on
 23148   *    how to obtain complete source code for the Vedis engine and any 
 23149   *    accompanying software that uses the Vedis engine software.
 23150   *    The source code must either be included in the distribution
 23151   *    or be available for no more than the cost of distribution plus
 23152   *    a nominal fee, and must be freely redistributable under reasonable
 23153   *    conditions. For an executable file, complete source code means
 23154   *    the source code for all modules it contains.It does not include
 23155   *    source code for modules or files that typically accompany the major
 23156   *    components of the operating system on which the executable file runs.
 23157   *
 23158   * THIS SOFTWARE IS PROVIDED BY SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS
 23159   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 23160   * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 23161   * NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO EVENT SHALL SYMISC SYSTEMS
 23162   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 23163   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 23164   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 23165   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 23166   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 23167   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 23168   * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 23169   */