]> sjero.net Git - linphone/blob - p2pproxy/dependencies-src/jxse-src-2.5/impl/src/net/jxta/impl/util/ResourceDispatcher.java
019ce2d0cdb8e5eb17ea27df58c0d321a5801e35
[linphone] / p2pproxy / dependencies-src / jxse-src-2.5 / impl / src / net / jxta / impl / util / ResourceDispatcher.java
1 /*
2  * Copyright (c) 2002-2007 Sun Microsystems, Inc.  All rights reserved.
3  *  
4  *  The Sun Project JXTA(TM) Software License
5  *  
6  *  Redistribution and use in source and binary forms, with or without 
7  *  modification, are permitted provided that the following conditions are met:
8  *  
9  *  1. Redistributions of source code must retain the above copyright notice,
10  *     this list of conditions and the following disclaimer.
11  *  
12  *  2. Redistributions in binary form must reproduce the above copyright notice, 
13  *     this list of conditions and the following disclaimer in the documentation 
14  *     and/or other materials provided with the distribution.
15  *  
16  *  3. The end-user documentation included with the redistribution, if any, must 
17  *     include the following acknowledgment: "This product includes software 
18  *     developed by Sun Microsystems, Inc. for JXTA(TM) technology." 
19  *     Alternately, this acknowledgment may appear in the software itself, if 
20  *     and wherever such third-party acknowledgments normally appear.
21  *  
22  *  4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must 
23  *     not be used to endorse or promote products derived from this software 
24  *     without prior written permission. For written permission, please contact 
25  *     Project JXTA at http://www.jxta.org.
26  *  
27  *  5. Products derived from this software may not be called "JXTA", nor may 
28  *     "JXTA" appear in their name, without prior written permission of Sun.
29  *  
30  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
32  *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN 
33  *  MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
34  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
35  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
36  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
37  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
38  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
39  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *  
41  *  JXTA is a registered trademark of Sun Microsystems, Inc. in the United 
42  *  States and other countries.
43  *  
44  *  Please see the license information page at :
45  *  <http://www.jxta.org/project/www/license.html> for instructions on use of 
46  *  the license in source files.
47  *  
48  *  ====================================================================
49  *  
50  *  This software consists of voluntary contributions made by many individuals 
51  *  on behalf of Project JXTA. For more information on Project JXTA, please see 
52  *  http://www.jxta.org.
53  *  
54  *  This license is based on the BSD license adopted by the Apache Foundation. 
55  */
56
57 package net.jxta.impl.util;
58
59
60 import java.util.LinkedList;
61
62 import java.util.logging.Logger;
63 import java.util.logging.Level;
64 import net.jxta.logging.Logging;
65
66 import net.jxta.impl.util.ResourceAccount;
67
68
69 /**
70  * This class does not in itself allocate anything; it just does accounting.
71  * Its role is to make sure that resource consumers ("accounts")
72  * are guaranteed to be able to hold a pre-determined number of items,
73  * the extra being granted on a first-come-first-serve basis.
74  * It just replies yes/no to an account that wants to allocate an item.
75  * Synchronization is external.
76  *
77  * <p/><em>Note that this is all essentially a limiter device. It assumes
78  * that the resources that are dispatched in that way are not otherwise
79  * in short supply.</em>
80  *
81  * <p/>The rules of the game are as follows:
82  * <p/>At initialization, an absolute maximum authorized number of items
83  * is computed. All item reservations and authorizations are done
84  * within this budget.
85  * <p/>At any given point in time, out of this maximum, a number of items are
86  * permanently reserved for the minimum guaranteed to each current account,
87  * a number of items are set aside for future accounts guarantee reservation,
88  * and the rest is open for dynamic attribution on a first come first serve
89  * basis.
90  *
91  * <p/>The current strategy is as follows:
92  *
93  * The initialization parameters are:<ul>
94  * <li>minimum number of guaranteed accounts: {@code minAccounts}</li>
95  * <li>minimum commitment to new accounts up to minAccounts: {@code minReserve}</li>
96  * <li>maximum commitment to new accounts: {@code maxReserve}</li>
97  * <li>extra number of dynamically allocatable items: {@code extraItems}</li>
98  * </ul>
99  *
100  * <p/>We infer the number of items dedicated to reservation: {@code reservedItems}
101  * That is {@code minReserve * minAccounts}.
102  *
103  * <p/>Accounts can ask for a commitment in excess of minReserve. Any reservation
104  * made by an account beyond the minimum is satisfied from extraItems
105  * limited by what's available and maxReserve. When minAccounts have
106  * registered, it is possible that reservedItems is exhausted. New accounts
107  * are then accepted on a best effort basis using extra items exclusively. This
108  * may cause such new accounts to be given a commitment inferior to minReserve,
109  * including zero. It is up to the account to reject the offer and give up
110  * by closing, or to go along with the offer. At this time, we do not try
111  * to raise the commitment made to an account while it is registered.
112  *
113  * <p/>During the life of the account, items are allocated first from the set
114  * reserved by this account. If the account is out of reserved items, an attempt
115  * is made at getting the item from extraItems.
116  *
117  * <p/>For each account we count the number of items reserved from reservedItems,
118  * reserved from extraItems, allocated from the local reserved items
119  * and allocated from extraItems separately. When an item is released, it is
120  * accounted to extraItems if the account had anything allocated from
121  * extra items, or to the local reserved items.
122  * When an account goes away, the number of items that were reserved from
123  * reserveItems go back to reserveItems and likewise for those coming
124  * from extraItems. This is done rather than giving priority to reserve
125  * items so that the system does not favor reservation beyond its initial
126  * parameters when an account goes away under load.
127  *
128  * <p/>When resources are scarce, two modes of operations are available.
129  * <dl>
130  * <dt>Unfair</dt>
131  * <dd>each account keeps its items as long it has a use for them. If
132  * the allocation of a new item is denied for an account, the account just has
133  * to live with it and try again the next time more items are desired.
134  * <dd>
135  * <dt>RoundRobin<dt>
136  * <dd>Each account releases each item after one use. When allocation
137  * of a new item is denied for an account by reason of item shortage, the
138  * account is placed on a list of eligible accounts. Every time an item is
139  * released, it is re-assigned to the oldest eligible account.
140  * </dd>
141  * </dl>
142  * <p/>From an API point of view the difference is not visible: account users
143  * are advised to release items after one use. Release returns the account to
144  * which the item has been re-assigned. If RoundRobin is not used, then
145  * the item is always re-assigned to the account that releases it unless it
146  * is not needed, in which case it returns to the available pool.
147  * So, with round-robin off the following is true:
148  * <pre>
149  * a.releaseItem() == (a.needs ? a : null);
150  * </pre>
151  */
152
153 public class ResourceDispatcher {
154     
155     /**
156      *  Logger
157      */
158     private final static transient Logger LOG = Logger.getLogger(ResourceDispatcher.class.getName());
159     
160     private long extraItems;
161     private long reservedItems;
162     private final long maxReservedPerAccount;
163     private final long minReservedPerAccount;
164     private final long maxExtraPerAccount;
165     private final long minExtraPoolSize;
166     private int nbEligibles;
167     
168     private final String myName;
169     
170     class ClientAccount extends Dlink implements ResourceAccount {
171         
172         /**
173          * Tells whether this account has any use for extra resources
174          * or not. This feature is required to support roundRobin mode
175          * properly when resources are scarce.
176          */
177         private boolean needs;
178         
179         /**
180          * The number of items reserved for this account that may still be
181          * allocated. This decrements when we grant an item allocation. When
182          * it is <= 0, new items may be obtained from extraItems. If obtained
183          * we still decrement. When an item is released, if this counter is
184          * < 0 we return the item to extra items. This counter gets
185          * incremented either way.
186          */
187         private long nbReserved;
188         
189         /**
190          * The number out of nbReserved that is due back in reservedItems
191          * when this account disappears.
192          * The rest goes back to extraItems.
193          * NOTE: If we go away with items unaccounted for, we take the option
194          * of accounting them as allocated. In other words, that amount is
195          * not returned to its right full item account. That's why we do not
196          * need to keep track of allocated items. The leak is felt
197          * by this allocator. Alternatively we could pretend that the
198          * leaked resources are not ours; but that might break the actual
199          * allocator of the resource if it relies on our accounting.
200          */
201         private long fromReservedItems;
202         
203         /**
204          * Same idea but they have been reserved by reducing the number
205          * of extra items available.
206          */
207         private final long fromExtraItems;
208         
209         /**
210          * The limit for extra items allocation.
211          * When nbReserved is at or below that, extra items cannot be
212          * granted.
213          */
214         private final long extraLimit;
215         
216         /**
217          * The external object for which this account manages items.
218          * This is an opaque cookie to us. Whatever code invokes
219          * releaseItem knows what to do with it and the re-assigned item, but
220          * it needs to be told which of its own object got an item assigned.
221          */
222         private Object userObject;
223         
224         /**
225          * Creates a client account with this resource manager.
226          * Not for external use.
227          * @param fromReservedItems
228          * @param fromExtraItems
229          * @param extraLimit
230          * @param userObject
231          */
232         ClientAccount(long fromReservedItems, long fromExtraItems, long extraLimit, Object userObject) {
233             
234             this.nbReserved = fromReservedItems + fromExtraItems;
235             this.fromReservedItems = fromReservedItems;
236             this.fromExtraItems = fromExtraItems;
237             this.extraLimit = -extraLimit;
238             this.userObject = userObject;
239             this.needs = false;
240         }
241         
242         /**
243          * {@inheritDoc}
244          *
245          * <p/>To accelerate return of resources to the global pool, one
246          * may call close() explicitly. Otherwise it is called by
247          * {@code finalize}.
248          *
249          * <p/>Calling close() or letting the account be GC'ed while some of the
250          * resources have not been returned is an error, may create a leak and
251          * may display a warning message.
252          */
253         public void close() {
254             notEligible();
255             userObject = null;
256             
257             if ((nbReserved == 0) && (fromReservedItems == 0) && (fromExtraItems == 0)) {
258                 return;
259             }
260             
261             if (nbReserved < (fromReservedItems + fromExtraItems)) {
262                 // !!! someone just gave up on its resource controller
263                 // without returning the resources !
264                 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
265                     LOG.warning("An account was abandoned with resources still allocated.");
266                 }
267                 
268                 // Release whatever we can.
269                 if (nbReserved >= fromReservedItems) {
270                     releaseExtra(nbReserved - fromReservedItems);
271                     releaseReserved(fromReservedItems);
272                 } else if (nbReserved > 0) {
273                     releaseReserved(nbReserved);
274                 }
275                 
276             } else {
277                 releaseReserved(fromReservedItems);
278                 releaseExtra(fromExtraItems);
279             }
280             
281             nbReserved = 0;
282         }
283         
284         /**
285          *  {@inheritDoc}
286          *
287          *  <p/>Will close the account. (close is idempotent).
288          */
289         @Override
290         protected void finalize() throws Throwable {
291             close();
292             
293             super.finalize();
294         }
295         
296         /**
297          *  {@inheritDoc}
298          */
299         public boolean isIdle() {
300             return (nbReserved == fromExtraItems + fromReservedItems);
301         }
302         
303         public boolean isEligible() {
304             return isLinked();
305         }
306         
307         /**
308          * Put that account in the queue of accounts eligible to
309          * receive a resource when one becomes available.
310          */
311         public void beEligible() {
312             if ((eligibles != null) && !isEligible()) {
313                 newEligible(this);
314             }
315         }
316         
317         /**
318          * Remove that account from the queue of accounts eligible to
319          * receive a resource when one becomes available.
320          */
321         public void notEligible() {
322             if ((eligibles != null) && isEligible()) {
323                 unEligible(this);
324             }
325         }
326         
327         // An extra item is being granted to this account (by being reassigned
328         // from another account upon release).
329         private void granted() {
330             
331             // In theory, there cannot be an account that should NOT be granted
332             // an item in the eligibles list. For now, check whether the theory
333             // survives observations.
334             // It could happen that the need flag was turned off while this
335             // account was in the eligible list. That's not realy a problem.
336             // Either it will be released immediately, or we could filter
337             // it in mostEligible().
338             if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
339                 if (nbReserved <= extraLimit) {
340                     LOG.warning("An account that should not get an item was found in the eligibles list");
341                 }
342             }
343             
344             --nbReserved;
345             
346             // We've been assigned an item. No-longer eligible.
347             notEligible();
348         }
349         
350         /**
351          * {@inheritDoc}
352          */
353         public boolean obtainQuantity(long quantity) {
354             
355             if ((nbReserved - quantity) < extraLimit) {
356                 // That's asking too much. Denied.
357                 return false;
358             }
359             
360             if (quantity > nbReserved) {
361                 // We need to get some or all of it from the extra items.
362                 long toAsk = nbReserved > 0 ? quantity - nbReserved : quantity;
363                 long res = holdExtra(toAsk);
364
365                 if (res != toAsk) {
366                     // Could not get enough. We got nothing.
367                     releaseExtra(res);
368                     return false;
369                 }
370             }
371             
372             // Now record it.
373             nbReserved -= quantity;
374             
375             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
376                 if (nbReserved > fromReservedItems + fromExtraItems) {
377                     LOG.severe("Incorrect values after obtaining " + quantity + " : [" + this + "]");
378                 }
379             }
380             
381             return true;
382         }
383         
384         /**
385          * {@inheritDoc}
386          */
387         public boolean obtainItem() {
388             
389             // Set it for consistency. It will get cleared when
390             // the item is used to satisfy the need.
391             needs = true;
392             
393             if (nbReserved > 0) {
394                 notEligible();
395                 --nbReserved;
396                 return true; // Its pre-reserved.
397             }
398             
399             // This account may deliberately limit the number of extra
400             // items it uses. this translates into a lower limit for
401             // nbReserved when <= 0.
402             if (nbReserved <= extraLimit) {
403                 notEligible();
404                 return false;
405             }
406             
407             if (holdExtra(1) == 1) { // Need authorization.
408                 notEligible();
409                 --nbReserved;
410                 return true;
411             }
412             
413             // We are out of luck but eligible.
414             beEligible();
415             return false;
416         }
417         
418         /**
419          * {@inheritDoc}
420          */
421         public void releaseQuantity(long quantity) {
422             if (nbReserved < 0) {
423                 releaseExtra(quantity < -nbReserved ? quantity : -nbReserved);
424             }
425             nbReserved += quantity;
426             if (Logging.SHOW_SEVERE && LOG.isLoggable(Level.SEVERE)) {
427                 if (nbReserved > fromReservedItems + fromExtraItems) {
428                     LOG.severe("Incorrect values after releasing " + quantity + " : [" + this + "]");
429                 }
430             }
431         }
432         
433         /**
434          *  {@inheritDoc}
435          */
436         public ResourceAccount releaseItem() {
437             if (nbReserved < 0) {
438                 if (eligibles == null) {
439                     // RoundRobin is OFF either we reuse it or we let
440                     // it go.
441                     if (needs) {
442                         return this;
443                     }
444                     
445                     ++nbReserved;
446                     releaseExtra(1);
447                     return null;
448                 }
449                 
450                 // RoundRobin is ON, we compete with others for this item.
451                 ++nbReserved;
452                 
453                 // Update our eligibility which depends on extraLimit and
454                 // whether we have a use for the item or not.
455                 if ((nbReserved > extraLimit) && needs) {
456                     beEligible();
457                 }
458                 
459                 ClientAccount next = mostEligible();
460                 
461                 if (next == null) {
462                     releaseExtra(1); // noone wants it. return to main pool
463                 } else {
464                     next.granted();
465                 }
466                 return next;
467             }
468             
469             // Since we are (back) in our reserved range, we can't be eligible
470             // for extra.
471             notEligible();
472             
473             // In reserved range; we keep using the item if we need it.
474             if (needs) {
475                 return this;
476             }
477             
478             ++nbReserved;
479             return null;
480         }
481         
482         /**
483          *  {@inheritDoc}
484          */
485         public void inNeed(boolean needs) {
486             this.needs = needs;
487             if ((nbReserved < 0) && (nbReserved > extraLimit) && needs) {
488                 beEligible();
489             } else {
490                 notEligible();
491             }
492         }
493         
494         /**
495          *  {@inheritDoc}
496          */
497         public Object getUserObject() {
498             return userObject;
499         }
500         
501         /**
502          *  {@inheritDoc}
503          */
504         public void setUserObject(Object object) {
505             userObject = object;
506         }
507         
508         /**
509          *  {@inheritDoc}
510          */
511         public long getNbReserved() {
512             return nbReserved;
513         }
514         
515         /**
516          *  {@inheritDoc}
517          *
518          *  <p/>Returns some human-readable status and identity information useful for debugging.
519          */
520         @Override
521         public String toString() {
522             return super.toString() + " : needs=" + needs + " nbReserved=" + nbReserved + " fromReservedItems="
523                     + fromReservedItems + " fromExtraItems=" + fromExtraItems + " extraLimit=" + extraLimit;
524         }
525         
526     }
527     
528     /**
529      * The list of eligible accounts.
530      */
531     private Dlist eligibles;
532     
533     /**
534      * Construct a Fair Resource Allocator with the given parameters:
535      * @param minAccounts The minimum number of client accounts that we want to
536      * guarantee we can handle. <0 means 0
537      *
538      * @param minReservedPerAccount The minimum reservation request that we will
539      * always grant to accounts as long as we have less than minAccounts <0 means
540      * 0.
541      * @param maxReservedPerAccount The maximum reservation request that we ever
542      * will grant to any given account. <minReservedPerAccount means ==
543      * @param extraItems The total number of items that we will authorize
544      * beyond what has been reserved. <0 means 0.
545      * @param maxExtraPerAccount The maximum number of extra items we will ever
546      * let any given account occupy. <0 or >extraItems means ==extraItems.
547      * @param minExtraPoolSize The number of extra items that can never be
548      * taken out of the extra pool to satisfy a reservation request.
549      * @param roundRobin If true, when there is no items available, all
550      * eligible accounts are put in a FIFO. Accounts release items often, and the
551      * oldest account in the FIFO will get it. If false, accounts always keep
552      * items for as long as they can use them, and there is no FIFO of eligible
553      * accounts. Accounts can obtain new resources only if available at the time
554      * they try to aquire it. RoundRobin is more fair but has more overhead.
555      * Neither mode will cause starvation as long as accounts reserve at least
556      * one item each. RoundRobin is most useful when allocating threads.
557      */
558     public ResourceDispatcher(long minAccounts, long minReservedPerAccount, long maxReservedPerAccount, long extraItems, long maxExtraPerAccount, long minExtraPoolSize, boolean roundRobin, String dispatcherName) {
559         if (minAccounts < 0) {
560             minAccounts = 0;
561         }
562         if (minReservedPerAccount < 0) {
563             minReservedPerAccount = 0;
564         }
565         if (maxReservedPerAccount < minReservedPerAccount) {
566             maxReservedPerAccount = minReservedPerAccount;
567         }
568         if (extraItems < 0) {
569             extraItems = 0;
570         }
571         if (minExtraPoolSize < 0) {
572             minExtraPoolSize = 0;
573         }
574         
575         if ((maxExtraPerAccount < 0) || (maxExtraPerAccount > extraItems)) {
576             maxExtraPerAccount = extraItems;
577         }
578         
579         this.extraItems = extraItems;
580         this.minExtraPoolSize = minExtraPoolSize;
581         this.maxReservedPerAccount = maxReservedPerAccount;
582         this.minReservedPerAccount = minReservedPerAccount;
583         this.reservedItems = minAccounts * minReservedPerAccount;
584         this.maxExtraPerAccount = maxExtraPerAccount;
585         nbEligibles = 0;
586         if (roundRobin) {
587             eligibles = new Dlist();
588         }
589         
590         this.myName = dispatcherName;
591     }
592     
593     private long holdReserved(long req) {
594         if (req > reservedItems) {
595             req = reservedItems;
596         }
597         reservedItems -= req;
598         return req;
599     }
600     
601     private void releaseReserved(long nb) {
602         reservedItems += nb;
603     }
604     
605     private long holdExtra(long req) {
606         if (req > extraItems) {
607             req = extraItems;
608         }
609         extraItems -= req;
610         return req;
611     }
612     
613     // Get items from the extra pool but only if there is at least
614     // minExtraPoolSize item
615     // left after that. The goal is to make sure we keep at least one
616     // un-reserved item when granting reserved items from the extra pool.
617     // Thanks to that, even accounts that could not get a single reserved
618     // item still stand a chance to make progress by taking turns using
619     // the one extra item left.
620     private long holdExtraKeepSome(long req) {
621         if (extraItems <= minExtraPoolSize) {
622             return 0;
623         }
624         long allowed = extraItems - minExtraPoolSize;
625
626         if (req > allowed) {
627             req = allowed;
628         }
629         extraItems -= req;
630         return req;
631     }
632     
633     private void releaseExtra(long nb) {
634         extraItems += nb;
635     }
636     
637     private void newEligible(ClientAccount account) {
638         ++nbEligibles;
639         eligibles.putLast(account);
640     }
641     
642     private ClientAccount mostEligible() {
643         if (nbEligibles == 0) {
644             return null;
645         }
646         return (ClientAccount) eligibles.getFirst();
647     }
648     
649     private void unEligible(ClientAccount account) {
650         --nbEligibles;
651         account.unlink();
652     }
653     
654     // Not synch; it's just a snapshot for trace purposes.
655     public int getNbEligibles() {
656         return nbEligibles;
657     }
658     
659     /**
660      * Creates and returns a new client account.
661      *
662      * @param nbReq the number of reserved items requested (may not be
663      * always granted in full). A negative value is taken to mean 0.
664      * @param maxExtra the number of additional items that this account
665      * authorizes to be allocated in addition to the reserved ones. This
666      * is typically useful if the items are threads and if some accounts
667      * are not re-entrant. Then nbReq would be 1 and maxExtra would be 0.
668      * It is also permitted to have some accounts receive no items at all
669      * ever by setting nbReq and maxExtra both to zero. A negative maxExtra
670      * is taken as meaning no specified limit, in which case an actual limit
671      * may be set silently.
672      * @param userObject An opaque cookie that the account object will return
673      * when requested. This is useful to relate an account returned by
674      * ClientAccount.releaseItem() to an invoking code relevant object.
675      * @return ResourceAccount An account with this allocator.
676      */
677     public ResourceAccount newAccount(long nbReq, long maxExtra, Object userObject) {
678         
679         long extra = 0; // reserved from extra pool
680         long reserved = 0; // reserved from reserved pool
681         
682         if (nbReq > maxReservedPerAccount) {
683             nbReq = maxReservedPerAccount;
684         }
685         
686         // Anything beyond the minimum comes from extra items if there's
687         // enough.
688         if (nbReq > minReservedPerAccount) {
689             extra = holdExtraKeepSome(nbReq - minReservedPerAccount);
690             nbReq = minReservedPerAccount;
691         }
692         
693         // Then the minimum comes from reserved items, if we can.
694         reserved = holdReserved(nbReq);
695         nbReq -= reserved;
696         
697         // If there's some letf to be had, it means that we're getting
698         // short on reserved items, we'll try to compensate by getting
699         // more items from extra, but the app should start getting rid
700         // of stale accounts if it can.
701         if (nbReq > 0) {
702             if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
703                 LOG.info("Accepting extra account on a best effort basis.");
704             }
705             
706             extra += holdExtraKeepSome(nbReq);
707             if (extra + reserved < minReservedPerAccount) {
708                 // Even that was not enough to reach our minimal commitment.
709                 // The app should realy consider some cleanup.
710                 if (Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) {
711                     LOG.warning("[" + myName + "] Accepting extra account with below-minimal commitment:[" + userObject + "]");
712                 }
713             }
714         }
715         
716         if ((maxExtra > maxExtraPerAccount) || (maxExtra < 0)) {
717             maxExtra = maxExtraPerAccount;
718         }
719         
720         return new ClientAccount(reserved, extra, maxExtra, userObject);
721     }
722 }