OpenSolaris_b135/cmd/isns/isnsd/cache.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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