RSRC(COMMON )

Shore Programmer's Manual - 2 August 96

NAME

rsrc_m, rsrc_i \- Resource Manager and Iterator Classes

SYNOPSIS

#include <rsrc.h>

template <class TYPE, class KEY>
class rsrc_m : public w_base_t {
    friend class rsrc_i<TYPE, KEY>;
public:
    NORET			rsrc_m(
	TYPE* 			    space,
	int 			    n, 
	char*			    descriptor=0);
    NORET			~rsrc_m();

    void			mutex_acquire();
    void			mutex_release();

    bool			is_cached(const KEY& k);

    w_rc_t 			grab(
	TYPE*&			    ret,
	const KEY& 		    k,
	bool&			    found,
	bool&			    is_new,
	latch_mode_t		    mode = LATCH_EX,
	int			    timeout = sthread_base_t::WAIT_FOREVER);

    w_rc_t 			find(
	TYPE*&			    ret,
	const KEY& 		    k, 
	latch_mode_t 		    mode = LATCH_EX,
	int 			    ref_bit = 1,
	int 			    timeout = sthread_base_t::WAIT_FOREVER);

    void			publish_partial(const TYPE* rsrc);
    void			publish(
	const TYPE* 		    rsrc,
	bool			    error_occurred = false);
    
    bool 			is_mine(const TYPE* rsrc);

    void 			pin(
	const TYPE* 		    rsrc,
	latch_mode_t		    mode = LATCH_EX);

    void 			upgrade_latch_if_not_block(
	const TYPE* 		    rsrc,
	bool&			    would_block);

    void			unpin(
	const TYPE*& 		    rsrc,
	int			    ref_bit = 1);
    // number of times pinned
    int				pin_cnt(const TYPE* t);
    w_rc_t			remove(const TYPE*& t) { 
	w_rc_t rc;
	bool get_mutex = ! _mutex.is_mine();
	if (get_mutex)    W_COERCE(_mutex.acquire());
	rc = _remove(t);
	if (get_mutex)    _mutex.release();
	return rc;
    }

    void 			dump(ostream &o,bool debugging=1)const;
    int				audit(bool prt= false) const;

    void			snapshot(u_int& npinned, u_int& nfree);

    unsigned long 		ref_cnt, hit_cnt;

// iterator
template <class TYPE, class KEY>
class rsrc_i {
public:
    NORET			rsrc_i(
	rsrc_m<TYPE, KEY>&	    r,
	latch_mode_t 		    m = LATCH_EX,
	int 			    start = 0)
	: _mode(m), _idx(start), _curr(0), _r(r) {};

    NORET			~rsrc_i();
    
