674 lines
27 KiB
C
674 lines
27 KiB
C
/*
|
|
* Copyright (c) 2012-2013 Spotify AB
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
* the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
#ifndef SPOTIFY_SPARKEY_H_INCLUDED
|
|
#define SPOTIFY_SPARKEY_H_INCLUDED
|
|
|
|
/**
|
|
* \mainpage Sparkey C API
|
|
* \section intro_sec Getting started
|
|
*
|
|
* For a complete listing of available functions, see sparkey.h .
|
|
*
|
|
* \section logwriter Writing to a log file
|
|
*
|
|
* This section contains all functions relevant for writing entries to a log.
|
|
* Writing to the same log file is not thread safe. Only use the writer objects
|
|
* from one thread at a time, and make sure to only write to a file from one process.
|
|
* The library will not do any form of locking or checking for other writers, so be
|
|
* careful.
|
|
*
|
|
* Basic workflow:
|
|
* - Create and initialize the logwriter:
|
|
* \code
|
|
* sparkey_logwriter *mywriter;
|
|
* sparkey_returncode returncode = sparkey_logwriter_create(&mywriter, "mylog.spl", SPARKEY_COMPRESSION_NONE, 0);
|
|
* // TODO: check the returncode
|
|
* \endcode
|
|
* - Write to the log:
|
|
* \code
|
|
* const char *mykey = "mykey";
|
|
* const char *myvalue = "this is my value";
|
|
* sparkey_returncode returncode = sparkey_logwriter_put(mywriter, strlen(mykey), (uint8_t*)mykey, strlen(myvalue), (uint8_t*)myvalue);
|
|
* // TODO: check the returncode
|
|
* \endcode
|
|
* - Close it when you're done:
|
|
* \code
|
|
* sparkey_returncode returncode = sparkey_logwriter_close(&mywriter);
|
|
* // TODO: check the returncode
|
|
* \endcode
|
|
*
|
|
* \section logreader Reading from a log file
|
|
*
|
|
* This section contains all functions relevant for reading entries from a log.
|
|
* A sparkey_logreader may be shared between multiple threads, but \ref sparkey_logreader_open
|
|
* and \ref sparkey_logreader_close are not thread safe.
|
|
*
|
|
* The logreader is not useful by itself. You also need a sparkey_logiter to iterate through the entries.
|
|
* This is a highly mutable struct and should not be shared between threads. It is not threadsafe.
|
|
*
|
|
* Here is a basic workflow for iterating through all entries in a logfile:
|
|
* - Create a logreader
|
|
* \code
|
|
* sparkey_logreader *myreader;
|
|
* sparkey_returncode returncode = sparkey_logreader_open(&myreader, "mylog.spl");
|
|
* \endcode
|
|
* - Create a logiter
|
|
* \code
|
|
* sparkey_logiter *myiter;
|
|
* sparkey_returncode returncode = sparkey_logiter_create(&myiter, myreader);
|
|
* \endcode
|
|
* - Perform the iteration:
|
|
* \code
|
|
* while (1) {
|
|
* sparkey_returncode returncode = sparkey_logiter_next(myiter, myreader);
|
|
* // TODO: check the returncode
|
|
* if (sparkey_logiter_state(myiter) != SPARKEY_ITER_ACTIVE) {
|
|
* break;
|
|
* }
|
|
* uint64_t wanted_keylen = sparkey_logiter_keylen(myiter);
|
|
* uint8_t *keybuf = malloc(wanted_keylen);
|
|
* uint64_t actual_keylen;
|
|
* returncode = sparkey_logiter_fill_key(myiter, myreader, wanted_keylen, keybuf, &actual_keylen);
|
|
* // TODO: check the returncode
|
|
* // TODO: assert actual_keylen == wanted_keylen
|
|
* uint64_t wanted_valuelen = sparkey_logiter_valuelen(myiter);
|
|
* uint8_t *valuebuf = malloc(wanted_valuelen);
|
|
* uint64_t actual_valuelen;
|
|
* returncode = sparkey_logiter_fill_value(myiter, myreader, wanted_valuelen, valuebuf, &actual_valuelen);
|
|
* // TODO: check the returncode
|
|
* // TODO: assert actual_valuelen == wanted_valuelen
|
|
* // Do stuff with key and value
|
|
* free(keybuf);
|
|
* free(valuebuf);
|
|
* }
|
|
* \endcode
|
|
* Note that you have to allocate memory for the key and value manually - Sparkey does not allocate memory except for when
|
|
* creating readers, writers and iterators.
|
|
*
|
|
* - Alternatively, you can preallocate the buffers by using
|
|
* max_key_len and max_value_len provided by the log header:
|
|
* \code
|
|
* uint8_t *keybuf = malloc(sparkey_logreader_maxkeylen(sparkey_hash_getreader(myreader)));
|
|
* uint8_t *valuebuf = malloc(sparkey_logreader_maxvaluelen(sparkey_hash_getreader(myreader)));
|
|
* while (1) {
|
|
* sparkey_returncode returncode = sparkey_logiter_next(&myiter, &myreader);
|
|
* // TODO: check the returncode
|
|
* if (sparkey_logiter_state(myiter) != SPARKEY_ITER_ACTIVE) {
|
|
* break;
|
|
* }
|
|
* uint64_t wanted_keylen = sparkey_logiter_keylen(myiter);
|
|
* uint64_t actual_keylen;
|
|
* returncode = sparkey_logiter_fill_key(&myiter, &myreader, wanted_keylen, keybuf, &actual_keylen);
|
|
* // TODO: check the returncode
|
|
* // TODO: assert actual_keylen == wanted_keylen
|
|
* uint64_t wanted_valuelen = sparkey_logiter_valuelen(myiter);
|
|
* uint64_t actual_valuelen;
|
|
* returncode = sparkey_logiter_fill_value(&myiter, &myreader, wanted_valuelen, valuebuf, &actual_valuelen);
|
|
* // TODO: check the returncode
|
|
* // TODO: assert actual_valuelen == wanted_valuelen
|
|
* // Do stuff with key and value
|
|
* }
|
|
* free(keybuf);
|
|
* free(valuebuf);
|
|
* \endcode
|
|
* - You can also skip allocating at all, if you can process the key and/or value in chunks. Here's an example for processing a key in chunks,
|
|
* but the same can be applied for values:
|
|
* \code
|
|
* uint64_t total_len = sparkey_logiter_keylen(myiter);
|
|
* while (total_len > 0) {
|
|
* uint8_t *buf;
|
|
* uint64_t len;
|
|
* sparkey_returncode returncode = sparkey_logiter_keychunk(&myiter, &myreader, total_len, &buf, &len);
|
|
* // TODO: check the returncode
|
|
* // Example: use the chunks to write to standard out
|
|
* fwrite(buf, 1, len, stdout);
|
|
* total_len -= len;
|
|
* }
|
|
* \endcode
|
|
* - Close everything when you're done:
|
|
* \code
|
|
* sparkey_logreader_close(&myreader);
|
|
* sparkey_logiter_close(&myiter);
|
|
* \endcode
|
|
*
|
|
* \section hashwriter Creating hash files from log files
|
|
*
|
|
* This header only contains the function sparkey_hash_write which creates a hash file.
|
|
*
|
|
* This is all you need to do to create a hash file based on an existing log file:
|
|
* \code
|
|
* sparkey_returncode returncode = sparkey_hash_write("mylog.spi", "mylog.spl", 0);
|
|
* // TODO: check the returncode
|
|
* \endcode
|
|
*
|
|
* \section hashreader Reading from a hash-file/log-file pair
|
|
*
|
|
* This header contains all functions relevant for reading live key/value pairs from a log and hash file.
|
|
* The documentation is very similar to the one for reading from a log file, because this api is an extension.
|
|
* Random lookups is the only feature that's added, and iteration simply skips dead entries.
|
|
*
|
|
* A sparkey_hashreader may be shared between multiple threads, but \ref sparkey_hash_open
|
|
* and \ref sparkey_hash_close are not thread safe.
|
|
*
|
|
* The hashreader is not useful by itself. You also need a sparkey_logiter to do random lookups and
|
|
* iterate through the entries.
|
|
* This is a highly mutable struct and should not be shared between threads. It is not threadsafe.
|
|
*
|
|
* Here is a basic workflow for iterating through all live entries in a log and hash file:
|
|
* - Create a hashreader
|
|
* \code
|
|
* sparkey_hashreader *myreader;
|
|
* sparkey_returncode returncode = sparkey_hash_open(&myreader, "mylog.spi", "mylog.spl");
|
|
* // TODO: check the returncode
|
|
* \endcode
|
|
* \code
|
|
* sparkey_logiter *myiter;
|
|
* sparkey_returncode returncode = sparkey_logiter_create(&myiter, sparkey_hash_getreader(myreader));
|
|
* // TODO: check the returncode
|
|
* \endcode
|
|
* - Iteration is exactly as described previously, but uses \ref sparkey_logiter_hashnext instead of
|
|
* \ref sparkey_logiter_next.
|
|
* - Random lookup
|
|
* \code
|
|
* sparkey_returncode returncode = sparkey_hash_get(myreader, (uint8_t*)"mykey", 5, myiter);
|
|
* if (sparkey_logiter_state(myiter) != SPARKEY_ITER_ACTIVE) {
|
|
* // Entry not found;
|
|
* } else {
|
|
* // Extracting value is done the same as when iterating.
|
|
* uint64_t wanted_valuelen = sparkey_logiter_valuelen(myiter);
|
|
* uint8_t *valuebuf = malloc(wanted_valuelen);
|
|
* uint64_t actual_valuelen;
|
|
* returncode = sparkey_logiter_fill_value(myiter, sparkey_hash_getreader(myreader), wanted_valuelen, valuebuf, &actual_valuelen);
|
|
* }
|
|
* \endcode
|
|
* Note that this API allows you to do a random seek and then iterate through the following entries. This may be
|
|
* useful when you insert groups of entries in order and quickly want to access all of them.
|
|
* - Close everything when you're done:
|
|
* \code
|
|
* sparkey_hash_close(&myreader);
|
|
* sparkey_logiter_close(&myiter);
|
|
* \endcode
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef enum {
|
|
SPARKEY_SUCCESS = 0,
|
|
SPARKEY_INTERNAL_ERROR = -1,
|
|
|
|
SPARKEY_FILE_NOT_FOUND = -100,
|
|
SPARKEY_PERMISSION_DENIED = -101,
|
|
SPARKEY_TOO_MANY_OPEN_FILES = -102,
|
|
SPARKEY_FILE_TOO_LARGE = -103,
|
|
SPARKEY_FILE_ALREADY_EXISTS = -104,
|
|
SPARKEY_FILE_BUSY = -105,
|
|
SPARKEY_FILE_IS_DIRECTORY = -106,
|
|
SPARKEY_FILE_SIZE_EXCEEDED = -107,
|
|
SPARKEY_FILE_CLOSED = -108,
|
|
SPARKEY_OUT_OF_DISK = -109,
|
|
SPARKEY_UNEXPECTED_EOF = -110,
|
|
SPARKEY_MMAP_FAILED = -111,
|
|
|
|
SPARKEY_WRONG_LOG_MAGIC_NUMBER = -200,
|
|
SPARKEY_WRONG_LOG_MAJOR_VERSION = -201,
|
|
SPARKEY_UNSUPPORTED_LOG_MINOR_VERSION = -202,
|
|
SPARKEY_LOG_TOO_SMALL = -203,
|
|
SPARKEY_LOG_CLOSED = -204,
|
|
SPARKEY_LOG_ITERATOR_INACTIVE = -205,
|
|
SPARKEY_LOG_ITERATOR_MISMATCH = -206,
|
|
SPARKEY_LOG_ITERATOR_CLOSED = -207,
|
|
SPARKEY_LOG_HEADER_CORRUPT = -208,
|
|
SPARKEY_INVALID_COMPRESSION_BLOCK_SIZE = -209,
|
|
SPARKEY_INVALID_COMPRESSION_TYPE = -210,
|
|
|
|
SPARKEY_WRONG_HASH_MAGIC_NUMBER = -300,
|
|
SPARKEY_WRONG_HASH_MAJOR_VERSION = -301,
|
|
SPARKEY_UNSUPPORTED_HASH_MINOR_VERSION = -302,
|
|
SPARKEY_HASH_TOO_SMALL = -303,
|
|
SPARKEY_HASH_CLOSED = -304,
|
|
SPARKEY_FILE_IDENTIFIER_MISMATCH = -305,
|
|
SPARKEY_HASH_HEADER_CORRUPT = -306,
|
|
SPARKEY_HASH_SIZE_INVALID = -307,
|
|
|
|
} sparkey_returncode;
|
|
|
|
/**
|
|
* Get a human readable string from a return code.
|
|
* @param code a return code
|
|
* @returns a string representing the return code.
|
|
*/
|
|
const char * sparkey_errstring(sparkey_returncode code);
|
|
|
|
/* logwriter */
|
|
|
|
/**
|
|
* A structure holding all the data necessary to add entries to a log file.
|
|
*/
|
|
struct sparkey_logwriter;
|
|
typedef struct sparkey_logwriter sparkey_logwriter;
|
|
|
|
typedef enum {
|
|
SPARKEY_COMPRESSION_NONE,
|
|
SPARKEY_COMPRESSION_SNAPPY
|
|
} sparkey_compression_type;
|
|
|
|
typedef enum {
|
|
SPARKEY_ENTRY_PUT,
|
|
SPARKEY_ENTRY_DELETE
|
|
} sparkey_entry_type;
|
|
|
|
typedef enum {
|
|
SPARKEY_ITER_NEW,
|
|
SPARKEY_ITER_ACTIVE,
|
|
SPARKEY_ITER_CLOSED,
|
|
SPARKEY_ITER_INVALID
|
|
} sparkey_iter_state;
|
|
|
|
struct sparkey_logreader;
|
|
typedef struct sparkey_logreader sparkey_logreader;
|
|
|
|
struct sparkey_logiter;
|
|
typedef struct sparkey_logiter sparkey_logiter;
|
|
|
|
struct sparkey_hashreader;
|
|
typedef struct sparkey_hashreader sparkey_hashreader;
|
|
|
|
|
|
/**
|
|
* Creates a new Sparkey log file, possibly overwriting an already existing.
|
|
* @param log a double reference to a sparkey_logwriter structure that gets allocated and initialized by this call.
|
|
* @param filename the file to create.
|
|
* @param compression_type NONE or SNAPPY, specifies if block compression should be used or not.
|
|
* @param compression_block_size is only relevant if compression type is not NONE.
|
|
* It represents the maximum number of bytes of an uncompressed block.
|
|
* @return SPARKEY_SUCCESS if all goes well.
|
|
*/
|
|
sparkey_returncode sparkey_logwriter_create(sparkey_logwriter **log, const char *filename, sparkey_compression_type compression_type, int compression_block_size);
|
|
|
|
/**
|
|
* Append to an existing Sparkey log file.
|
|
* @param log a double reference to a sparkey_logwriter structure that gets allocated and initialized by this call.
|
|
* @param filename the file to open for appending.
|
|
* It represents the maximum number of bytes of an uncompressed block.
|
|
* @return SPARKEY_SUCCESS if all goes well.
|
|
*/
|
|
sparkey_returncode sparkey_logwriter_append(sparkey_logwriter **log, const char *filename);
|
|
|
|
/**
|
|
* Append a key/value pair to the log file
|
|
* @param log a reference to an open log writer.
|
|
* @param keylen the number of bytes of the key data block
|
|
* @param key a pointer to a block of continuous data where the key can be found.
|
|
* Does not need to be NUL-terminated.
|
|
* @param valuelen the number of bytes of the value data block
|
|
* @param value a pointer to a block of continuous data where the value can be found.
|
|
* Does not need to be NUL-terminated.
|
|
* @return SPARKEY_SUCCESS if all goes well.
|
|
*/
|
|
sparkey_returncode sparkey_logwriter_put(sparkey_logwriter *log, uint64_t keylen, const uint8_t *key, uint64_t valuelen, const uint8_t *value);
|
|
|
|
/**
|
|
* Append a delete operation for a key to the log file
|
|
* @param log a reference to an open log writer.
|
|
* @param keylen the number of bytes of the key data block
|
|
* @param key a pointer to a block of continuous data where the key can be found.
|
|
* Does not need to be NUL-terminated.
|
|
* @return SPARKEY_SUCCESS if all goes well.
|
|
*/
|
|
sparkey_returncode sparkey_logwriter_delete(sparkey_logwriter *log, uint64_t keylen, const uint8_t *key);
|
|
|
|
/**
|
|
* Flush any open compression block to file buffer.
|
|
* Flush any open file buffer to disk.
|
|
* Rewrite the header on disk.
|
|
* This enables readers to read from the log.
|
|
* @param log a reference to an open log writer.
|
|
* @return SPARKEY_SUCCESS if all goes well.
|
|
*/
|
|
sparkey_returncode sparkey_logwriter_flush(sparkey_logwriter *log);
|
|
|
|
/**
|
|
* Flushes the log, then closes the file and marks the log as closed.
|
|
* The log will be closed after this, the sparkey_logwriter struct
|
|
* referenced will be freed and *log will be set to NULL.
|
|
* @param log a double reference to an open log writer.
|
|
* @return SPARKEY_SUCCESS if all goes well.
|
|
*/
|
|
sparkey_returncode sparkey_logwriter_close(sparkey_logwriter **log);
|
|
|
|
/* logreader */
|
|
|
|
/**
|
|
* Opens a log file for reading. The logreader is threadsafe, except during opening or closing.
|
|
* @param log a double reference to a logreader.
|
|
* @param filename a filename of a file containing a sparkey log.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a return code indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logreader_open(sparkey_logreader **log, const char *filename);
|
|
|
|
/**
|
|
* Closes a logreader.
|
|
* It's allowed to close a logreader while there are open logiterators.
|
|
* Further operations on such logiterators will fail.
|
|
* This is a failsafe operation.
|
|
* @param log a double reference to a logreader
|
|
* This will be set to NULL after close.
|
|
*/
|
|
void sparkey_logreader_close(sparkey_logreader **log);
|
|
|
|
/**
|
|
* Get the size of the largest key in the log.
|
|
* @param log a reference to a logreader.
|
|
* @returns
|
|
*/
|
|
uint64_t sparkey_logreader_maxkeylen(sparkey_logreader *log);
|
|
|
|
/**
|
|
* Get the size of the largest value in the log.
|
|
* @param log a reference to a logreader.
|
|
* @returns
|
|
*/
|
|
uint64_t sparkey_logreader_maxvaluelen(sparkey_logreader *log);
|
|
|
|
/**
|
|
* Get the blocksize for a reader
|
|
* @param log a reference to a logreader.
|
|
* @returns the blocksize
|
|
*/
|
|
int sparkey_logreader_get_compression_blocksize(sparkey_logreader *log);
|
|
|
|
/**
|
|
* Get the compression type for a reader
|
|
* @param log a reference to a logreader.
|
|
* @returns the compression type
|
|
*/
|
|
sparkey_compression_type sparkey_logreader_get_compression_type(sparkey_logreader *log);
|
|
|
|
/**
|
|
* Initializes a logiter and associates it with a logreader.
|
|
* The logreader must be open. The logiter is not threadsafe.
|
|
* @param iter a double reference to an uninitialized logiter. Will be set on success.
|
|
* @param log an open logreader
|
|
* @returns SPARKEY_SUCCESS or all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_create(sparkey_logiter **iter, sparkey_logreader *log);
|
|
|
|
/**
|
|
* Closes a log iterator.
|
|
* This is a failsafe operation.
|
|
* @param iter a double reference to a log iterator.
|
|
* This will be set to NULL after close.
|
|
*/
|
|
void sparkey_logiter_close(sparkey_logiter **iter);
|
|
|
|
/**
|
|
* Skips to a specific block in the logfile.
|
|
* The position must be a valid block start, but that will not be verified by the function.
|
|
* If an illegal position is used, all other operations on this logiterator are undefined,
|
|
* and may even segfault.
|
|
* @param iter an open log iterator.
|
|
* @param log an open logreader associated with iter.
|
|
* @param position an offset into the logfile where a block begins.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_seek(sparkey_logiter *iter, sparkey_logreader *log, uint64_t position);
|
|
|
|
/**
|
|
* Skip a number of entries.
|
|
* This is equivalent to calling sparkey_logiter_next count number of times.
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @param count the number of entries to skip.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_skip(sparkey_logiter *iter, sparkey_logreader *log, int count);
|
|
|
|
/**
|
|
* Prepares the logiter to start reading from the next entry.
|
|
* iter->state will be SPARKEY_ITER_CLOSED if the last entry has been passed.
|
|
* iter->state will be SPARKEY_ITER_INVALID if anything goes wrong.
|
|
* iter->state will be SPARKEY_ITER_ACTIVE if it successfully reached the next entry.
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_next(sparkey_logiter *iter, sparkey_logreader *log);
|
|
|
|
/**
|
|
* Resets the iterator to the start of the current entry. This is only valid if
|
|
* iter->state is SPARKEY_ITER_ACTIVE.
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_reset(sparkey_logiter *iter, sparkey_logreader *log);
|
|
|
|
/**
|
|
* Consumes and returns part of or all of the key of the current entry.
|
|
* Usage example:
|
|
* uint8_t *res;
|
|
* uint64_t len;
|
|
* sparkey_returncode code = sparkey_logiter_keychunk(iter, log, 1 << 30, &res, &len);
|
|
*
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @param maxlen a limit for how much data you want to handle.
|
|
* @param res (output parameter) reference to a read only array of data. The array is of size res, and is not NUL-terminated.
|
|
* You can not use this as a string, and you may not modify it. The data in the array is valid until the next operation on the
|
|
* logiter or until the log is closed.
|
|
* @param len (output parameter) reference to a variable holding the size of res.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_keychunk(sparkey_logiter *iter, sparkey_logreader *log, uint64_t maxlen, uint8_t ** res, uint64_t *len);
|
|
|
|
/**
|
|
* First consumes and discards any remaining key parts.
|
|
* Then consumes and returns part of or all of the value of the current entry.
|
|
* Usage example:
|
|
* uint8_t *res;
|
|
* uint64_t len;
|
|
* sparkey_returncode code = sparkey_logiter_valuechunk(iter, log, 1 << 30, &res, &len);
|
|
*
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @param maxlen a limit for how much data you want to handle.
|
|
* @param res (output parameter) reference to a read only array of data. The array is of size res, and is not NUL-terminated.
|
|
* You can not use this as a string, and you may not modify it. The data in the array is valid until the next operation on the
|
|
* logiter or until the log is closed.
|
|
* @param len (output parameter) reference to a variable holding the size of res.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_valuechunk(sparkey_logiter *iter, sparkey_logreader *log, uint64_t maxlen, uint8_t ** res, uint64_t *len);
|
|
|
|
/**
|
|
* Convenience function around sparkey_logiter_keychunk.
|
|
* Takes a user allocated buffer and fills it as much as possible by consuming parts of the key of the current entry.
|
|
* No NUL will be appended after the data, so you may not use it as a string unless you add the NUL manually.
|
|
* Usage example:
|
|
* uint8_t *buf = malloc(iter->keylen);
|
|
* uint64_t len;
|
|
* sparkey_returncode code = sparkey_logiter_fill_key(iter, log, iter->keylen, buf, &len);
|
|
*
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @param maxlen a limit for how much data you want to handle.
|
|
* @param buf a writable array of data. The array must at least be of size maxlen.
|
|
* @param len (output parameter) reference to a variable holding the amount of data written to buf.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_fill_key(sparkey_logiter *iter, sparkey_logreader *log, uint64_t maxlen, uint8_t *buf, uint64_t *len);
|
|
|
|
/**
|
|
* Convenience function around sparkey_logiter_valuechunk.
|
|
* Takes a user allocated buffer and fills it as much as possible by consuming parts of the key of the current entry.
|
|
* No NUL will be appended after the data, so you may not use it as a string unless you add the NUL manually.
|
|
* Usage example:
|
|
* uint8_t *buf = malloc(iter->valuelen);
|
|
* uint64_t len;
|
|
* sparkey_returncode code = sparkey_logiter_fill_value(iter, log, iter->valuelen, buf, &len);
|
|
*
|
|
* @param iter an open logiter
|
|
* @param log an open logreader associated with iter.
|
|
* @param maxlen a limit for how much data you want to handle.
|
|
* @param buf a writable array of data. The array must at least be of size maxlen.
|
|
* @param len (output parameter) reference to a variable holding the amount of data written to buf.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_fill_value(sparkey_logiter *iter, sparkey_logreader *log, uint64_t maxlen, uint8_t *buf, uint64_t *len);
|
|
|
|
/**
|
|
* Compares the keys of two iterators pointing to the same log.
|
|
* It assumes that the iterators are both clean, i.e. nothing has been consumed from the current entry.
|
|
*
|
|
* @param iter1 an open logiter
|
|
* @param iter2 an open logiter
|
|
* @param log an open logreader associated with iter1 and iter2.
|
|
* @param res (output parameter) reference to a variable holding the result of the comparison.
|
|
* It will be zero if the keys are equal, negative if key1 is smaller than key2 and positive if key1 is larger than key2.
|
|
* The behaviour is thus Like memcmp.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_keycmp(sparkey_logiter *iter1, sparkey_logiter *iter2, sparkey_logreader *log, int *res);
|
|
|
|
/**
|
|
* Get the state for an iterator.
|
|
* @returns iter->state
|
|
*/
|
|
sparkey_iter_state sparkey_logiter_state(sparkey_logiter *iter);
|
|
|
|
/**
|
|
* Get the type of an iterator.
|
|
* @returns iter->type
|
|
*/
|
|
sparkey_entry_type sparkey_logiter_type(sparkey_logiter *iter);
|
|
|
|
/**
|
|
* Get the keylen of an iterator.
|
|
* @returns iter->keylen
|
|
*/
|
|
uint64_t sparkey_logiter_keylen(sparkey_logiter *iter);
|
|
|
|
/**
|
|
* Get the valuelen of an iterator.
|
|
* @returns iter->valuelen
|
|
*/
|
|
uint64_t sparkey_logiter_valuelen(sparkey_logiter *iter);
|
|
|
|
/* hashwriter */
|
|
|
|
/**
|
|
* Creates a hash table for a specific log file.
|
|
* It's safe and efficient to run this multiple times.
|
|
* If the hash file already exists, it will be used to speed up the creation of the new file
|
|
* by reusing the existing entries, and only update the new hash table based on
|
|
* the entries in the log that are new since the last hash was built.
|
|
* Note that the hash file is never overwritten, instead the old file is unlinked from
|
|
* the filesystem and the new one is created. Thus, it's safe to rewrite the hash table while
|
|
* other processes are reading from it.
|
|
* @param hash_filename the file to create and put the sparkey hash table in.
|
|
* @param log_filename a file that must exist and be a sparkey log file.
|
|
* @param hash_size size of the hashes for keys.
|
|
Valid values are 4 (32 bit murmurhash3_x86_32) and
|
|
8 (lower 64-bit part of murmurhash3_x64_128).
|
|
A value of zero will make it autoselect hash size, depending on number of entries.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_hash_write(const char *hash_filename, const char *log_filename, int hash_size);
|
|
|
|
/* hashreader */
|
|
/**
|
|
* Opens a hash file and a log file for reading. The the hashreader is threadsafe, except during opening or closing.
|
|
* @param reader a double reference to an uninitialized hashreader. Will be set on success.
|
|
* @param hash_filename a filename of a file containing a sparkey hash table.
|
|
* @param log_filename a filename of a file containing a sparkey log.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a return code indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_hash_open(sparkey_hashreader **reader, const char *hash_filename, const char *log_filename);
|
|
|
|
/**
|
|
* Gets the logreader that is referenced by the hashreader
|
|
* @param reader an open reader.
|
|
* @returns the associated logreader
|
|
*/
|
|
sparkey_logreader * sparkey_hash_getreader(sparkey_hashreader *reader);
|
|
|
|
/**
|
|
* Closes a hashreader.
|
|
* It's allowed to close a hashreader while there are open logiterators associated with it.
|
|
* Further operations on such logiterators will fail.
|
|
* This is a failsafe operation.
|
|
* @param reader a double reference to a hashreader
|
|
*/
|
|
void sparkey_hash_close(sparkey_hashreader **reader);
|
|
|
|
/**
|
|
* Performs a hash table lookup of a key. If the key is found,
|
|
* the iterator will have state SPARKEY_ITER_ACTIVE and the key chunk will be consumed.
|
|
* Otherwise, the iterator will have state SPARKEY_ITER_INVALID.
|
|
* @param reader an open reader.
|
|
* @param key a buffer containing the key. It does not have be NUL terminated.
|
|
* @param keylen the length of the key.
|
|
* @param iter an iterator associated with the reader. Will be mutated.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a return code indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_hash_get(sparkey_hashreader *reader, const uint8_t *key, uint64_t keylen, sparkey_logiter *iter);
|
|
|
|
/**
|
|
* Works the same as sparkey_logiter_next, except it skips entries that are not of type SPARKEY_ENTRY_PUT
|
|
* and entries that have been overwritten or deleted. Thus it only stops at live entries.
|
|
* iter->state will be SPARKEY_ITER_CLOSED if the last entry has been passed.
|
|
* iter->state will be SPARKEY_ITER_INVALID if anything goes wrong.
|
|
* iter->state will be SPARKEY_ITER_ACTIVE if it successfully reached the next entry.
|
|
* @see sparkey_logiter_next
|
|
* @param iter an open logiter
|
|
* @param reader an open reader associated with iter.
|
|
* @returns SPARKEY_SUCCESS if all goes well. Otherwise a returncode indicating the error.
|
|
*/
|
|
sparkey_returncode sparkey_logiter_hashnext(sparkey_logiter *iter, sparkey_hashreader *reader);
|
|
|
|
uint64_t sparkey_hash_numentries(sparkey_hashreader *reader);
|
|
|
|
uint64_t sparkey_hash_numcollisions(sparkey_hashreader *reader);
|
|
|
|
/* util */
|
|
|
|
/**
|
|
* Allocates and creates a string denoting a log file from an index file.
|
|
* This is simply a string replacement of .spi$ to .spl$
|
|
* @param index_filename the filename representing the index file
|
|
* @returns NULL if the index_filename does not end with ".spi"
|
|
*/
|
|
char * sparkey_create_log_filename(const char *index_filename);
|
|
|
|
/**
|
|
* Allocates and creates a string denoting an index file from a log file.
|
|
* This is simply a string replacement of .spl$ to .spi$
|
|
* @param log_filename the filename representing the log file
|
|
* @returns NULL if the log_filename does not end with ".spl"
|
|
*/
|
|
char * sparkey_create_index_filename(const char *log_filename);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|