📄 resourcedispatcher.java
字号:
long res = holdExtra(toAsk); if (res != toAsk) { // Could not get enough. We got nothing. releaseExtra(res); return false; } } // Now record it. nbReserved -= quantity; if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { if (nbReserved > fromReservedItems + fromExtraItems) { LOG.severe("Incorrect values after obtaining " + quantity + " : [" + this + "]"); } } return true; } /** * {@inheritDoc} */ public boolean obtainItem() { // Set it for consistency. It will get cleared when // the item is used to satisfy the need. needs = true; if (nbReserved > 0) { notEligible(); --nbReserved; return true; // Its pre-reserved. } // This account may deliberately limit the number of extra // items it uses. this translates into a lower limit for // nbReserved when <= 0. if (nbReserved <= extraLimit) { notEligible(); return false; } if (holdExtra(1) == 1) { // Need authorization. notEligible(); --nbReserved; return true; } // We are out of luck but eligible. beEligible(); return false; } /** * {@inheritDoc} */ public void releaseQuantity(long quantity) { if (nbReserved < 0) { releaseExtra(quantity < -nbReserved ? quantity : -nbReserved); } nbReserved += quantity; if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) { if (nbReserved > fromReservedItems + fromExtraItems) { LOG.severe("Incorrect values after releasing " + quantity + " : [" + this + "]"); } } } /** * {@inheritDoc} */ public ResourceAccount releaseItem() { if (nbReserved < 0) { if (eligibles == null) { // RoundRobin is OFF either we reuse it or we let // it go. if (needs) { return this; } ++nbReserved; releaseExtra(1); return null; } // RoundRobin is ON, we compete with others for this item. ++nbReserved; // Update our eligibility which depends on extraLimit and // whether we have a use for the item or not. if ((nbReserved > extraLimit) && needs) { beEligible(); } ClientAccount next = mostEligible(); if (next == null) { releaseExtra(1); // noone wants it. return to main pool } else { next.granted(); } return next; } // Since we are (back) in our reserved range, we can't be eligible // for extra. notEligible(); // In reserved range; we keep using the item if we need it. if (needs) { return this; } ++nbReserved; return null; } /** * {@inheritDoc} */ public void inNeed(boolean needs) { this.needs = needs; if ((nbReserved < 0) && (nbReserved > extraLimit) && needs) { beEligible(); } else { notEligible(); } } /** * {@inheritDoc} */ public Object getUserObject() { return userObject; } /** * {@inheritDoc} */ public void setUserObject(Object object) { userObject = object; } /** * {@inheritDoc} */ public long getNbReserved() { return nbReserved; } /** * {@inheritDoc} * * <p/>Returns some human-readable status and identity information useful for debugging. */ @Override public String toString() { return super.toString() + " : needs=" + needs + " nbReserved=" + nbReserved + " fromReservedItems=" + fromReservedItems + " fromExtraItems=" + fromExtraItems + " extraLimit=" + extraLimit; } } /** * The list of eligible accounts. */ private Dlist eligibles; /** * Construct a Fair Resource Allocator with the given parameters: * @param minAccounts The minimum number of client accounts that we want to * guarantee we can handle. <0 means 0 * * @param minReservedPerAccount The minimum reservation request that we will * always grant to accounts as long as we have less than minAccounts <0 means * 0. * @param maxReservedPerAccount The maximum reservation request that we ever * will grant to any given account. <minReservedPerAccount means == * @param extraItems The total number of items that we will authorize * beyond what has been reserved. <0 means 0. * @param maxExtraPerAccount The maximum number of extra items we will ever * let any given account occupy. <0 or >extraItems means ==extraItems. * @param minExtraPoolSize The number of extra items that can never be * taken out of the extra pool to satisfy a reservation request. * @param roundRobin If true, when there is no items available, all * eligible accounts are put in a FIFO. Accounts release items often, and the * oldest account in the FIFO will get it. If false, accounts always keep * items for as long as they can use them, and there is no FIFO of eligible * accounts. Accounts can obtain new resources only if available at the time * they try to aquire it. RoundRobin is more fair but has more overhead. * Neither mode will cause starvation as long as accounts reserve at least * one item each. RoundRobin is most useful when allocating threads. */ public ResourceDispatcher(long minAccounts, long minReservedPerAccount, long maxReservedPerAccount, long extraItems, long maxExtraPerAccount, long minExtraPoolSize, boolean roundRobin, String dispatcherName) { if (minAccounts < 0) { minAccounts = 0; } if (minReservedPerAccount < 0) { minReservedPerAccount = 0; } if (maxReservedPerAccount < minReservedPerAccount) { maxReservedPerAccount = minReservedPerAccount; } if (extraItems < 0) { extraItems = 0; } if (minExtraPoolSize < 0) { minExtraPoolSize = 0; } if ((maxExtraPerAccount < 0) || (maxExtraPerAccount > extraItems)) { maxExtraPerAccount = extraItems; } this.extraItems = extraItems; this.minExtraPoolSize = minExtraPoolSize; this.maxReservedPerAccount = maxReservedPerAccount; this.minReservedPerAccount = minReservedPerAccount; this.reservedItems = minAccounts * minReservedPerAccount; this.maxExtraPerAccount = maxExtraPerAccount; nbEligibles = 0; if (roundRobin) { eligibles = new Dlist(); } this.myName = dispatcherName; } private long holdReserved(long req) { if (req > reservedItems) { req = reservedItems; } reservedItems -= req; return req; } private void releaseReserved(long nb) { reservedItems += nb; } private long holdExtra(long req) { if (req > extraItems) { req = extraItems; } extraItems -= req; return req; } // Get items from the extra pool but only if there is at least // minExtraPoolSize item // left after that. The goal is to make sure we keep at least one // un-reserved item when granting reserved items from the extra pool. // Thanks to that, even accounts that could not get a single reserved // item still stand a chance to make progress by taking turns using // the one extra item left. private long holdExtraKeepSome(long req) { if (extraItems <= minExtraPoolSize) { return 0; } long allowed = extraItems - minExtraPoolSize; if (req > allowed) { req = allowed; } extraItems -= req; return req; } private void releaseExtra(long nb) { extraItems += nb; } private void newEligible(ClientAccount account) { ++nbEligibles; eligibles.putLast(account); } private ClientAccount mostEligible() { if (nbEligibles == 0) { return null; } return (ClientAccount) eligibles.getFirst(); } private void unEligible(ClientAccount account) { --nbEligibles; account.unlink(); } // Not synch; it's just a snapshot for trace purposes. public int getNbEligibles() { return nbEligibles; } /** * Creates and returns a new client account. * * @param nbReq the number of reserved items requested (may not be * always granted in full). A negative value is taken to mean 0. * @param maxExtra the number of additional items that this account * authorizes to be allocated in addition to the reserved ones. This * is typically useful if the items are threads and if some accounts * are not re-entrant. Then nbReq would be 1 and maxExtra would be 0. * It is also permitted to have some accounts receive no items at all * ever by setting nbReq and maxExtra both to zero. A negative maxExtra * is taken as meaning no specified limit, in which case an actual limit * may be set silently. * @param userObject An opaque cookie that the account object will return * when requested. This is useful to relate an account returned by * ClientAccount.releaseItem() to an invoking code relevant object. * @return ResourceAccount An account with this allocator. */ public ResourceAccount newAccount(long nbReq, long maxExtra, Object userObject) { long extra = 0; // reserved from extra pool long reserved = 0; // reserved from reserved pool if (nbReq > maxReservedPerAccount) { nbReq = maxReservedPerAccount; } // Anything beyond the minimum comes from extra items if there's // enough. if (nbReq > minReservedPerAccount) { extra = holdExtraKeepSome(nbReq - minReservedPerAccount); nbReq = minReservedPerAccount; } // Then the minimum comes from reserved items, if we can. reserved = holdReserved(nbReq); nbReq -= reserved; // If there's some letf to be had, it means that we're getting // short on reserved items, we'll try to compensate by getting // more items from extra, but the app should start getting rid // of stale accounts if it can. if (nbReq > 0) { if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) { LOG.info("Accepting extra account on a best effort basis."); } extra += holdExtraKeepSome(nbReq); if (extra + reserved < minReservedPerAccount) { // Even that was not enough to reach our minimal commitment. // The app should realy consider some cleanup. if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.warning("[" + myName + "] Accepting extra account with below-minimal commitment:[" + userObject + "]"); } } } if ((maxExtra > maxExtraPerAccount) || (maxExtra < 0)) { maxExtra = maxExtraPerAccount; } return new ClientAccount(reserved, extra, maxExtra, userObject); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -