/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "isns_server.h"
#include "isns_cache.h"
#include "isns_msgq.h"
#include "isns_obj.h"
#include "isns_htab.h"
/*
* external variables
*/
extern msg_queue_t *sys_q;
#ifdef DEBUG
extern int verbose_lock;
#endif
/*
* global data
*/
int cache_flag = 0;
/*
* local variables
*/
static cache_t *imc;
/*
* local functions.
*/
/*
* ****************************************************************************
* cache_init:
* create the cache data initially, including to invoke individual
* functions for creating the hash tables for object storage and
* discovery domain membership matrix.
*
* return - 0: no error; 1: otherwise.
*
* ****************************************************************************
*/
int
cache_init(
)
{
/*
* allocate global cache memory.
*/
imc = (cache_t *)calloc(sizeof (cache_t), 1);
if (imc == NULL ||
obj_tab_init(imc) != 0 ||
dd_matrix_init(imc) != 0) {
cache_destroy();
return (1); /* no memory */
}
/*
* initialize global cache rwlock.
*/
(void) rwlock_init(&imc->l, NULL, NULL);
/*
* inintialize global cache functions.
*/
imc->get_hval = obj_hval;
imc->get_uid = get_obj_uid;
imc->set_uid = set_obj_uid;
imc->timestamp = get_timestamp;
imc->add_hook = add_object;
imc->replace_hook = replace_object;
imc->cmp = obj_cmp;
imc->clone = assoc_clone;
imc->ddd = update_ddd;
#ifdef DEBUG
imc->dump = obj_dump;
#endif
return (0);
}
/*
* ****************************************************************************
* cache_destroy:
* destroy the cache data.
*
* ****************************************************************************
*/
void
cache_destroy(
)
{
/* do nothing */
}
/*
* ****************************************************************************
* cache_lock:
* grab the lock on the cache data.
*
* mode - the read/write mode of the lock.
* return - error code.
*
* ****************************************************************************
*/
int
cache_lock(
int mode
)
{
int ret = 0;
switch (mode) {
case CACHE_WRITE:
ret = rw_wrlock(&imc->l);
#ifdef DEBUG
if (verbose_lock) {
printf("cache locked for writing.\n");
}
#endif
break;
case CACHE_READ:
ret = rw_rdlock(&imc->l);
#ifdef DEBUG
if (verbose_lock) {
printf("cache locked for reading.\n");
}
#endif
break;
case CACHE_TRY_READ:
ret = rw_tryrdlock(&imc->l);
#ifdef DEBUG
if (verbose_lock) {
if (ret == 0) {
printf("cache locked for reading.\n");
} else {
printf("cache locked for reading failed.\n");
}
}
#endif
break;
default:
break;
}
return (ret);
}
/*
* ****************************************************************************
* cache_unlock:
* release the lock on the cache data.
* if the cache was locked for writing, a synchronization between
* the cache and persistent data store needs to be performed.
*
* mode - the read/write mode which the cache data was locked for.
* ec - 0: commit the cache update; otherwise retreat it.
* return - error code.
*
* ****************************************************************************
*/
int
cache_unlock(
int mode,
int ec
)
{
if (mode != CACHE_NO_ACTION) {
/* sync between cache and data store */
if (mode == CACHE_WRITE) {
if (sys_q) {
ec = data_sync(ec);
}
/* rest the cache update flag */
RESET_CACHE_UPDATED();
}
ASSERT(!IS_CACHE_UPDATED());
/* unlock it */
(void) rw_unlock(&imc->l);
#ifdef DEBUG
if (verbose_lock) {
printf("cache unlocked.\n");
}
#endif
}
return (ec);
}
/*
* ****************************************************************************
* cache_lock_read:
* grab the read lock on the cache.
*
* return - error code.
*
* ****************************************************************************
*/
int
cache_lock_read(
)
{
return (cache_lock(CACHE_READ));
}
/*
* ****************************************************************************
* cache_lock_write:
* grab the write lock on the cache.
*
* return - error code.
*
* ****************************************************************************
*/
int
cache_lock_write(
)
{
return (cache_lock(CACHE_WRITE));
}
/*
* ****************************************************************************
* cache_unlock_sync:
* synchronize the cache with persistent data store and
* release the lock.
*
* ec - 0: commit the cache update; otherwise retreat it.
* return - error code.
*
* ****************************************************************************
*/
int
cache_unlock_sync(
int ec
)
{
return (cache_unlock(CACHE_WRITE, ec));
}
/*
* ****************************************************************************
* cache_unlock_nosync:
* release the lock, no need to sync the data between cache and
* data store.
* if the cache has been updated, do not call this function, call
* cache_unlock_sync() with non-zero error code to indicate the
* sync action.
*
* return - error code.
*
* ****************************************************************************
*/
int
cache_unlock_nosync(
)
{
return (cache_unlock(CACHE_READ, 0));
}
/*
* ****************************************************************************
* cache_get_htab:
* get the hash table for individual type of object.
*
* type - the object type.
* return - the hash table.
*
* ****************************************************************************
*/
htab_t *
cache_get_htab(
isns_type_t type
)
{
if (type > 0 && type < MAX_OBJ_TYPE) {
return (imc->t[type]);
}
return (NULL);
}
/*
* ****************************************************************************
* cache_get_matrix:
* get the membership matrix for a discovery domain or a
* discovery domain set.
*
* type - the discovery domain or discovery domain set object type.
* return - the matrix.
*
* ****************************************************************************
*/
matrix_t *
cache_get_matrix(
isns_type_t type
)
{
matrix_t *x = NULL;
switch (type) {
case OBJ_DD:
x = imc->x[0];
break;
case OBJ_DDS:
x = imc->x[1];
break;
default:
break;
}
return (x);
}
/*
* ****************************************************************************
* cache_lookup:
* invoke the hash table lookup for looking up a specific object and
* perform the callback function on the object.
*
* lcp - the object lookup control data.
* uid_p - the pointer of object UID for returning.
* callback - the callback function for the object.
* return - error code.
*
* ****************************************************************************
*/
int
cache_lookup(
lookup_ctrl_t *lcp,
uint32_t *uid_p,
int (*callback)(void *, void *)
)
{
return (htab_lookup(imc->t[lcp->type],
lcp,
(lcp->op[0] == OP_INTEGER) ? lcp->data[0].ui : 0,
uid_p,
callback,
0));
}
/*
* ****************************************************************************
* cache_lookup:
* invoke the hash table lookup for looking up a specific object,
* the callback function is going to change the key of the object.
*
* lcp - the object lookup control data.
* uid_p - the pointer of object UID for returning.
* callback - the callback function for the object.
* return - error code.
*
* ****************************************************************************
*/
int
cache_rekey(
lookup_ctrl_t *lcp,
uint32_t *uid_p,
int (*callback)(void *, void *)
)
{
return (htab_lookup(imc->t[lcp->type],
lcp,
(lcp->op[0] == OP_INTEGER) ? lcp->data[0].ui : 0,
uid_p,
callback,
1));
}
/*
* ****************************************************************************
* cache_add:
* invoke hash table add to add an object.
*
* obj - the object being added.
* flag - 0: a real object;
* otherwise an association object for discovery domain membership.
* uid_p - the pointer of object UID for returning.
* update_p - the pointer of flag (update object or newly register)
* for returning.
* return - error code.
*
* ****************************************************************************
*/
int
cache_add(
isns_obj_t *obj,
int flag,
uint32_t *uid_p,
int *update_p
)
{
return (htab_add(imc->t[obj->type], obj, flag, uid_p, update_p));
}
/*
* ****************************************************************************
* cache_remove:
* invoke hash table remove to remove an object.
*
* lcp - the lookup control data for the object being removed.
* flag - 0: a real object;
* otherwise an association object for discovery domain membership.
* return - the removed object.
*
* ****************************************************************************
*/
isns_obj_t *
cache_remove(
lookup_ctrl_t *lcp,
int flag
)
{
return (htab_remove(imc->t[lcp->type],
lcp,
(lcp->op[0] == OP_INTEGER) ? lcp->data[0].ui : 0,
flag));
}
/*
* ****************************************************************************
* cache_dump_htab:
* dump the hash table for debugging purpose.
*
* type - the object type.
*
* ****************************************************************************
*/
#ifdef DEBUG
void
cache_dump_htab(
isns_type_t type
)
{
(void) htab_dump(imc->t[type]);
}
#endif