root/usr/src/cmd/nscd/cache.h
/*
 * 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 (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _NSCD_H
#define _NSCD_H

/*
 * This is a private header file.  Applications should not directly include
 * this file.
 */

#ifdef  __cplusplus
extern "C" {
#endif

#include <sys/avl.h>
#include <thread.h>
#include <synch.h>
#include <nss_dbdefs.h>
#include "getxby_door.h"
#include "nscd_common.h"
#include "nscd_config.h"

/*
 * OR'D in by server to call self for updates
 */
#define UPDATEBIT       (1<<30)
#define MASKUPDATEBIT(a) ((~UPDATEBIT)&(a))

/*
 * debug levels
 */
#define DBG_OFF         0
#define DBG_CANT_FIND   2
#define DBG_NETLOOKUPS  4
#define DBG_ALL         6

/*
 * Max size name we allow to be passed to avoid
 * buffer overflow problems
 */
#define NSCDMAXNAMELEN  255

/*
 * cached entry status
 */
#define ST_UPDATE_PENDING       0x1
#define ST_LOOKUP_PENDING       0x2
#define ST_PENDING              (ST_LOOKUP_PENDING | ST_UPDATE_PENDING)
#define ST_NEW_ENTRY            0x4
#define ST_DISCARD              0x8

/*
 * Cache eviction start and stop levels
 */
#define _NSC_EVICTION_START_LEVEL       90
#define _NSC_EVICTION_SAFE_LEVEL        80

/*
 * other internal constants
 */
#define _NSC_MAX_DB             3
#define _NSC_PUBLIC_ACCESS      -1
#define _NSC_FILE_CHECK_TIME    0       /* check always for backwards compat */

/*
 * Macros used for logging purposes
 */
#define yes_no(flag)    (flag == nscd_true)?"yes":"no"
#define check_null(str) (str)?str:"<null>"

/*
 * Macros used by compare routines
 */
#define _NSC_INT_KEY_CMP(n1, n2) \
        (n1 > n2)?1:((n1 == n2)?0:-1)

#define _NSC_GET_HITRATE(sp) \
        sp->hitrate = sp->pos_misses + sp->neg_misses + \
                sp->pos_hits + sp->neg_hits; \
        if (sp->hitrate > 0.0) \
                sp->hitrate = (100.0 * \
                        ((double)sp->pos_hits + \
                        (double)sp->neg_hits)) / sp->hitrate;

/*
 * nsc_lookup action
 */
typedef enum {
        _NSC_NSLOOKUP = 0,
        _NSC_WAIT,
        _NSC_USECACHED
} nsc_action_t;

/*
 *  What each entry in the nameserver cache looks like.
 */

typedef struct nsc_entry_stat {
        uint_t          hits;           /* number of hits */
        uint8_t         status;         /* activity status */
        time_t          timestamp;      /* expiry time */
        int             refcount;       /* reference count */
} nsc_entry_stat_t;

typedef struct nsc_entry {
        avl_node_t              avl_link;       /* libavl requirement */
        struct nsc_entry        *qnext;         /* next on pqueue */
        struct nsc_entry        *qprev;         /* prev on pqueue */
        nsc_entry_stat_t        stats;          /* entry's statistics */
        nss_XbyY_key_t          key;            /* entry's key */
        void                    *buffer;        /* data buffer */
        size_t                  bufsize;        /* data buffer length */
} nsc_entry_t;

typedef struct nsc_keephot {
        void    *ptr;
        uint_t  num;
} nsc_keephot_t;

/*
 * Structure to handle waiting for pending name service requests
 */
typedef struct waiter {
        cond_t          w_waitcv;
        uint8_t         w_signaled;
        nsc_entry_t     *w_key;
        struct waiter   *w_next, *w_prev;
} waiter_t;

/*
 * Macros used by hash table
 *
 * _NSC_HTSIZE_PRIMES are prime numbers that are used as hash table
 * sizes when hash table type is nsc_ht_prime. For hash tables of
 * type nsc_ht_power2, the size is automatically calculated.
 * Number of primes listed below is _NSC_HTSIZE_NUM_SLOTS + 1.
 * Each number (except the first) is a prime closest to a
 * power of 2 in increasing order. Ex: 509 is the closest prime to
 * 512 (2**9), 1021 is closest to 1024 (2**10), and so on.
 * The first prime is chosen as 211 for historical reasons.
 */
#define _NSC_INIT_HTSIZE_PRIME  211
#define _NSC_INIT_HTSIZE_POWER2 256
#define _NSC_INIT_HTSIZE_SLOT_VALUE     2896
#define _NSC_HTSIZE_NUM_SLOTS   10
#define _NSC_HTSIZE_PRIMES      211, 509, 1021, 2053, 4099, 8191, \
                                16381, 32771, 65537, 131071, 262147

#define _NSC_DB_CES_KEY(ptr) \
                ((ptr)->db_type == nsc_key_ces)
#define _NSC_DB_CIS_KEY(ptr) \
                ((ptr)->db_type == nsc_key_cis)
#define _NSC_DB_STR_KEY(ptr) \
                _NSC_DB_CES_KEY(ptr) || _NSC_DB_CIS_KEY(ptr)
#define _NSC_DB_INT_KEY(ptr) \
                ((ptr)->db_type == nsc_key_int)

/*
 * cache backend param group (global)
 */
#define NSCD_CFG_GROUP_INFO_GLOBAL_CACHE        {1, 0x0001}
typedef struct nscd_cfg_global_cache {
        nscd_cfg_group_info_t   gi;     /* config requirement */
        nscd_bool_t     enable;
} nscd_cfg_global_cache_t;

#define NSCD_CFG_GLOBAL_CACHE_DEFAULTS \
        { NSCD_CFG_GROUP_INFO_GLOBAL_CACHE, nscd_true }

/*
 * cache backend param group (per database)
 */
#define NSCD_CFG_GROUP_INFO_CACHE       {12, 0x0fff}
typedef struct nscd_cfg_cache {
        nscd_cfg_group_info_t   gi;     /* config requirement */
        nscd_bool_t     enable;         /* if false return NOSERVER */
        nscd_bool_t     per_user;       /* if true per user access */
        nscd_bool_t     avoid_ns;       /* if true avoid name service */
        nscd_bool_t     check_files;    /* if true check file */
        int             check_interval; /* check interval */
        int             pos_ttl;        /* time to live for +ve entries */
        int             neg_ttl;        /* time to live for -ve entries */
        int             keephot;        /* keep hot count */
        int             hint_size;      /* size to return for a GETHINTS */
        ulong_t         maxentries;     /* maximum entries allowed */
        int             suggestedsize;  /* obsolete */
        nscd_bool_t     old_data_ok;    /* obsolete */
} nscd_cfg_cache_t;

#define NSCD_CFG_CACHE_DEFAULTS \
        { \
                NSCD_CFG_GROUP_INFO_CACHE, \
                nscd_true, nscd_false, nscd_false, nscd_true, \
                _NSC_FILE_CHECK_TIME, 600, 10, 0, 1 << 11, 0, \
                0,  nscd_false \
        }

/*
 * cache backend stat group (per database)
 */
#define NSCD_CFG_STAT_GROUP_INFO_CACHE  {9, 0x01ff}
typedef struct nscd_cfg_stat_cache {
        nscd_cfg_group_info_t   gi;     /* config requirement */
        ulong_t pos_hits;               /* hits on +ve entries */
        ulong_t neg_hits;               /* hits on -ve entries */
        ulong_t pos_misses;             /* misses on +ve entries */
        ulong_t neg_misses;             /* misses on -ve entries */
        ulong_t entries;                /* count of cache entries */
        ulong_t drop_count;             /* cache queries dropped */
        ulong_t wait_count;             /* cache queries queued */
        ulong_t invalidate_count;       /* count for cache invalidation */
        double  hitrate;                /* computed from other fields */
} nscd_cfg_stat_cache_t;

typedef struct nsc_db {
        /*
         * Data
         */
        avl_tree_t      tree;
        nsc_entry_t     **htable;
        nsc_entry_t     *qhead;
        nsc_entry_t     *qtail;
        nsc_entry_t     *reap_node;
        int             callnumber;
        int             dbop;
        char            *name;
        mutex_t         db_mutex;
        waiter_t        db_wait;        /* lookup wait CV */
        int             htsize;
        enum hash_type {
                nsc_ht_default = 0,
                nsc_ht_prime = 1,
                nsc_ht_power2 = 2
        } hash_type;
        enum db_type {
                nsc_key_ces = 0,
                nsc_key_cis = 1,
                nsc_key_int = 2,
                nsc_key_other = 3
        } db_type;
        /*
         * Methods
         */
        uint_t (*gethash)(nss_XbyY_key_t *, int);
        int (*compar)(const void *, const void *);
        void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *);
        /*
         * Config
         */
        nscd_cfg_cache_t        cfg;
        time_t                  cfg_mtime;
} nsc_db_t;


