mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-18 10:35:55 +00:00
06a99fe36f
databases. - Make nsswitch support caching. Submitted by: Michael Bushkov <bushman__at__rsu.ru> Sponsored by: Google Summer of Code 2005
282 lines
8.2 KiB
C
282 lines
8.2 KiB
C
/*-
|
|
* Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#ifndef __CACHED_CACHELIB_H__
|
|
#define __CACHED_CACHELIB_H__
|
|
|
|
#include <sys/queue.h>
|
|
#include <sys/time.h>
|
|
#include <stdlib.h>
|
|
#include "hashtable.h"
|
|
#include "cacheplcs.h"
|
|
|
|
enum cache_entry_t {
|
|
CET_COMMON = 0, /* cache item is atomic */
|
|
CET_MULTIPART /* cache item is formed part by part */
|
|
};
|
|
|
|
enum cache_transformation_t {
|
|
CTT_FLUSH = 0, /* flush the cache - delete all obsolete items */
|
|
CTT_CLEAR = 1 /* delete all items in the cache */
|
|
};
|
|
|
|
/* cache deletion policy type enum */
|
|
enum cache_policy_t {
|
|
CPT_FIFO = 0, /* first-in first-out */
|
|
CPT_LRU = 1, /* least recently used */
|
|
CPT_LFU = 2 /* least frequently used */
|
|
};
|
|
|
|
/* multipart sessions can be used for reading and writing */
|
|
enum cache_mp_session_t {
|
|
CMPT_READ_SESSION,
|
|
CMPT_WRITE_SESSION
|
|
};
|
|
|
|
/*
|
|
* When doing partial transformations of entries (which are applied for
|
|
* elements with keys, that contain specified buffer in its left or
|
|
* right part), this enum will show the needed position of the key part.
|
|
*/
|
|
enum part_position_t {
|
|
KPPT_LEFT,
|
|
KPPT_RIGHT
|
|
};
|
|
|
|
/* num_levels attribute is obsolete, i think - user can always emulate it
|
|
* by using one entry.
|
|
* get_time_func is needed to have the clocks-independent counter
|
|
*/
|
|
struct cache_params
|
|
{
|
|
void (*get_time_func)(struct timeval *);
|
|
};
|
|
|
|
/*
|
|
* base structure - normal_cache_entry_params and multipart_cache_entry_params
|
|
* are "inherited" from it
|
|
*/
|
|
struct cache_entry_params
|
|
{
|
|
enum cache_entry_t entry_type;
|
|
char *entry_name;
|
|
};
|
|
|
|
/* params, used for most entries */
|
|
struct common_cache_entry_params
|
|
{
|
|
/* inherited fields */
|
|
enum cache_entry_t entry_type;
|
|
|
|
/* unique fields */
|
|
char *entry_name;
|
|
size_t cache_entries_size;
|
|
|
|
size_t max_elemsize; /* if 0 then no check is made */
|
|
size_t satisf_elemsize; /* if entry size is exceeded,
|
|
* this number of elements will be left,
|
|
* others will be deleted */
|
|
struct timeval max_lifetime; /* if 0 then no check is made */
|
|
enum cache_policy_t policy; /* policy used for transformations */
|
|
};
|
|
|
|
/* params, used for multipart entries */
|
|
struct mp_cache_entry_params
|
|
{
|
|
/* inherited fields */
|
|
enum cache_entry_t entry_type;
|
|
char *entry_name;
|
|
|
|
/* unique fields */
|
|
size_t max_elemsize; /* if 0 then no check is made */
|
|
size_t max_sessions; /* maximum number of active sessions */
|
|
|
|
struct timeval max_lifetime; /* maximum elements lifetime */
|
|
};
|
|
|
|
struct cache_ht_item_data_
|
|
{
|
|
/* key is the bytes sequence only - not the null-terminated string */
|
|
char *key;
|
|
size_t key_size;
|
|
|
|
char *value;
|
|
size_t value_size;
|
|
|
|
struct cache_policy_item_ *fifo_policy_item;
|
|
};
|
|
|
|
struct cache_ht_item_
|
|
{
|
|
HASHTABLE_ENTRY_HEAD(ht_item_, struct cache_ht_item_data_) data;
|
|
};
|
|
|
|
struct cache_entry_
|
|
{
|
|
char *name;
|
|
struct cache_entry_params *params;
|
|
};
|
|
|
|
struct cache_common_entry_
|
|
{
|
|
char *name;
|
|
struct cache_entry_params *params;
|
|
|
|
struct common_cache_entry_params common_params;
|
|
|
|
HASHTABLE_HEAD(cache_ht_, cache_ht_item_) items;
|
|
size_t items_size;
|
|
|
|
/*
|
|
* Entry always has the FIFO policy, that is used to eliminate old
|
|
* elements (the ones, with lifetime more than max_lifetime). Besides,
|
|
* user can specify another policy to be applied, when there are too
|
|
* many elements in the entry. So policies_size can be 1 or 2.
|
|
*/
|
|
struct cache_policy_ **policies;
|
|
size_t policies_size;
|
|
|
|
void (*get_time_func)(struct timeval *);
|
|
};
|
|
|
|
struct cache_mp_data_item_ {
|
|
char *value;
|
|
size_t value_size;
|
|
|
|
TAILQ_ENTRY(cache_mp_data_item_) entries;
|
|
};
|
|
|
|
struct cache_mp_write_session_
|
|
{
|
|
struct cache_mp_entry_ *parent_entry;
|
|
|
|
/*
|
|
* All items are accumulated in this queue. When the session is
|
|
* committed, they all will be copied to the multipart entry.
|
|
*/
|
|
TAILQ_HEAD(cache_mp_data_item_head, cache_mp_data_item_) items;
|
|
size_t items_size;
|
|
|
|
TAILQ_ENTRY(cache_mp_write_session_) entries;
|
|
};
|
|
|
|
struct cache_mp_read_session_
|
|
{
|
|
struct cache_mp_entry_ *parent_entry;
|
|
struct cache_mp_data_item_ *current_item;
|
|
|
|
TAILQ_ENTRY(cache_mp_read_session_) entries;
|
|
};
|
|
|
|
struct cache_mp_entry_
|
|
{
|
|
char *name;
|
|
struct cache_entry_params *params;
|
|
|
|
struct mp_cache_entry_params mp_params;
|
|
|
|
/* All opened write sessions */
|
|
TAILQ_HEAD(write_sessions_head, cache_mp_write_session_) ws_head;
|
|
size_t ws_size;
|
|
|
|
/* All opened read sessions */
|
|
TAILQ_HEAD(read_sessions_head, cache_mp_read_session_) rs_head;
|
|
size_t rs_size;
|
|
|
|
/*
|
|
* completed_write_session is the committed write sessions. All read
|
|
* sessions use data from it. If the completed_write_session is out of
|
|
* date, but still in use by some of the read sessions, the newly
|
|
* committed write session is stored in the pending_write_session.
|
|
* In such a case, completed_write_session will be substituted with
|
|
* pending_write_session as soon as it won't be used by any of
|
|
* the read sessions.
|
|
*/
|
|
struct cache_mp_write_session_ *completed_write_session;
|
|
struct cache_mp_write_session_ *pending_write_session;
|
|
struct timeval creation_time;
|
|
struct timeval last_request_time;
|
|
|
|
void (*get_time_func)(struct timeval *);
|
|
};
|
|
|
|
struct cache_
|
|
{
|
|
struct cache_params params;
|
|
|
|
struct cache_entry_ **entries;
|
|
size_t entries_capacity;
|
|
size_t entries_size;
|
|
};
|
|
|
|
/* simple abstractions - for not to write "struct" every time */
|
|
typedef struct cache_ *cache;
|
|
typedef struct cache_entry_ *cache_entry;
|
|
typedef struct cache_mp_write_session_ *cache_mp_write_session;
|
|
typedef struct cache_mp_read_session_ *cache_mp_read_session;
|
|
|
|
#define INVALID_CACHE (NULL)
|
|
#define INVALID_CACHE_ENTRY (NULL)
|
|
#define INVALID_CACHE_MP_WRITE_SESSION (NULL)
|
|
#define INVALID_CACHE_MP_READ_SESSION (NULL)
|
|
|
|
/*
|
|
* NOTE: all cache operations are thread-unsafe. You must ensure thread-safety
|
|
* externally, by yourself.
|
|
*/
|
|
|
|
/* cache initialization/destruction routines */
|
|
extern cache init_cache(struct cache_params const *);
|
|
extern void destroy_cache(cache);
|
|
|
|
/* cache entries manipulation routines */
|
|
extern int register_cache_entry(cache, struct cache_entry_params const *);
|
|
extern int unregister_cache_entry(cache, const char *);
|
|
extern cache_entry find_cache_entry(cache, const char *);
|
|
|
|
/* read/write operations used on common entries */
|
|
extern int cache_read(cache_entry, const char *, size_t, char *, size_t *);
|
|
extern int cache_write(cache_entry, const char *, size_t, char const *, size_t);
|
|
|
|
/* read/write operations used on multipart entries */
|
|
extern cache_mp_write_session open_cache_mp_write_session(cache_entry);
|
|
extern int cache_mp_write(cache_mp_write_session, char *, size_t);
|
|
extern void abandon_cache_mp_write_session(cache_mp_write_session);
|
|
extern void close_cache_mp_write_session(cache_mp_write_session);
|
|
|
|
extern cache_mp_read_session open_cache_mp_read_session(cache_entry);
|
|
extern int cache_mp_read(cache_mp_read_session, char *, size_t *);
|
|
extern void close_cache_mp_read_session(cache_mp_read_session);
|
|
|
|
/* transformation routines */
|
|
extern int transform_cache_entry(cache_entry, enum cache_transformation_t);
|
|
extern int transform_cache_entry_part(cache_entry, enum cache_transformation_t,
|
|
const char *, size_t, enum part_position_t);
|
|
|
|
#endif
|