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 */