/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _NFS4_DB_IMPL_H
#define _NFS4_DB_IMPL_H
/*
* This is a private header file. Applications should not directly include
* this file.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define SEARCH_DEBUG 0x0001
#define CREATE_DEBUG 0x0002
#define CACHED_DEBUG 0x0004
#define DESTROY_DEBUG 0x0008
#define REAP_DEBUG 0x0010
#define OTHER_DEBUG 0x0020
#define WALK_DEBUG 0x0040
/*
* A database is made up of a collection of tables.
* Tables are in turn made up of a collection of
* entries. Each table may haveone or more indices
* associtated with it.
*/
/* Private implementation */
typedef struct rfs4_link {
struct rfs4_link *next;
struct rfs4_link *prev;
rfs4_dbe_t *entry;
} rfs4_link_t;
struct rfs4_dbe {
kmutex_t dbe_lock[1]; /* Exclusive lock for entry */
uint32_t dbe_refcnt; /* # of references */
unsigned dbe_skipsearch:1; /* skip search */
unsigned dbe_invalid:1; /* invalid/"freed" entry */
unsigned dbe_reserved:31;
time_t dbe_time_rele; /* Time of last rele */
id_t dbe_id; /* unique identifier */
kcondvar_t dbe_cv[1];
rfs4_entry_t dbe_data;
rfs4_table_t *dbe_table;
rfs4_link_t dbe_indices[1]; /* Array of indices for entry */
};
typedef struct rfs4_bucket {
krwlock_t dbk_lock[1]; /* lock hash chain */
rfs4_link_t *dbk_head;
} rfs4_bucket_t;
struct rfs4_index {
uint32_t dbi_tblidx; /* which indice in entry */
bool_t dbi_createable; /* Can create entries */
rfs4_table_t *dbi_table; /* Pointer to table */
char *dbi_keyname; /* String rep of key */
rfs4_bucket_t *dbi_buckets; /* Hash buckets */
uint32_t (*dbi_hash)(void *); /* Given key find bucket */
bool_t (*dbi_compare)(rfs4_entry_t, void *); /* Key match entry? */
void *(*dbi_mkkey)(rfs4_entry_t); /* Given data generate a key */
struct rfs4_index *dbi_inext; /* next index on table */
};
struct rfs4_table {
rfs4_table_t *dbt_tnext; /* next table in db */
struct rfs4_database *dbt_db; /* db that holds this table */
krwlock_t dbt_t_lock[1]; /* lock table for resize */
kmutex_t dbt_lock[1]; /* mutex for count and cached */
char *dbt_name; /* Table name */
id_space_t *dbt_id_space; /* space for unique entry ids */
time_t dbt_min_cache_time; /* How long to cache entries */
time_t dbt_max_cache_time; /* How long to cache entries */
uint32_t dbt_usize; /* User entry size */
uint32_t dbt_maxentries; /* max # of entries in table */
uint32_t dbt_len; /* # of buckets in table */
uint32_t dbt_count; /* # of entries in table */
uint32_t dbt_idxcnt; /* # of indices in table */
uint32_t dbt_maxcnt; /* max # of indices */
uint32_t dbt_ccnt; /* # of creatable entries */
uint32_t dbt_id_lwat; /* lo wtrmrk; 50% ids in use */
uint32_t dbt_id_hwat; /* hi wtrmrk; 75% ids in use */
time_t dbt_id_reap; /* table's reap interval */
rfs4_index_t *dbt_indices; /* list of indices */
/* Given entry and data construct entry */
bool_t (*dbt_create)(rfs4_entry_t, void *data);
void (*dbt_destroy)(rfs4_entry_t); /* Destroy entry */
bool_t (*dbt_expiry)(rfs4_entry_t); /* Has this entry expired */
kmem_cache_t *dbt_mem_cache; /* Cache for table entries */
uint32_t dbt_debug; /* Debug Flags */
/* set of vars used for managing the reaper thread */
unsigned dbt_reaper_shutdown:1; /* table shutting down? */
kcondvar_t dbt_reaper_wait; /* reaper thread waits here */
kmutex_t dbt_reaper_cv_lock; /* lock used for cpr wait */
callb_cpr_t dbt_reaper_cpr_info; /* cpr the reaper thread */
};
struct rfs4_database {
kmutex_t db_lock[1];
uint32_t db_debug_flags; /* Table debug flags to set */
uint32_t db_shutdown_count; /* count to manage shutdown */
kcondvar_t db_shutdown_wait; /* where the shutdown waits */
rfs4_table_t *db_tables; /* list of tables in db */
};
#define RFS4_RECLAIM_PERCENT 10
#define RFS4_REAP_INTERVAL 300
#define HASH(idx, key) (idx->dbi_hash(key) % idx->dbi_table->dbt_len)
#define ENQUEUE(head, l) { \
(l)->prev = NULL; \
(l)->next = (head); \
if ((l)->next) \
(l)->next->prev = (l); \
(head) = (l); \
}
#define DEQUEUE(head, l) { \
if ((l)->prev) \
(l)->prev->next = (l)->next; \
else \
(head) = (l)->next; \
if ((l)->next) \
(l)->next->prev = (l)->prev; \
}
#define INVALIDATE_ADDR(a) ((a) = (void *)((unsigned long)(a) | 1L))
#define VALIDATE_ADDR(a) ((a) = (void *)((unsigned long)(a) & ~1L))
#define INVALID_ADDR(a) (((unsigned long)(a) & 1L))
#define INVALID_LINK(l) (INVALID_ADDR(l->entry))
#define ENQUEUE_IDX(bp, l) { \
rw_enter((bp)->dbk_lock, RW_WRITER); \
ENQUEUE((bp)->dbk_head, l); \
VALIDATE_ADDR((l)->entry); \
rw_exit((bp)->dbk_lock); \
}
#define DEQUEUE_IDX(bp, l) { \
rw_enter((bp)->dbk_lock, RW_WRITER); \
INVALIDATE_ADDR((l)->entry); \
DEQUEUE((bp)->dbk_head, l); \
rw_exit((bp)->dbk_lock); \
}
#ifdef __cplusplus
}
#endif
#endif /* _NFS4_DB_IMPL_H */