⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resourcedispatcher.java

📁 jxme的一些相关程序,主要是手机上程序开发以及手机和计算机通信的一些程序资料,程序编译需要Ant支持
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (c) 2002 Sun Microsystems, Inc.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *       Sun Microsystems, Inc. for Project JXTA."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact Project JXTA at http://www.jxta.org.
 *
 * 5. Products derived from this software may not be called "JXTA",
 *    nor may "JXTA" appear in their name, without prior written
 *    permission of Sun.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL SUN MICROSYSTEMS OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of Project JXTA.  For more
 * information on Project JXTA, please see
 * <http://www.jxta.org/>.
 *
 * This license is based on the BSD license adopted by the Apache Foundation.
 *
 * $Id: ResourceDispatcher.java,v 1.6 2002/06/20 19:33:12 jice Exp $
 *
 */

package net.jxta.impl.util;

// This class does not in itself allocate anything; it just does accounting.
// Its role is to make sure that resource consumers ("accounts")
// are garanteed to be able to hold a pre-determined number of items,
// the extra being granted on a first-come-first-serve basis.
// It just replies yes/no to an account that wants to allocate an item.
// Synchronizarion is external.
// Note that this is all essentialy a limitter device. It assumes
// that the resources that are dispatched in that way are not otherwise
// in short supply.
//
// The rules of the game are as follows:
// At initialization, an absolute maximum authorized number of items
// is computed. All item reservations and authorizations are done
// within this budget.
// At any given point in time, out of this maximum, a number of items are
// permanently reserved for the minimum garanteed to each current account,
// a number of items are set aside for future accounts garantee reservation,
// and the rest is open for dynamic attribution on a first come first serve
// basis.
// The current strategy is as follows:
//
// The initialization parameters are:
// - minimum number of garanteed accounts: minAccounts
// - minimum commitement to new accounts up to minAccounts: minReserve
// - maximum commitement to new accounts: maxReserve
// - extra number of dynamically allocatable items: extraItems
//
// We infer the number of items dedicated to reservation: reservedItems
// That is minReserve * minAccounts.
//
// Accounts can ask for a commitment in excess of minReserve. Any reservation
// made by an account beyond the minimum is satified from extraItems
// limitted by what's available and maxReserve. When minAccounts have
// registered, it is possible that reservedItems is exhausted. New accounts
// are then accepted on a best effort basis using extra items exclusively. This
// may cause such new accounts to be given a commitement inferior to minReserve,
// including zero. It is up to the account to reject the offer and give up
// by closing, or to go along with the offer. At this time, we do not try
// to raise the commitement made to an account while it is registered.
//
// During the life of the account, items are allocated first from the set
// reserved by this account. If the account is out of reserved items, an attempt
// is made at getting the item from extraItems.
//
// For each account we count the number of items reserved from reservedItems,
// reserved from extraItems, allocated from the local reserved items
// and allocated from extraItems separately. When an item is released, it is
// accounted to extraItems if the account had anything allocated from
// extra items, or to the local reserved items.
// When an account goes away, the number of items that were reserved from
// reserveItems go back to reserveItems and likewise for those comming
// from extraItems. This is done rather than giving priority to reserve
// items so that the system does not favor reservation beyond its initial
// parameters when an account goes away under load.
//
// When resources are scarce, two modes of operations are available.
// Unfair: each account keeps its items as long it has a use for them. If
// the allocation of a new item is denied for an account, the account just has
// to live with it and try again the next time more items are desired.
// RoundRobin: each account releases each item after one use. When allocation
// of a new item is denied for an account by reason of item shortage, the
// account is placed on a list of eligible accounts. Every time an item is
// released, it is re-assigned to the oldest eligible account.
// From an API point of view the difference is not visible: account users
// are advised to release items after one use. Release returns the account to
// which the item has been re-assigned. If RoundRobin is not used, then
// the item is always re-assigned to the account that releases it unless it
// is not needed, in which case it returns to the available pool.
// So, with round-robin off the following is true:
// a.releaseItem() == (a.needs ? a : null);

import org.apache.log4j.Category;
import org.apache.log4j.Priority;
import net.jxta.impl.util.ResourceAccount;
import java.util.LinkedList;

public class ResourceDispatcher {

    private final static Category LOG =
	Category.getInstance(ResourceDispatcher.class.getName());

    private long extraItems;
    private long reservedItems;
    private long maxReservedPerAccount;
    private long minReservedPerAccount;
    private long maxExtraPerAccount;
    private int nbEligibles;

    class ClientAccount extends Dlink implements ResourceAccount {

	/**
	 * Tells whether this account has any use for extra resources
	 * or not. This feature is required to support roundRobin mode
	 * properly when resources are scarce.
	 */
	private boolean needs;

	/**
	 * The number of items reserved for this account that may still be
	 * allocated. This decrements when we grant an item allocation. When
	 * it is <= 0, new items may be obtained from extraItems. If obtained
	 * we still decrement. When an item is released, if this counter is
	 * < 0 we return the item to extra items. This counter gets
	 * incremented either way.
	 */
	private long nbReserved; 

	/**
	 * The number out of nbReserved that is due back in reservedItems
	 * when this account disapears.
	 * The rest goes back to extraItems.
	 * NOTE: If we go away with items unaccounted for, we take the option
	 * of accouting them as allocated. In other words, that amount is
	 * not returned to its right full item account. That's why we do not
	 * need to keep track of allocated items. The leak is felt
	 * by this allocator. Alternatively we could pretend that the
	 * leaked resources are not ours; but that migh break the actual
	 * allocator of the resource if it relies on our accounting.
	 */
	private long fromReservedItems;

