1
0
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:
drh
2015-11-16 16:00:22 +00:00
parent 3fd415b2bf
commit a0b7ffb184
17 changed files with 20250 additions and 7 deletions

33
ext/lsm1/Makefile Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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
View 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
View 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

File diff suppressed because it is too large Load Diff

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
View 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

File diff suppressed because it is too large Load Diff

741
ext/lsm1/lsm_unix.c Normal file
View 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
View 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);
}

View File

@ -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

View File

@ -1 +1 @@
ad5fcaa583ef743d143b6c030e0d78019709fe71 3d930501a2acb7f20932cfeb4e3fe308b4569cd6