mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Import the LSM code from SQLite4 for use in an experimental virtual table.
NB: This is a speculative experiment and could easily result in a dead-end branch. FossilOrigin-Name: 3d930501a2acb7f20932cfeb4e3fe308b4569cd6
This commit is contained in:
33
ext/lsm1/Makefile
Normal file
33
ext/lsm1/Makefile
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/make
|
||||||
|
#
|
||||||
|
# This is a temporary makefile for use during experimental development.
|
||||||
|
# Replace with something more portable, if the experiments actually work out.
|
||||||
|
#
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS =-g -fPIC -Wall -I. -I/home/drh/sqlite/bld
|
||||||
|
|
||||||
|
LSMOBJ = \
|
||||||
|
lsm_ckpt.o \
|
||||||
|
lsm_file.o \
|
||||||
|
lsm_log.o \
|
||||||
|
lsm_main.o \
|
||||||
|
lsm_mem.o \
|
||||||
|
lsm_mutex.o \
|
||||||
|
lsm_shared.o \
|
||||||
|
lsm_sorted.o \
|
||||||
|
lsm_str.o \
|
||||||
|
lsm_tree.o \
|
||||||
|
lsm_unix.o \
|
||||||
|
lsm_varint.o
|
||||||
|
|
||||||
|
LSMHDR = \
|
||||||
|
lsm.h \
|
||||||
|
lsmInt.h
|
||||||
|
|
||||||
|
all: lsm.so
|
||||||
|
|
||||||
|
lsm.so: $(LSMOBJ)
|
||||||
|
$(CC) $(CFLAGS) -shared -o lsm.so $(LSMOBJ)
|
||||||
|
|
||||||
|
%.o: %.c $(LSMHDR)
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
684
ext/lsm1/lsm.h
Normal file
684
ext/lsm1/lsm.h
Normal file
@ -0,0 +1,684 @@
|
|||||||
|
/*
|
||||||
|
** 2011-08-10
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** This file defines the LSM API.
|
||||||
|
*/
|
||||||
|
#ifndef _LSM_H
|
||||||
|
#define _LSM_H
|
||||||
|
#include <stddef.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Opaque handle types.
|
||||||
|
*/
|
||||||
|
typedef struct lsm_compress lsm_compress; /* Compression library functions */
|
||||||
|
typedef struct lsm_compress_factory lsm_compress_factory;
|
||||||
|
typedef struct lsm_cursor lsm_cursor; /* Database cursor handle */
|
||||||
|
typedef struct lsm_db lsm_db; /* Database connection handle */
|
||||||
|
typedef struct lsm_env lsm_env; /* Runtime environment */
|
||||||
|
typedef struct lsm_file lsm_file; /* OS file handle */
|
||||||
|
typedef struct lsm_mutex lsm_mutex; /* Mutex handle */
|
||||||
|
|
||||||
|
/* 64-bit integer type used for file offsets. */
|
||||||
|
typedef long long int lsm_i64; /* 64-bit signed integer type */
|
||||||
|
|
||||||
|
/* Candidate values for the 3rd argument to lsm_env.xLock() */
|
||||||
|
#define LSM_LOCK_UNLOCK 0
|
||||||
|
#define LSM_LOCK_SHARED 1
|
||||||
|
#define LSM_LOCK_EXCL 2
|
||||||
|
|
||||||
|
/* Flags for lsm_env.xOpen() */
|
||||||
|
#define LSM_OPEN_READONLY 0x0001
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Database Runtime Environment
|
||||||
|
**
|
||||||
|
** Run-time environment used by LSM
|
||||||
|
*/
|
||||||
|
struct lsm_env {
|
||||||
|
int nByte; /* Size of this structure in bytes */
|
||||||
|
int iVersion; /* Version number of this structure (1) */
|
||||||
|
/****** file i/o ***********************************************/
|
||||||
|
void *pVfsCtx;
|
||||||
|
int (*xFullpath)(lsm_env*, const char *, char *, int *);
|
||||||
|
int (*xOpen)(lsm_env*, const char *, int flags, lsm_file **);
|
||||||
|
int (*xRead)(lsm_file *, lsm_i64, void *, int);
|
||||||
|
int (*xWrite)(lsm_file *, lsm_i64, void *, int);
|
||||||
|
int (*xTruncate)(lsm_file *, lsm_i64);
|
||||||
|
int (*xSync)(lsm_file *);
|
||||||
|
int (*xSectorSize)(lsm_file *);
|
||||||
|
int (*xRemap)(lsm_file *, lsm_i64, void **, lsm_i64*);
|
||||||
|
int (*xFileid)(lsm_file *, void *pBuf, int *pnBuf);
|
||||||
|
int (*xClose)(lsm_file *);
|
||||||
|
int (*xUnlink)(lsm_env*, const char *);
|
||||||
|
int (*xLock)(lsm_file*, int, int);
|
||||||
|
int (*xTestLock)(lsm_file*, int, int, int);
|
||||||
|
int (*xShmMap)(lsm_file*, int, int, void **);
|
||||||
|
void (*xShmBarrier)(void);
|
||||||
|
int (*xShmUnmap)(lsm_file*, int);
|
||||||
|
/****** memory allocation ****************************************/
|
||||||
|
void *pMemCtx;
|
||||||
|
void *(*xMalloc)(lsm_env*, size_t); /* malloc(3) function */
|
||||||
|
void *(*xRealloc)(lsm_env*, void *, size_t); /* realloc(3) function */
|
||||||
|
void (*xFree)(lsm_env*, void *); /* free(3) function */
|
||||||
|
size_t (*xSize)(lsm_env*, void *); /* xSize function */
|
||||||
|
/****** mutexes ****************************************************/
|
||||||
|
void *pMutexCtx;
|
||||||
|
int (*xMutexStatic)(lsm_env*,int,lsm_mutex**); /* Obtain a static mutex */
|
||||||
|
int (*xMutexNew)(lsm_env*, lsm_mutex**); /* Get a new dynamic mutex */
|
||||||
|
void (*xMutexDel)(lsm_mutex *); /* Delete an allocated mutex */
|
||||||
|
void (*xMutexEnter)(lsm_mutex *); /* Grab a mutex */
|
||||||
|
int (*xMutexTry)(lsm_mutex *); /* Attempt to obtain a mutex */
|
||||||
|
void (*xMutexLeave)(lsm_mutex *); /* Leave a mutex */
|
||||||
|
int (*xMutexHeld)(lsm_mutex *); /* Return true if mutex is held */
|
||||||
|
int (*xMutexNotHeld)(lsm_mutex *); /* Return true if mutex not held */
|
||||||
|
/****** other ****************************************************/
|
||||||
|
int (*xSleep)(lsm_env*, int microseconds);
|
||||||
|
|
||||||
|
/* New fields may be added in future releases, in which case the
|
||||||
|
** iVersion value will increase. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Values that may be passed as the second argument to xMutexStatic.
|
||||||
|
*/
|
||||||
|
#define LSM_MUTEX_GLOBAL 1
|
||||||
|
#define LSM_MUTEX_HEAP 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: LSM Error Codes
|
||||||
|
*/
|
||||||
|
#define LSM_OK 0
|
||||||
|
#define LSM_ERROR 1
|
||||||
|
#define LSM_BUSY 5
|
||||||
|
#define LSM_NOMEM 7
|
||||||
|
#define LSM_READONLY 8
|
||||||
|
#define LSM_IOERR 10
|
||||||
|
#define LSM_CORRUPT 11
|
||||||
|
#define LSM_FULL 13
|
||||||
|
#define LSM_CANTOPEN 14
|
||||||
|
#define LSM_PROTOCOL 15
|
||||||
|
#define LSM_MISUSE 21
|
||||||
|
|
||||||
|
#define LSM_MISMATCH 50
|
||||||
|
|
||||||
|
|
||||||
|
#define LSM_IOERR_NOENT (LSM_IOERR | (1<<8))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Creating and Destroying Database Connection Handles
|
||||||
|
**
|
||||||
|
** Open and close a database connection handle.
|
||||||
|
*/
|
||||||
|
int lsm_new(lsm_env*, lsm_db **ppDb);
|
||||||
|
int lsm_close(lsm_db *pDb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Connecting to a Database
|
||||||
|
*/
|
||||||
|
int lsm_open(lsm_db *pDb, const char *zFilename);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Obtaining pointers to database environments
|
||||||
|
**
|
||||||
|
** Return a pointer to the environment used by the database connection
|
||||||
|
** passed as the first argument. Assuming the argument is valid, this
|
||||||
|
** function always returns a valid environment pointer - it cannot fail.
|
||||||
|
*/
|
||||||
|
lsm_env *lsm_get_env(lsm_db *pDb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The lsm_default_env() function returns a pointer to the default LSM
|
||||||
|
** environment for the current platform.
|
||||||
|
*/
|
||||||
|
lsm_env *lsm_default_env(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Configuring a database connection.
|
||||||
|
**
|
||||||
|
** The lsm_config() function is used to configure a database connection.
|
||||||
|
*/
|
||||||
|
int lsm_config(lsm_db *, int, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following values may be passed as the second argument to lsm_config().
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_AUTOFLUSH:
|
||||||
|
** A read/write integer parameter.
|
||||||
|
**
|
||||||
|
** This value determines the amount of data allowed to accumulate in a
|
||||||
|
** live in-memory tree before it is marked as old. After committing a
|
||||||
|
** transaction, a connection checks if the size of the live in-memory tree,
|
||||||
|
** including data structure overhead, is greater than the value of this
|
||||||
|
** option in KB. If it is, and there is not already an old in-memory tree,
|
||||||
|
** the live in-memory tree is marked as old.
|
||||||
|
**
|
||||||
|
** The maximum allowable value is 1048576 (1GB). There is no minimum
|
||||||
|
** value. If this parameter is set to zero, then an attempt is made to
|
||||||
|
** mark the live in-memory tree as old after each transaction is committed.
|
||||||
|
**
|
||||||
|
** The default value is 1024 (1MB).
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_PAGE_SIZE:
|
||||||
|
** A read/write integer parameter. This parameter may only be set before
|
||||||
|
** lsm_open() has been called.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_BLOCK_SIZE:
|
||||||
|
** A read/write integer parameter.
|
||||||
|
**
|
||||||
|
** This parameter may only be set before lsm_open() has been called. It
|
||||||
|
** must be set to a power of two between 64 and 65536, inclusive (block
|
||||||
|
** sizes between 64KB and 64MB).
|
||||||
|
**
|
||||||
|
** If the connection creates a new database, the block size of the new
|
||||||
|
** database is set to the value of this option in KB. After lsm_open()
|
||||||
|
** has been called, querying this parameter returns the actual block
|
||||||
|
** size of the opened database.
|
||||||
|
**
|
||||||
|
** The default value is 1024 (1MB blocks).
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_SAFETY:
|
||||||
|
** A read/write integer parameter. Valid values are 0, 1 (the default)
|
||||||
|
** and 2. This parameter determines how robust the database is in the
|
||||||
|
** face of a system crash (e.g. a power failure or operating system
|
||||||
|
** crash). As follows:
|
||||||
|
**
|
||||||
|
** 0 (off): No robustness. A system crash may corrupt the database.
|
||||||
|
**
|
||||||
|
** 1 (normal): Some robustness. A system crash may not corrupt the
|
||||||
|
** database file, but recently committed transactions may
|
||||||
|
** be lost following recovery.
|
||||||
|
**
|
||||||
|
** 2 (full): Full robustness. A system crash may not corrupt the
|
||||||
|
** database file. Following recovery the database file
|
||||||
|
** contains all successfully committed transactions.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_AUTOWORK:
|
||||||
|
** A read/write integer parameter.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_AUTOCHECKPOINT:
|
||||||
|
** A read/write integer parameter.
|
||||||
|
**
|
||||||
|
** If this option is set to non-zero value N, then a checkpoint is
|
||||||
|
** automatically attempted after each N KB of data have been written to
|
||||||
|
** the database file.
|
||||||
|
**
|
||||||
|
** The amount of uncheckpointed data already written to the database file
|
||||||
|
** is a global parameter. After performing database work (writing to the
|
||||||
|
** database file), the process checks if the total amount of uncheckpointed
|
||||||
|
** data exceeds the value of this paramter. If so, a checkpoint is performed.
|
||||||
|
** This means that this option may cause the connection to perform a
|
||||||
|
** checkpoint even if the current connection has itself written very little
|
||||||
|
** data into the database file.
|
||||||
|
**
|
||||||
|
** The default value is 2048 (checkpoint every 2MB).
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_MMAP:
|
||||||
|
** A read/write integer parameter. If this value is set to 0, then the
|
||||||
|
** database file is accessed using ordinary read/write IO functions. Or,
|
||||||
|
** if it is set to 1, then the database file is memory mapped and accessed
|
||||||
|
** that way. If this parameter is set to any value N greater than 1, then
|
||||||
|
** up to the first N KB of the file are memory mapped, and any remainder
|
||||||
|
** accessed using read/write IO.
|
||||||
|
**
|
||||||
|
** The default value is 1 on 64-bit platforms and 32768 on 32-bit platforms.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_USE_LOG:
|
||||||
|
** A read/write boolean parameter. True (the default) to use the log
|
||||||
|
** file normally. False otherwise.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_AUTOMERGE:
|
||||||
|
** A read/write integer parameter. The minimum number of segments to
|
||||||
|
** merge together at a time. Default value 4.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_MAX_FREELIST:
|
||||||
|
** A read/write integer parameter. The maximum number of free-list
|
||||||
|
** entries that are stored in a database checkpoint (the others are
|
||||||
|
** stored elsewhere in the database).
|
||||||
|
**
|
||||||
|
** There is no reason for an application to configure or query this
|
||||||
|
** parameter. It is only present because configuring a small value
|
||||||
|
** makes certain parts of the lsm code easier to test.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_MULTIPLE_PROCESSES:
|
||||||
|
** A read/write boolean parameter. This parameter may only be set before
|
||||||
|
** lsm_open() has been called. If true, the library uses shared-memory
|
||||||
|
** and posix advisory locks to co-ordinate access by clients from within
|
||||||
|
** multiple processes. Otherwise, if false, all database clients must be
|
||||||
|
** located in the same process. The default value is true.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_SET_COMPRESSION:
|
||||||
|
** Set the compression methods used to compress and decompress database
|
||||||
|
** content. The argument to this option should be a pointer to a structure
|
||||||
|
** of type lsm_compress. The lsm_config() method takes a copy of the
|
||||||
|
** structures contents.
|
||||||
|
**
|
||||||
|
** This option may only be used before lsm_open() is called. Invoking it
|
||||||
|
** after lsm_open() has been called results in an LSM_MISUSE error.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_GET_COMPRESSION:
|
||||||
|
** Query the compression methods used to compress and decompress database
|
||||||
|
** content.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_SET_COMPRESSION_FACTORY:
|
||||||
|
** Configure a factory method to be invoked in case of an LSM_MISMATCH
|
||||||
|
** error.
|
||||||
|
**
|
||||||
|
** LSM_CONFIG_READONLY:
|
||||||
|
** A read/write boolean parameter. This parameter may only be set before
|
||||||
|
** lsm_open() is called.
|
||||||
|
*/
|
||||||
|
#define LSM_CONFIG_AUTOFLUSH 1
|
||||||
|
#define LSM_CONFIG_PAGE_SIZE 2
|
||||||
|
#define LSM_CONFIG_SAFETY 3
|
||||||
|
#define LSM_CONFIG_BLOCK_SIZE 4
|
||||||
|
#define LSM_CONFIG_AUTOWORK 5
|
||||||
|
#define LSM_CONFIG_MMAP 7
|
||||||
|
#define LSM_CONFIG_USE_LOG 8
|
||||||
|
#define LSM_CONFIG_AUTOMERGE 9
|
||||||
|
#define LSM_CONFIG_MAX_FREELIST 10
|
||||||
|
#define LSM_CONFIG_MULTIPLE_PROCESSES 11
|
||||||
|
#define LSM_CONFIG_AUTOCHECKPOINT 12
|
||||||
|
#define LSM_CONFIG_SET_COMPRESSION 13
|
||||||
|
#define LSM_CONFIG_GET_COMPRESSION 14
|
||||||
|
#define LSM_CONFIG_SET_COMPRESSION_FACTORY 15
|
||||||
|
#define LSM_CONFIG_READONLY 16
|
||||||
|
|
||||||
|
#define LSM_SAFETY_OFF 0
|
||||||
|
#define LSM_SAFETY_NORMAL 1
|
||||||
|
#define LSM_SAFETY_FULL 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Compression and/or Encryption Hooks
|
||||||
|
*/
|
||||||
|
struct lsm_compress {
|
||||||
|
void *pCtx;
|
||||||
|
unsigned int iId;
|
||||||
|
int (*xBound)(void *, int nSrc);
|
||||||
|
int (*xCompress)(void *, char *, int *, const char *, int);
|
||||||
|
int (*xUncompress)(void *, char *, int *, const char *, int);
|
||||||
|
void (*xFree)(void *pCtx);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lsm_compress_factory {
|
||||||
|
void *pCtx;
|
||||||
|
int (*xFactory)(void *, lsm_db *, unsigned int);
|
||||||
|
void (*xFree)(void *pCtx);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LSM_COMPRESSION_EMPTY 0
|
||||||
|
#define LSM_COMPRESSION_NONE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Allocating and Freeing Memory
|
||||||
|
**
|
||||||
|
** Invoke the memory allocation functions that belong to environment
|
||||||
|
** pEnv. Or the system defaults if no memory allocation functions have
|
||||||
|
** been registered.
|
||||||
|
*/
|
||||||
|
void *lsm_malloc(lsm_env*, size_t);
|
||||||
|
void *lsm_realloc(lsm_env*, void *, size_t);
|
||||||
|
void lsm_free(lsm_env*, void *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Querying a Connection For Operational Data
|
||||||
|
**
|
||||||
|
** Query a database connection for operational statistics or data.
|
||||||
|
*/
|
||||||
|
int lsm_info(lsm_db *, int, ...);
|
||||||
|
|
||||||
|
int lsm_get_user_version(lsm_db *, unsigned int *);
|
||||||
|
int lsm_set_user_version(lsm_db *, unsigned int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following values may be passed as the second argument to lsm_info().
|
||||||
|
**
|
||||||
|
** LSM_INFO_NWRITE:
|
||||||
|
** The third parameter should be of type (int *). The location pointed
|
||||||
|
** to by the third parameter is set to the number of 4KB pages written to
|
||||||
|
** the database file during the lifetime of this connection.
|
||||||
|
**
|
||||||
|
** LSM_INFO_NREAD:
|
||||||
|
** The third parameter should be of type (int *). The location pointed
|
||||||
|
** to by the third parameter is set to the number of 4KB pages read from
|
||||||
|
** the database file during the lifetime of this connection.
|
||||||
|
**
|
||||||
|
** LSM_INFO_DB_STRUCTURE:
|
||||||
|
** The third argument should be of type (char **). The location pointed
|
||||||
|
** to is populated with a pointer to a nul-terminated string containing
|
||||||
|
** the string representation of a Tcl data-structure reflecting the
|
||||||
|
** current structure of the database file. Specifically, the current state
|
||||||
|
** of the worker snapshot. The returned string should be eventually freed
|
||||||
|
** by the caller using lsm_free().
|
||||||
|
**
|
||||||
|
** The returned list contains one element for each level in the database,
|
||||||
|
** in order from most to least recent. Each element contains a
|
||||||
|
** single element for each segment comprising the corresponding level,
|
||||||
|
** starting with the lhs segment, then each of the rhs segments (if any)
|
||||||
|
** in order from most to least recent.
|
||||||
|
**
|
||||||
|
** Each segment element is itself a list of 4 integer values, as follows:
|
||||||
|
**
|
||||||
|
** <ol><li> First page of segment
|
||||||
|
** <li> Last page of segment
|
||||||
|
** <li> Root page of segment (if applicable)
|
||||||
|
** <li> Total number of pages in segment
|
||||||
|
** </ol>
|
||||||
|
**
|
||||||
|
** LSM_INFO_ARRAY_STRUCTURE:
|
||||||
|
** There should be two arguments passed following this option (i.e. a
|
||||||
|
** total of four arguments passed to lsm_info()). The first argument
|
||||||
|
** should be the page number of the first page in a database array
|
||||||
|
** (perhaps obtained from an earlier INFO_DB_STRUCTURE call). The second
|
||||||
|
** trailing argument should be of type (char **). The location pointed
|
||||||
|
** to is populated with a pointer to a nul-terminated string that must
|
||||||
|
** be eventually freed using lsm_free() by the caller.
|
||||||
|
**
|
||||||
|
** The output string contains the text representation of a Tcl list of
|
||||||
|
** integers. Each pair of integers represent a range of pages used by
|
||||||
|
** the identified array. For example, if the array occupies database
|
||||||
|
** pages 993 to 1024, then pages 2048 to 2777, then the returned string
|
||||||
|
** will be "993 1024 2048 2777".
|
||||||
|
**
|
||||||
|
** If the specified integer argument does not correspond to the first
|
||||||
|
** page of any database array, LSM_ERROR is returned and the output
|
||||||
|
** pointer is set to a NULL value.
|
||||||
|
**
|
||||||
|
** LSM_INFO_LOG_STRUCTURE:
|
||||||
|
** The third argument should be of type (char **). The location pointed
|
||||||
|
** to is populated with a pointer to a nul-terminated string containing
|
||||||
|
** the string representation of a Tcl data-structure. The returned
|
||||||
|
** string should be eventually freed by the caller using lsm_free().
|
||||||
|
**
|
||||||
|
** The Tcl structure returned is a list of six integers that describe
|
||||||
|
** the current structure of the log file.
|
||||||
|
**
|
||||||
|
** LSM_INFO_ARRAY_PAGES:
|
||||||
|
**
|
||||||
|
** LSM_INFO_PAGE_ASCII_DUMP:
|
||||||
|
** As with LSM_INFO_ARRAY_STRUCTURE, there should be two arguments passed
|
||||||
|
** with calls that specify this option - an integer page number and a
|
||||||
|
** (char **) used to return a nul-terminated string that must be later
|
||||||
|
** freed using lsm_free(). In this case the output string is populated
|
||||||
|
** with a human-readable description of the page content.
|
||||||
|
**
|
||||||
|
** If the page cannot be decoded, it is not an error. In this case the
|
||||||
|
** human-readable output message will report the systems failure to
|
||||||
|
** interpret the page data.
|
||||||
|
**
|
||||||
|
** LSM_INFO_PAGE_HEX_DUMP:
|
||||||
|
** This argument is similar to PAGE_ASCII_DUMP, except that keys and
|
||||||
|
** values are represented using hexadecimal notation instead of ascii.
|
||||||
|
**
|
||||||
|
** LSM_INFO_FREELIST:
|
||||||
|
** The third argument should be of type (char **). The location pointed
|
||||||
|
** to is populated with a pointer to a nul-terminated string containing
|
||||||
|
** the string representation of a Tcl data-structure. The returned
|
||||||
|
** string should be eventually freed by the caller using lsm_free().
|
||||||
|
**
|
||||||
|
** The Tcl structure returned is a list containing one element for each
|
||||||
|
** free block in the database. The element itself consists of two
|
||||||
|
** integers - the block number and the id of the snapshot that freed it.
|
||||||
|
**
|
||||||
|
** LSM_INFO_CHECKPOINT_SIZE:
|
||||||
|
** The third argument should be of type (int *). The location pointed to
|
||||||
|
** by this argument is populated with the number of KB written to the
|
||||||
|
** database file since the most recent checkpoint.
|
||||||
|
**
|
||||||
|
** LSM_INFO_TREE_SIZE:
|
||||||
|
** If this value is passed as the second argument to an lsm_info() call, it
|
||||||
|
** should be followed by two arguments of type (int *) (for a total of four
|
||||||
|
** arguments).
|
||||||
|
**
|
||||||
|
** At any time, there are either one or two tree structures held in shared
|
||||||
|
** memory that new database clients will access (there may also be additional
|
||||||
|
** tree structures being used by older clients - this API does not provide
|
||||||
|
** information on them). One tree structure - the current tree - is used to
|
||||||
|
** accumulate new data written to the database. The other tree structure -
|
||||||
|
** the old tree - is a read-only tree holding older data and may be flushed
|
||||||
|
** to disk at any time.
|
||||||
|
**
|
||||||
|
** Assuming no error occurs, the location pointed to by the first of the two
|
||||||
|
** (int *) arguments is set to the size of the old in-memory tree in KB.
|
||||||
|
** The second is set to the size of the current, or live in-memory tree.
|
||||||
|
**
|
||||||
|
** LSM_INFO_COMPRESSION_ID:
|
||||||
|
** This value should be followed by a single argument of type
|
||||||
|
** (unsigned int *). If successful, the location pointed to is populated
|
||||||
|
** with the database compression id before returning.
|
||||||
|
*/
|
||||||
|
#define LSM_INFO_NWRITE 1
|
||||||
|
#define LSM_INFO_NREAD 2
|
||||||
|
#define LSM_INFO_DB_STRUCTURE 3
|
||||||
|
#define LSM_INFO_LOG_STRUCTURE 4
|
||||||
|
#define LSM_INFO_ARRAY_STRUCTURE 5
|
||||||
|
#define LSM_INFO_PAGE_ASCII_DUMP 6
|
||||||
|
#define LSM_INFO_PAGE_HEX_DUMP 7
|
||||||
|
#define LSM_INFO_FREELIST 8
|
||||||
|
#define LSM_INFO_ARRAY_PAGES 9
|
||||||
|
#define LSM_INFO_CHECKPOINT_SIZE 10
|
||||||
|
#define LSM_INFO_TREE_SIZE 11
|
||||||
|
#define LSM_INFO_FREELIST_SIZE 12
|
||||||
|
#define LSM_INFO_COMPRESSION_ID 13
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Opening and Closing Write Transactions
|
||||||
|
**
|
||||||
|
** These functions are used to open and close transactions and nested
|
||||||
|
** sub-transactions.
|
||||||
|
**
|
||||||
|
** The lsm_begin() function is used to open transactions and sub-transactions.
|
||||||
|
** A successful call to lsm_begin() ensures that there are at least iLevel
|
||||||
|
** nested transactions open. To open a top-level transaction, pass iLevel=1.
|
||||||
|
** To open a sub-transaction within the top-level transaction, iLevel=2.
|
||||||
|
** Passing iLevel=0 is a no-op.
|
||||||
|
**
|
||||||
|
** lsm_commit() is used to commit transactions and sub-transactions. A
|
||||||
|
** successful call to lsm_commit() ensures that there are at most iLevel
|
||||||
|
** nested transactions open. To commit a top-level transaction, pass iLevel=0.
|
||||||
|
** To commit all sub-transactions inside the main transaction, pass iLevel=1.
|
||||||
|
**
|
||||||
|
** Function lsm_rollback() is used to roll back transactions and
|
||||||
|
** sub-transactions. A successful call to lsm_rollback() restores the database
|
||||||
|
** to the state it was in when the iLevel'th nested sub-transaction (if any)
|
||||||
|
** was first opened. And then closes transactions to ensure that there are
|
||||||
|
** at most iLevel nested transactions open. Passing iLevel=0 rolls back and
|
||||||
|
** closes the top-level transaction. iLevel=1 also rolls back the top-level
|
||||||
|
** transaction, but leaves it open. iLevel=2 rolls back the sub-transaction
|
||||||
|
** nested directly inside the top-level transaction (and leaves it open).
|
||||||
|
*/
|
||||||
|
int lsm_begin(lsm_db *pDb, int iLevel);
|
||||||
|
int lsm_commit(lsm_db *pDb, int iLevel);
|
||||||
|
int lsm_rollback(lsm_db *pDb, int iLevel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Writing to a Database
|
||||||
|
**
|
||||||
|
** Write a new value into the database. If a value with a duplicate key
|
||||||
|
** already exists it is replaced.
|
||||||
|
*/
|
||||||
|
int lsm_insert(lsm_db*, const void *pKey, int nKey, const void *pVal, int nVal);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Delete a value from the database. No error is returned if the specified
|
||||||
|
** key value does not exist in the database.
|
||||||
|
*/
|
||||||
|
int lsm_delete(lsm_db *, const void *pKey, int nKey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Delete all database entries with keys that are greater than (pKey1/nKey1)
|
||||||
|
** and smaller than (pKey2/nKey2). Note that keys (pKey1/nKey1) and
|
||||||
|
** (pKey2/nKey2) themselves, if they exist in the database, are not deleted.
|
||||||
|
**
|
||||||
|
** Return LSM_OK if successful, or an LSM error code otherwise.
|
||||||
|
*/
|
||||||
|
int lsm_delete_range(lsm_db *,
|
||||||
|
const void *pKey1, int nKey1, const void *pKey2, int nKey2
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Explicit Database Work and Checkpointing
|
||||||
|
**
|
||||||
|
** This function is called by a thread to work on the database structure.
|
||||||
|
*/
|
||||||
|
int lsm_work(lsm_db *pDb, int nMerge, int nKB, int *pnWrite);
|
||||||
|
|
||||||
|
int lsm_flush(lsm_db *pDb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Attempt to checkpoint the current database snapshot. Return an LSM
|
||||||
|
** error code if an error occurs or LSM_OK otherwise.
|
||||||
|
**
|
||||||
|
** If the current snapshot has already been checkpointed, calling this
|
||||||
|
** function is a no-op. In this case if pnKB is not NULL, *pnKB is
|
||||||
|
** set to 0. Or, if the current snapshot is successfully checkpointed
|
||||||
|
** by this function and pbKB is not NULL, *pnKB is set to the number
|
||||||
|
** of bytes written to the database file since the previous checkpoint
|
||||||
|
** (the same measure as returned by the LSM_INFO_CHECKPOINT_SIZE query).
|
||||||
|
*/
|
||||||
|
int lsm_checkpoint(lsm_db *pDb, int *pnKB);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Opening and Closing Database Cursors
|
||||||
|
**
|
||||||
|
** Open and close a database cursor.
|
||||||
|
*/
|
||||||
|
int lsm_csr_open(lsm_db *pDb, lsm_cursor **ppCsr);
|
||||||
|
int lsm_csr_close(lsm_cursor *pCsr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Positioning Database Cursors
|
||||||
|
**
|
||||||
|
** If the fourth parameter is LSM_SEEK_EQ, LSM_SEEK_GE or LSM_SEEK_LE,
|
||||||
|
** this function searches the database for an entry with key (pKey/nKey).
|
||||||
|
** If an error occurs, an LSM error code is returned. Otherwise, LSM_OK.
|
||||||
|
**
|
||||||
|
** If no error occurs and the requested key is present in the database, the
|
||||||
|
** cursor is left pointing to the entry with the specified key. Or, if the
|
||||||
|
** specified key is not present in the database the state of the cursor
|
||||||
|
** depends on the value passed as the final parameter, as follows:
|
||||||
|
**
|
||||||
|
** LSM_SEEK_EQ:
|
||||||
|
** The cursor is left at EOF (invalidated). A call to lsm_csr_valid()
|
||||||
|
** returns non-zero.
|
||||||
|
**
|
||||||
|
** LSM_SEEK_LE:
|
||||||
|
** The cursor is left pointing to the largest key in the database that
|
||||||
|
** is smaller than (pKey/nKey). If the database contains no keys smaller
|
||||||
|
** than (pKey/nKey), the cursor is left at EOF.
|
||||||
|
**
|
||||||
|
** LSM_SEEK_GE:
|
||||||
|
** The cursor is left pointing to the smallest key in the database that
|
||||||
|
** is larger than (pKey/nKey). If the database contains no keys larger
|
||||||
|
** than (pKey/nKey), the cursor is left at EOF.
|
||||||
|
**
|
||||||
|
** If the fourth parameter is LSM_SEEK_LEFAST, this function searches the
|
||||||
|
** database in a similar manner to LSM_SEEK_LE, with two differences:
|
||||||
|
**
|
||||||
|
** <ol><li>Even if a key can be found (the cursor is not left at EOF), the
|
||||||
|
** lsm_csr_value() function may not be used (attempts to do so return
|
||||||
|
** LSM_MISUSE).
|
||||||
|
**
|
||||||
|
** <li>The key that the cursor is left pointing to may be one that has
|
||||||
|
** been recently deleted from the database. In this case it is
|
||||||
|
** guaranteed that the returned key is larger than any key currently
|
||||||
|
** in the database that is less than or equal to (pKey/nKey).
|
||||||
|
** </ol>
|
||||||
|
**
|
||||||
|
** LSM_SEEK_LEFAST requests are intended to be used to allocate database
|
||||||
|
** keys.
|
||||||
|
*/
|
||||||
|
int lsm_csr_seek(lsm_cursor *pCsr, const void *pKey, int nKey, int eSeek);
|
||||||
|
|
||||||
|
int lsm_csr_first(lsm_cursor *pCsr);
|
||||||
|
int lsm_csr_last(lsm_cursor *pCsr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Advance the specified cursor to the next or previous key in the database.
|
||||||
|
** Return LSM_OK if successful, or an LSM error code otherwise.
|
||||||
|
**
|
||||||
|
** Functions lsm_csr_seek(), lsm_csr_first() and lsm_csr_last() are "seek"
|
||||||
|
** functions. Whether or not lsm_csr_next and lsm_csr_prev may be called
|
||||||
|
** successfully also depends on the most recent seek function called on
|
||||||
|
** the cursor. Specifically:
|
||||||
|
**
|
||||||
|
** <ul>
|
||||||
|
** <li> At least one seek function must have been called on the cursor.
|
||||||
|
** <li> To call lsm_csr_next(), the most recent call to a seek function must
|
||||||
|
** have been either lsm_csr_first() or a call to lsm_csr_seek() specifying
|
||||||
|
** LSM_SEEK_GE.
|
||||||
|
** <li> To call lsm_csr_prev(), the most recent call to a seek function must
|
||||||
|
** have been either lsm_csr_first() or a call to lsm_csr_seek() specifying
|
||||||
|
** LSM_SEEK_GE.
|
||||||
|
** </ul>
|
||||||
|
**
|
||||||
|
** Otherwise, if the above conditions are not met when lsm_csr_next or
|
||||||
|
** lsm_csr_prev is called, LSM_MISUSE is returned and the cursor position
|
||||||
|
** remains unchanged.
|
||||||
|
*/
|
||||||
|
int lsm_csr_next(lsm_cursor *pCsr);
|
||||||
|
int lsm_csr_prev(lsm_cursor *pCsr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Values that may be passed as the fourth argument to lsm_csr_seek().
|
||||||
|
*/
|
||||||
|
#define LSM_SEEK_LEFAST -2
|
||||||
|
#define LSM_SEEK_LE -1
|
||||||
|
#define LSM_SEEK_EQ 0
|
||||||
|
#define LSM_SEEK_GE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Extracting Data From Database Cursors
|
||||||
|
**
|
||||||
|
** Retrieve data from a database cursor.
|
||||||
|
*/
|
||||||
|
int lsm_csr_valid(lsm_cursor *pCsr);
|
||||||
|
int lsm_csr_key(lsm_cursor *pCsr, const void **ppKey, int *pnKey);
|
||||||
|
int lsm_csr_value(lsm_cursor *pCsr, const void **ppVal, int *pnVal);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If no error occurs, this function compares the database key passed via
|
||||||
|
** the pKey/nKey arguments with the key that the cursor passed as the first
|
||||||
|
** argument currently points to. If the cursors key is less than, equal to
|
||||||
|
** or greater than pKey/nKey, *piRes is set to less than, equal to or greater
|
||||||
|
** than zero before returning. LSM_OK is returned in this case.
|
||||||
|
**
|
||||||
|
** Or, if an error occurs, an LSM error code is returned and the final
|
||||||
|
** value of *piRes is undefined. If the cursor does not point to a valid
|
||||||
|
** key when this function is called, LSM_MISUSE is returned.
|
||||||
|
*/
|
||||||
|
int lsm_csr_cmp(lsm_cursor *pCsr, const void *pKey, int nKey, int *piRes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI: Change these!!
|
||||||
|
**
|
||||||
|
** Configure a callback to which debugging and other messages should
|
||||||
|
** be directed. Only useful for debugging lsm.
|
||||||
|
*/
|
||||||
|
void lsm_config_log(lsm_db *, void (*)(void *, int, const char *), void *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Configure a callback that is invoked if the database connection ever
|
||||||
|
** writes to the database file.
|
||||||
|
*/
|
||||||
|
void lsm_config_work_hook(lsm_db *, void (*)(lsm_db *, void *), void *);
|
||||||
|
|
||||||
|
/* ENDOFAPI */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* End of the 'extern "C"' block */
|
||||||
|
#endif
|
||||||
|
#endif /* ifndef _LSM_H */
|
974
ext/lsm1/lsmInt.h
Normal file
974
ext/lsm1/lsmInt.h
Normal file
@ -0,0 +1,974 @@
|
|||||||
|
/*
|
||||||
|
** 2011-08-18
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
** Internal structure definitions for the LSM module.
|
||||||
|
*/
|
||||||
|
#ifndef _LSM_INT_H
|
||||||
|
#define _LSM_INT_H
|
||||||
|
|
||||||
|
#include "lsm.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
# ifdef LSM_DEBUG_EXPENSIVE
|
||||||
|
# undef LSM_DEBUG_EXPENSIVE
|
||||||
|
# endif
|
||||||
|
# ifdef LSM_DEBUG
|
||||||
|
# undef LSM_DEBUG
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# ifndef LSM_DEBUG
|
||||||
|
# define LSM_DEBUG
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Default values for various data structure parameters. These may be
|
||||||
|
** overridden by calls to lsm_config().
|
||||||
|
*/
|
||||||
|
#define LSM_DFLT_PAGE_SIZE (4 * 1024)
|
||||||
|
#define LSM_DFLT_BLOCK_SIZE (1 * 1024 * 1024)
|
||||||
|
#define LSM_DFLT_AUTOFLUSH (1 * 1024 * 1024)
|
||||||
|
#define LSM_DFLT_AUTOCHECKPOINT (i64)(2 * 1024 * 1024)
|
||||||
|
#define LSM_DFLT_AUTOWORK 1
|
||||||
|
#define LSM_DFLT_LOG_SIZE (128*1024)
|
||||||
|
#define LSM_DFLT_AUTOMERGE 4
|
||||||
|
#define LSM_DFLT_SAFETY LSM_SAFETY_NORMAL
|
||||||
|
#define LSM_DFLT_MMAP (LSM_IS_64_BIT ? 1 : 32768)
|
||||||
|
#define LSM_DFLT_MULTIPLE_PROCESSES 1
|
||||||
|
#define LSM_DFLT_USE_LOG 1
|
||||||
|
|
||||||
|
/* Initial values for log file checksums. These are only used if the
|
||||||
|
** database file does not contain a valid checkpoint. */
|
||||||
|
#define LSM_CKSUM0_INIT 42
|
||||||
|
#define LSM_CKSUM1_INIT 42
|
||||||
|
|
||||||
|
#define LSM_META_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
/* "mmap" mode is currently only used in environments with 64-bit address
|
||||||
|
** spaces. The following macro is used to test for this. */
|
||||||
|
#define LSM_IS_64_BIT (sizeof(void*)==8)
|
||||||
|
|
||||||
|
#define LSM_AUTOWORK_QUANT 32
|
||||||
|
|
||||||
|
typedef struct Database Database;
|
||||||
|
typedef struct DbLog DbLog;
|
||||||
|
typedef struct FileSystem FileSystem;
|
||||||
|
typedef struct Freelist Freelist;
|
||||||
|
typedef struct FreelistEntry FreelistEntry;
|
||||||
|
typedef struct Level Level;
|
||||||
|
typedef struct LogMark LogMark;
|
||||||
|
typedef struct LogRegion LogRegion;
|
||||||
|
typedef struct LogWriter LogWriter;
|
||||||
|
typedef struct LsmString LsmString;
|
||||||
|
typedef struct Mempool Mempool;
|
||||||
|
typedef struct Merge Merge;
|
||||||
|
typedef struct MergeInput MergeInput;
|
||||||
|
typedef struct MetaPage MetaPage;
|
||||||
|
typedef struct MultiCursor MultiCursor;
|
||||||
|
typedef struct Page Page;
|
||||||
|
typedef struct Redirect Redirect;
|
||||||
|
typedef struct Segment Segment;
|
||||||
|
typedef struct SegmentMerger SegmentMerger;
|
||||||
|
typedef struct ShmChunk ShmChunk;
|
||||||
|
typedef struct ShmHeader ShmHeader;
|
||||||
|
typedef struct ShmReader ShmReader;
|
||||||
|
typedef struct Snapshot Snapshot;
|
||||||
|
typedef struct TransMark TransMark;
|
||||||
|
typedef struct Tree Tree;
|
||||||
|
typedef struct TreeCursor TreeCursor;
|
||||||
|
typedef struct TreeHeader TreeHeader;
|
||||||
|
typedef struct TreeMark TreeMark;
|
||||||
|
typedef struct TreeRoot TreeRoot;
|
||||||
|
|
||||||
|
#ifndef _SQLITEINT_H_
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short int u16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef lsm_i64 i64;
|
||||||
|
typedef unsigned long long int u64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* A page number is a 64-bit integer. */
|
||||||
|
typedef i64 Pgno;
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
int lsmErrorBkpt(int);
|
||||||
|
#else
|
||||||
|
# define lsmErrorBkpt(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LSM_PROTOCOL_BKPT lsmErrorBkpt(LSM_PROTOCOL)
|
||||||
|
#define LSM_IOERR_BKPT lsmErrorBkpt(LSM_IOERR)
|
||||||
|
#define LSM_NOMEM_BKPT lsmErrorBkpt(LSM_NOMEM)
|
||||||
|
#define LSM_CORRUPT_BKPT lsmErrorBkpt(LSM_CORRUPT)
|
||||||
|
#define LSM_MISUSE_BKPT lsmErrorBkpt(LSM_MISUSE)
|
||||||
|
|
||||||
|
#define unused_parameter(x) (void)(x)
|
||||||
|
#define array_size(x) (sizeof(x)/sizeof(x[0]))
|
||||||
|
|
||||||
|
|
||||||
|
/* The size of each shared-memory chunk */
|
||||||
|
#define LSM_SHM_CHUNK_SIZE (32*1024)
|
||||||
|
|
||||||
|
/* The number of bytes reserved at the start of each shm chunk for MM. */
|
||||||
|
#define LSM_SHM_CHUNK_HDR (sizeof(ShmChunk))
|
||||||
|
|
||||||
|
/* The number of available read locks. */
|
||||||
|
#define LSM_LOCK_NREADER 6
|
||||||
|
|
||||||
|
/* The number of available read-write client locks. */
|
||||||
|
#define LSM_LOCK_NRWCLIENT 16
|
||||||
|
|
||||||
|
/* Lock definitions.
|
||||||
|
*/
|
||||||
|
#define LSM_LOCK_DMS1 1 /* Serialize connect/disconnect ops */
|
||||||
|
#define LSM_LOCK_DMS2 2 /* Read-write connections */
|
||||||
|
#define LSM_LOCK_DMS3 3 /* Read-only connections */
|
||||||
|
#define LSM_LOCK_WRITER 4
|
||||||
|
#define LSM_LOCK_WORKER 5
|
||||||
|
#define LSM_LOCK_CHECKPOINTER 6
|
||||||
|
#define LSM_LOCK_ROTRANS 7
|
||||||
|
#define LSM_LOCK_READER(i) ((i) + LSM_LOCK_ROTRANS + 1)
|
||||||
|
#define LSM_LOCK_RWCLIENT(i) ((i) + LSM_LOCK_READER(LSM_LOCK_NREADER))
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Hard limit on the number of free-list entries that may be stored in
|
||||||
|
** a checkpoint (the remainder are stored as a system record in the LSM).
|
||||||
|
** See also LSM_CONFIG_MAX_FREELIST.
|
||||||
|
*/
|
||||||
|
#define LSM_MAX_FREELIST_ENTRIES 24
|
||||||
|
|
||||||
|
#define LSM_MAX_BLOCK_REDIRECTS 16
|
||||||
|
|
||||||
|
#define LSM_ATTEMPTS_BEFORE_PROTOCOL 10000
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Each entry stored in the LSM (or in-memory tree structure) has an
|
||||||
|
** associated mask of the following flags.
|
||||||
|
*/
|
||||||
|
#define LSM_START_DELETE 0x01 /* Start of open-ended delete range */
|
||||||
|
#define LSM_END_DELETE 0x02 /* End of open-ended delete range */
|
||||||
|
#define LSM_POINT_DELETE 0x04 /* Delete this key */
|
||||||
|
#define LSM_INSERT 0x08 /* Insert this key and value */
|
||||||
|
#define LSM_SEPARATOR 0x10 /* True if entry is separator key only */
|
||||||
|
#define LSM_SYSTEMKEY 0x20 /* True if entry is a system key (FREELIST) */
|
||||||
|
|
||||||
|
#define LSM_CONTIGUOUS 0x40 /* Used in lsm_tree.c */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A string that can grow by appending.
|
||||||
|
*/
|
||||||
|
struct LsmString {
|
||||||
|
lsm_env *pEnv; /* Run-time environment */
|
||||||
|
int n; /* Size of string. -1 indicates error */
|
||||||
|
int nAlloc; /* Space allocated for z[] */
|
||||||
|
char *z; /* The string content */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct LsmFile LsmFile;
|
||||||
|
struct LsmFile {
|
||||||
|
lsm_file *pFile;
|
||||||
|
LsmFile *pNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of the following type is used to store an ordered list of
|
||||||
|
** u32 values.
|
||||||
|
**
|
||||||
|
** Note: This is a place-holder implementation. It should be replaced by
|
||||||
|
** a version that avoids making a single large allocation when the array
|
||||||
|
** contains a large number of values. For this reason, the internals of
|
||||||
|
** this object should only manipulated by the intArrayXXX() functions in
|
||||||
|
** lsm_tree.c.
|
||||||
|
*/
|
||||||
|
typedef struct IntArray IntArray;
|
||||||
|
struct IntArray {
|
||||||
|
int nAlloc;
|
||||||
|
int nArray;
|
||||||
|
u32 *aArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Redirect {
|
||||||
|
int n; /* Number of redirects */
|
||||||
|
struct RedirectEntry {
|
||||||
|
int iFrom;
|
||||||
|
int iTo;
|
||||||
|
} *a;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of this structure represents a point in the history of the
|
||||||
|
** tree structure to roll back to. Refer to comments in lsm_tree.c for
|
||||||
|
** details.
|
||||||
|
*/
|
||||||
|
struct TreeMark {
|
||||||
|
u32 iRoot; /* Offset of root node in shm file */
|
||||||
|
u32 nHeight; /* Current height of tree structure */
|
||||||
|
u32 iWrite; /* Write offset in shm file */
|
||||||
|
u32 nChunk; /* Number of chunks in shared-memory file */
|
||||||
|
u32 iFirst; /* First chunk in linked list */
|
||||||
|
u32 iNextShmid; /* Next id to allocate */
|
||||||
|
int iRollback; /* Index in lsm->rollback to revert to */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of this structure represents a point in the database log.
|
||||||
|
*/
|
||||||
|
struct LogMark {
|
||||||
|
i64 iOff; /* Offset into log (see lsm_log.c) */
|
||||||
|
int nBuf; /* Size of in-memory buffer here */
|
||||||
|
u8 aBuf[8]; /* Bytes of content in aBuf[] */
|
||||||
|
u32 cksum0; /* Checksum 0 at offset (iOff-nBuf) */
|
||||||
|
u32 cksum1; /* Checksum 1 at offset (iOff-nBuf) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransMark {
|
||||||
|
TreeMark tree;
|
||||||
|
LogMark log;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A structure that defines the start and end offsets of a region in the
|
||||||
|
** log file. The size of the region in bytes is (iEnd - iStart), so if
|
||||||
|
** iEnd==iStart the region is zero bytes in size.
|
||||||
|
*/
|
||||||
|
struct LogRegion {
|
||||||
|
i64 iStart; /* Start of region in log file */
|
||||||
|
i64 iEnd; /* End of region in log file */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DbLog {
|
||||||
|
u32 cksum0; /* Checksum 0 at offset iOff */
|
||||||
|
u32 cksum1; /* Checksum 1 at offset iOff */
|
||||||
|
i64 iSnapshotId; /* Log space has been reclaimed to this ss */
|
||||||
|
LogRegion aRegion[3]; /* Log file regions (see docs in lsm_log.c) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TreeRoot {
|
||||||
|
u32 iRoot;
|
||||||
|
u32 nHeight;
|
||||||
|
u32 nByte; /* Total size of this tree in bytes */
|
||||||
|
u32 iTransId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Tree header structure.
|
||||||
|
*/
|
||||||
|
struct TreeHeader {
|
||||||
|
u32 iUsedShmid; /* Id of first shm chunk used by this tree */
|
||||||
|
u32 iNextShmid; /* Shm-id of next chunk allocated */
|
||||||
|
u32 iFirst; /* Chunk number of smallest shm-id */
|
||||||
|
u32 nChunk; /* Number of chunks in shared-memory file */
|
||||||
|
TreeRoot root; /* Root and height of current tree */
|
||||||
|
u32 iWrite; /* Write offset in shm file */
|
||||||
|
TreeRoot oldroot; /* Root and height of the previous tree */
|
||||||
|
u32 iOldShmid; /* Last shm-id used by previous tree */
|
||||||
|
u32 iUsrVersion; /* get/set_user_version() value */
|
||||||
|
i64 iOldLog; /* Log offset associated with old tree */
|
||||||
|
u32 oldcksum0;
|
||||||
|
u32 oldcksum1;
|
||||||
|
DbLog log; /* Current layout of log file */
|
||||||
|
u32 aCksum[2]; /* Checksums 1 and 2. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Database handle structure.
|
||||||
|
**
|
||||||
|
** mLock:
|
||||||
|
** A bitmask representing the locks currently held by the connection.
|
||||||
|
** An LSM database supports N distinct locks, where N is some number less
|
||||||
|
** than or equal to 32. Locks are numbered starting from 1 (see the
|
||||||
|
** definitions for LSM_LOCK_WRITER and co.).
|
||||||
|
**
|
||||||
|
** The least significant 32-bits in mLock represent EXCLUSIVE locks. The
|
||||||
|
** most significant are SHARED locks. So, if a connection holds a SHARED
|
||||||
|
** lock on lock region iLock, then the following is true:
|
||||||
|
**
|
||||||
|
** (mLock & ((iLock+32-1) << 1))
|
||||||
|
**
|
||||||
|
** Or for an EXCLUSIVE lock:
|
||||||
|
**
|
||||||
|
** (mLock & ((iLock-1) << 1))
|
||||||
|
**
|
||||||
|
** pCsr:
|
||||||
|
** Points to the head of a linked list that contains all currently open
|
||||||
|
** cursors. Once this list becomes empty, the user has no outstanding
|
||||||
|
** cursors and the database handle can be successfully closed.
|
||||||
|
**
|
||||||
|
** pCsrCache:
|
||||||
|
** This list contains cursor objects that have been closed using
|
||||||
|
** lsm_csr_close(). Each time a cursor is closed, it is shifted from
|
||||||
|
** the pCsr list to this list. When a new cursor is opened, this list
|
||||||
|
** is inspected to see if there exists a cursor object that can be
|
||||||
|
** reused. This is an optimization only.
|
||||||
|
*/
|
||||||
|
struct lsm_db {
|
||||||
|
|
||||||
|
/* Database handle configuration */
|
||||||
|
lsm_env *pEnv; /* runtime environment */
|
||||||
|
int (*xCmp)(void *, int, void *, int); /* Compare function */
|
||||||
|
|
||||||
|
/* Values configured by calls to lsm_config */
|
||||||
|
int eSafety; /* LSM_SAFETY_OFF, NORMAL or FULL */
|
||||||
|
int bAutowork; /* Configured by LSM_CONFIG_AUTOWORK */
|
||||||
|
int nTreeLimit; /* Configured by LSM_CONFIG_AUTOFLUSH */
|
||||||
|
int nMerge; /* Configured by LSM_CONFIG_AUTOMERGE */
|
||||||
|
int bUseLog; /* Configured by LSM_CONFIG_USE_LOG */
|
||||||
|
int nDfltPgsz; /* Configured by LSM_CONFIG_PAGE_SIZE */
|
||||||
|
int nDfltBlksz; /* Configured by LSM_CONFIG_BLOCK_SIZE */
|
||||||
|
int nMaxFreelist; /* Configured by LSM_CONFIG_MAX_FREELIST */
|
||||||
|
int iMmap; /* Configured by LSM_CONFIG_MMAP */
|
||||||
|
i64 nAutockpt; /* Configured by LSM_CONFIG_AUTOCHECKPOINT */
|
||||||
|
int bMultiProc; /* Configured by L_C_MULTIPLE_PROCESSES */
|
||||||
|
int bReadonly; /* Configured by LSM_CONFIG_READONLY */
|
||||||
|
lsm_compress compress; /* Compression callbacks */
|
||||||
|
lsm_compress_factory factory; /* Compression callback factory */
|
||||||
|
|
||||||
|
/* Sub-system handles */
|
||||||
|
FileSystem *pFS; /* On-disk portion of database */
|
||||||
|
Database *pDatabase; /* Database shared data */
|
||||||
|
|
||||||
|
int iRwclient; /* Read-write client lock held (-1 == none) */
|
||||||
|
|
||||||
|
/* Client transaction context */
|
||||||
|
Snapshot *pClient; /* Client snapshot */
|
||||||
|
int iReader; /* Read lock held (-1 == unlocked) */
|
||||||
|
int bRoTrans; /* True if a read-only db trans is open */
|
||||||
|
MultiCursor *pCsr; /* List of all open cursors */
|
||||||
|
LogWriter *pLogWriter; /* Context for writing to the log file */
|
||||||
|
int nTransOpen; /* Number of opened write transactions */
|
||||||
|
int nTransAlloc; /* Allocated size of aTrans[] array */
|
||||||
|
TransMark *aTrans; /* Array of marks for transaction rollback */
|
||||||
|
IntArray rollback; /* List of tree-nodes to roll back */
|
||||||
|
int bDiscardOld; /* True if lsmTreeDiscardOld() was called */
|
||||||
|
|
||||||
|
MultiCursor *pCsrCache; /* List of all closed cursors */
|
||||||
|
|
||||||
|
/* Worker context */
|
||||||
|
Snapshot *pWorker; /* Worker snapshot (or NULL) */
|
||||||
|
Freelist *pFreelist; /* See sortedNewToplevel() */
|
||||||
|
int bUseFreelist; /* True to use pFreelist */
|
||||||
|
int bIncrMerge; /* True if currently doing a merge */
|
||||||
|
|
||||||
|
int bInFactory; /* True if within factory.xFactory() */
|
||||||
|
|
||||||
|
/* Debugging message callback */
|
||||||
|
void (*xLog)(void *, int, const char *);
|
||||||
|
void *pLogCtx;
|
||||||
|
|
||||||
|
/* Work done notification callback */
|
||||||
|
void (*xWork)(lsm_db *, void *);
|
||||||
|
void *pWorkCtx;
|
||||||
|
|
||||||
|
u64 mLock; /* Mask of current locks. See lsmShmLock(). */
|
||||||
|
lsm_db *pNext; /* Next connection to same database */
|
||||||
|
|
||||||
|
int nShm; /* Size of apShm[] array */
|
||||||
|
void **apShm; /* Shared memory chunks */
|
||||||
|
ShmHeader *pShmhdr; /* Live shared-memory header */
|
||||||
|
TreeHeader treehdr; /* Local copy of tree-header */
|
||||||
|
u32 aSnapshot[LSM_META_PAGE_SIZE / sizeof(u32)];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Segment {
|
||||||
|
Pgno iFirst; /* First page of this run */
|
||||||
|
Pgno iLastPg; /* Last page of this run */
|
||||||
|
Pgno iRoot; /* Root page number (if any) */
|
||||||
|
int nSize; /* Size of this run in pages */
|
||||||
|
|
||||||
|
Redirect *pRedirect; /* Block redirects (or NULL) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** iSplitTopic/pSplitKey/nSplitKey:
|
||||||
|
** If nRight>0, this buffer contains a copy of the largest key that has
|
||||||
|
** already been written to the left-hand-side of the level.
|
||||||
|
*/
|
||||||
|
struct Level {
|
||||||
|
Segment lhs; /* Left-hand (main) segment */
|
||||||
|
int nRight; /* Size of apRight[] array */
|
||||||
|
Segment *aRhs; /* Old segments being merged into this */
|
||||||
|
int iSplitTopic; /* Split key topic (if nRight>0) */
|
||||||
|
void *pSplitKey; /* Pointer to split-key (if nRight>0) */
|
||||||
|
int nSplitKey; /* Number of bytes in split-key */
|
||||||
|
|
||||||
|
u16 iAge; /* Number of times data has been written */
|
||||||
|
u16 flags; /* Mask of LEVEL_XXX bits */
|
||||||
|
Merge *pMerge; /* Merge operation currently underway */
|
||||||
|
Level *pNext; /* Next level in tree */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The Level.flags field is set to a combination of the following bits.
|
||||||
|
**
|
||||||
|
** LEVEL_FREELIST_ONLY:
|
||||||
|
** Set if the level consists entirely of free-list entries.
|
||||||
|
**
|
||||||
|
** LEVEL_INCOMPLETE:
|
||||||
|
** This is set while a new toplevel level is being constructed. It is
|
||||||
|
** never set for any level other than a new toplevel.
|
||||||
|
*/
|
||||||
|
#define LEVEL_FREELIST_ONLY 0x0001
|
||||||
|
#define LEVEL_INCOMPLETE 0x0002
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A structure describing an ongoing merge. There is an instance of this
|
||||||
|
** structure for every Level currently undergoing a merge in the worker
|
||||||
|
** snapshot.
|
||||||
|
**
|
||||||
|
** It is assumed that code that uses an instance of this structure has
|
||||||
|
** access to the associated Level struct.
|
||||||
|
**
|
||||||
|
** iOutputOff:
|
||||||
|
** The byte offset to write to next within the last page of the
|
||||||
|
** output segment.
|
||||||
|
*/
|
||||||
|
struct MergeInput {
|
||||||
|
Pgno iPg; /* Page on which next input is stored */
|
||||||
|
int iCell; /* Cell containing next input to merge */
|
||||||
|
};
|
||||||
|
struct Merge {
|
||||||
|
int nInput; /* Number of input runs being merged */
|
||||||
|
MergeInput *aInput; /* Array nInput entries in size */
|
||||||
|
MergeInput splitkey; /* Location in file of current splitkey */
|
||||||
|
int nSkip; /* Number of separators entries to skip */
|
||||||
|
int iOutputOff; /* Write offset on output page */
|
||||||
|
Pgno iCurrentPtr; /* Current pointer value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The first argument to this macro is a pointer to a Segment structure.
|
||||||
|
** Returns true if the structure instance indicates that the separators
|
||||||
|
** array is valid.
|
||||||
|
*/
|
||||||
|
#define segmentHasSeparators(pSegment) ((pSegment)->sep.iFirst>0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The values that accompany the lock held by a database reader.
|
||||||
|
*/
|
||||||
|
struct ShmReader {
|
||||||
|
u32 iTreeId;
|
||||||
|
i64 iLsmId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of this structure is stored in the first shared-memory
|
||||||
|
** page. The shared-memory header.
|
||||||
|
**
|
||||||
|
** bWriter:
|
||||||
|
** Immediately after opening a write transaction taking the WRITER lock,
|
||||||
|
** each writer client sets this flag. It is cleared right before the
|
||||||
|
** WRITER lock is relinquished. If a subsequent writer finds that this
|
||||||
|
** flag is already set when a write transaction is opened, this indicates
|
||||||
|
** that a previous writer failed mid-transaction.
|
||||||
|
**
|
||||||
|
** iMetaPage:
|
||||||
|
** If the database file does not contain a valid, synced, checkpoint, this
|
||||||
|
** value is set to 0. Otherwise, it is set to the meta-page number that
|
||||||
|
** contains the most recently written checkpoint (either 1 or 2).
|
||||||
|
**
|
||||||
|
** hdr1, hdr2:
|
||||||
|
** The two copies of the in-memory tree header. Two copies are required
|
||||||
|
** in case a writer fails while updating one of them.
|
||||||
|
*/
|
||||||
|
struct ShmHeader {
|
||||||
|
u32 aSnap1[LSM_META_PAGE_SIZE / 4];
|
||||||
|
u32 aSnap2[LSM_META_PAGE_SIZE / 4];
|
||||||
|
u32 bWriter;
|
||||||
|
u32 iMetaPage;
|
||||||
|
TreeHeader hdr1;
|
||||||
|
TreeHeader hdr2;
|
||||||
|
ShmReader aReader[LSM_LOCK_NREADER];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of this structure is stored at the start of each shared-memory
|
||||||
|
** chunk except the first (which is the header chunk - see above).
|
||||||
|
*/
|
||||||
|
struct ShmChunk {
|
||||||
|
u32 iShmid;
|
||||||
|
u32 iNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Maximum number of shared-memory chunks allowed in the *-shm file. Since
|
||||||
|
** each shared-memory chunk is 32KB in size, this is a theoretical limit only.
|
||||||
|
*/
|
||||||
|
#define LSM_MAX_SHMCHUNKS (1<<30)
|
||||||
|
|
||||||
|
/* Return true if shm-sequence "a" is larger than or equal to "b" */
|
||||||
|
#define shm_sequence_ge(a, b) (((u32)a-(u32)b) < LSM_MAX_SHMCHUNKS)
|
||||||
|
|
||||||
|
#define LSM_APPLIST_SZ 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of the following structure stores the in-memory part of
|
||||||
|
** the current free block list. This structure is to the free block list
|
||||||
|
** as the in-memory tree is to the users database content. The contents
|
||||||
|
** of the free block list is found by merging the in-memory components
|
||||||
|
** with those stored in the LSM, just as the contents of the database is
|
||||||
|
** found by merging the in-memory tree with the user data entries in the
|
||||||
|
** LSM.
|
||||||
|
**
|
||||||
|
** Each FreelistEntry structure in the array represents either an insert
|
||||||
|
** or delete operation on the free-list. For deletes, the FreelistEntry.iId
|
||||||
|
** field is set to -1. For inserts, it is set to zero or greater.
|
||||||
|
**
|
||||||
|
** The array of FreelistEntry structures is always sorted in order of
|
||||||
|
** block number (ascending).
|
||||||
|
**
|
||||||
|
** When the in-memory free block list is written into the LSM, each insert
|
||||||
|
** operation is written separately. The entry key is the bitwise inverse
|
||||||
|
** of the block number as a 32-bit big-endian integer. This is done so that
|
||||||
|
** the entries in the LSM are sorted in descending order of block id.
|
||||||
|
** The associated value is the snapshot id, formated as a varint.
|
||||||
|
*/
|
||||||
|
struct Freelist {
|
||||||
|
FreelistEntry *aEntry; /* Free list entries */
|
||||||
|
int nEntry; /* Number of valid slots in aEntry[] */
|
||||||
|
int nAlloc; /* Allocated size of aEntry[] */
|
||||||
|
};
|
||||||
|
struct FreelistEntry {
|
||||||
|
u32 iBlk; /* Block number */
|
||||||
|
i64 iId; /* Largest snapshot id to use this block */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A snapshot of a database. A snapshot contains all the information required
|
||||||
|
** to read or write a database file on disk. See the description of struct
|
||||||
|
** Database below for futher details.
|
||||||
|
*/
|
||||||
|
struct Snapshot {
|
||||||
|
Database *pDatabase; /* Database this snapshot belongs to */
|
||||||
|
u32 iCmpId; /* Id of compression scheme */
|
||||||
|
Level *pLevel; /* Pointer to level 0 of snapshot (or NULL) */
|
||||||
|
i64 iId; /* Snapshot id */
|
||||||
|
i64 iLogOff; /* Log file offset */
|
||||||
|
Redirect redirect; /* Block redirection array */
|
||||||
|
|
||||||
|
/* Used by worker snapshots only */
|
||||||
|
int nBlock; /* Number of blocks in database file */
|
||||||
|
Pgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
|
||||||
|
Freelist freelist; /* Free block list */
|
||||||
|
u32 nWrite; /* Total number of pages written to disk */
|
||||||
|
};
|
||||||
|
#define LSM_INITIAL_SNAPSHOT_ID 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "lsm_ckpt.c".
|
||||||
|
*/
|
||||||
|
int lsmCheckpointWrite(lsm_db *, int, u32 *);
|
||||||
|
int lsmCheckpointLevels(lsm_db *, int, void **, int *);
|
||||||
|
int lsmCheckpointLoadLevels(lsm_db *pDb, void *pVal, int nVal);
|
||||||
|
|
||||||
|
int lsmCheckpointRecover(lsm_db *);
|
||||||
|
int lsmCheckpointDeserialize(lsm_db *, int, u32 *, Snapshot **);
|
||||||
|
|
||||||
|
int lsmCheckpointLoadWorker(lsm_db *pDb);
|
||||||
|
int lsmCheckpointStore(lsm_db *pDb, int);
|
||||||
|
|
||||||
|
int lsmCheckpointLoad(lsm_db *pDb, int *);
|
||||||
|
int lsmCheckpointLoadOk(lsm_db *pDb, int);
|
||||||
|
int lsmCheckpointClientCacheOk(lsm_db *);
|
||||||
|
|
||||||
|
u32 lsmCheckpointNBlock(u32 *);
|
||||||
|
i64 lsmCheckpointId(u32 *, int);
|
||||||
|
u32 lsmCheckpointNWrite(u32 *, int);
|
||||||
|
i64 lsmCheckpointLogOffset(u32 *);
|
||||||
|
int lsmCheckpointPgsz(u32 *);
|
||||||
|
int lsmCheckpointBlksz(u32 *);
|
||||||
|
void lsmCheckpointLogoffset(u32 *aCkpt, DbLog *pLog);
|
||||||
|
void lsmCheckpointZeroLogoffset(lsm_db *);
|
||||||
|
|
||||||
|
int lsmCheckpointSaveWorker(lsm_db *pDb, int);
|
||||||
|
int lsmDatabaseFull(lsm_db *pDb);
|
||||||
|
int lsmCheckpointSynced(lsm_db *pDb, i64 *piId, i64 *piLog, u32 *pnWrite);
|
||||||
|
|
||||||
|
int lsmCheckpointSize(lsm_db *db, int *pnByte);
|
||||||
|
|
||||||
|
int lsmInfoCompressionId(lsm_db *db, u32 *piCmpId);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "lsm_tree.c".
|
||||||
|
*/
|
||||||
|
int lsmTreeNew(lsm_env *, int (*)(void *, int, void *, int), Tree **ppTree);
|
||||||
|
void lsmTreeRelease(lsm_env *, Tree *);
|
||||||
|
int lsmTreeInit(lsm_db *);
|
||||||
|
int lsmTreeRepair(lsm_db *);
|
||||||
|
|
||||||
|
void lsmTreeMakeOld(lsm_db *pDb);
|
||||||
|
void lsmTreeDiscardOld(lsm_db *pDb);
|
||||||
|
int lsmTreeHasOld(lsm_db *pDb);
|
||||||
|
|
||||||
|
int lsmTreeSize(lsm_db *);
|
||||||
|
int lsmTreeEndTransaction(lsm_db *pDb, int bCommit);
|
||||||
|
int lsmTreeLoadHeader(lsm_db *pDb, int *);
|
||||||
|
int lsmTreeLoadHeaderOk(lsm_db *, int);
|
||||||
|
|
||||||
|
int lsmTreeInsert(lsm_db *pDb, void *pKey, int nKey, void *pVal, int nVal);
|
||||||
|
int lsmTreeDelete(lsm_db *db, void *pKey1, int nKey1, void *pKey2, int nKey2);
|
||||||
|
void lsmTreeRollback(lsm_db *pDb, TreeMark *pMark);
|
||||||
|
void lsmTreeMark(lsm_db *pDb, TreeMark *pMark);
|
||||||
|
|
||||||
|
int lsmTreeCursorNew(lsm_db *pDb, int, TreeCursor **);
|
||||||
|
void lsmTreeCursorDestroy(TreeCursor *);
|
||||||
|
|
||||||
|
int lsmTreeCursorSeek(TreeCursor *pCsr, void *pKey, int nKey, int *pRes);
|
||||||
|
int lsmTreeCursorNext(TreeCursor *pCsr);
|
||||||
|
int lsmTreeCursorPrev(TreeCursor *pCsr);
|
||||||
|
int lsmTreeCursorEnd(TreeCursor *pCsr, int bLast);
|
||||||
|
void lsmTreeCursorReset(TreeCursor *pCsr);
|
||||||
|
int lsmTreeCursorKey(TreeCursor *pCsr, int *pFlags, void **ppKey, int *pnKey);
|
||||||
|
int lsmTreeCursorFlags(TreeCursor *pCsr);
|
||||||
|
int lsmTreeCursorValue(TreeCursor *pCsr, void **ppVal, int *pnVal);
|
||||||
|
int lsmTreeCursorValid(TreeCursor *pCsr);
|
||||||
|
int lsmTreeCursorSave(TreeCursor *pCsr);
|
||||||
|
|
||||||
|
void lsmFlagsToString(int flags, char *zFlags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "mem.c".
|
||||||
|
*/
|
||||||
|
void *lsmMalloc(lsm_env*, size_t);
|
||||||
|
void lsmFree(lsm_env*, void *);
|
||||||
|
void *lsmRealloc(lsm_env*, void *, size_t);
|
||||||
|
void *lsmReallocOrFree(lsm_env*, void *, size_t);
|
||||||
|
void *lsmReallocOrFreeRc(lsm_env *, void *, size_t, int *);
|
||||||
|
|
||||||
|
void *lsmMallocZeroRc(lsm_env*, size_t, int *);
|
||||||
|
void *lsmMallocRc(lsm_env*, size_t, int *);
|
||||||
|
|
||||||
|
void *lsmMallocZero(lsm_env *pEnv, size_t);
|
||||||
|
char *lsmMallocStrdup(lsm_env *pEnv, const char *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "lsm_mutex.c".
|
||||||
|
*/
|
||||||
|
int lsmMutexStatic(lsm_env*, int, lsm_mutex **);
|
||||||
|
int lsmMutexNew(lsm_env*, lsm_mutex **);
|
||||||
|
void lsmMutexDel(lsm_env*, lsm_mutex *);
|
||||||
|
void lsmMutexEnter(lsm_env*, lsm_mutex *);
|
||||||
|
int lsmMutexTry(lsm_env*, lsm_mutex *);
|
||||||
|
void lsmMutexLeave(lsm_env*, lsm_mutex *);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
int lsmMutexHeld(lsm_env *, lsm_mutex *);
|
||||||
|
int lsmMutexNotHeld(lsm_env *, lsm_mutex *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
** Start of functions from "lsm_file.c".
|
||||||
|
*/
|
||||||
|
int lsmFsOpen(lsm_db *, const char *, int);
|
||||||
|
int lsmFsOpenLog(lsm_db *, int *);
|
||||||
|
void lsmFsCloseLog(lsm_db *);
|
||||||
|
void lsmFsClose(FileSystem *);
|
||||||
|
|
||||||
|
int lsmFsConfigure(lsm_db *db);
|
||||||
|
|
||||||
|
int lsmFsBlockSize(FileSystem *);
|
||||||
|
void lsmFsSetBlockSize(FileSystem *, int);
|
||||||
|
int lsmFsMoveBlock(FileSystem *pFS, Segment *pSeg, int iTo, int iFrom);
|
||||||
|
|
||||||
|
int lsmFsPageSize(FileSystem *);
|
||||||
|
void lsmFsSetPageSize(FileSystem *, int);
|
||||||
|
|
||||||
|
int lsmFsFileid(lsm_db *pDb, void **ppId, int *pnId);
|
||||||
|
|
||||||
|
/* Creating, populating, gobbling and deleting sorted runs. */
|
||||||
|
void lsmFsGobble(lsm_db *, Segment *, Pgno *, int);
|
||||||
|
int lsmFsSortedDelete(FileSystem *, Snapshot *, int, Segment *);
|
||||||
|
int lsmFsSortedFinish(FileSystem *, Segment *);
|
||||||
|
int lsmFsSortedAppend(FileSystem *, Snapshot *, Level *, int, Page **);
|
||||||
|
int lsmFsSortedPadding(FileSystem *, Snapshot *, Segment *);
|
||||||
|
|
||||||
|
/* Functions to retrieve the lsm_env pointer from a FileSystem or Page object */
|
||||||
|
lsm_env *lsmFsEnv(FileSystem *);
|
||||||
|
lsm_env *lsmPageEnv(Page *);
|
||||||
|
FileSystem *lsmPageFS(Page *);
|
||||||
|
|
||||||
|
int lsmFsSectorSize(FileSystem *);
|
||||||
|
|
||||||
|
void lsmSortedSplitkey(lsm_db *, Level *, int *);
|
||||||
|
|
||||||
|
/* Reading sorted run content. */
|
||||||
|
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg);
|
||||||
|
int lsmFsDbPageGet(FileSystem *, Segment *, Pgno, Page **);
|
||||||
|
int lsmFsDbPageNext(Segment *, Page *, int eDir, Page **);
|
||||||
|
|
||||||
|
u8 *lsmFsPageData(Page *, int *);
|
||||||
|
int lsmFsPageRelease(Page *);
|
||||||
|
int lsmFsPagePersist(Page *);
|
||||||
|
void lsmFsPageRef(Page *);
|
||||||
|
Pgno lsmFsPageNumber(Page *);
|
||||||
|
|
||||||
|
int lsmFsNRead(FileSystem *);
|
||||||
|
int lsmFsNWrite(FileSystem *);
|
||||||
|
|
||||||
|
int lsmFsMetaPageGet(FileSystem *, int, int, MetaPage **);
|
||||||
|
int lsmFsMetaPageRelease(MetaPage *);
|
||||||
|
u8 *lsmFsMetaPageData(MetaPage *, int *);
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg);
|
||||||
|
int lsmFsIntegrityCheck(lsm_db *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Pgno lsmFsRedirectPage(FileSystem *, Redirect *, Pgno);
|
||||||
|
|
||||||
|
int lsmFsPageWritable(Page *);
|
||||||
|
|
||||||
|
/* Functions to read, write and sync the log file. */
|
||||||
|
int lsmFsWriteLog(FileSystem *pFS, i64 iOff, LsmString *pStr);
|
||||||
|
int lsmFsSyncLog(FileSystem *pFS);
|
||||||
|
int lsmFsReadLog(FileSystem *pFS, i64 iOff, int nRead, LsmString *pStr);
|
||||||
|
int lsmFsTruncateLog(FileSystem *pFS, i64 nByte);
|
||||||
|
int lsmFsTruncateDb(FileSystem *pFS, i64 nByte);
|
||||||
|
int lsmFsCloseAndDeleteLog(FileSystem *pFS);
|
||||||
|
|
||||||
|
LsmFile *lsmFsDeferClose(FileSystem *pFS);
|
||||||
|
|
||||||
|
/* And to sync the db file */
|
||||||
|
int lsmFsSyncDb(FileSystem *, int);
|
||||||
|
|
||||||
|
void lsmFsFlushWaiting(FileSystem *, int *);
|
||||||
|
|
||||||
|
/* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */
|
||||||
|
int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, Pgno iFirst, char **pzOut);
|
||||||
|
int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut);
|
||||||
|
int lsmConfigMmap(lsm_db *pDb, int *piParam);
|
||||||
|
|
||||||
|
int lsmEnvOpen(lsm_env *, const char *, int, lsm_file **);
|
||||||
|
int lsmEnvClose(lsm_env *pEnv, lsm_file *pFile);
|
||||||
|
int lsmEnvLock(lsm_env *pEnv, lsm_file *pFile, int iLock, int eLock);
|
||||||
|
int lsmEnvTestLock(lsm_env *pEnv, lsm_file *pFile, int iLock, int nLock, int);
|
||||||
|
|
||||||
|
int lsmEnvShmMap(lsm_env *, lsm_file *, int, int, void **);
|
||||||
|
void lsmEnvShmBarrier(lsm_env *);
|
||||||
|
void lsmEnvShmUnmap(lsm_env *, lsm_file *, int);
|
||||||
|
|
||||||
|
void lsmEnvSleep(lsm_env *, int);
|
||||||
|
|
||||||
|
int lsmFsReadSyncedId(lsm_db *db, int, i64 *piVal);
|
||||||
|
|
||||||
|
int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, Pgno, int *);
|
||||||
|
|
||||||
|
void lsmFsPurgeCache(FileSystem *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** End of functions from "lsm_file.c".
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "lsm_sorted.c".
|
||||||
|
*/
|
||||||
|
int lsmInfoPageDump(lsm_db *, Pgno, int, char **);
|
||||||
|
void lsmSortedCleanup(lsm_db *);
|
||||||
|
int lsmSortedAutoWork(lsm_db *, int nUnit);
|
||||||
|
|
||||||
|
int lsmSortedWalkFreelist(lsm_db *, int, int (*)(void *, int, i64), void *);
|
||||||
|
|
||||||
|
int lsmSaveWorker(lsm_db *, int);
|
||||||
|
|
||||||
|
int lsmFlushTreeToDisk(lsm_db *pDb);
|
||||||
|
|
||||||
|
void lsmSortedRemap(lsm_db *pDb);
|
||||||
|
|
||||||
|
void lsmSortedFreeLevel(lsm_env *pEnv, Level *);
|
||||||
|
|
||||||
|
int lsmSortedAdvanceAll(lsm_db *pDb);
|
||||||
|
|
||||||
|
int lsmSortedLoadMerge(lsm_db *, Level *, u32 *, int *);
|
||||||
|
int lsmSortedLoadFreelist(lsm_db *pDb, void **, int *);
|
||||||
|
|
||||||
|
void *lsmSortedSplitKey(Level *pLevel, int *pnByte);
|
||||||
|
|
||||||
|
void lsmSortedSaveTreeCursors(lsm_db *);
|
||||||
|
|
||||||
|
int lsmMCursorNew(lsm_db *, MultiCursor **);
|
||||||
|
void lsmMCursorClose(MultiCursor *, int);
|
||||||
|
int lsmMCursorSeek(MultiCursor *, int, void *, int , int);
|
||||||
|
int lsmMCursorFirst(MultiCursor *);
|
||||||
|
int lsmMCursorPrev(MultiCursor *);
|
||||||
|
int lsmMCursorLast(MultiCursor *);
|
||||||
|
int lsmMCursorValid(MultiCursor *);
|
||||||
|
int lsmMCursorNext(MultiCursor *);
|
||||||
|
int lsmMCursorKey(MultiCursor *, void **, int *);
|
||||||
|
int lsmMCursorValue(MultiCursor *, void **, int *);
|
||||||
|
int lsmMCursorType(MultiCursor *, int *);
|
||||||
|
lsm_db *lsmMCursorDb(MultiCursor *);
|
||||||
|
void lsmMCursorFreeCache(lsm_db *);
|
||||||
|
|
||||||
|
int lsmSaveCursors(lsm_db *pDb);
|
||||||
|
int lsmRestoreCursors(lsm_db *pDb);
|
||||||
|
|
||||||
|
void lsmSortedDumpStructure(lsm_db *pDb, Snapshot *, int, int, const char *);
|
||||||
|
void lsmFsDumpBlocklists(lsm_db *);
|
||||||
|
|
||||||
|
void lsmSortedExpandBtreePage(Page *pPg, int nOrig);
|
||||||
|
|
||||||
|
void lsmPutU32(u8 *, u32);
|
||||||
|
u32 lsmGetU32(u8 *);
|
||||||
|
u64 lsmGetU64(u8 *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from "lsm_varint.c".
|
||||||
|
*/
|
||||||
|
int lsmVarintPut32(u8 *, int);
|
||||||
|
int lsmVarintGet32(u8 *, int *);
|
||||||
|
int lsmVarintPut64(u8 *aData, i64 iVal);
|
||||||
|
int lsmVarintGet64(const u8 *aData, i64 *piVal);
|
||||||
|
|
||||||
|
int lsmVarintLen32(int);
|
||||||
|
int lsmVarintSize(u8 c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "main.c".
|
||||||
|
*/
|
||||||
|
void lsmLogMessage(lsm_db *, int, const char *, ...);
|
||||||
|
int lsmInfoFreelist(lsm_db *pDb, char **pzOut);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Functions from file "lsm_log.c".
|
||||||
|
*/
|
||||||
|
int lsmLogBegin(lsm_db *pDb);
|
||||||
|
int lsmLogWrite(lsm_db *, void *, int, void *, int);
|
||||||
|
int lsmLogCommit(lsm_db *);
|
||||||
|
void lsmLogEnd(lsm_db *pDb, int bCommit);
|
||||||
|
void lsmLogTell(lsm_db *, LogMark *);
|
||||||
|
void lsmLogSeek(lsm_db *, LogMark *);
|
||||||
|
void lsmLogClose(lsm_db *);
|
||||||
|
|
||||||
|
int lsmLogRecover(lsm_db *);
|
||||||
|
int lsmInfoLogStructure(lsm_db *pDb, char **pzVal);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
** Functions from file "lsm_shared.c".
|
||||||
|
*/
|
||||||
|
|
||||||
|
int lsmDbDatabaseConnect(lsm_db*, const char *);
|
||||||
|
void lsmDbDatabaseRelease(lsm_db *);
|
||||||
|
|
||||||
|
int lsmBeginReadTrans(lsm_db *);
|
||||||
|
int lsmBeginWriteTrans(lsm_db *);
|
||||||
|
int lsmBeginFlush(lsm_db *);
|
||||||
|
|
||||||
|
int lsmDetectRoTrans(lsm_db *db, int *);
|
||||||
|
int lsmBeginRoTrans(lsm_db *db);
|
||||||
|
|
||||||
|
int lsmBeginWork(lsm_db *);
|
||||||
|
void lsmFinishWork(lsm_db *, int, int *);
|
||||||
|
|
||||||
|
int lsmFinishRecovery(lsm_db *);
|
||||||
|
void lsmFinishReadTrans(lsm_db *);
|
||||||
|
int lsmFinishWriteTrans(lsm_db *, int);
|
||||||
|
int lsmFinishFlush(lsm_db *, int);
|
||||||
|
|
||||||
|
int lsmSnapshotSetFreelist(lsm_db *, int *, int);
|
||||||
|
|
||||||
|
Snapshot *lsmDbSnapshotClient(lsm_db *);
|
||||||
|
Snapshot *lsmDbSnapshotWorker(lsm_db *);
|
||||||
|
|
||||||
|
void lsmSnapshotSetCkptid(Snapshot *, i64);
|
||||||
|
|
||||||
|
Level *lsmDbSnapshotLevel(Snapshot *);
|
||||||
|
void lsmDbSnapshotSetLevel(Snapshot *, Level *);
|
||||||
|
|
||||||
|
void lsmDbRecoveryComplete(lsm_db *, int);
|
||||||
|
|
||||||
|
int lsmBlockAllocate(lsm_db *, int, int *);
|
||||||
|
int lsmBlockFree(lsm_db *, int);
|
||||||
|
int lsmBlockRefree(lsm_db *, int);
|
||||||
|
|
||||||
|
void lsmFreelistDeltaBegin(lsm_db *);
|
||||||
|
void lsmFreelistDeltaEnd(lsm_db *);
|
||||||
|
int lsmFreelistDelta(lsm_db *pDb);
|
||||||
|
|
||||||
|
DbLog *lsmDatabaseLog(lsm_db *pDb);
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
int lsmHoldingClientMutex(lsm_db *pDb);
|
||||||
|
int lsmShmAssertLock(lsm_db *db, int iLock, int eOp);
|
||||||
|
int lsmShmAssertWorker(lsm_db *db);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void lsmFreeSnapshot(lsm_env *, Snapshot *);
|
||||||
|
|
||||||
|
|
||||||
|
/* Candidate values for the 3rd argument to lsmShmLock() */
|
||||||
|
#define LSM_LOCK_UNLOCK 0
|
||||||
|
#define LSM_LOCK_SHARED 1
|
||||||
|
#define LSM_LOCK_EXCL 2
|
||||||
|
|
||||||
|
int lsmShmCacheChunks(lsm_db *db, int nChunk);
|
||||||
|
int lsmShmLock(lsm_db *db, int iLock, int eOp, int bBlock);
|
||||||
|
int lsmShmTestLock(lsm_db *db, int iLock, int nLock, int eOp);
|
||||||
|
void lsmShmBarrier(lsm_db *db);
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
void lsmShmHasLock(lsm_db *db, int iLock, int eOp);
|
||||||
|
#else
|
||||||
|
# define lsmShmHasLock(x,y,z)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int lsmReadlock(lsm_db *, i64 iLsm, u32 iShmMin, u32 iShmMax);
|
||||||
|
|
||||||
|
int lsmLsmInUse(lsm_db *db, i64 iLsmId, int *pbInUse);
|
||||||
|
int lsmTreeInUse(lsm_db *db, u32 iLsmId, int *pbInUse);
|
||||||
|
int lsmFreelistAppend(lsm_env *pEnv, Freelist *p, int iBlk, i64 iId);
|
||||||
|
|
||||||
|
int lsmDbMultiProc(lsm_db *);
|
||||||
|
void lsmDbDeferredClose(lsm_db *, lsm_file *, LsmFile *);
|
||||||
|
LsmFile *lsmDbRecycleFd(lsm_db *);
|
||||||
|
|
||||||
|
int lsmWalkFreelist(lsm_db *, int, int (*)(void *, int, i64), void *);
|
||||||
|
|
||||||
|
int lsmCheckCompressionId(lsm_db *, u32);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
** functions in lsm_str.c
|
||||||
|
*/
|
||||||
|
void lsmStringInit(LsmString*, lsm_env *pEnv);
|
||||||
|
int lsmStringExtend(LsmString*, int);
|
||||||
|
int lsmStringAppend(LsmString*, const char *, int);
|
||||||
|
void lsmStringVAppendf(LsmString*, const char *zFormat, va_list, va_list);
|
||||||
|
void lsmStringAppendf(LsmString*, const char *zFormat, ...);
|
||||||
|
void lsmStringClear(LsmString*);
|
||||||
|
char *lsmMallocPrintf(lsm_env*, const char*, ...);
|
||||||
|
int lsmStringBinAppend(LsmString *pStr, const u8 *a, int n);
|
||||||
|
|
||||||
|
int lsmStrlen(const char *zName);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Round up a number to the next larger multiple of 8. This is used
|
||||||
|
** to force 8-byte alignment on 64-bit architectures.
|
||||||
|
*/
|
||||||
|
#define ROUND8(x) (((x)+7)&~7)
|
||||||
|
|
||||||
|
#define LSM_MIN(x,y) ((x)>(y) ? (y) : (x))
|
||||||
|
#define LSM_MAX(x,y) ((x)>(y) ? (x) : (y))
|
||||||
|
|
||||||
|
#endif
|
1237
ext/lsm1/lsm_ckpt.c
Normal file
1237
ext/lsm1/lsm_ckpt.c
Normal file
File diff suppressed because it is too large
Load Diff
3292
ext/lsm1/lsm_file.c
Normal file
3292
ext/lsm1/lsm_file.c
Normal file
File diff suppressed because it is too large
Load Diff
1134
ext/lsm1/lsm_log.c
Normal file
1134
ext/lsm1/lsm_log.c
Normal file
File diff suppressed because it is too large
Load Diff
1009
ext/lsm1/lsm_main.c
Normal file
1009
ext/lsm1/lsm_main.c
Normal file
File diff suppressed because it is too large
Load Diff
104
ext/lsm1/lsm_mem.c
Normal file
104
ext/lsm1/lsm_mem.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
** 2011-08-18
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** Helper routines for memory allocation.
|
||||||
|
*/
|
||||||
|
#include "lsmInt.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following routines are called internally by LSM sub-routines. In
|
||||||
|
** this case a valid environment pointer must be supplied.
|
||||||
|
*/
|
||||||
|
void *lsmMalloc(lsm_env *pEnv, size_t N){
|
||||||
|
assert( pEnv );
|
||||||
|
return pEnv->xMalloc(pEnv, N);
|
||||||
|
}
|
||||||
|
void lsmFree(lsm_env *pEnv, void *p){
|
||||||
|
assert( pEnv );
|
||||||
|
pEnv->xFree(pEnv, p);
|
||||||
|
}
|
||||||
|
void *lsmRealloc(lsm_env *pEnv, void *p, size_t N){
|
||||||
|
assert( pEnv );
|
||||||
|
return pEnv->xRealloc(pEnv, p, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Core memory allocation routines for LSM.
|
||||||
|
*/
|
||||||
|
void *lsm_malloc(lsm_env *pEnv, size_t N){
|
||||||
|
return lsmMalloc(pEnv ? pEnv : lsm_default_env(), N);
|
||||||
|
}
|
||||||
|
void lsm_free(lsm_env *pEnv, void *p){
|
||||||
|
lsmFree(pEnv ? pEnv : lsm_default_env(), p);
|
||||||
|
}
|
||||||
|
void *lsm_realloc(lsm_env *pEnv, void *p, size_t N){
|
||||||
|
return lsmRealloc(pEnv ? pEnv : lsm_default_env(), p, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *lsmMallocZero(lsm_env *pEnv, size_t N){
|
||||||
|
void *pRet;
|
||||||
|
assert( pEnv );
|
||||||
|
pRet = lsmMalloc(pEnv, N);
|
||||||
|
if( pRet ) memset(pRet, 0, N);
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *lsmMallocRc(lsm_env *pEnv, size_t N, int *pRc){
|
||||||
|
void *pRet = 0;
|
||||||
|
if( *pRc==LSM_OK ){
|
||||||
|
pRet = lsmMalloc(pEnv, N);
|
||||||
|
if( pRet==0 ){
|
||||||
|
*pRc = LSM_NOMEM_BKPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *lsmMallocZeroRc(lsm_env *pEnv, size_t N, int *pRc){
|
||||||
|
void *pRet = 0;
|
||||||
|
if( *pRc==LSM_OK ){
|
||||||
|
pRet = lsmMallocZero(pEnv, N);
|
||||||
|
if( pRet==0 ){
|
||||||
|
*pRc = LSM_NOMEM_BKPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *lsmReallocOrFree(lsm_env *pEnv, void *p, size_t N){
|
||||||
|
void *pNew;
|
||||||
|
pNew = lsm_realloc(pEnv, p, N);
|
||||||
|
if( !pNew ) lsm_free(pEnv, p);
|
||||||
|
return pNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *lsmReallocOrFreeRc(lsm_env *pEnv, void *p, size_t N, int *pRc){
|
||||||
|
void *pRet = 0;
|
||||||
|
if( *pRc ){
|
||||||
|
lsmFree(pEnv, p);
|
||||||
|
}else{
|
||||||
|
pRet = lsmReallocOrFree(pEnv, p, N);
|
||||||
|
if( !pRet ) *pRc = LSM_NOMEM_BKPT;
|
||||||
|
}
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *lsmMallocStrdup(lsm_env *pEnv, const char *zIn){
|
||||||
|
int nByte;
|
||||||
|
char *zRet;
|
||||||
|
nByte = strlen(zIn);
|
||||||
|
zRet = lsmMalloc(pEnv, nByte+1);
|
||||||
|
if( zRet ){
|
||||||
|
memcpy(zRet, zIn, nByte+1);
|
||||||
|
}
|
||||||
|
return zRet;
|
||||||
|
}
|
88
ext/lsm1/lsm_mutex.c
Normal file
88
ext/lsm1/lsm_mutex.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
** 2012-01-30
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** Mutex functions for LSM.
|
||||||
|
*/
|
||||||
|
#include "lsmInt.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Allocate a new mutex.
|
||||||
|
*/
|
||||||
|
int lsmMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
|
||||||
|
return pEnv->xMutexNew(pEnv, ppNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return a handle for one of the static mutexes.
|
||||||
|
*/
|
||||||
|
int lsmMutexStatic(lsm_env *pEnv, int iMutex, lsm_mutex **ppStatic){
|
||||||
|
return pEnv->xMutexStatic(pEnv, iMutex, ppStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Free a mutex allocated by lsmMutexNew().
|
||||||
|
*/
|
||||||
|
void lsmMutexDel(lsm_env *pEnv, lsm_mutex *pMutex){
|
||||||
|
if( pMutex ) pEnv->xMutexDel(pMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Enter a mutex.
|
||||||
|
*/
|
||||||
|
void lsmMutexEnter(lsm_env *pEnv, lsm_mutex *pMutex){
|
||||||
|
pEnv->xMutexEnter(pMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Attempt to enter a mutex, but do not block. If successful, return zero.
|
||||||
|
** Otherwise, if the mutex is already held by some other thread and is not
|
||||||
|
** entered, return non zero.
|
||||||
|
**
|
||||||
|
** Each successful call to this function must be matched by a call to
|
||||||
|
** lsmMutexLeave().
|
||||||
|
*/
|
||||||
|
int lsmMutexTry(lsm_env *pEnv, lsm_mutex *pMutex){
|
||||||
|
return pEnv->xMutexTry(pMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Leave a mutex.
|
||||||
|
*/
|
||||||
|
void lsmMutexLeave(lsm_env *pEnv, lsm_mutex *pMutex){
|
||||||
|
pEnv->xMutexLeave(pMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
/*
|
||||||
|
** Return non-zero if the mutex passed as the second argument is held
|
||||||
|
** by the calling thread, or zero otherwise. If the implementation is not
|
||||||
|
** able to tell if the mutex is held by the caller, it should return
|
||||||
|
** non-zero.
|
||||||
|
**
|
||||||
|
** This function is only used as part of assert() statements.
|
||||||
|
*/
|
||||||
|
int lsmMutexHeld(lsm_env *pEnv, lsm_mutex *pMutex){
|
||||||
|
return pEnv->xMutexHeld ? pEnv->xMutexHeld(pMutex) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return non-zero if the mutex passed as the second argument is not
|
||||||
|
** held by the calling thread, or zero otherwise. If the implementation
|
||||||
|
** is not able to tell if the mutex is held by the caller, it should
|
||||||
|
** return non-zero.
|
||||||
|
**
|
||||||
|
** This function is only used as part of assert() statements.
|
||||||
|
*/
|
||||||
|
int lsmMutexNotHeld(lsm_env *pEnv, lsm_mutex *pMutex){
|
||||||
|
return pEnv->xMutexNotHeld ? pEnv->xMutexNotHeld(pMutex) : 1;
|
||||||
|
}
|
||||||
|
#endif
|
1970
ext/lsm1/lsm_shared.c
Normal file
1970
ext/lsm1/lsm_shared.c
Normal file
File diff suppressed because it is too large
Load Diff
6149
ext/lsm1/lsm_sorted.c
Normal file
6149
ext/lsm1/lsm_sorted.c
Normal file
File diff suppressed because it is too large
Load Diff
150
ext/lsm1/lsm_str.c
Normal file
150
ext/lsm1/lsm_str.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
** 2012-04-27
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** Dynamic string functions.
|
||||||
|
*/
|
||||||
|
#include "lsmInt.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Turn bulk and uninitialized memory into an LsmString object
|
||||||
|
*/
|
||||||
|
void lsmStringInit(LsmString *pStr, lsm_env *pEnv){
|
||||||
|
memset(pStr, 0, sizeof(pStr[0]));
|
||||||
|
pStr->pEnv = pEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Increase the memory allocated for holding the string. Realloc as needed.
|
||||||
|
**
|
||||||
|
** If a memory allocation error occurs, set pStr->n to -1 and free the existing
|
||||||
|
** allocation. If a prior memory allocation has occurred, this routine is a
|
||||||
|
** no-op.
|
||||||
|
*/
|
||||||
|
int lsmStringExtend(LsmString *pStr, int nNew){
|
||||||
|
assert( nNew>0 );
|
||||||
|
if( pStr->n<0 ) return LSM_NOMEM;
|
||||||
|
if( pStr->n + nNew >= pStr->nAlloc ){
|
||||||
|
int nAlloc = pStr->n + nNew + 100;
|
||||||
|
char *zNew = lsmRealloc(pStr->pEnv, pStr->z, nAlloc);
|
||||||
|
if( zNew==0 ){
|
||||||
|
lsmFree(pStr->pEnv, pStr->z);
|
||||||
|
nAlloc = 0;
|
||||||
|
pStr->n = -1;
|
||||||
|
pStr->z = 0;
|
||||||
|
}else{
|
||||||
|
pStr->nAlloc = nAlloc;
|
||||||
|
pStr->z = zNew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (pStr->z ? LSM_OK : LSM_NOMEM_BKPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Clear an LsmString object, releasing any allocated memory that it holds.
|
||||||
|
** This also clears the error indication (if any).
|
||||||
|
*/
|
||||||
|
void lsmStringClear(LsmString *pStr){
|
||||||
|
lsmFree(pStr->pEnv, pStr->z);
|
||||||
|
lsmStringInit(pStr, pStr->pEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Append N bytes of text to the end of an LsmString object. If
|
||||||
|
** N is negative, append the entire string.
|
||||||
|
**
|
||||||
|
** If the string is in an error state, this routine is a no-op.
|
||||||
|
*/
|
||||||
|
int lsmStringAppend(LsmString *pStr, const char *z, int N){
|
||||||
|
int rc;
|
||||||
|
if( N<0 ) N = (int)strlen(z);
|
||||||
|
rc = lsmStringExtend(pStr, N+1);
|
||||||
|
if( pStr->nAlloc ){
|
||||||
|
memcpy(pStr->z+pStr->n, z, N+1);
|
||||||
|
pStr->n += N;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmStringBinAppend(LsmString *pStr, const u8 *a, int n){
|
||||||
|
int rc;
|
||||||
|
rc = lsmStringExtend(pStr, n);
|
||||||
|
if( pStr->nAlloc ){
|
||||||
|
memcpy(pStr->z+pStr->n, a, n);
|
||||||
|
pStr->n += n;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Append printf-formatted content to an LsmString.
|
||||||
|
*/
|
||||||
|
void lsmStringVAppendf(
|
||||||
|
LsmString *pStr,
|
||||||
|
const char *zFormat,
|
||||||
|
va_list ap1,
|
||||||
|
va_list ap2
|
||||||
|
){
|
||||||
|
#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__<199901L)) && \
|
||||||
|
!defined(__APPLE__)
|
||||||
|
extern int vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
|
/* Compatibility crutch for C89 compilation mode. sqlite3_vsnprintf()
|
||||||
|
does not work identically and causes test failures if used here.
|
||||||
|
For the time being we are assuming that the target has vsnprintf(),
|
||||||
|
but that is not guaranteed to be the case for pure C89 platforms.
|
||||||
|
*/;
|
||||||
|
#endif
|
||||||
|
int nWrite;
|
||||||
|
int nAvail;
|
||||||
|
|
||||||
|
nAvail = pStr->nAlloc - pStr->n;
|
||||||
|
nWrite = vsnprintf(pStr->z + pStr->n, nAvail, zFormat, ap1);
|
||||||
|
|
||||||
|
if( nWrite>=nAvail ){
|
||||||
|
lsmStringExtend(pStr, nWrite+1);
|
||||||
|
if( pStr->nAlloc==0 ) return;
|
||||||
|
nWrite = vsnprintf(pStr->z + pStr->n, nWrite+1, zFormat, ap2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pStr->n += nWrite;
|
||||||
|
pStr->z[pStr->n] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lsmStringAppendf(LsmString *pStr, const char *zFormat, ...){
|
||||||
|
va_list ap, ap2;
|
||||||
|
va_start(ap, zFormat);
|
||||||
|
va_start(ap2, zFormat);
|
||||||
|
lsmStringVAppendf(pStr, zFormat, ap, ap2);
|
||||||
|
va_end(ap);
|
||||||
|
va_end(ap2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmStrlen(const char *zName){
|
||||||
|
int nRet = 0;
|
||||||
|
while( zName[nRet] ) nRet++;
|
||||||
|
return nRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Write into memory obtained from lsm_malloc().
|
||||||
|
*/
|
||||||
|
char *lsmMallocPrintf(lsm_env *pEnv, const char *zFormat, ...){
|
||||||
|
LsmString s;
|
||||||
|
va_list ap, ap2;
|
||||||
|
lsmStringInit(&s, pEnv);
|
||||||
|
va_start(ap, zFormat);
|
||||||
|
va_start(ap2, zFormat);
|
||||||
|
lsmStringVAppendf(&s, zFormat, ap, ap2);
|
||||||
|
va_end(ap);
|
||||||
|
va_end(ap2);
|
||||||
|
if( s.n<0 ) return 0;
|
||||||
|
return (char *)lsmReallocOrFree(pEnv, s.z, s.n+1);
|
||||||
|
}
|
2464
ext/lsm1/lsm_tree.c
Normal file
2464
ext/lsm1/lsm_tree.c
Normal file
File diff suppressed because it is too large
Load Diff
741
ext/lsm1/lsm_unix.c
Normal file
741
ext/lsm1/lsm_unix.c
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
/*
|
||||||
|
** 2011-12-03
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** Unix-specific run-time environment implementation for LSM.
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) || defined(__TINYC__)
|
||||||
|
/* workaround for ftruncate() visibility on gcc. */
|
||||||
|
# ifndef _XOPEN_SOURCE
|
||||||
|
# define _XOPEN_SOURCE 500
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include "lsmInt.h"
|
||||||
|
|
||||||
|
/* There is no fdatasync() call on Android */
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
# define fdatasync(x) fsync(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An open file is an instance of the following object
|
||||||
|
*/
|
||||||
|
typedef struct PosixFile PosixFile;
|
||||||
|
struct PosixFile {
|
||||||
|
lsm_env *pEnv; /* The run-time environment */
|
||||||
|
const char *zName; /* Full path to file */
|
||||||
|
int fd; /* The open file descriptor */
|
||||||
|
int shmfd; /* Shared memory file-descriptor */
|
||||||
|
void *pMap; /* Pointer to mapping of file fd */
|
||||||
|
off_t nMap; /* Size of mapping at pMap in bytes */
|
||||||
|
int nShm; /* Number of entries in array apShm[] */
|
||||||
|
void **apShm; /* Array of 32K shared memory segments */
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *posixShmFile(PosixFile *p){
|
||||||
|
char *zShm;
|
||||||
|
int nName = strlen(p->zName);
|
||||||
|
zShm = (char *)lsmMalloc(p->pEnv, nName+4+1);
|
||||||
|
if( zShm ){
|
||||||
|
memcpy(zShm, p->zName, nName);
|
||||||
|
memcpy(&zShm[nName], "-shm", 5);
|
||||||
|
}
|
||||||
|
return zShm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsOpen(
|
||||||
|
lsm_env *pEnv,
|
||||||
|
const char *zFile,
|
||||||
|
int flags,
|
||||||
|
lsm_file **ppFile
|
||||||
|
){
|
||||||
|
int rc = LSM_OK;
|
||||||
|
PosixFile *p;
|
||||||
|
|
||||||
|
p = lsm_malloc(pEnv, sizeof(PosixFile));
|
||||||
|
if( p==0 ){
|
||||||
|
rc = LSM_NOMEM;
|
||||||
|
}else{
|
||||||
|
int bReadonly = (flags & LSM_OPEN_READONLY);
|
||||||
|
int oflags = (bReadonly ? O_RDONLY : (O_RDWR|O_CREAT));
|
||||||
|
memset(p, 0, sizeof(PosixFile));
|
||||||
|
p->zName = zFile;
|
||||||
|
p->pEnv = pEnv;
|
||||||
|
p->fd = open(zFile, oflags, 0644);
|
||||||
|
if( p->fd<0 ){
|
||||||
|
lsm_free(pEnv, p);
|
||||||
|
p = 0;
|
||||||
|
if( errno==ENOENT ){
|
||||||
|
rc = lsmErrorBkpt(LSM_IOERR_NOENT);
|
||||||
|
}else{
|
||||||
|
rc = LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppFile = (lsm_file *)p;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsWrite(
|
||||||
|
lsm_file *pFile, /* File to write to */
|
||||||
|
lsm_i64 iOff, /* Offset to write to */
|
||||||
|
void *pData, /* Write data from this buffer */
|
||||||
|
int nData /* Bytes of data to write */
|
||||||
|
){
|
||||||
|
int rc = LSM_OK;
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
offset = lseek(p->fd, (off_t)iOff, SEEK_SET);
|
||||||
|
if( offset!=iOff ){
|
||||||
|
rc = LSM_IOERR_BKPT;
|
||||||
|
}else{
|
||||||
|
ssize_t prc = write(p->fd, pData, (size_t)nData);
|
||||||
|
if( prc<0 ) rc = LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsTruncate(
|
||||||
|
lsm_file *pFile, /* File to write to */
|
||||||
|
lsm_i64 nSize /* Size to truncate file to */
|
||||||
|
){
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
int rc = LSM_OK; /* Return code */
|
||||||
|
int prc; /* Posix Return Code */
|
||||||
|
struct stat sStat; /* Result of fstat() invocation */
|
||||||
|
|
||||||
|
prc = fstat(p->fd, &sStat);
|
||||||
|
if( prc==0 && sStat.st_size>nSize ){
|
||||||
|
prc = ftruncate(p->fd, (off_t)nSize);
|
||||||
|
}
|
||||||
|
if( prc<0 ) rc = LSM_IOERR_BKPT;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsRead(
|
||||||
|
lsm_file *pFile, /* File to read from */
|
||||||
|
lsm_i64 iOff, /* Offset to read from */
|
||||||
|
void *pData, /* Read data into this buffer */
|
||||||
|
int nData /* Bytes of data to read */
|
||||||
|
){
|
||||||
|
int rc = LSM_OK;
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
offset = lseek(p->fd, (off_t)iOff, SEEK_SET);
|
||||||
|
if( offset!=iOff ){
|
||||||
|
rc = LSM_IOERR_BKPT;
|
||||||
|
}else{
|
||||||
|
ssize_t prc = read(p->fd, pData, (size_t)nData);
|
||||||
|
if( prc<0 ){
|
||||||
|
rc = LSM_IOERR_BKPT;
|
||||||
|
}else if( prc<nData ){
|
||||||
|
memset(&((u8 *)pData)[prc], 0, nData - prc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsSync(lsm_file *pFile){
|
||||||
|
int rc = LSM_OK;
|
||||||
|
|
||||||
|
#ifndef LSM_NO_SYNC
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
int prc = 0;
|
||||||
|
|
||||||
|
if( p->pMap ){
|
||||||
|
prc = msync(p->pMap, p->nMap, MS_SYNC);
|
||||||
|
}
|
||||||
|
if( prc==0 ) prc = fdatasync(p->fd);
|
||||||
|
if( prc<0 ) rc = LSM_IOERR_BKPT;
|
||||||
|
#else
|
||||||
|
(void)pFile;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsSectorSize(lsm_file *pFile){
|
||||||
|
return 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsRemap(
|
||||||
|
lsm_file *pFile,
|
||||||
|
lsm_i64 iMin,
|
||||||
|
void **ppOut,
|
||||||
|
lsm_i64 *pnOut
|
||||||
|
){
|
||||||
|
off_t iSz;
|
||||||
|
int prc;
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
/* If the file is between 0 and 2MB in size, extend it in chunks of 256K.
|
||||||
|
** Thereafter, in chunks of 1MB at a time. */
|
||||||
|
const int aIncrSz[] = {256*1024, 1024*1024};
|
||||||
|
int nIncrSz = aIncrSz[iMin>(2*1024*1024)];
|
||||||
|
|
||||||
|
if( p->pMap ){
|
||||||
|
munmap(p->pMap, p->nMap);
|
||||||
|
*ppOut = p->pMap = 0;
|
||||||
|
*pnOut = p->nMap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iMin>=0 ){
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
prc = fstat(p->fd, &buf);
|
||||||
|
if( prc!=0 ) return LSM_IOERR_BKPT;
|
||||||
|
iSz = buf.st_size;
|
||||||
|
if( iSz<iMin ){
|
||||||
|
iSz = ((iMin + nIncrSz-1) / nIncrSz) * nIncrSz;
|
||||||
|
prc = ftruncate(p->fd, iSz);
|
||||||
|
if( prc!=0 ) return LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->pMap = mmap(0, iSz, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd, 0);
|
||||||
|
p->nMap = iSz;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppOut = p->pMap;
|
||||||
|
*pnOut = p->nMap;
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsFullpath(
|
||||||
|
lsm_env *pEnv,
|
||||||
|
const char *zName,
|
||||||
|
char *zOut,
|
||||||
|
int *pnOut
|
||||||
|
){
|
||||||
|
int nBuf = *pnOut;
|
||||||
|
int nReq;
|
||||||
|
|
||||||
|
if( zName[0]!='/' ){
|
||||||
|
char *z;
|
||||||
|
char *zTmp;
|
||||||
|
int nTmp = 512;
|
||||||
|
zTmp = lsmMalloc(pEnv, nTmp);
|
||||||
|
while( zTmp ){
|
||||||
|
z = getcwd(zTmp, nTmp);
|
||||||
|
if( z || errno!=ERANGE ) break;
|
||||||
|
nTmp = nTmp*2;
|
||||||
|
zTmp = lsmReallocOrFree(pEnv, zTmp, nTmp);
|
||||||
|
}
|
||||||
|
if( zTmp==0 ) return LSM_NOMEM_BKPT;
|
||||||
|
if( z==0 ) return LSM_IOERR_BKPT;
|
||||||
|
assert( z==zTmp );
|
||||||
|
|
||||||
|
nTmp = strlen(zTmp);
|
||||||
|
nReq = nTmp + 1 + strlen(zName) + 1;
|
||||||
|
if( nReq<=nBuf ){
|
||||||
|
memcpy(zOut, zTmp, nTmp);
|
||||||
|
zOut[nTmp] = '/';
|
||||||
|
memcpy(&zOut[nTmp+1], zName, strlen(zName)+1);
|
||||||
|
}
|
||||||
|
lsmFree(pEnv, zTmp);
|
||||||
|
}else{
|
||||||
|
nReq = strlen(zName)+1;
|
||||||
|
if( nReq<=nBuf ){
|
||||||
|
memcpy(zOut, zName, strlen(zName)+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pnOut = nReq;
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsFileid(
|
||||||
|
lsm_file *pFile,
|
||||||
|
void *pBuf,
|
||||||
|
int *pnBuf
|
||||||
|
){
|
||||||
|
int prc;
|
||||||
|
int nBuf;
|
||||||
|
int nReq;
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
struct stat buf;
|
||||||
|
|
||||||
|
nBuf = *pnBuf;
|
||||||
|
nReq = (sizeof(buf.st_dev) + sizeof(buf.st_ino));
|
||||||
|
*pnBuf = nReq;
|
||||||
|
if( nReq>nBuf ) return LSM_OK;
|
||||||
|
|
||||||
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
prc = fstat(p->fd, &buf);
|
||||||
|
if( prc!=0 ) return LSM_IOERR_BKPT;
|
||||||
|
|
||||||
|
memcpy(pBuf, &buf.st_dev, sizeof(buf.st_dev));
|
||||||
|
memcpy(&(((u8 *)pBuf)[sizeof(buf.st_dev)]), &buf.st_ino, sizeof(buf.st_ino));
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsUnlink(lsm_env *pEnv, const char *zFile){
|
||||||
|
int prc = unlink(zFile);
|
||||||
|
return prc ? LSM_IOERR_BKPT : LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmPosixOsLock(lsm_file *pFile, int iLock, int eType){
|
||||||
|
int rc = LSM_OK;
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
static const short aType[3] = { F_UNLCK, F_RDLCK, F_WRLCK };
|
||||||
|
struct flock lock;
|
||||||
|
|
||||||
|
assert( aType[LSM_LOCK_UNLOCK]==F_UNLCK );
|
||||||
|
assert( aType[LSM_LOCK_SHARED]==F_RDLCK );
|
||||||
|
assert( aType[LSM_LOCK_EXCL]==F_WRLCK );
|
||||||
|
assert( eType>=0 && eType<array_size(aType) );
|
||||||
|
assert( iLock>0 && iLock<=32 );
|
||||||
|
|
||||||
|
memset(&lock, 0, sizeof(lock));
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_len = 1;
|
||||||
|
lock.l_type = aType[eType];
|
||||||
|
lock.l_start = (4096-iLock);
|
||||||
|
|
||||||
|
if( fcntl(p->fd, F_SETLK, &lock) ){
|
||||||
|
int e = errno;
|
||||||
|
if( e==EACCES || e==EAGAIN ){
|
||||||
|
rc = LSM_BUSY;
|
||||||
|
}else{
|
||||||
|
rc = LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmPosixOsTestLock(lsm_file *pFile, int iLock, int nLock, int eType){
|
||||||
|
int rc = LSM_OK;
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
static const short aType[3] = { 0, F_RDLCK, F_WRLCK };
|
||||||
|
struct flock lock;
|
||||||
|
|
||||||
|
assert( eType==LSM_LOCK_SHARED || eType==LSM_LOCK_EXCL );
|
||||||
|
assert( aType[LSM_LOCK_SHARED]==F_RDLCK );
|
||||||
|
assert( aType[LSM_LOCK_EXCL]==F_WRLCK );
|
||||||
|
assert( eType>=0 && eType<array_size(aType) );
|
||||||
|
assert( iLock>0 && iLock<=32 );
|
||||||
|
|
||||||
|
memset(&lock, 0, sizeof(lock));
|
||||||
|
lock.l_whence = SEEK_SET;
|
||||||
|
lock.l_len = nLock;
|
||||||
|
lock.l_type = aType[eType];
|
||||||
|
lock.l_start = (4096-iLock);
|
||||||
|
|
||||||
|
if( fcntl(p->fd, F_GETLK, &lock) ){
|
||||||
|
rc = LSM_IOERR_BKPT;
|
||||||
|
}else if( lock.l_type!=F_UNLCK ){
|
||||||
|
rc = LSM_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmPosixOsShmMap(lsm_file *pFile, int iChunk, int sz, void **ppShm){
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
|
||||||
|
*ppShm = 0;
|
||||||
|
assert( sz==LSM_SHM_CHUNK_SIZE );
|
||||||
|
if( iChunk>=p->nShm ){
|
||||||
|
int i;
|
||||||
|
void **apNew;
|
||||||
|
int nNew = iChunk+1;
|
||||||
|
off_t nReq = nNew * LSM_SHM_CHUNK_SIZE;
|
||||||
|
struct stat sStat;
|
||||||
|
|
||||||
|
/* If the shared-memory file has not been opened, open it now. */
|
||||||
|
if( p->shmfd<=0 ){
|
||||||
|
char *zShm = posixShmFile(p);
|
||||||
|
if( !zShm ) return LSM_NOMEM_BKPT;
|
||||||
|
p->shmfd = open(zShm, O_RDWR|O_CREAT, 0644);
|
||||||
|
lsmFree(p->pEnv, zShm);
|
||||||
|
if( p->shmfd<0 ){
|
||||||
|
return LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the shared-memory file is not large enough to contain the
|
||||||
|
** requested chunk, cause it to grow. */
|
||||||
|
if( fstat(p->shmfd, &sStat) ){
|
||||||
|
return LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
if( sStat.st_size<nReq ){
|
||||||
|
if( ftruncate(p->shmfd, nReq) ){
|
||||||
|
return LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apNew = (void **)lsmRealloc(p->pEnv, p->apShm, sizeof(void *) * nNew);
|
||||||
|
if( !apNew ) return LSM_NOMEM_BKPT;
|
||||||
|
for(i=p->nShm; i<nNew; i++){
|
||||||
|
apNew[i] = 0;
|
||||||
|
}
|
||||||
|
p->apShm = apNew;
|
||||||
|
p->nShm = nNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->apShm[iChunk]==0 ){
|
||||||
|
p->apShm[iChunk] = mmap(0, LSM_SHM_CHUNK_SIZE,
|
||||||
|
PROT_READ|PROT_WRITE, MAP_SHARED, p->shmfd, iChunk*LSM_SHM_CHUNK_SIZE
|
||||||
|
);
|
||||||
|
if( p->apShm[iChunk]==0 ) return LSM_IOERR_BKPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppShm = p->apShm[iChunk];
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lsmPosixOsShmBarrier(void){
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmPosixOsShmUnmap(lsm_file *pFile, int bDelete){
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
if( p->shmfd>0 ){
|
||||||
|
int i;
|
||||||
|
for(i=0; i<p->nShm; i++){
|
||||||
|
if( p->apShm[i] ){
|
||||||
|
munmap(p->apShm[i], LSM_SHM_CHUNK_SIZE);
|
||||||
|
p->apShm[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(p->shmfd);
|
||||||
|
p->shmfd = 0;
|
||||||
|
if( bDelete ){
|
||||||
|
char *zShm = posixShmFile(p);
|
||||||
|
if( zShm ) unlink(zShm);
|
||||||
|
lsmFree(p->pEnv, zShm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int lsmPosixOsClose(lsm_file *pFile){
|
||||||
|
PosixFile *p = (PosixFile *)pFile;
|
||||||
|
lsmPosixOsShmUnmap(pFile, 0);
|
||||||
|
if( p->pMap ) munmap(p->pMap, p->nMap);
|
||||||
|
close(p->fd);
|
||||||
|
lsm_free(p->pEnv, p->apShm);
|
||||||
|
lsm_free(p->pEnv, p);
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsSleep(lsm_env *pEnv, int us){
|
||||||
|
#if 0
|
||||||
|
/* Apparently on Android usleep() returns void */
|
||||||
|
if( usleep(us) ) return LSM_IOERR;
|
||||||
|
#endif
|
||||||
|
usleep(us);
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
** Memory allocation routines.
|
||||||
|
*/
|
||||||
|
#define BLOCK_HDR_SIZE ROUND8( sizeof(size_t) )
|
||||||
|
|
||||||
|
static void *lsmPosixOsMalloc(lsm_env *pEnv, size_t N){
|
||||||
|
unsigned char * m;
|
||||||
|
N += BLOCK_HDR_SIZE;
|
||||||
|
m = (unsigned char *)malloc(N);
|
||||||
|
*((size_t*)m) = N;
|
||||||
|
return m + BLOCK_HDR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lsmPosixOsFree(lsm_env *pEnv, void *p){
|
||||||
|
if(p){
|
||||||
|
free( ((unsigned char *)p) - BLOCK_HDR_SIZE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *lsmPosixOsRealloc(lsm_env *pEnv, void *p, size_t N){
|
||||||
|
unsigned char * m = (unsigned char *)p;
|
||||||
|
if(1>N){
|
||||||
|
lsmPosixOsFree( pEnv, p );
|
||||||
|
return NULL;
|
||||||
|
}else if(NULL==p){
|
||||||
|
return lsmPosixOsMalloc(pEnv, N);
|
||||||
|
}else{
|
||||||
|
void * re = NULL;
|
||||||
|
m -= BLOCK_HDR_SIZE;
|
||||||
|
#if 0 /* arguable: don't shrink */
|
||||||
|
size_t * sz = (size_t*)m;
|
||||||
|
if(*sz >= (size_t)N){
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
re = realloc( m, N + BLOCK_HDR_SIZE );
|
||||||
|
if(re){
|
||||||
|
m = (unsigned char *)re;
|
||||||
|
*((size_t*)m) = N;
|
||||||
|
return m + BLOCK_HDR_SIZE;
|
||||||
|
}else{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t lsmPosixOsMSize(lsm_env *pEnv, void *p){
|
||||||
|
unsigned char * m = (unsigned char *)p;
|
||||||
|
return *((size_t*)(m-BLOCK_HDR_SIZE));
|
||||||
|
}
|
||||||
|
#undef BLOCK_HDR_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LSM_MUTEX_PTHREADS
|
||||||
|
/*************************************************************************
|
||||||
|
** Mutex methods for pthreads based systems. If LSM_MUTEX_PTHREADS is
|
||||||
|
** missing then a no-op implementation of mutexes found in lsm_mutex.c
|
||||||
|
** will be used instead.
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
typedef struct PthreadMutex PthreadMutex;
|
||||||
|
struct PthreadMutex {
|
||||||
|
lsm_env *pEnv;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
pthread_t owner;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
# define LSM_PTHREAD_STATIC_MUTEX { 0, PTHREAD_MUTEX_INITIALIZER, 0 }
|
||||||
|
#else
|
||||||
|
# define LSM_PTHREAD_STATIC_MUTEX { 0, PTHREAD_MUTEX_INITIALIZER }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int lsmPosixOsMutexStatic(
|
||||||
|
lsm_env *pEnv,
|
||||||
|
int iMutex,
|
||||||
|
lsm_mutex **ppStatic
|
||||||
|
){
|
||||||
|
static PthreadMutex sMutex[2] = {
|
||||||
|
LSM_PTHREAD_STATIC_MUTEX,
|
||||||
|
LSM_PTHREAD_STATIC_MUTEX
|
||||||
|
};
|
||||||
|
|
||||||
|
assert( iMutex==LSM_MUTEX_GLOBAL || iMutex==LSM_MUTEX_HEAP );
|
||||||
|
assert( LSM_MUTEX_GLOBAL==1 && LSM_MUTEX_HEAP==2 );
|
||||||
|
|
||||||
|
*ppStatic = (lsm_mutex *)&sMutex[iMutex-1];
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
|
||||||
|
PthreadMutex *pMutex; /* Pointer to new mutex */
|
||||||
|
pthread_mutexattr_t attr; /* Attributes object */
|
||||||
|
|
||||||
|
pMutex = (PthreadMutex *)lsmMallocZero(pEnv, sizeof(PthreadMutex));
|
||||||
|
if( !pMutex ) return LSM_NOMEM_BKPT;
|
||||||
|
|
||||||
|
pMutex->pEnv = pEnv;
|
||||||
|
pthread_mutexattr_init(&attr);
|
||||||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
pthread_mutex_init(&pMutex->mutex, &attr);
|
||||||
|
pthread_mutexattr_destroy(&attr);
|
||||||
|
|
||||||
|
*ppNew = (lsm_mutex *)pMutex;
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lsmPosixOsMutexDel(lsm_mutex *p){
|
||||||
|
PthreadMutex *pMutex = (PthreadMutex *)p;
|
||||||
|
pthread_mutex_destroy(&pMutex->mutex);
|
||||||
|
lsmFree(pMutex->pEnv, pMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lsmPosixOsMutexEnter(lsm_mutex *p){
|
||||||
|
PthreadMutex *pMutex = (PthreadMutex *)p;
|
||||||
|
pthread_mutex_lock(&pMutex->mutex);
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
assert( !pthread_equal(pMutex->owner, pthread_self()) );
|
||||||
|
pMutex->owner = pthread_self();
|
||||||
|
assert( pthread_equal(pMutex->owner, pthread_self()) );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lsmPosixOsMutexTry(lsm_mutex *p){
|
||||||
|
int ret;
|
||||||
|
PthreadMutex *pMutex = (PthreadMutex *)p;
|
||||||
|
ret = pthread_mutex_trylock(&pMutex->mutex);
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
if( ret==0 ){
|
||||||
|
assert( !pthread_equal(pMutex->owner, pthread_self()) );
|
||||||
|
pMutex->owner = pthread_self();
|
||||||
|
assert( pthread_equal(pMutex->owner, pthread_self()) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lsmPosixOsMutexLeave(lsm_mutex *p){
|
||||||
|
PthreadMutex *pMutex = (PthreadMutex *)p;
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
assert( pthread_equal(pMutex->owner, pthread_self()) );
|
||||||
|
pMutex->owner = 0;
|
||||||
|
assert( !pthread_equal(pMutex->owner, pthread_self()) );
|
||||||
|
#endif
|
||||||
|
pthread_mutex_unlock(&pMutex->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
static int lsmPosixOsMutexHeld(lsm_mutex *p){
|
||||||
|
PthreadMutex *pMutex = (PthreadMutex *)p;
|
||||||
|
return pMutex ? pthread_equal(pMutex->owner, pthread_self()) : 1;
|
||||||
|
}
|
||||||
|
static int lsmPosixOsMutexNotHeld(lsm_mutex *p){
|
||||||
|
PthreadMutex *pMutex = (PthreadMutex *)p;
|
||||||
|
return pMutex ? !pthread_equal(pMutex->owner, pthread_self()) : 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
** End of pthreads mutex implementation.
|
||||||
|
*************************************************************************/
|
||||||
|
#else
|
||||||
|
/*************************************************************************
|
||||||
|
** Noop mutex implementation
|
||||||
|
*/
|
||||||
|
typedef struct NoopMutex NoopMutex;
|
||||||
|
struct NoopMutex {
|
||||||
|
lsm_env *pEnv; /* Environment handle (for xFree()) */
|
||||||
|
int bHeld; /* True if mutex is held */
|
||||||
|
int bStatic; /* True for a static mutex */
|
||||||
|
};
|
||||||
|
static NoopMutex aStaticNoopMutex[2] = {
|
||||||
|
{0, 0, 1},
|
||||||
|
{0, 0, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int lsmPosixOsMutexStatic(
|
||||||
|
lsm_env *pEnv,
|
||||||
|
int iMutex,
|
||||||
|
lsm_mutex **ppStatic
|
||||||
|
){
|
||||||
|
assert( iMutex>=1 && iMutex<=(int)array_size(aStaticNoopMutex) );
|
||||||
|
*ppStatic = (lsm_mutex *)&aStaticNoopMutex[iMutex-1];
|
||||||
|
return LSM_OK;
|
||||||
|
}
|
||||||
|
static int lsmPosixOsMutexNew(lsm_env *pEnv, lsm_mutex **ppNew){
|
||||||
|
NoopMutex *p;
|
||||||
|
p = (NoopMutex *)lsmMallocZero(pEnv, sizeof(NoopMutex));
|
||||||
|
if( p ) p->pEnv = pEnv;
|
||||||
|
*ppNew = (lsm_mutex *)p;
|
||||||
|
return (p ? LSM_OK : LSM_NOMEM_BKPT);
|
||||||
|
}
|
||||||
|
static void lsmPosixOsMutexDel(lsm_mutex *pMutex) {
|
||||||
|
NoopMutex *p = (NoopMutex *)pMutex;
|
||||||
|
assert( p->bStatic==0 && p->pEnv );
|
||||||
|
lsmFree(p->pEnv, p);
|
||||||
|
}
|
||||||
|
static void lsmPosixOsMutexEnter(lsm_mutex *pMutex){
|
||||||
|
NoopMutex *p = (NoopMutex *)pMutex;
|
||||||
|
assert( p->bHeld==0 );
|
||||||
|
p->bHeld = 1;
|
||||||
|
}
|
||||||
|
static int lsmPosixOsMutexTry(lsm_mutex *pMutex){
|
||||||
|
NoopMutex *p = (NoopMutex *)pMutex;
|
||||||
|
assert( p->bHeld==0 );
|
||||||
|
p->bHeld = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static void lsmPosixOsMutexLeave(lsm_mutex *pMutex){
|
||||||
|
NoopMutex *p = (NoopMutex *)pMutex;
|
||||||
|
assert( p->bHeld==1 );
|
||||||
|
p->bHeld = 0;
|
||||||
|
}
|
||||||
|
#ifdef LSM_DEBUG
|
||||||
|
static int lsmPosixOsMutexHeld(lsm_mutex *pMutex){
|
||||||
|
NoopMutex *p = (NoopMutex *)pMutex;
|
||||||
|
return p ? p->bHeld : 1;
|
||||||
|
}
|
||||||
|
static int lsmPosixOsMutexNotHeld(lsm_mutex *pMutex){
|
||||||
|
NoopMutex *p = (NoopMutex *)pMutex;
|
||||||
|
return p ? !p->bHeld : 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/***************************************************************************/
|
||||||
|
#endif /* else LSM_MUTEX_NONE */
|
||||||
|
|
||||||
|
/* Without LSM_DEBUG, the MutexHeld tests are never called */
|
||||||
|
#ifndef LSM_DEBUG
|
||||||
|
# define lsmPosixOsMutexHeld 0
|
||||||
|
# define lsmPosixOsMutexNotHeld 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lsm_env *lsm_default_env(void){
|
||||||
|
static lsm_env posix_env = {
|
||||||
|
sizeof(lsm_env), /* nByte */
|
||||||
|
1, /* iVersion */
|
||||||
|
/***** file i/o ******************/
|
||||||
|
0, /* pVfsCtx */
|
||||||
|
lsmPosixOsFullpath, /* xFullpath */
|
||||||
|
lsmPosixOsOpen, /* xOpen */
|
||||||
|
lsmPosixOsRead, /* xRead */
|
||||||
|
lsmPosixOsWrite, /* xWrite */
|
||||||
|
lsmPosixOsTruncate, /* xTruncate */
|
||||||
|
lsmPosixOsSync, /* xSync */
|
||||||
|
lsmPosixOsSectorSize, /* xSectorSize */
|
||||||
|
lsmPosixOsRemap, /* xRemap */
|
||||||
|
lsmPosixOsFileid, /* xFileid */
|
||||||
|
lsmPosixOsClose, /* xClose */
|
||||||
|
lsmPosixOsUnlink, /* xUnlink */
|
||||||
|
lsmPosixOsLock, /* xLock */
|
||||||
|
lsmPosixOsTestLock, /* xTestLock */
|
||||||
|
lsmPosixOsShmMap, /* xShmMap */
|
||||||
|
lsmPosixOsShmBarrier, /* xShmBarrier */
|
||||||
|
lsmPosixOsShmUnmap, /* xShmUnmap */
|
||||||
|
/***** memory allocation *********/
|
||||||
|
0, /* pMemCtx */
|
||||||
|
lsmPosixOsMalloc, /* xMalloc */
|
||||||
|
lsmPosixOsRealloc, /* xRealloc */
|
||||||
|
lsmPosixOsFree, /* xFree */
|
||||||
|
lsmPosixOsMSize, /* xSize */
|
||||||
|
/***** mutexes *********************/
|
||||||
|
0, /* pMutexCtx */
|
||||||
|
lsmPosixOsMutexStatic, /* xMutexStatic */
|
||||||
|
lsmPosixOsMutexNew, /* xMutexNew */
|
||||||
|
lsmPosixOsMutexDel, /* xMutexDel */
|
||||||
|
lsmPosixOsMutexEnter, /* xMutexEnter */
|
||||||
|
lsmPosixOsMutexTry, /* xMutexTry */
|
||||||
|
lsmPosixOsMutexLeave, /* xMutexLeave */
|
||||||
|
lsmPosixOsMutexHeld, /* xMutexHeld */
|
||||||
|
lsmPosixOsMutexNotHeld, /* xMutexNotHeld */
|
||||||
|
/***** other *********************/
|
||||||
|
lsmPosixOsSleep, /* xSleep */
|
||||||
|
};
|
||||||
|
return &posix_env;
|
||||||
|
}
|
196
ext/lsm1/lsm_varint.c
Normal file
196
ext/lsm1/lsm_varint.c
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
** 2012-02-08
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** SQLite4-compatible varint implementation.
|
||||||
|
*/
|
||||||
|
#include "lsmInt.h"
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
** The following is a copy of the varint.c module from SQLite 4.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Decode the varint in z[]. Write the integer value into *pResult and
|
||||||
|
** return the number of bytes in the varint.
|
||||||
|
*/
|
||||||
|
static int lsmSqlite4GetVarint64(const unsigned char *z, u64 *pResult){
|
||||||
|
unsigned int x;
|
||||||
|
if( z[0]<=240 ){
|
||||||
|
*pResult = z[0];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( z[0]<=248 ){
|
||||||
|
*pResult = (z[0]-241)*256 + z[1] + 240;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if( z[0]==249 ){
|
||||||
|
*pResult = 2288 + 256*z[1] + z[2];
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if( z[0]==250 ){
|
||||||
|
*pResult = (z[1]<<16) + (z[2]<<8) + z[3];
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
x = (z[1]<<24) + (z[2]<<16) + (z[3]<<8) + z[4];
|
||||||
|
if( z[0]==251 ){
|
||||||
|
*pResult = x;
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if( z[0]==252 ){
|
||||||
|
*pResult = (((u64)x)<<8) + z[5];
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if( z[0]==253 ){
|
||||||
|
*pResult = (((u64)x)<<16) + (z[5]<<8) + z[6];
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if( z[0]==254 ){
|
||||||
|
*pResult = (((u64)x)<<24) + (z[5]<<16) + (z[6]<<8) + z[7];
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
*pResult = (((u64)x)<<32) +
|
||||||
|
(0xffffffff & ((z[5]<<24) + (z[6]<<16) + (z[7]<<8) + z[8]));
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Write a 32-bit unsigned integer as 4 big-endian bytes.
|
||||||
|
*/
|
||||||
|
static void lsmVarintWrite32(unsigned char *z, unsigned int y){
|
||||||
|
z[0] = (unsigned char)(y>>24);
|
||||||
|
z[1] = (unsigned char)(y>>16);
|
||||||
|
z[2] = (unsigned char)(y>>8);
|
||||||
|
z[3] = (unsigned char)(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Write a varint into z[]. The buffer z[] must be at least 9 characters
|
||||||
|
** long to accommodate the largest possible varint. Return the number of
|
||||||
|
** bytes of z[] used.
|
||||||
|
*/
|
||||||
|
static int lsmSqlite4PutVarint64(unsigned char *z, u64 x){
|
||||||
|
unsigned int w, y;
|
||||||
|
if( x<=240 ){
|
||||||
|
z[0] = (unsigned char)x;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( x<=2287 ){
|
||||||
|
y = (unsigned int)(x - 240);
|
||||||
|
z[0] = (unsigned char)(y/256 + 241);
|
||||||
|
z[1] = (unsigned char)(y%256);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if( x<=67823 ){
|
||||||
|
y = (unsigned int)(x - 2288);
|
||||||
|
z[0] = 249;
|
||||||
|
z[1] = (unsigned char)(y/256);
|
||||||
|
z[2] = (unsigned char)(y%256);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
y = (unsigned int)x;
|
||||||
|
w = (unsigned int)(x>>32);
|
||||||
|
if( w==0 ){
|
||||||
|
if( y<=16777215 ){
|
||||||
|
z[0] = 250;
|
||||||
|
z[1] = (unsigned char)(y>>16);
|
||||||
|
z[2] = (unsigned char)(y>>8);
|
||||||
|
z[3] = (unsigned char)(y);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
z[0] = 251;
|
||||||
|
lsmVarintWrite32(z+1, y);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if( w<=255 ){
|
||||||
|
z[0] = 252;
|
||||||
|
z[1] = (unsigned char)w;
|
||||||
|
lsmVarintWrite32(z+2, y);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if( w<=32767 ){
|
||||||
|
z[0] = 253;
|
||||||
|
z[1] = (unsigned char)(w>>8);
|
||||||
|
z[2] = (unsigned char)w;
|
||||||
|
lsmVarintWrite32(z+3, y);
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if( w<=16777215 ){
|
||||||
|
z[0] = 254;
|
||||||
|
z[1] = (unsigned char)(w>>16);
|
||||||
|
z[2] = (unsigned char)(w>>8);
|
||||||
|
z[3] = (unsigned char)w;
|
||||||
|
lsmVarintWrite32(z+4, y);
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
z[0] = 255;
|
||||||
|
lsmVarintWrite32(z+1, w);
|
||||||
|
lsmVarintWrite32(z+5, y);
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** End of SQLite 4 code.
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
int lsmVarintPut64(u8 *aData, i64 iVal){
|
||||||
|
return lsmSqlite4PutVarint64(aData, (u64)iVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmVarintGet64(const u8 *aData, i64 *piVal){
|
||||||
|
return lsmSqlite4GetVarint64(aData, (u64 *)piVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmVarintPut32(u8 *aData, int iVal){
|
||||||
|
return lsmSqlite4PutVarint64(aData, (u64)iVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmVarintGet32(u8 *z, int *piVal){
|
||||||
|
u64 i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if( z[0]<=240 ){
|
||||||
|
*piVal = z[0];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if( z[0]<=248 ){
|
||||||
|
*piVal = (z[0]-241)*256 + z[1] + 240;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if( z[0]==249 ){
|
||||||
|
*piVal = 2288 + 256*z[1] + z[2];
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if( z[0]==250 ){
|
||||||
|
*piVal = (z[1]<<16) + (z[2]<<8) + z[3];
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lsmSqlite4GetVarint64(z, &i);
|
||||||
|
*piVal = i;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsmVarintLen32(int n){
|
||||||
|
u8 aData[9];
|
||||||
|
return lsmVarintPut32(aData, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The argument is the first byte of a varint. This function returns the
|
||||||
|
** total number of bytes in the entire varint (including the first byte).
|
||||||
|
*/
|
||||||
|
int lsmVarintSize(u8 c){
|
||||||
|
if( c<241 ) return 1;
|
||||||
|
if( c<249 ) return 2;
|
||||||
|
return (int)(c - 246);
|
||||||
|
}
|
30
manifest
30
manifest
@ -1,5 +1,5 @@
|
|||||||
C In\sthe\sshell\stool,\savoid\stesting\sif\s(sqlite3_vfs.xGetCurrentInt64)\sis\sNULL\sfor\sa\sversion\s1\sVFS.\sThis\sfield\sis\sonly\sdefined\sfor\sversion\s2\sand\sgreater.
|
C Import\sthe\sLSM\scode\sfrom\sSQLite4\sfor\suse\sin\san\sexperimental\svirtual\stable.\nNB:\sThis\sis\sa\sspeculative\sexperiment\sand\scould\seasily\sresult\sin\sa\sdead-end\nbranch.
|
||||||
D 2015-11-16T08:54:10.841
|
D 2015-11-16T16:00:22.063
|
||||||
F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1
|
F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc e928e68168df69b353300ac87c10105206653a03
|
F Makefile.msc e928e68168df69b353300ac87c10105206653a03
|
||||||
@ -190,6 +190,21 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
|
|||||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||||
F ext/icu/icu.c b2732aef0b076e4276d9b39b5a33cec7a05e1413
|
F ext/icu/icu.c b2732aef0b076e4276d9b39b5a33cec7a05e1413
|
||||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||||
|
F ext/lsm1/Makefile a921a54e7364814897a6ea74638741c672f42f07
|
||||||
|
F ext/lsm1/lsm.h d88fce3ea06730f7967159b7459b037e01d82df5
|
||||||
|
F ext/lsm1/lsmInt.h bc270dd81b3355c7410b06a6d54dd3eb9493a3e8
|
||||||
|
F ext/lsm1/lsm_ckpt.c e7907e782fe2e95de0833675e35e726e487cc4cd
|
||||||
|
F ext/lsm1/lsm_file.c 63796f5741422064b146cfbffbaeaeda14b70175
|
||||||
|
F ext/lsm1/lsm_log.c 5b3e855fcfb85de9fb86fcbf65696cc6886d3231
|
||||||
|
F ext/lsm1/lsm_main.c f52eada2910f8a57bd4cafcee39c6c375f6b7ed8
|
||||||
|
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
|
||||||
|
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
|
||||||
|
F ext/lsm1/lsm_shared.c 54cc3a5157c6abd77f7d3ae60708b9f7bf022b3c
|
||||||
|
F ext/lsm1/lsm_sorted.c aca377f4091263a1103cf409340130bcafd87939
|
||||||
|
F ext/lsm1/lsm_str.c 77ebdd5040ddf267a6f724d4c83132d2dce8a226
|
||||||
|
F ext/lsm1/lsm_tree.c 5d9fb2bc58a1a70c75126bd8d7198f7b627e165b
|
||||||
|
F ext/lsm1/lsm_unix.c fcaf5b6738713f1229dc0e1a90393ecf24f787f2
|
||||||
|
F ext/lsm1/lsm_varint.c b19ae9bd26b5a1e8402fb8a564b25d9542338a41
|
||||||
F ext/misc/amatch.c a1a8f66c29d40bd71b075546ddeddb477b17a2bb
|
F ext/misc/amatch.c a1a8f66c29d40bd71b075546ddeddb477b17a2bb
|
||||||
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
|
||||||
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
|
||||||
@ -1403,7 +1418,10 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P 791761ebac26c82ab67bdf867117ec5b5d8b20b0
|
P ad5fcaa583ef743d143b6c030e0d78019709fe71
|
||||||
R a635725b446415a63ce3c96185f06f0a
|
R c1b42294f3f880839d2371f275775b59
|
||||||
U dan
|
T *branch * lsm-vtab
|
||||||
Z ecc9df21b64c8edc0682f60d01379dbf
|
T *sym-lsm-vtab *
|
||||||
|
T -sym-trunk *
|
||||||
|
U drh
|
||||||
|
Z b1fe55788e9f370521e84a28fea017e9
|
||||||
|
@ -1 +1 @@
|
|||||||
ad5fcaa583ef743d143b6c030e0d78019709fe71
|
3d930501a2acb7f20932cfeb4e3fe308b4569cd6
|
Reference in New Issue
Block a user