	/**
	 * Same idea but they have been reserved by reducing the number
	 * of extra items available.
	 */
	private long fromExtraItems;

	/**
	 * The limit for extra items allocation.
	 * When nbReserved is at or below that, extra items cannot be
	 * granted.
	 */
	private long extraLimit;

	/**
	 * The external object for which this account manages items.
	 * This is an opaque cookie to us. Whatever code invokes
	 * releaseItem knows what to do with it and the re-assigned item, but
	 * it needs to be told which of its own object got an item assigned.
	 */
	private Object userObject;

	/**
	 * Creates a client account with this resource manager.
	 * Not for external use.
	 * @param fromReservedItems
	 * @param fromExtraItems
	 * @param extraLimit
	 * @param userObject
	 */
	ClientAccount(long fromReservedItems, long fromExtraItems,
		      long extraLimit, Object userObject) {

	    this.nbReserved = fromReservedItems + fromExtraItems;
	    this.fromReservedItems = fromReservedItems;
	    this.fromExtraItems = fromExtraItems;
	    this.extraLimit = -extraLimit;
	    this.userObject = userObject;
	    this.needs = false;
	}

	/**
	 * Tear down this client account.
	 * Return reserved resources to the main pool.
	 * To accelerate return of resources to the global pool, one
	 * may call close() explicitly. Otherwise it is called by finalize.
	 * Calling close() or letting the account be GC'ed while some of the
	 * resources have not been returned is an error, may create a
	 * leak and may display a warning message.
	 */
	public void close() {
	    notEligible();
	    userObject = null;

	    if ((nbReserved == 0)
		&& (fromReservedItems == 0)
		&& (fromExtraItems == 0)) return;

	    if (nbReserved < (fromReservedItems + fromExtraItems)) {
		// !!! someone just gave up on its resource controler
		// without returning the resources !
		if (LOG.isEnabledFor(Priority.WARN)) {
		    LOG.warn("An account was abandonned with resources"
			     + " still allocated.");
		}

		// Release whatever we can.
		if (nbReserved >= fromReservedItems) {
		    releaseExtra(nbReserved - fromReservedItems);
		    releaseReserved(fromReservedItems);
		} else if (nbReserved > 0) {
		    releaseReserved(nbReserved);
		}

	    } else {
		releaseReserved(fromReservedItems);
		releaseExtra(fromExtraItems);
	    }

	    nbReserved = fromReservedItems = fromExtraItems = 0;
	}

	/**
	 * Will close the account.
	 * (close is idempotent).
	 */
	public void finalize() {
	    close();
	}

	/**
	 * Tells if this account is idle (that is, none of the resources
	 * that it controls are currently in use). This means it can be closed
	 * safely.
	 */
	public boolean isIdle() {
	    return (nbReserved == fromExtraItems + fromReservedItems);
	}

	public boolean isEligible() {
	    return isLinked();
	}

	/**
	 * Put that account in the queue of accounts elligible to
	 * receive a resource when one becomes available.
	 */
	public void beEligible() {
	    if ((eligibles != null) && ! isEligible()) newEligible(this);
	}

	/**
	 * Remove that account from the queue of accounts elligible to
	 * receive a resource when one becomes available.
	 */
	public void notEligible() {
	    if ((eligibles != null) && isEligible()) unEligible(this);
	}

	// An extra item is being granted to this account (by being reassigned
	// from another account upon release).
	private void granted() {

	    // In theory, there cannot be an account that should NOT be granted
	    // an item in the eligibles list. For now, check whether the theory
	    // survives observations.
	    // It could happen that the need flag was turned off while this
	    // account was in the eligible list. That's not realy a problem.
	    // Either it will be released immediately, or we could filter
	    // it in mostEligible().
	    if (LOG.isEnabledFor(Priority.WARN)) {
		if (nbReserved <= extraLimit) {
		    LOG.warn("An account that should not get an item" +
			     " was found in the eligibles list");
		}
	    }

	    --nbReserved;

	    // We've been assigned an item. No-longer eligible.
	    notEligible();
        }

	/**
	 * Try and grant a certain quantity.
	 *
	 * It is usefull to manage the allocation of variable sized aggregates
	 * when what matters is the cummulated quantity rather than an item
	 * count. Quantity could be a number of bytes needed to store
	 * something for example. The advantage of using this method rather
	 * than obtainItem repeatedly is that it is obvisouly faster if
	 * quantity is more than one or two, and also that it is atomic;
	 * the entire quantity is either granted or denied.
	 * Using this routine is by definition incompatible with the round-robin
	 * mode, which could only re-assign quantities of 1.
	 *
	 * It is legal to use this routine along with round-robin mode if the
	 * same dispatcher is used to manage quantities of 1 in this manner,
	 * but an account that has failed to obtain its desired quantity is
	 * not queued for later re-assignment. And items released with
	 * releaseQuantity() are not re-assigned, so overall it is
	 * probably best to not mix the two.
	 *
	 * @param number The number of units wanted. The unit is harbitrary
	 * It is only meaningfull to the code that uses this dispatcher.
	 * @return boolean whether the requested quantity is authorized.
	 */
	public boolean obtainQuantity(long quantity) {

	    if ((nbReserved - quantity) < extraLimit) {
		// That's asking too much. Denied.
		return false;
	    }

	    if (quantity > nbReserved) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -