packages feed

diskhash-0.0.1.2: src/diskhash.h

#ifndef DISKHASH_H_INCLUDE_GUARD__
#define DISKHASH_H_INCLUDE_GUARD__
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif


/**
 * key_maxlen is the maximum key length not including the terminator NUL, i.e.,
 * diskhash will check that for every key you insert `strlen(key) <
 * opts.key_maxlen`.
 *
 * Internally, space is allocated on 8-Byte aligned boundaries, so numbers such
 * as 7, 15, 23, 31, ... (i.e., multiples of 8 minus 1 for NUL) are good
 * choices for key_maxlen.
 *
 * object_datalen is the number of Bytes that your data elements occupy.
 */
typedef struct HashTableOpts {
    size_t key_maxlen;
    size_t object_datalen;
} HashTableOpts;

typedef struct HashTable {
    int fd_;
    const char* fname_;
    void* data_;
    size_t datasize_;
} HashTable;


/** Zero-valued options
 */
HashTableOpts dht_zero_opts(void);

/** Open a hash table file
 *
 * fpath is the file path
 * flags are passed to call to open() and the user should read the documentation therein
 *
 * Values returned from dht_open must be freed with dht_free.
 *
 * Examples:
 *
 * Read-write:
 *
 *      HashTableOpts opts;
 *      opts.key_maxlen = 15;
 *      opts.object_datalen = 8;
 *      char* err;
 *      HashTable* ht = dht_open("hashtable.dht", opts, O_RDWR|O_CREAT, &err);
 *
 * Read-only:
 *
 *      char* err;
 *      HashTable* ht = dht_open("hashtable.dht", opts, O_RDONLY, &err);
 *
 * When opening an existing disk table, you can pass `{ 0, 0 }` (the return
 * value of `dht_zero_opts()`) as the options, in which case the values will be
 * taken from the table on disk. If you do pass values, they are checked
 * against the values on disk and it is an error if there is a mismatch.
 *
 * The last argument is an error output argument. If it is set to a non-NULL
 * value, then the memory must be released with free(). Passing NULL is valid
 * (and no error message will be produced). An error return with *err == NULL
 * will mean an out-of-memory error (when dht fails to allocate memory, it does
 * not try to allocate memory for an error message).
 */
HashTable* dht_open(const char* fpath, HashTableOpts opts, int flags, char**);

/** Lookup a value by key
 *
 * If the hash table was opened in read-write mode, then the memory returned
 * can be written to (the hash table itself does not inspect the values in any
 * way). Writing to a read-only hashtable will probably trigger a segmentation
 * fault.
 *
 * If the object is not found, returns NULL.
 *
 * Thread safety: multiple concurrent reads are perfectly safe. No guarantees
 * are given whenever writing is performed. Similarly, if you write to the
 * output of this function (the ht_data field), no guarantees are given.
 */
void* dht_lookup(const HashTable*, const char* key);

/** Insert a value.
 *
 * The hashtable must be opened in read write mode.
 *
 * If a value with the given key is already present in the table, then no
 * action is performed and 0 is returned. If you want to overwrite that value,
 * you can use `dht_lookup` and write to its output.
 *
 * This operation is typically O(1) amortized. However, if table is at capacity
 * when dht_insert is called, then it must be grown which can be a
 * time-consuming operation as all the values are copied to the newly allocated
 * memory block (see dht_reserve).
 *
 * Errors can occur if table expansion is needed and memory cannot be
 * allocated.
 *
 * Returns 1 if the value was inserted.
 *         0 if the key was already present in the table. The hash table was
 *         not modified.
 *         -EINVAL : key is too long
 *	   -ENOMEM : dht_reserve failed.
 *
 * The last argument is an error output argument. If it is set to a non-NULL
 * value, then the memory must be released with free(). Passing NULL is valid
 * (and no error message will be produced). An error return with *err == NULL
 * will mean an out-of-memory error (when dht fails to allocate memory, it does
 * not try to allocate memory for an error message).
 */
int dht_insert(HashTable*, const char* key, const void* data, char** err);

/** Preallocate memory for the table.
 *
 * Calling this function if the number of elements is known apriori can improve
 * performance. Additionally, if capacity exists, then dht_insert never fails.
 *
 * This function returns the actual capacity allocated (which may be more than
 * requested, but never less). Calling dht_reserve asking for _less_ capacity
 * than is currently used is a no-op.
 *
 * If capacity cannot be allocated, this function returns 0 (but no changes to
 * the hash table are made).
 *
 * This function can be used to query the current capacity by passing the value
 * 1 as the desired capacity.
 *
 * The last argument is an error output argument. If it is set to a non-NULL
 * value, then the memory must be released with free(). Passing NULL is valid
 * (and no error message will be produced).
 */
size_t dht_reserve(HashTable*, size_t capacity, char** err);

/**
 * Return the number of elements
 */
size_t dht_size(const HashTable*);

/** Free the hashtable and sync to disk.
 */
void dht_free(HashTable*);

/** For debug use only */
void show_ht(const HashTable*);


#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* DISKHASH_H_INCLUDE_GUARD__*/