mirror of https://github.com/getdnsapi/getdns.git
Import lruhash and lookup3 from unbound
This commit is contained in:
parent
5b5123a79d
commit
f751de696a
|
@ -79,7 +79,7 @@ LIBOBJDIR=
|
|||
LIBOBJS=@LIBOBJS@
|
||||
COMPAT_OBJ=$(LIBOBJS:.o=.lo)
|
||||
|
||||
UTIL_OBJ=rbtree.lo val_secalgo.lo
|
||||
UTIL_OBJ=rbtree.lo val_secalgo.lo lruhash.lo lookup3.lo locks.lo
|
||||
|
||||
JSMN_OBJ=jsmn.lo
|
||||
|
||||
|
@ -341,9 +341,18 @@ inet_ntop.lo inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h
|
|||
inet_pton.lo inet_pton.o: $(srcdir)/compat/inet_pton.c config.h
|
||||
sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h
|
||||
strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h
|
||||
locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
|
||||
$(srcdir)/util/auxiliary/$(srcdir)/util/log.h $(srcdir)/debug.h config.h
|
||||
lookup3.lo lookup3.o: $(srcdir)/util/lookup3.c config.h $(srcdir)/util/auxiliary/$(srcdir)/util/storage/lookup3.h \
|
||||
$(srcdir)/util/lookup3.h $(srcdir)/util/orig-headers/lookup3.h
|
||||
lruhash.lo lruhash.o: $(srcdir)/util/lruhash.c config.h $(srcdir)/util/auxiliary/$(srcdir)/util/storage/lruhash.h \
|
||||
$(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \
|
||||
$(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/$(srcdir)/util/log.h $(srcdir)/debug.h config.h \
|
||||
$(srcdir)/util/auxiliary/$(srcdir)/util/fptr_wlist.h
|
||||
rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/auxiliary/log.h \
|
||||
$(srcdir)/util/auxiliary/$(srcdir)/util/log.h $(srcdir)/debug.h config.h $(srcdir)/util/auxiliary/fptr_wlist.h \
|
||||
$(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h
|
||||
$(srcdir)/util/auxiliary/$(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util/orig-headers/rbtree.h
|
||||
val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h \
|
||||
$(srcdir)/util/auxiliary/$(srcdir)/util/data/packed_rrset.h \
|
||||
$(srcdir)/util/auxiliary/validator/val_secalgo.h $(srcdir)/util/val_secalgo.h \
|
||||
|
|
|
@ -1,42 +1 @@
|
|||
/**
|
||||
*
|
||||
* /brief dummy prototypes for function pointer whitelisting
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_FPTR_WLIST_H
|
||||
#define UTIL_FPTR_WLIST_H
|
||||
|
||||
#define fptr_ok(x)
|
||||
#define fptr_whitelist_event(x)
|
||||
#define fptr_whitelist_rbtree_cmp(x)
|
||||
|
||||
#endif /* UTIL_FPTR_WLIST_H */
|
||||
|
||||
#include "util/fptr_wlist.h"
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
*
|
||||
* /brief dummy prototypes for function pointer whitelisting
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_FPTR_WLIST_H
|
||||
#define UTIL_FPTR_WLIST_H
|
||||
|
||||
#define fptr_ok(x)
|
||||
#define fptr_whitelist_event(x)
|
||||
#define fptr_whitelist_rbtree_cmp(x)
|
||||
|
||||
#endif /* UTIL_FPTR_WLIST_H */
|
||||
|
|
@ -37,15 +37,22 @@
|
|||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
#if defined(SEC_DEBUG) && SEC_DEBUG
|
||||
#ifdef DEBUGGING
|
||||
#define verbose(x, ...) DEBUG_NL(__VA_ARGS__)
|
||||
#define log_err(...) DEBUG_NL(__VA_ARGS__)
|
||||
#define log_err(...) DEBUG_NL(__VA_ARGS__)
|
||||
#define log_info(...) DEBUG_NL(__VA_ARGS__)
|
||||
#define fatal_exit(...) do { DEBUG_NL(__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
|
||||
#define log_assert(x) do { if(!(x)) fatal_exit("%s:%d: %s: assertion %s failed", \
|
||||
__FILE__, __LINE__, __FUNC__, #x); \
|
||||
} while(0)
|
||||
#else
|
||||
#define verbose(...)
|
||||
#define log_err(...)
|
||||
#define verbose(...) ((void)0)
|
||||
#define log_err(...) ((void)0)
|
||||
#define log_info(...) ((void)0)
|
||||
#define fatal_exit(...) ((void)0)
|
||||
#define log_assert(x) ((void)0)
|
||||
#endif
|
||||
|
||||
#define log_assert(x)
|
||||
|
||||
#endif /* UTIL_LOG_H */
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "util/lookup3.h"
|
|
@ -0,0 +1 @@
|
|||
#include "util/lruhash.h"
|
|
@ -6,3 +6,9 @@ wget -O rbtree.c ${REPO}/util/rbtree.c
|
|||
wget -O orig-headers/rbtree.h ${REPO}/util/rbtree.h
|
||||
wget -O val_secalgo.c ${REPO}/validator/val_secalgo.c
|
||||
wget -O orig-headers/val_secalgo.h ${REPO}/validator/val_secalgo.h
|
||||
wget -O lruhash.c ${REPO}/util/storage/lruhash.c
|
||||
wget -O orig-headers/lruhash.h ${REPO}/util/storage/lruhash.h
|
||||
wget -O lookup3.c ${REPO}/util/storage/lookup3.c
|
||||
wget -O orig-headers/lookup3.h ${REPO}/util/storage/lookup3.h
|
||||
wget -O locks.c ${REPO}/util/locks.c
|
||||
wget -O orig-headers/locks.h ${REPO}/util/locks.h
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
/**
|
||||
* util/locks.c - unbound locking primitives
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Implementation of locking and threading support.
|
||||
* A place for locking debug code since most locking functions are macros.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "util/locks.h"
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
/** block all signals, masks them away. */
|
||||
void
|
||||
ub_thread_blocksigs(void)
|
||||
{
|
||||
#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK)
|
||||
# if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)
|
||||
int err;
|
||||
# endif
|
||||
sigset_t sigset;
|
||||
sigfillset(&sigset);
|
||||
#ifdef HAVE_PTHREAD
|
||||
if((err=pthread_sigmask(SIG_SETMASK, &sigset, NULL)))
|
||||
fatal_exit("pthread_sigmask: %s", strerror(err));
|
||||
#else
|
||||
# ifdef HAVE_SOLARIS_THREADS
|
||||
if((err=thr_sigsetmask(SIG_SETMASK, &sigset, NULL)))
|
||||
fatal_exit("thr_sigsetmask: %s", strerror(err));
|
||||
# else
|
||||
/* have nothing, do single process signal mask */
|
||||
if(sigprocmask(SIG_SETMASK, &sigset, NULL))
|
||||
fatal_exit("sigprocmask: %s", strerror(errno));
|
||||
# endif /* HAVE_SOLARIS_THREADS */
|
||||
#endif /* HAVE_PTHREAD */
|
||||
#endif /* have signal stuff */
|
||||
}
|
||||
|
||||
/** unblock one signal, so we can catch it */
|
||||
void ub_thread_sig_unblock(int sig)
|
||||
{
|
||||
#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK)
|
||||
# if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)
|
||||
int err;
|
||||
# endif
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, sig);
|
||||
#ifdef HAVE_PTHREAD
|
||||
if((err=pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)))
|
||||
fatal_exit("pthread_sigmask: %s", strerror(err));
|
||||
#else
|
||||
# ifdef HAVE_SOLARIS_THREADS
|
||||
if((err=thr_sigsetmask(SIG_UNBLOCK, &sigset, NULL)))
|
||||
fatal_exit("thr_sigsetmask: %s", strerror(err));
|
||||
# else
|
||||
/* have nothing, do single thread case */
|
||||
if(sigprocmask(SIG_UNBLOCK, &sigset, NULL))
|
||||
fatal_exit("sigprocmask: %s", strerror(errno));
|
||||
# endif /* HAVE_SOLARIS_THREADS */
|
||||
#endif /* HAVE_PTHREAD */
|
||||
#else
|
||||
(void)sig;
|
||||
#endif /* have signal stuff */
|
||||
}
|
||||
|
||||
#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS)
|
||||
/**
|
||||
* No threading available: fork a new process.
|
||||
* This means no shared data structure, and no locking.
|
||||
* Only the main thread ever returns. Exits on errors.
|
||||
* @param thr: the location where to store the thread-id.
|
||||
* @param func: function body of the thread. Return value of func is lost.
|
||||
* @param arg: user argument to func.
|
||||
*/
|
||||
void
|
||||
ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
switch(pid) {
|
||||
default: /* main */
|
||||
*thr = (ub_thread_type)pid;
|
||||
return;
|
||||
case 0: /* child */
|
||||
*thr = (ub_thread_type)getpid();
|
||||
(void)(*func)(arg);
|
||||
exit(0);
|
||||
case -1: /* error */
|
||||
fatal_exit("could not fork: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no threading. Wait for a process to terminate.
|
||||
* Note that ub_thread_type is defined as pid_t.
|
||||
* @param thread: the process id to wait for.
|
||||
*/
|
||||
void ub_thr_fork_wait(ub_thread_type thread)
|
||||
{
|
||||
int status = 0;
|
||||
if(waitpid((pid_t)thread, &status, 0) == -1)
|
||||
log_err("waitpid(%d): %s", (int)thread, strerror(errno));
|
||||
if(status != 0)
|
||||
log_warn("process %d abnormal exit with status %d",
|
||||
(int)thread, status);
|
||||
}
|
||||
#endif /* !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) */
|
||||
|
||||
#ifdef HAVE_SOLARIS_THREADS
|
||||
void* ub_thread_key_get(ub_thread_key_type key)
|
||||
{
|
||||
void* ret=NULL;
|
||||
LOCKRET(thr_getspecific(key, &ret));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_THREADS
|
||||
/** log a windows GetLastError message */
|
||||
static void log_win_err(const char* str, DWORD err)
|
||||
{
|
||||
LPTSTR buf;
|
||||
if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL, err, 0, (LPTSTR)&buf, 0, NULL) == 0) {
|
||||
/* could not format error message */
|
||||
log_err("%s, GetLastError=%d", str, (int)err);
|
||||
return;
|
||||
}
|
||||
log_err("%s, (err=%d): %s", str, (int)err, buf);
|
||||
LocalFree(buf);
|
||||
}
|
||||
|
||||
void lock_basic_init(lock_basic_type* lock)
|
||||
{
|
||||
/* implement own lock, because windows HANDLE as Mutex usage
|
||||
* uses too many handles and would bog down the whole system. */
|
||||
(void)InterlockedExchange(lock, 0);
|
||||
}
|
||||
|
||||
void lock_basic_destroy(lock_basic_type* lock)
|
||||
{
|
||||
(void)InterlockedExchange(lock, 0);
|
||||
}
|
||||
|
||||
void lock_basic_lock(lock_basic_type* lock)
|
||||
{
|
||||
LONG wait = 1; /* wait 1 msec at first */
|
||||
|
||||
while(InterlockedExchange(lock, 1)) {
|
||||
/* if the old value was 1 then if was already locked */
|
||||
Sleep(wait); /* wait with sleep */
|
||||
wait *= 2; /* exponential backoff for waiting */
|
||||
}
|
||||
/* the old value was 0, but we inserted 1, we locked it! */
|
||||
}
|
||||
|
||||
void lock_basic_unlock(lock_basic_type* lock)
|
||||
{
|
||||
/* unlock it by inserting the value of 0. xchg for cache coherency. */
|
||||
(void)InterlockedExchange(lock, 0);
|
||||
}
|
||||
|
||||
void ub_thread_key_create(ub_thread_key_type* key, void* f)
|
||||
{
|
||||
*key = TlsAlloc();
|
||||
if(*key == TLS_OUT_OF_INDEXES) {
|
||||
*key = 0;
|
||||
log_win_err("TlsAlloc Failed(OUT_OF_INDEXES)", GetLastError());
|
||||
}
|
||||
else ub_thread_key_set(*key, f);
|
||||
}
|
||||
|
||||
void ub_thread_key_set(ub_thread_key_type key, void* v)
|
||||
{
|
||||
if(!TlsSetValue(key, v)) {
|
||||
log_win_err("TlsSetValue failed", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
void* ub_thread_key_get(ub_thread_key_type key)
|
||||
{
|
||||
void* ret = (void*)TlsGetValue(key);
|
||||
if(ret == NULL && GetLastError() != ERROR_SUCCESS) {
|
||||
log_win_err("TlsGetValue failed", GetLastError());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg)
|
||||
{
|
||||
#ifndef HAVE__BEGINTHREADEX
|
||||
*thr = CreateThread(NULL, /* default security (no inherit handle) */
|
||||
0, /* default stack size */
|
||||
(LPTHREAD_START_ROUTINE)func, arg,
|
||||
0, /* default flags, run immediately */
|
||||
NULL); /* do not store thread identifier anywhere */
|
||||
#else
|
||||
/* the beginthreadex routine setups for the C lib; aligns stack */
|
||||
*thr=(ub_thread_type)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL);
|
||||
#endif
|
||||
if(*thr == NULL) {
|
||||
log_win_err("CreateThread failed", GetLastError());
|
||||
fatal_exit("thread create failed");
|
||||
}
|
||||
}
|
||||
|
||||
ub_thread_type ub_thread_self(void)
|
||||
{
|
||||
return GetCurrentThread();
|
||||
}
|
||||
|
||||
void ub_thread_join(ub_thread_type thr)
|
||||
{
|
||||
DWORD ret = WaitForSingleObject(thr, INFINITE);
|
||||
if(ret == WAIT_FAILED) {
|
||||
log_win_err("WaitForSingleObject(Thread):WAIT_FAILED",
|
||||
GetLastError());
|
||||
} else if(ret == WAIT_TIMEOUT) {
|
||||
log_win_err("WaitForSingleObject(Thread):WAIT_TIMEOUT",
|
||||
GetLastError());
|
||||
}
|
||||
/* and close the handle to the thread */
|
||||
if(!CloseHandle(thr)) {
|
||||
log_win_err("CloseHandle(Thread) failed", GetLastError());
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_WINDOWS_THREADS */
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
*
|
||||
* \file locks.h
|
||||
* /brief Alternative symbol names for unbound's locks.h
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2017, NLnet Labs, the getdns team
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef LOCKS_H_SYMBOLS
|
||||
#define LOCKS_H_SYMBOLS
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define ub_thread_blocksigs _getdns_ub_thread_blocksigs
|
||||
#define ub_thread_sig_unblock _getdns_ub_thread_sig_unblock
|
||||
|
||||
#define ub_thread_type _getdns_ub_thread_type
|
||||
#define ub_thr_fork_create _getdns_ub_thr_fork_create
|
||||
#define ub_thr_fork_wait _getdns_ub_thr_fork_wait
|
||||
|
||||
#if defined(HAVE_SOLARIS_THREADS) || defined(HAVE_WINDOWS_THREADS)
|
||||
#define ub_thread_key_type _getdns_ub_thread_key_type
|
||||
#define ub_thread_key_create _getdns_ub_thread_key_create
|
||||
#define ub_thread_key_set _getdns_ub_thread_key_set
|
||||
#define ub_thread_key_get _getdns_ub_thread_key_get
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDOWS_THREADS
|
||||
#define lock_basic_type _getdns_lock_basic_type
|
||||
#define lock_basic_init _getdns_lock_basic_init
|
||||
#define lock_basic_destroy _getdns_lock_basic_destroy
|
||||
#define lock_basic_lock _getdns_lock_basic_lock_
|
||||
#define lock_basic_unlock _getdns_lock_basic_unlock
|
||||
|
||||
#define ub_thread_create _getdns_ub_thread_create
|
||||
#define ub_thread_self _getdns_ub_thread_self
|
||||
#endif
|
||||
|
||||
#include "util/orig-headers/locks.h"
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
*
|
||||
* \file lookup3.h
|
||||
* /brief Alternative symbol names for unbound's lookup3.h
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2017, NLnet Labs, the getdns team
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef LOOKUP3_H_SYMBOLS
|
||||
#define LOOKUP3_H_SYMBOLS
|
||||
|
||||
#define hashword _getdns_hashword
|
||||
#define hashlittle _getdns_hashlittle
|
||||
#define hash_set_raninit _getdns_hash_set_raninit
|
||||
|
||||
#include "util/orig-headers/lookup3.h"
|
||||
#endif
|
|
@ -0,0 +1,545 @@
|
|||
/*
|
||||
* util/storage/lruhash.c - hashtable, hash function, LRU keeping.
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains a hashtable with LRU keeping of entries.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "util/storage/lruhash.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
|
||||
void
|
||||
bin_init(struct lruhash_bin* array, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
#ifdef THREADS_DISABLED
|
||||
(void)array;
|
||||
#endif
|
||||
for(i=0; i<size; i++) {
|
||||
lock_quick_init(&array[i].lock);
|
||||
lock_protect(&array[i].lock, &array[i],
|
||||
sizeof(struct lruhash_bin));
|
||||
}
|
||||
}
|
||||
|
||||
struct lruhash*
|
||||
lruhash_create(size_t start_size, size_t maxmem,
|
||||
lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc,
|
||||
lruhash_delkeyfunc_type delkeyfunc,
|
||||
lruhash_deldatafunc_type deldatafunc, void* arg)
|
||||
{
|
||||
struct lruhash* table = (struct lruhash*)calloc(1,
|
||||
sizeof(struct lruhash));
|
||||
if(!table)
|
||||
return NULL;
|
||||
lock_quick_init(&table->lock);
|
||||
table->sizefunc = sizefunc;
|
||||
table->compfunc = compfunc;
|
||||
table->delkeyfunc = delkeyfunc;
|
||||
table->deldatafunc = deldatafunc;
|
||||
table->cb_arg = arg;
|
||||
table->size = start_size;
|
||||
table->size_mask = (int)(start_size-1);
|
||||
table->lru_start = NULL;
|
||||
table->lru_end = NULL;
|
||||
table->num = 0;
|
||||
table->space_used = 0;
|
||||
table->space_max = maxmem;
|
||||
table->array = calloc(table->size, sizeof(struct lruhash_bin));
|
||||
if(!table->array) {
|
||||
lock_quick_destroy(&table->lock);
|
||||
free(table);
|
||||
return NULL;
|
||||
}
|
||||
bin_init(table->array, table->size);
|
||||
lock_protect(&table->lock, table, sizeof(*table));
|
||||
lock_protect(&table->lock, table->array,
|
||||
table->size*sizeof(struct lruhash_bin));
|
||||
return table;
|
||||
}
|
||||
|
||||
void
|
||||
bin_delete(struct lruhash* table, struct lruhash_bin* bin)
|
||||
{
|
||||
struct lruhash_entry* p, *np;
|
||||
void *d;
|
||||
if(!bin)
|
||||
return;
|
||||
lock_quick_destroy(&bin->lock);
|
||||
p = bin->overflow_list;
|
||||
bin->overflow_list = NULL;
|
||||
while(p) {
|
||||
np = p->overflow_next;
|
||||
d = p->data;
|
||||
(*table->delkeyfunc)(p->key, table->cb_arg);
|
||||
(*table->deldatafunc)(d, table->cb_arg);
|
||||
p = np;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bin_split(struct lruhash* table, struct lruhash_bin* newa,
|
||||
int newmask)
|
||||
{
|
||||
size_t i;
|
||||
struct lruhash_entry *p, *np;
|
||||
struct lruhash_bin* newbin;
|
||||
/* move entries to new table. Notice that since hash x is mapped to
|
||||
* bin x & mask, and new mask uses one more bit, so all entries in
|
||||
* one bin will go into the old bin or bin | newbit */
|
||||
#ifndef THREADS_DISABLED
|
||||
int newbit = newmask - table->size_mask;
|
||||
#endif
|
||||
/* so, really, this task could also be threaded, per bin. */
|
||||
/* LRU list is not changed */
|
||||
for(i=0; i<table->size; i++)
|
||||
{
|
||||
lock_quick_lock(&table->array[i].lock);
|
||||
p = table->array[i].overflow_list;
|
||||
/* lock both destination bins */
|
||||
lock_quick_lock(&newa[i].lock);
|
||||
lock_quick_lock(&newa[newbit|i].lock);
|
||||
while(p) {
|
||||
np = p->overflow_next;
|
||||
/* link into correct new bin */
|
||||
newbin = &newa[p->hash & newmask];
|
||||
p->overflow_next = newbin->overflow_list;
|
||||
newbin->overflow_list = p;
|
||||
p=np;
|
||||
}
|
||||
lock_quick_unlock(&newa[i].lock);
|
||||
lock_quick_unlock(&newa[newbit|i].lock);
|
||||
lock_quick_unlock(&table->array[i].lock);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_delete(struct lruhash* table)
|
||||
{
|
||||
size_t i;
|
||||
if(!table)
|
||||
return;
|
||||
/* delete lock on hashtable to force check its OK */
|
||||
lock_quick_destroy(&table->lock);
|
||||
for(i=0; i<table->size; i++)
|
||||
bin_delete(table, &table->array[i]);
|
||||
free(table->array);
|
||||
free(table);
|
||||
}
|
||||
|
||||
void
|
||||
bin_overflow_remove(struct lruhash_bin* bin, struct lruhash_entry* entry)
|
||||
{
|
||||
struct lruhash_entry* p = bin->overflow_list;
|
||||
struct lruhash_entry** prevp = &bin->overflow_list;
|
||||
while(p) {
|
||||
if(p == entry) {
|
||||
*prevp = p->overflow_next;
|
||||
return;
|
||||
}
|
||||
prevp = &p->overflow_next;
|
||||
p = p->overflow_next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
reclaim_space(struct lruhash* table, struct lruhash_entry** list)
|
||||
{
|
||||
struct lruhash_entry* d;
|
||||
struct lruhash_bin* bin;
|
||||
log_assert(table);
|
||||
/* does not delete MRU entry, so table will not be empty. */
|
||||
while(table->num > 1 && table->space_used > table->space_max) {
|
||||
/* notice that since we hold the hashtable lock, nobody
|
||||
can change the lru chain. So it cannot be deleted underneath
|
||||
us. We still need the hashbin and entry write lock to make
|
||||
sure we flush all users away from the entry.
|
||||
which is unlikely, since it is LRU, if someone got a rdlock
|
||||
it would be moved to front, but to be sure. */
|
||||
d = table->lru_end;
|
||||
/* specialised, delete from end of double linked list,
|
||||
and we know num>1, so there is a previous lru entry. */
|
||||
log_assert(d && d->lru_prev);
|
||||
table->lru_end = d->lru_prev;
|
||||
d->lru_prev->lru_next = NULL;
|
||||
/* schedule entry for deletion */
|
||||
bin = &table->array[d->hash & table->size_mask];
|
||||
table->num --;
|
||||
lock_quick_lock(&bin->lock);
|
||||
bin_overflow_remove(bin, d);
|
||||
d->overflow_next = *list;
|
||||
*list = d;
|
||||
lock_rw_wrlock(&d->lock);
|
||||
table->space_used -= table->sizefunc(d->key, d->data);
|
||||
if(table->markdelfunc)
|
||||
(*table->markdelfunc)(d->key);
|
||||
lock_rw_unlock(&d->lock);
|
||||
lock_quick_unlock(&bin->lock);
|
||||
}
|
||||
}
|
||||
|
||||
struct lruhash_entry*
|
||||
bin_find_entry(struct lruhash* table,
|
||||
struct lruhash_bin* bin, hashvalue_type hash, void* key)
|
||||
{
|
||||
struct lruhash_entry* p = bin->overflow_list;
|
||||
while(p) {
|
||||
if(p->hash == hash && table->compfunc(p->key, key) == 0)
|
||||
return p;
|
||||
p = p->overflow_next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
table_grow(struct lruhash* table)
|
||||
{
|
||||
struct lruhash_bin* newa;
|
||||
int newmask;
|
||||
size_t i;
|
||||
if(table->size_mask == (int)(((size_t)-1)>>1)) {
|
||||
log_err("hash array malloc: size_t too small");
|
||||
return;
|
||||
}
|
||||
/* try to allocate new array, if not fail */
|
||||
newa = calloc(table->size*2, sizeof(struct lruhash_bin));
|
||||
if(!newa) {
|
||||
log_err("hash grow: malloc failed");
|
||||
/* continue with smaller array. Though its slower. */
|
||||
return;
|
||||
}
|
||||
bin_init(newa, table->size*2);
|
||||
newmask = (table->size_mask << 1) | 1;
|
||||
bin_split(table, newa, newmask);
|
||||
/* delete the old bins */
|
||||
lock_unprotect(&table->lock, table->array);
|
||||
for(i=0; i<table->size; i++) {
|
||||
lock_quick_destroy(&table->array[i].lock);
|
||||
}
|
||||
free(table->array);
|
||||
|
||||
table->size *= 2;
|
||||
table->size_mask = newmask;
|
||||
table->array = newa;
|
||||
lock_protect(&table->lock, table->array,
|
||||
table->size*sizeof(struct lruhash_bin));
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
lru_front(struct lruhash* table, struct lruhash_entry* entry)
|
||||
{
|
||||
entry->lru_prev = NULL;
|
||||
entry->lru_next = table->lru_start;
|
||||
if(!table->lru_start)
|
||||
table->lru_end = entry;
|
||||
else table->lru_start->lru_prev = entry;
|
||||
table->lru_start = entry;
|
||||
}
|
||||
|
||||
void
|
||||
lru_remove(struct lruhash* table, struct lruhash_entry* entry)
|
||||
{
|
||||
if(entry->lru_prev)
|
||||
entry->lru_prev->lru_next = entry->lru_next;
|
||||
else table->lru_start = entry->lru_next;
|
||||
if(entry->lru_next)
|
||||
entry->lru_next->lru_prev = entry->lru_prev;
|
||||
else table->lru_end = entry->lru_prev;
|
||||
}
|
||||
|
||||
void
|
||||
lru_touch(struct lruhash* table, struct lruhash_entry* entry)
|
||||
{
|
||||
log_assert(table && entry);
|
||||
if(entry == table->lru_start)
|
||||
return; /* nothing to do */
|
||||
/* remove from current lru position */
|
||||
lru_remove(table, entry);
|
||||
/* add at front */
|
||||
lru_front(table, entry);
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_insert(struct lruhash* table, hashvalue_type hash,
|
||||
struct lruhash_entry* entry, void* data, void* cb_arg)
|
||||
{
|
||||
struct lruhash_bin* bin;
|
||||
struct lruhash_entry* found, *reclaimlist=NULL;
|
||||
size_t need_size;
|
||||
fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
|
||||
fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
|
||||
fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
|
||||
fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
|
||||
fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
|
||||
need_size = table->sizefunc(entry->key, data);
|
||||
if(cb_arg == NULL) cb_arg = table->cb_arg;
|
||||
|
||||
/* find bin */
|
||||
lock_quick_lock(&table->lock);
|
||||
bin = &table->array[hash & table->size_mask];
|
||||
lock_quick_lock(&bin->lock);
|
||||
|
||||
/* see if entry exists already */
|
||||
if(!(found=bin_find_entry(table, bin, hash, entry->key))) {
|
||||
/* if not: add to bin */
|
||||
entry->overflow_next = bin->overflow_list;
|
||||
bin->overflow_list = entry;
|
||||
lru_front(table, entry);
|
||||
table->num++;
|
||||
table->space_used += need_size;
|
||||
} else {
|
||||
/* if so: update data - needs a writelock */
|
||||
table->space_used += need_size -
|
||||
(*table->sizefunc)(found->key, found->data);
|
||||
(*table->delkeyfunc)(entry->key, cb_arg);
|
||||
lru_touch(table, found);
|
||||
lock_rw_wrlock(&found->lock);
|
||||
(*table->deldatafunc)(found->data, cb_arg);
|
||||
found->data = data;
|
||||
lock_rw_unlock(&found->lock);
|
||||
}
|
||||
lock_quick_unlock(&bin->lock);
|
||||
if(table->space_used > table->space_max)
|
||||
reclaim_space(table, &reclaimlist);
|
||||
if(table->num >= table->size)
|
||||
table_grow(table);
|
||||
lock_quick_unlock(&table->lock);
|
||||
|
||||
/* finish reclaim if any (outside of critical region) */
|
||||
while(reclaimlist) {
|
||||
struct lruhash_entry* n = reclaimlist->overflow_next;
|
||||
void* d = reclaimlist->data;
|
||||
(*table->delkeyfunc)(reclaimlist->key, cb_arg);
|
||||
(*table->deldatafunc)(d, cb_arg);
|
||||
reclaimlist = n;
|
||||
}
|
||||
}
|
||||
|
||||
struct lruhash_entry*
|
||||
lruhash_lookup(struct lruhash* table, hashvalue_type hash, void* key, int wr)
|
||||
{
|
||||
struct lruhash_entry* entry;
|
||||
struct lruhash_bin* bin;
|
||||
fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
|
||||
|
||||
lock_quick_lock(&table->lock);
|
||||
bin = &table->array[hash & table->size_mask];
|
||||
lock_quick_lock(&bin->lock);
|
||||
if((entry=bin_find_entry(table, bin, hash, key)))
|
||||
lru_touch(table, entry);
|
||||
lock_quick_unlock(&table->lock);
|
||||
|
||||
if(entry) {
|
||||
if(wr) { lock_rw_wrlock(&entry->lock); }
|
||||
else { lock_rw_rdlock(&entry->lock); }
|
||||
}
|
||||
lock_quick_unlock(&bin->lock);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key)
|
||||
{
|
||||
struct lruhash_entry* entry;
|
||||
struct lruhash_bin* bin;
|
||||
void *d;
|
||||
fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
|
||||
fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
|
||||
fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
|
||||
fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
|
||||
fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
|
||||
|
||||
lock_quick_lock(&table->lock);
|
||||
bin = &table->array[hash & table->size_mask];
|
||||
lock_quick_lock(&bin->lock);
|
||||
if((entry=bin_find_entry(table, bin, hash, key))) {
|
||||
bin_overflow_remove(bin, entry);
|
||||
lru_remove(table, entry);
|
||||
} else {
|
||||
lock_quick_unlock(&table->lock);
|
||||
lock_quick_unlock(&bin->lock);
|
||||
return;
|
||||
}
|
||||
table->num--;
|
||||
table->space_used -= (*table->sizefunc)(entry->key, entry->data);
|
||||
lock_quick_unlock(&table->lock);
|
||||
lock_rw_wrlock(&entry->lock);
|
||||
if(table->markdelfunc)
|
||||
(*table->markdelfunc)(entry->key);
|
||||
lock_rw_unlock(&entry->lock);
|
||||
lock_quick_unlock(&bin->lock);
|
||||
/* finish removal */
|
||||
d = entry->data;
|
||||
(*table->delkeyfunc)(entry->key, table->cb_arg);
|
||||
(*table->deldatafunc)(d, table->cb_arg);
|
||||
}
|
||||
|
||||
/** clear bin, respecting locks, does not do space, LRU */
|
||||
static void
|
||||
bin_clear(struct lruhash* table, struct lruhash_bin* bin)
|
||||
{
|
||||
struct lruhash_entry* p, *np;
|
||||
void *d;
|
||||
lock_quick_lock(&bin->lock);
|
||||
p = bin->overflow_list;
|
||||
while(p) {
|
||||
lock_rw_wrlock(&p->lock);
|
||||
np = p->overflow_next;
|
||||
d = p->data;
|
||||
if(table->markdelfunc)
|
||||
(*table->markdelfunc)(p->key);
|
||||
lock_rw_unlock(&p->lock);
|
||||
(*table->delkeyfunc)(p->key, table->cb_arg);
|
||||
(*table->deldatafunc)(d, table->cb_arg);
|
||||
p = np;
|
||||
}
|
||||
bin->overflow_list = NULL;
|
||||
lock_quick_unlock(&bin->lock);
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_clear(struct lruhash* table)
|
||||
{
|
||||
size_t i;
|
||||
if(!table)
|
||||
return;
|
||||
fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
|
||||
fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
|
||||
fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
|
||||
|
||||
lock_quick_lock(&table->lock);
|
||||
for(i=0; i<table->size; i++) {
|
||||
bin_clear(table, &table->array[i]);
|
||||
}
|
||||
table->lru_start = NULL;
|
||||
table->lru_end = NULL;
|
||||
table->num = 0;
|
||||
table->space_used = 0;
|
||||
lock_quick_unlock(&table->lock);
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_status(struct lruhash* table, const char* id, int extended)
|
||||
{
|
||||
lock_quick_lock(&table->lock);
|
||||
log_info("%s: %u entries, memory %u / %u",
|
||||
id, (unsigned)table->num, (unsigned)table->space_used,
|
||||
(unsigned)table->space_max);
|
||||
log_info(" itemsize %u, array %u, mask %d",
|
||||
(unsigned)(table->num? table->space_used/table->num : 0),
|
||||
(unsigned)table->size, table->size_mask);
|
||||
if(extended) {
|
||||
size_t i;
|
||||
int min=(int)table->size*2, max=-2;
|
||||
for(i=0; i<table->size; i++) {
|
||||
int here = 0;
|
||||
struct lruhash_entry *en;
|
||||
lock_quick_lock(&table->array[i].lock);
|
||||
en = table->array[i].overflow_list;
|
||||
while(en) {
|
||||
here ++;
|
||||
en = en->overflow_next;
|
||||
}
|
||||
lock_quick_unlock(&table->array[i].lock);
|
||||
if(extended >= 2)
|
||||
log_info("bin[%d] %d", (int)i, here);
|
||||
if(here > max) max = here;
|
||||
if(here < min) min = here;
|
||||
}
|
||||
log_info(" bin min %d, avg %.2lf, max %d", min,
|
||||
(double)table->num/(double)table->size, max);
|
||||
}
|
||||
lock_quick_unlock(&table->lock);
|
||||
}
|
||||
|
||||
size_t
|
||||
lruhash_get_mem(struct lruhash* table)
|
||||
{
|
||||
size_t s;
|
||||
lock_quick_lock(&table->lock);
|
||||
s = sizeof(struct lruhash) + table->space_used;
|
||||
#ifdef USE_THREAD_DEBUG
|
||||
if(table->size != 0) {
|
||||
size_t i;
|
||||
for(i=0; i<table->size; i++)
|
||||
s += sizeof(struct lruhash_bin) +
|
||||
lock_get_mem(&table->array[i].lock);
|
||||
}
|
||||
#else /* no THREAD_DEBUG */
|
||||
if(table->size != 0)
|
||||
s += (table->size)*(sizeof(struct lruhash_bin) +
|
||||
lock_get_mem(&table->array[0].lock));
|
||||
#endif
|
||||
lock_quick_unlock(&table->lock);
|
||||
s += lock_get_mem(&table->lock);
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md)
|
||||
{
|
||||
lock_quick_lock(&table->lock);
|
||||
table->markdelfunc = md;
|
||||
lock_quick_unlock(&table->lock);
|
||||
}
|
||||
|
||||
void
|
||||
lruhash_traverse(struct lruhash* h, int wr,
|
||||
void (*func)(struct lruhash_entry*, void*), void* arg)
|
||||
{
|
||||
size_t i;
|
||||
struct lruhash_entry* e;
|
||||
|
||||
lock_quick_lock(&h->lock);
|
||||
for(i=0; i<h->size; i++) {
|
||||
lock_quick_lock(&h->array[i].lock);
|
||||
for(e = h->array[i].overflow_list; e; e = e->overflow_next) {
|
||||
if(wr) {
|
||||
lock_rw_wrlock(&e->lock);
|
||||
} else {
|
||||
lock_rw_rdlock(&e->lock);
|
||||
}
|
||||
(*func)(e, arg);
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
lock_quick_unlock(&h->array[i].lock);
|
||||
}
|
||||
lock_quick_unlock(&h->lock);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
*
|
||||
* \file lruhash.h
|
||||
* /brief Alternative symbol names for unbound's lruhash.h
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2017, NLnet Labs, the getdns team
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef LRUHASH_H_SYMBOLS
|
||||
#define LRUHASH_H_SYMBOLS
|
||||
|
||||
#define lruhash _getdns_lruhash
|
||||
#define lruhash_bin _getdns_lruhash_bin
|
||||
#define lruhash_entry _getdns_lruhash_entry
|
||||
#define hashvalue_type _getdns_hashvalue_type
|
||||
#define lruhash_sizefunc_type _getdns_lruhash_sizefunc_type
|
||||
#define lruhash_compfunc_type _getdns_lruhash_compfunc_type
|
||||
#define lruhash_delkeyfunc_type _getdns_lruhash_delkeyfunc_type
|
||||
#define lruhash_deldatafunc_type _getdns_lruhash_deldatafunc_type
|
||||
#define lruhash_markdelfunc_type _getdns_lruhash_markdelfunc_type
|
||||
#define lruhash_create _getdns_lruhash_create
|
||||
#define lruhash_delete _getdns_lruhash_delete
|
||||
#define lruhash_clear _getdns_lruhash_clear
|
||||
#define lruhash_insert _getdns_lruhash_insert
|
||||
#define lruhash_lookup _getdns_lruhash_lookup
|
||||
#define lru_touch _getdns_lru_touch
|
||||
#define lruhash_setmarkdel _getdns_lruhash_setmarkdel
|
||||
|
||||
#define lruhash_remove _getdns_lruhash_remove
|
||||
#define bin_init _getdns_bin_init
|
||||
#define bin_delete _getdns_bin_delete
|
||||
#define bin_find_entry _getdns_bin_find_entry
|
||||
#define bin_overflow_remove _getdns_bin_overflow_remove
|
||||
#define bin_split _getdns_bin_split
|
||||
#define reclaim_space _getdns_reclaim_space
|
||||
#define table_grow _getdns_table_grow
|
||||
#define lru_front _getdns_lru_front
|
||||
#define lru_remove _getdns_lru_remove
|
||||
#define lruhash_status _getdns_lruhash_status
|
||||
#define lruhash_get_mem _getdns_lruhash_get_mem
|
||||
#define lruhash_traverse _getdns_lruhash_traverse
|
||||
|
||||
#include "util/orig-headers/lruhash.h"
|
||||
#endif
|
|
@ -0,0 +1,313 @@
|
|||
/**
|
||||
* util/locks.h - unbound locking primitives
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_LOCKS_H
|
||||
#define UTIL_LOCKS_H
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Locking primitives.
|
||||
* If pthreads is available, these are used.
|
||||
* If no locking exists, they do nothing.
|
||||
*
|
||||
* The idea is to have different sorts of locks for different tasks.
|
||||
* This allows the locking code to be ported more easily.
|
||||
*
|
||||
* Types of locks that are supported.
|
||||
* o lock_rw: lock that has many readers and one writer (to a data entry).
|
||||
* o lock_basic: simple mutex. Blocking, one person has access only.
|
||||
* This lock is meant for non performance sensitive uses.
|
||||
* o lock_quick: speed lock. For performance sensitive locking of critical
|
||||
* sections. Could be implemented by a mutex or a spinlock.
|
||||
*
|
||||
* Also thread creation and deletion functions are defined here.
|
||||
*/
|
||||
|
||||
/* if you define your own LOCKRET before including locks.h, you can get most
|
||||
* locking functions without the dependency on log_err. */
|
||||
#ifndef LOCKRET
|
||||
#include "util/log.h"
|
||||
/**
|
||||
* The following macro is used to check the return value of the
|
||||
* pthread calls. They return 0 on success and an errno on error.
|
||||
* The errno is logged to the logfile with a descriptive comment.
|
||||
*/
|
||||
#define LOCKRET(func) do {\
|
||||
int lockret_err; \
|
||||
if( (lockret_err=(func)) != 0) \
|
||||
log_err("%s at %d could not " #func ": %s", \
|
||||
__FILE__, __LINE__, strerror(lockret_err)); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/** DEBUG: use thread debug whenever possible */
|
||||
#if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
|
||||
# define USE_THREAD_DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef USE_THREAD_DEBUG
|
||||
/******************* THREAD DEBUG ************************/
|
||||
/* (some) checking; to detect races and deadlocks. */
|
||||
#include "testcode/checklocks.h"
|
||||
|
||||
#else /* USE_THREAD_DEBUG */
|
||||
#define lock_protect(lock, area, size) /* nop */
|
||||
#define lock_unprotect(lock, area) /* nop */
|
||||
#define lock_get_mem(lock) (0) /* nothing */
|
||||
#define checklock_start() /* nop */
|
||||
#define checklock_stop() /* nop */
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h>
|
||||
|
||||
/******************* PTHREAD ************************/
|
||||
|
||||
/** use pthread mutex for basic lock */
|
||||
typedef pthread_mutex_t lock_basic_type;
|
||||
/** small front for pthread init func, NULL is default attrs. */
|
||||
#define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
|
||||
#define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
|
||||
#define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
|
||||
#define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
|
||||
|
||||
#ifndef HAVE_PTHREAD_RWLOCK_T
|
||||
/** in case rwlocks are not supported, use a mutex. */
|
||||
typedef pthread_mutex_t lock_rw_type;
|
||||
#define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
|
||||
#define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
|
||||
#define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
|
||||
#define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
|
||||
#define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
|
||||
#else /* HAVE_PTHREAD_RWLOCK_T */
|
||||
/** we use the pthread rwlock */
|
||||
typedef pthread_rwlock_t lock_rw_type;
|
||||
/** small front for pthread init func, NULL is default attrs. */
|
||||
#define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
|
||||
#define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
|
||||
#define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
|
||||
#define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
|
||||
#define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
|
||||
#endif /* HAVE_PTHREAD_RWLOCK_T */
|
||||
|
||||
#ifndef HAVE_PTHREAD_SPINLOCK_T
|
||||
/** in case spinlocks are not supported, use a mutex. */
|
||||
typedef pthread_mutex_t lock_quick_type;
|
||||
/** small front for pthread init func, NULL is default attrs. */
|
||||
#define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
|
||||
#define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
|
||||
#define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
|
||||
#define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
|
||||
|
||||
#else /* HAVE_PTHREAD_SPINLOCK_T */
|
||||
/** use pthread spinlock for the quick lock */
|
||||
typedef pthread_spinlock_t lock_quick_type;
|
||||
/**
|
||||
* allocate process private since this is available whether
|
||||
* Thread Process-Shared Synchronization is supported or not.
|
||||
* This means only threads inside this process may access the lock.
|
||||
* (not threads from another process that shares memory).
|
||||
* spinlocks are not supported on all pthread platforms.
|
||||
*/
|
||||
#define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
|
||||
#define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
|
||||
#define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
|
||||
#define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
|
||||
|
||||
#endif /* HAVE SPINLOCK */
|
||||
|
||||
/** Thread creation */
|
||||
typedef pthread_t ub_thread_type;
|
||||
/** On alpine linux default thread stack size is 80 Kb. See
|
||||
http://wiki.musl-libc.org/wiki/Functional_differences_from_glibc#Thread_stack_size
|
||||
This is not enough and cause segfault. Other linux distros have 2 Mb at least.
|
||||
Wrapper for set up thread stack size */
|
||||
#define PTHREADSTACKSIZE 2*1024*1024
|
||||
#define PTHREADCREATE(thr, stackrequired, func, arg) do {\
|
||||
pthread_attr_t attr; \
|
||||
size_t stacksize; \
|
||||
LOCKRET(pthread_attr_init(&attr)); \
|
||||
LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \
|
||||
if (stacksize < stackrequired) { \
|
||||
LOCKRET(pthread_attr_setstacksize(&attr, stackrequired)); \
|
||||
LOCKRET(pthread_create(thr, &attr, func, arg)); \
|
||||
LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \
|
||||
verbose(VERB_ALGO, "Thread stack size set to %u", (unsigned)stacksize); \
|
||||
} else {LOCKRET(pthread_create(thr, NULL, func, arg));} \
|
||||
} while(0)
|
||||
/** Use wrapper for set thread stack size on attributes. */
|
||||
#define ub_thread_create(thr, func, arg) PTHREADCREATE(thr, PTHREADSTACKSIZE, func, arg)
|
||||
/** get self id. */
|
||||
#define ub_thread_self() pthread_self()
|
||||
/** wait for another thread to terminate */
|
||||
#define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
|
||||
typedef pthread_key_t ub_thread_key_type;
|
||||
#define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
|
||||
#define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
|
||||
#define ub_thread_key_get(key) pthread_getspecific(key)
|
||||
|
||||
#else /* we do not HAVE_PTHREAD */
|
||||
#ifdef HAVE_SOLARIS_THREADS
|
||||
|
||||
/******************* SOLARIS THREADS ************************/
|
||||
#include <synch.h>
|
||||
#include <thread.h>
|
||||
|
||||
typedef rwlock_t lock_rw_type;
|
||||
#define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
|
||||
#define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
|
||||
#define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
|
||||
#define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
|
||||
#define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
|
||||
|
||||
/** use basic mutex */
|
||||
typedef mutex_t lock_basic_type;
|
||||
#define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
|
||||
#define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
|
||||
#define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
|
||||
#define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
|
||||
|
||||
/** No spinlocks in solaris threads API. Use a mutex. */
|
||||
typedef mutex_t lock_quick_type;
|
||||
#define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
|
||||
#define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
|
||||
#define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
|
||||
#define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
|
||||
|
||||
/** Thread creation, create a default thread. */
|
||||
typedef thread_t ub_thread_type;
|
||||
#define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
|
||||
#define ub_thread_self() thr_self()
|
||||
#define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
|
||||
typedef thread_key_t ub_thread_key_type;
|
||||
#define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
|
||||
#define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
|
||||
void* ub_thread_key_get(ub_thread_key_type key);
|
||||
|
||||
|
||||
#else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
|
||||
/******************* WINDOWS THREADS ************************/
|
||||
#ifdef HAVE_WINDOWS_THREADS
|
||||
#include <windows.h>
|
||||
|
||||
/* Use a mutex */
|
||||
typedef LONG lock_rw_type;
|
||||
#define lock_rw_init(lock) lock_basic_init(lock)
|
||||
#define lock_rw_destroy(lock) lock_basic_destroy(lock)
|
||||
#define lock_rw_rdlock(lock) lock_basic_lock(lock)
|
||||
#define lock_rw_wrlock(lock) lock_basic_lock(lock)
|
||||
#define lock_rw_unlock(lock) lock_basic_unlock(lock)
|
||||
|
||||
/** the basic lock is a mutex, implemented opaquely, for error handling. */
|
||||
typedef LONG lock_basic_type;
|
||||
void lock_basic_init(lock_basic_type* lock);
|
||||
void lock_basic_destroy(lock_basic_type* lock);
|
||||
void lock_basic_lock(lock_basic_type* lock);
|
||||
void lock_basic_unlock(lock_basic_type* lock);
|
||||
|
||||
/** on windows no spinlock, use mutex too. */
|
||||
typedef LONG lock_quick_type;
|
||||
#define lock_quick_init(lock) lock_basic_init(lock)
|
||||
#define lock_quick_destroy(lock) lock_basic_destroy(lock)
|
||||
#define lock_quick_lock(lock) lock_basic_lock(lock)
|
||||
#define lock_quick_unlock(lock) lock_basic_unlock(lock)
|
||||
|
||||
/** Thread creation, create a default thread. */
|
||||
typedef HANDLE ub_thread_type;
|
||||
void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
|
||||
ub_thread_type ub_thread_self(void);
|
||||
void ub_thread_join(ub_thread_type thr);
|
||||
typedef DWORD ub_thread_key_type;
|
||||
void ub_thread_key_create(ub_thread_key_type* key, void* f);
|
||||
void ub_thread_key_set(ub_thread_key_type key, void* v);
|
||||
void* ub_thread_key_get(ub_thread_key_type key);
|
||||
|
||||
#else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
|
||||
|
||||
/******************* NO THREADS ************************/
|
||||
#define THREADS_DISABLED 1
|
||||
/** In case there is no thread support, define locks to do nothing */
|
||||
typedef int lock_rw_type;
|
||||
#define lock_rw_init(lock) /* nop */
|
||||
#define lock_rw_destroy(lock) /* nop */
|
||||
#define lock_rw_rdlock(lock) /* nop */
|
||||
#define lock_rw_wrlock(lock) /* nop */
|
||||
#define lock_rw_unlock(lock) /* nop */
|
||||
|
||||
/** define locks to do nothing */
|
||||
typedef int lock_basic_type;
|
||||
#define lock_basic_init(lock) /* nop */
|
||||
#define lock_basic_destroy(lock) /* nop */
|
||||
#define lock_basic_lock(lock) /* nop */
|
||||
#define lock_basic_unlock(lock) /* nop */
|
||||
|
||||
/** define locks to do nothing */
|
||||
typedef int lock_quick_type;
|
||||
#define lock_quick_init(lock) /* nop */
|
||||
#define lock_quick_destroy(lock) /* nop */
|
||||
#define lock_quick_lock(lock) /* nop */
|
||||
#define lock_quick_unlock(lock) /* nop */
|
||||
|
||||
/** Thread creation, threads do not exist */
|
||||
typedef pid_t ub_thread_type;
|
||||
/** ub_thread_create is simulated with fork (extremely heavy threads,
|
||||
* with no shared memory). */
|
||||
#define ub_thread_create(thr, func, arg) \
|
||||
ub_thr_fork_create(thr, func, arg)
|
||||
#define ub_thread_self() getpid()
|
||||
#define ub_thread_join(thread) ub_thr_fork_wait(thread)
|
||||
void ub_thr_fork_wait(ub_thread_type thread);
|
||||
void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
|
||||
typedef void* ub_thread_key_type;
|
||||
#define ub_thread_key_create(key, f) (*(key)) = NULL
|
||||
#define ub_thread_key_set(key, v) (key) = (v)
|
||||
#define ub_thread_key_get(key) (key)
|
||||
|
||||
#endif /* HAVE_WINDOWS_THREADS */
|
||||
#endif /* HAVE_SOLARIS_THREADS */
|
||||
#endif /* HAVE_PTHREAD */
|
||||
#endif /* USE_THREAD_DEBUG */
|
||||
|
||||
/**
|
||||
* Block all signals for this thread.
|
||||
* fatal exit on error.
|
||||
*/
|
||||
void ub_thread_blocksigs(void);
|
||||
|
||||
/**
|
||||
* unblock one signal for this thread.
|
||||
*/
|
||||
void ub_thread_sig_unblock(int sig);
|
||||
|
||||
#endif /* UTIL_LOCKS_H */
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* util/storage/lookup3.h - header file for hashing functions.
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains header definitions for the hash functions we use.
|
||||
* The hash functions are public domain (see lookup3.c).
|
||||
*/
|
||||
|
||||
#ifndef UTIL_STORAGE_LOOKUP3_H
|
||||
#define UTIL_STORAGE_LOOKUP3_H
|
||||
|
||||
/**
|
||||
* Hash key made of 4byte chunks.
|
||||
* @param k: the key, an array of uint32_t values
|
||||
* @param length: the length of the key, in uint32_ts
|
||||
* @param initval: the previous hash, or an arbitrary value
|
||||
* @return: hash value.
|
||||
*/
|
||||
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval);
|
||||
|
||||
/**
|
||||
* Hash key data.
|
||||
* @param k: the key, array of uint8_t
|
||||
* @param length: the length of the key, in uint8_ts
|
||||
* @param initval: the previous hash, or an arbitrary value
|
||||
* @return: hash value.
|
||||
*/
|
||||
uint32_t hashlittle(const void *k, size_t length, uint32_t initval);
|
||||
|
||||
/**
|
||||
* Set the randomisation initial value, set this before threads start,
|
||||
* and before hashing stuff (because it changes subsequent results).
|
||||
* @param v: value
|
||||
*/
|
||||
void hash_set_raninit(uint32_t v);
|
||||
|
||||
#endif /* UTIL_STORAGE_LOOKUP3_H */
|
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* util/storage/lruhash.h - hashtable, hash function, LRU keeping.
|
||||
*
|
||||
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the NLNET LABS nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains a hashtable with LRU keeping of entries.
|
||||
*
|
||||
* The hash table keeps a maximum memory size. Old entries are removed
|
||||
* to make space for new entries.
|
||||
*
|
||||
* The locking strategy is as follows:
|
||||
* o since (almost) every read also implies a LRU update, the
|
||||
* hashtable lock is a spinlock, not rwlock.
|
||||
* o the idea is to move every thread through the hash lock quickly,
|
||||
* so that the next thread can access the lookup table.
|
||||
* o User performs hash function.
|
||||
*
|
||||
* For read:
|
||||
* o lock hashtable.
|
||||
* o lookup hash bin.
|
||||
* o lock hash bin.
|
||||
* o find entry (if failed, unlock hash, unl bin, exit).
|
||||
* o swizzle pointers for LRU update.
|
||||
* o unlock hashtable.
|
||||
* o lock entry (rwlock).
|
||||
* o unlock hash bin.
|
||||
* o work on entry.
|
||||
* o unlock entry.
|
||||
*
|
||||
* To update an entry, gain writelock and change the entry.
|
||||
* (the entry must keep the same hashvalue, so a data update.)
|
||||
* (you cannot upgrade a readlock to a writelock, because the item may
|
||||
* be deleted, it would cause race conditions. So instead, unlock and
|
||||
* relookup it in the hashtable.)
|
||||
*
|
||||
* To delete an entry:
|
||||
* o unlock the entry if you hold the lock already.
|
||||
* o lock hashtable.
|
||||
* o lookup hash bin.
|
||||
* o lock hash bin.
|
||||
* o find entry (if failed, unlock hash, unl bin, exit).
|
||||
* o remove entry from hashtable bin overflow chain.
|
||||
* o unlock hashtable.
|
||||
* o lock entry (writelock).
|
||||
* o unlock hash bin.
|
||||
* o unlock entry (nobody else should be waiting for this lock,
|
||||
* since you removed it from hashtable, and you got writelock while
|
||||
* holding the hashbinlock so you are the only one.)
|
||||
* Note you are only allowed to obtain a lock while holding hashbinlock.
|
||||
* o delete entry.
|
||||
*
|
||||
* The above sequence is:
|
||||
* o race free, works with read, write and delete.
|
||||
* o but has a queue, imagine someone needing a writelock on an item.
|
||||
* but there are still readlocks. The writelocker waits, but holds
|
||||
* the hashbinlock. The next thread that comes in and needs the same
|
||||
* hashbin will wait for the lock while holding the hashtable lock.
|
||||
* thus halting the entire system on hashtable.
|
||||
* This is because of the delete protection.
|
||||
* Readlocks will be easier on the rwlock on entries.
|
||||
* While the writer is holding writelock, similar problems happen with
|
||||
* a reader or writer needing the same item.
|
||||
* the scenario requires more than three threads.
|
||||
* o so the queue length is 3 threads in a bad situation. The fourth is
|
||||
* unable to use the hashtable.
|
||||
*
|
||||
* If you need to acquire locks on multiple items from the hashtable.
|
||||
* o you MUST release all locks on items from the hashtable before
|
||||
* doing the next lookup/insert/delete/whatever.
|
||||
* o To acquire multiple items you should use a special routine that
|
||||
* obtains the locks on those multiple items in one go.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_STORAGE_LRUHASH_H
|
||||
#define UTIL_STORAGE_LRUHASH_H
|
||||
#include "util/locks.h"
|
||||
struct lruhash_bin;
|
||||
struct lruhash_entry;
|
||||
|
||||
/** default start size for hash arrays */
|
||||
#define HASH_DEFAULT_STARTARRAY 1024 /* entries in array */
|
||||
/** default max memory for hash arrays */
|
||||
#define HASH_DEFAULT_MAXMEM 4*1024*1024 /* bytes */
|
||||
|
||||
/** the type of a hash value */
|
||||
typedef uint32_t hashvalue_type;
|
||||
|
||||
/**
|
||||
* Type of function that calculates the size of an entry.
|
||||
* Result must include the size of struct lruhash_entry.
|
||||
* Keys that are identical must also calculate to the same size.
|
||||
* size = func(key, data).
|
||||
*/
|
||||
typedef size_t (*lruhash_sizefunc_type)(void*, void*);
|
||||
|
||||
/** type of function that compares two keys. return 0 if equal. */
|
||||
typedef int (*lruhash_compfunc_type)(void*, void*);
|
||||
|
||||
/** old keys are deleted.
|
||||
* The RRset type has to revoke its ID number, markdel() is used first.
|
||||
* This function is called: func(key, userarg) */
|
||||
typedef void (*lruhash_delkeyfunc_type)(void*, void*);
|
||||
|
||||
/** old data is deleted. This function is called: func(data, userarg). */
|
||||
typedef void (*lruhash_deldatafunc_type)(void*, void*);
|
||||
|
||||
/** mark a key as pending to be deleted (and not to be used by anyone).
|
||||
* called: func(key) */
|
||||
typedef void (*lruhash_markdelfunc_type)(void*);
|
||||
|
||||
/**
|
||||
* Hash table that keeps LRU list of entries.
|
||||
*/
|
||||
struct lruhash {
|
||||
/** lock for exclusive access, to the lookup array */
|
||||
lock_quick_type lock;
|
||||
/** the size function for entries in this table */
|
||||
lruhash_sizefunc_type sizefunc;
|
||||
/** the compare function for entries in this table. */
|
||||
lruhash_compfunc_type compfunc;
|
||||
/** how to delete keys. */
|
||||
lruhash_delkeyfunc_type delkeyfunc;
|
||||
/** how to delete data. */
|
||||
lruhash_deldatafunc_type deldatafunc;
|
||||
/** how to mark a key pending deletion */
|
||||
lruhash_markdelfunc_type markdelfunc;
|
||||
/** user argument for user functions */
|
||||
void* cb_arg;
|
||||
|
||||
/** the size of the lookup array */
|
||||
size_t size;
|
||||
/** size bitmask - since size is a power of 2 */
|
||||
int size_mask;
|
||||
/** lookup array of bins */
|
||||
struct lruhash_bin* array;
|
||||
|
||||
/** the lru list, start and end, noncyclical double linked list. */
|
||||
struct lruhash_entry* lru_start;
|
||||
/** lru list end item (least recently used) */
|
||||
struct lruhash_entry* lru_end;
|
||||
|
||||
/** the number of entries in the hash table. */
|
||||
size_t num;
|
||||
/** the amount of space used, roughly the number of bytes in use. */
|
||||
size_t space_used;
|
||||
/** the amount of space the hash table is maximally allowed to use. */
|
||||
size_t space_max;
|
||||
};
|
||||
|
||||
/**
|
||||
* A single bin with a linked list of entries in it.
|
||||
*/
|
||||
struct lruhash_bin {
|
||||
/**
|
||||
* Lock for exclusive access to the linked list
|
||||
* This lock makes deletion of items safe in this overflow list.
|
||||
*/
|
||||
lock_quick_type lock;
|
||||
/** linked list of overflow entries */
|
||||
struct lruhash_entry* overflow_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* An entry into the hash table.
|
||||
* To change overflow_next you need to hold the bin lock.
|
||||
* To change the lru items you need to hold the hashtable lock.
|
||||
* This structure is designed as part of key struct. And key pointer helps
|
||||
* to get the surrounding structure. Data should be allocated on its own.
|
||||
*/
|
||||
struct lruhash_entry {
|
||||
/**
|
||||
* rwlock for access to the contents of the entry
|
||||
* Note that it does _not_ cover the lru_ and overflow_ ptrs.
|
||||
* Even with a writelock, you cannot change hash and key.
|
||||
* You need to delete it to change hash or key.
|
||||
*/
|
||||
lock_rw_type lock;
|
||||
/** next entry in overflow chain. Covered by hashlock and binlock. */
|
||||
struct lruhash_entry* overflow_next;
|
||||
/** next entry in lru chain. covered by hashlock. */
|
||||
struct lruhash_entry* lru_next;
|
||||
/** prev entry in lru chain. covered by hashlock. */
|
||||
struct lruhash_entry* lru_prev;
|
||||
/** hash value of the key. It may not change, until entry deleted. */
|
||||
hashvalue_type hash;
|
||||
/** key */
|
||||
void* key;
|
||||
/** data */
|
||||
void* data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create new hash table.
|
||||
* @param start_size: size of hashtable array at start, must be power of 2.
|
||||
* @param maxmem: maximum amount of memory this table is allowed to use.
|
||||
* @param sizefunc: calculates memory usage of entries.
|
||||
* @param compfunc: compares entries, 0 on equality.
|
||||
* @param delkeyfunc: deletes key.
|
||||
* Calling both delkey and deldata will also free the struct lruhash_entry.
|
||||
* Make it part of the key structure and delete it in delkeyfunc.
|
||||
* @param deldatafunc: deletes data.
|
||||
* @param arg: user argument that is passed to user function calls.
|
||||
* @return: new hash table or NULL on malloc failure.
|
||||
*/
|
||||
struct lruhash* lruhash_create(size_t start_size, size_t maxmem,
|
||||
lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc,
|
||||
lruhash_delkeyfunc_type delkeyfunc,
|
||||
lruhash_deldatafunc_type deldatafunc, void* arg);
|
||||
|
||||
/**
|
||||
* Delete hash table. Entries are all deleted.
|
||||
* @param table: to delete.
|
||||
*/
|
||||
void lruhash_delete(struct lruhash* table);
|
||||
|
||||
/**
|
||||
* Clear hash table. Entries are all deleted, while locking them before
|
||||
* doing so. At end the table is empty.
|
||||
* @param table: to make empty.
|
||||
*/
|
||||
void lruhash_clear(struct lruhash* table);
|
||||
|
||||
/**
|
||||
* Insert a new element into the hashtable.
|
||||
* If key is already present data pointer in that entry is updated.
|
||||
* The space calculation function is called with the key, data.
|
||||
* If necessary the least recently used entries are deleted to make space.
|
||||
* If necessary the hash array is grown up.
|
||||
*
|
||||
* @param table: hash table.
|
||||
* @param hash: hash value. User calculates the hash.
|
||||
* @param entry: identifies the entry.
|
||||
* If key already present, this entry->key is deleted immediately.
|
||||
* But entry->data is set to NULL before deletion, and put into
|
||||
* the existing entry. The data is then freed.
|
||||
* @param data: the data.
|
||||
* @param cb_override: if not null overrides the cb_arg for the deletefunc.
|
||||
*/
|
||||
void lruhash_insert(struct lruhash* table, hashvalue_type hash,
|
||||
struct lruhash_entry* entry, void* data, void* cb_override);
|
||||
|
||||
/**
|
||||
* Lookup an entry in the hashtable.
|
||||
* At the end of the function you hold a (read/write)lock on the entry.
|
||||
* The LRU is updated for the entry (if found).
|
||||
* @param table: hash table.
|
||||
* @param hash: hash of key.
|
||||
* @param key: what to look for, compared against entries in overflow chain.
|
||||
* the hash value must be set, and must work with compare function.
|
||||
* @param wr: set to true if you desire a writelock on the entry.
|
||||
* with a writelock you can update the data part.
|
||||
* @return: pointer to the entry or NULL. The entry is locked.
|
||||
* The user must unlock the entry when done.
|
||||
*/
|
||||
struct lruhash_entry* lruhash_lookup(struct lruhash* table,
|
||||
hashvalue_type hash, void* key, int wr);
|
||||
|
||||
/**
|
||||
* Touch entry, so it becomes the most recently used in the LRU list.
|
||||
* Caller must hold hash table lock. The entry must be inserted already.
|
||||
* @param table: hash table.
|
||||
* @param entry: entry to make first in LRU.
|
||||
*/
|
||||
void lru_touch(struct lruhash* table, struct lruhash_entry* entry);
|
||||
|
||||
/**
|
||||
* Set the markdelfunction (or NULL)
|
||||
*/
|
||||
void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md);
|
||||
|
||||
/************************* Internal functions ************************/
|
||||
/*** these are only exposed for unit tests. ***/
|
||||
|
||||
/**
|
||||
* Remove entry from hashtable. Does nothing if not found in hashtable.
|
||||
* Delfunc is called for the entry.
|
||||
* @param table: hash table.
|
||||
* @param hash: hash of key.
|
||||
* @param key: what to look for.
|
||||
*/
|
||||
void lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key);
|
||||
|
||||
/** init the hash bins for the table */
|
||||
void bin_init(struct lruhash_bin* array, size_t size);
|
||||
|
||||
/** delete the hash bin and entries inside it */
|
||||
void bin_delete(struct lruhash* table, struct lruhash_bin* bin);
|
||||
|
||||
/**
|
||||
* Find entry in hash bin. You must have locked the bin.
|
||||
* @param table: hash table with function pointers.
|
||||
* @param bin: hash bin to look into.
|
||||
* @param hash: hash value to look for.
|
||||
* @param key: key to look for.
|
||||
* @return: the entry or NULL if not found.
|
||||
*/
|
||||
struct lruhash_entry* bin_find_entry(struct lruhash* table,
|
||||
struct lruhash_bin* bin, hashvalue_type hash, void* key);
|
||||
|
||||
/**
|
||||
* Remove entry from bin overflow chain.
|
||||
* You must have locked the bin.
|
||||
* @param bin: hash bin to look into.
|
||||
* @param entry: entry ptr that needs removal.
|
||||
*/
|
||||
void bin_overflow_remove(struct lruhash_bin* bin,
|
||||
struct lruhash_entry* entry);
|
||||
|
||||
/**
|
||||
* Split hash bin into two new ones. Based on increased size_mask.
|
||||
* Caller must hold hash table lock.
|
||||
* At the end the routine acquires all hashbin locks (in the old array).
|
||||
* This makes it wait for other threads to finish with the bins.
|
||||
* So the bins are ready to be deleted after this function.
|
||||
* @param table: hash table with function pointers.
|
||||
* @param newa: new increased array.
|
||||
* @param newmask: new lookup mask.
|
||||
*/
|
||||
void bin_split(struct lruhash* table, struct lruhash_bin* newa,
|
||||
int newmask);
|
||||
|
||||
/**
|
||||
* Try to make space available by deleting old entries.
|
||||
* Assumes that the lock on the hashtable is being held by caller.
|
||||
* Caller must not hold bin locks.
|
||||
* @param table: hash table.
|
||||
* @param list: list of entries that are to be deleted later.
|
||||
* Entries have been removed from the hash table and writelock is held.
|
||||
*/
|
||||
void reclaim_space(struct lruhash* table, struct lruhash_entry** list);
|
||||
|
||||
/**
|
||||
* Grow the table lookup array. Becomes twice as large.
|
||||
* Caller must hold the hash table lock. Must not hold any bin locks.
|
||||
* Tries to grow, on malloc failure, nothing happened.
|
||||
* @param table: hash table.
|
||||
*/
|
||||
void table_grow(struct lruhash* table);
|
||||
|
||||
/**
|
||||
* Put entry at front of lru. entry must be unlinked from lru.
|
||||
* Caller must hold hash table lock.
|
||||
* @param table: hash table with lru head and tail.
|
||||
* @param entry: entry to make most recently used.
|
||||
*/
|
||||
void lru_front(struct lruhash* table, struct lruhash_entry* entry);
|
||||
|
||||
/**
|
||||
* Remove entry from lru list.
|
||||
* Caller must hold hash table lock.
|
||||
* @param table: hash table with lru head and tail.
|
||||
* @param entry: entry to remove from lru.
|
||||
*/
|
||||
void lru_remove(struct lruhash* table, struct lruhash_entry* entry);
|
||||
|
||||
/**
|
||||
* Output debug info to the log as to state of the hash table.
|
||||
* @param table: hash table.
|
||||
* @param id: string printed with table to identify the hash table.
|
||||
* @param extended: set to true to print statistics on overflow bin lengths.
|
||||
*/
|
||||
void lruhash_status(struct lruhash* table, const char* id, int extended);
|
||||
|
||||
/**
|
||||
* Get memory in use now by the lruhash table.
|
||||
* @param table: hash table. Will be locked before use. And unlocked after.
|
||||
* @return size in bytes.
|
||||
*/
|
||||
size_t lruhash_get_mem(struct lruhash* table);
|
||||
|
||||
/**
|
||||
* Traverse a lruhash. Call back for every element in the table.
|
||||
* @param h: hash table. Locked before use.
|
||||
* @param wr: if true writelock is obtained on element, otherwise readlock.
|
||||
* @param func: function for every element. Do not lock or unlock elements.
|
||||
* @param arg: user argument to func.
|
||||
*/
|
||||
void lruhash_traverse(struct lruhash* h, int wr,
|
||||
void (*func)(struct lruhash_entry*, void*), void* arg);
|
||||
|
||||
#endif /* UTIL_STORAGE_LRUHASH_H */
|
Loading…
Reference in New Issue