    TYPE* 			next();
    TYPE* 			curr() 	{ return _curr ? _curr->ptr : 0; }
    w_rc_t			discard_curr();

private: // disabled methods
    NORET			rsrc_i(const rsrc_i&);
    rsrc_i&			operator=(const rsrc_i&);
};

/*
 *  rsrc_t
 *	control block (handle) to a resource
 */
template <class TYPE, class KEY>
struct rsrc_t {
public:
    NORET			rsrc_t()    {};
    NORET			~rsrc_t()   {};
    w_link_t			link;		// used in resource hash table
    latch_t 			latch;		// latch on the resource
    KEY				key;		// key of the resource
    KEY				old_key;
    bool			old_key_valid;
    TYPE* 			ptr;		// pointer to the resource
    w_base_t::uint4_t		waiters;	// # of waiters
    w_base_t::uint4_t		ref;		// ref count
    scond_t			exit_transit;	// signaled when
						// initialization is done
    
};


DESCRIPTION

The rsrc_m template class manages a fixed size pool of "resources" (of type T) in a multi-threaded environment. A structure, rsrc_t, is associated with each resource. Class rsrc_t contains a key, K, a pointer to the resource and a latch to protect access to the resource. The rsrc_t elements are stored in a hash table, hash_t. Because of the latches, each resource can be individually "pinned" for any desired length of time without restricting access to other resources.

The template class rsrc_i is the iterator for the rsrc_m class.

When a entry needs to be added and the table is full, on old entry is removed based on an LRU policy.

The rsrc_m is relatively expensive, so it is probably best used to manage large resources or where high concurrency is needed. A good example is managing access to pages in a buffer pool.

Requirements:

The rsrc_m template takes two class parameters:
T
the class type of the resources to be manages.
K
the unique key of the resource for lookup purposes. Note: that K must define K::operator=() for copying since rsrc_m saves a copy of K for lookup purpose, and u_long hash(const K&) hash function for K because rsrc_m is hash-table based.

A resource in rsrc_m can be in one of three states:

unused
the resource is free; no key is associated with the resource.
cached
the resource is cached and is associated with a key.
in-transit
the resource is begin replaced; its key is being changed.

Rsrc_m Interface

rsrc_m(rsrc, cnt, desc)

The constructor creates a resource manager to manage the resources specified by the array rsrc. The number of resources (ie. the length of the array) is specified by cnt. The desc is an optional string used for naming the latches protecting the resources. It can be useful in debugging.

~rsrc_m()

The destructor destroys the resource manager. There should not be any resources pinned when the resource manager is is destroyed.

grab(ret, key, found, is_new, mode, timeout)

The grab method pins the resource associated with key and sets a latch in mode mode on the resource. The calling thread should subsequently free rsrc by calling unpin.
If the resource is cached, grab simply returns it. Otherwise, grab will either allocate an unused resource or find another cached resource to replace using a pseudo-LRU (clock) algorithm. The calling thread could potentially block if mode causes a latch conflict (i.e.\,when there is contention to the resource). If grab is successful, a pointer to the cached/allocated/replacement resource is returned in ret. The found flag is set to indicate cache hit/miss. In the case of a cache miss, the resource returned is said to be in-transit, and the is_new flag indicates whether ret points to:
(1) a previously unused resource (true), or
(2) a previously cached resource of another key (false).

In case 1, the in-transit resource returned simply needs to be initialized with the new key. All other threads that ask for a resource with the new key will block. The caller should initialize the resource and subsequently call publish, which formally publishes the new key and resets the resource's in-transit status.

In case 2, the in-transit resource returned is temporarily associated with both the new key (as specified in grab and the old key. All other threads that ask for a resource with any of these keys will block. The caller sehould first clean up the resource (invalidate the old key) and call publish_partial, which informs rsrc_m that the old key is no longer valid. The caller should then proceed as in case 1.

In essense, the caller should proceed as follows:

    grab the resource
    if not found then
	if not is_new then
	    clean up the resource (optional), e.g.,flush the dirty page
	    call publish_partial() (optional)
	initialize the resource (obligatory), e.g.,read the new page
	call publish() (obligatory)
    ... use the resource ...
    call unpin() to free the resource

find(ret, key, mode, ref_bit, timeout)

The find method looks up and pins a cached resource identified by key. It returns an the error fcNOTFOUND if the resource is not cached. If the resource is cached, a mode latch is acquired on the resource and a pointer to the resource is returned in ret. The calling thread should subsequently free the resource by calling unpin. As in grab, the calling thread could potentially block if mode causes a latch conflict (i.e.,when there is contention to the resource). The refbit parameter is a hint to the rsrc_m replacement algorithm; refbit is directly proportional to the duration that a resource remained cached. Thus, a zero refbit implies that the rsrc_m should reuse the resource as soon as needed after it is unpinned.

pin(rsrc, mode)

The pin method pins the resource rsrc. The latch on the resource is acquired in mode mode. The calling thread should subsequently free rsrc by calling unpin.

publish(rsrc, error_flag)

The publish method makes the resource rsrc, that was previously obtained by a grab call with a cache miss, available. See the description of grab for more details. The error_flag parameter is informs the rsrc_m that the resource has not been successfully initialized, and should be invalidated.

publish_partial(rsrc)

The publish_partial method partially publishes the resource rsrc that was previously obtained with a call to grab. See the description of grab for more details.

unpin(rsrc, refbit)

The unpin method releases the latch on the resource rsrc. The refbit parameter is a hint to the rsrc_m replacement algorithm; refbit is directly proportional to the duration that a resource remained cached. Thus, a zero refbit implies that the rsrc_m should reuse the resource as soon as needed.

Rsrc_i Interface

The rsrc_i template is used to iterate over all of the resources in an instance of rsrc_m.

rsrc_m(r, mode, start)

The constructor initilizes an iterator for the rsrc_m instance indicated by parameter r. Each resource will be pinned (latched) in mode mode. The iterator starts at the start, element in the array of resources that r manages. The iterator will only return those resources actually in the hash table.

~rsrc_m()

The destructor ends the iterator by unpinning and currently pinned resource.

next()

The next method unpins the current resource, advances the iterator to the next resource, and pins it. Next returns a pointer to the resource after it has advanced. It will return 0 if there are no more resources. Next skips any resources not in the hash table.

curr()

The curr method returns a pointer to the currently pinned resource.

discard_curr()

The discard_curr method unpins the current resource and removes it from the hash table. TODO

VERSION

This manual page applies to Version 1.0 of theShore software.

SPONSORSHIP

The Shore project is sponsored by the Advanced Research Project Agency, ARPA order number 018 (formerly 8230), monitored by the U.S. Army Research Laboratory under contract DAAB07-92-C-Q508.

COPYRIGHT

Copyright (c) 1994, 1995, 1996 Computer Sciences Department, University of Wisconsin -- Madison. All Rights Reserved.

SEE ALSO

latch_t(common) , intro(common) .