typedef struct nsc_ctx {
        char            *dbname;                /* cache name */
        nscd_cfg_stat_cache_t   stats;          /* statistics */
        nscd_cfg_cache_t        cfg;            /* configs */
        time_t          cfg_mtime;              /* config last modified time */
        rwlock_t        cfg_rwlp;               /* config rwlock */
        mutex_t         stats_mutex;            /* stats mutex */
        mutex_t         file_mutex;             /* file mutex */
        time_t          file_mtime;             /* file last modified time */
        time_t          file_chktime;           /* file last checked time */
        off_t           file_size;              /* file size at last check */
        ino_t           file_ino;               /* file inode at last check */
        const char      *file_name;             /* filename for check_files */
        int             db_count;       /* number of caches, max _NSC_MAX_DB */
        nsc_db_t        *nsc_db[_NSC_MAX_DB];   /* caches */
        sema_t          throttle_sema;          /* throttle lookups */
        sema_t          revalidate_sema;        /* revalidation threads */
        nscd_bool_t     revalidate_on;          /* reval. thread started */
        nscd_bool_t     reaper_on;              /* reaper thread started */
} nsc_ctx_t;

typedef struct nsc_lookup_args {
        nsc_ctx_t       *ctx;
        nsc_db_t        *nscdb;
        void            *buffer;
        size_t          bufsize;
} nsc_lookup_args_t;

#define CACHE_CTX_COUNT 19

/* Context initialization */
extern void passwd_init_ctx(nsc_ctx_t *);
extern void group_init_ctx(nsc_ctx_t *);
extern void host_init_ctx(nsc_ctx_t *);
extern void ipnode_init_ctx(nsc_ctx_t *);
extern void exec_init_ctx(nsc_ctx_t *);
extern void prof_init_ctx(nsc_ctx_t *);
extern void user_init_ctx(nsc_ctx_t *);
extern void ether_init_ctx(nsc_ctx_t *);
extern void rpc_init_ctx(nsc_ctx_t *);
extern void proto_init_ctx(nsc_ctx_t *);
extern void net_init_ctx(nsc_ctx_t *);
extern void bootp_init_ctx(nsc_ctx_t *);
extern void auth_init_ctx(nsc_ctx_t *);
extern void serv_init_ctx(nsc_ctx_t *);
extern void netmask_init_ctx(nsc_ctx_t *);
extern void printer_init_ctx(nsc_ctx_t *);
extern void project_init_ctx(nsc_ctx_t *);
extern void tnrhtp_init_ctx(nsc_ctx_t *);
extern void tnrhdb_init_ctx(nsc_ctx_t *);

/* Functions used to throttle threads */
extern int nscd_wait(nsc_ctx_t *, nsc_db_t *, nsc_entry_t *);
extern int nscd_signal(nsc_ctx_t *, nsc_db_t *, nsc_entry_t *);

/* Cache creation and initialization */
extern nscd_rc_t init_cache();
extern nsc_db_t *make_cache(enum db_type, int, char *,
        int (*compar) (const void *, const void *),
        void (*getlogstr)(char *, char *, size_t, nss_XbyY_args_t *),
        uint_t (*gethash)(nss_XbyY_key_t *, int),
        enum hash_type, int);

/* Cache backend lookup */
extern void nsc_lookup(nsc_lookup_args_t *, int);

/* Cache backend info */
extern void nsc_info(nsc_ctx_t *, char *, nscd_cfg_cache_t cfg[],
                nscd_cfg_stat_cache_t stats[]);
#ifdef NSCD_DEBUG
extern int nsc_dump(char *, int);
#endif  /* NSCD_DEBUG */

/* Cache invalidate */
extern void nsc_invalidate(nsc_ctx_t *, char *, nsc_ctx_t **);

/* Keep hot functions */
extern nsc_keephot_t *maken(int);
extern void *insertn(nsc_keephot_t *, uint_t, void *);

/* hash related routines */
extern uint_t cis_gethash(const char *, int);
extern uint_t ces_gethash(const char *, int);
extern uint_t db_gethash(const void *, int, int);

extern void leave(int n);
extern int get_cache_idx(char *);

#ifdef  __cplusplus
}
#endif

#endif  /* _NSCD_H */