001 package edu.nrao.sss.model.resource.evla; 002 003 import java.util.ArrayList; 004 import java.util.HashMap; 005 import java.util.HashSet; 006 import java.util.List; 007 import java.util.Map; 008 009 import javax.xml.bind.annotation.XmlAttribute; 010 import javax.xml.bind.annotation.XmlElement; 011 012 import edu.nrao.sss.model.resource.CorrelationProductGroup; 013 import edu.nrao.sss.model.resource.CorrelatorBaseband; 014 import edu.nrao.sss.model.resource.CorrelatorSubband; 015 016 /** 017 * The complete collection of baseline board pairs for the WIDAR correlator. 018 * <p> 019 * <b>Version Info:</b> 020 * <table style="margin-left:2em"> 021 * <tr><td>$Revision: 2298 $</td></tr> 022 * <tr><td>$Date: 2009-05-13 16:26:11 -0600 (Wed, 13 May 2009) $</td></tr> 023 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 024 * </table></p> 025 * 026 * @author David M. Harland 027 * @since 2009-02-20 028 */ 029 @javax.xml.bind.annotation.XmlRootElement 030 public class BlbpPool 031 { 032 private static final int WIDAR_BLBP_COUNT = 64; 033 034 private EvlaWidarConfiguration poolOwner; 035 036 //Key is UUID of WidarCorrelationProductGroup, 037 //value is # of BLBPs owned by that group. 038 private Map<String, Integer> blbpOwners; 039 040 /** 041 * Creates a new pool for the given owner. 042 * @param ownerOfThisPool the owner of this pool 043 */ 044 BlbpPool(EvlaWidarConfiguration ownerOfThisPool) 045 { 046 poolOwner = ownerOfThisPool; 047 blbpOwners = new HashMap<String, Integer>(); 048 } 049 050 @SuppressWarnings("unused") //Used by JAXB and maybe Hibernate 051 private BlbpPool() { this(null); } 052 053 /** Intended for the sole use of <tt>EvlaWidarConfiguration</tt>. */ 054 void setPoolOwner(EvlaWidarConfiguration ownerOfThisPool) 055 { 056 poolOwner = ownerOfThisPool; 057 } 058 059 //============================================================================ 060 // ALLOCATING & RECLAIMING BLBPs 061 //============================================================================ 062 063 /** 064 * Attempts to add the given number of BLBPs to {@code owner}. 065 * <p> 066 * The number of BLBPs allocated will be such that the total number of 067 * BLBPs owned by {@code owner} after allocation will be the largest 068 * valid number that is less than or equal to the desired new total. 069 * This is best explained via an example:</p> 070 * <blockquote> 071 * Let the valid total number of boards for owner be in the set 072 * {0, 4, 8, 12, 16}. Let the currently owned number be 8. 073 * If pairCount is 6, the desired new total is 14. However, 14 is 074 * not a valid value. The largest valid number that is less than 075 * or equal to 14 is 12, thus the value allocated, and returned by 076 * this method, is 4, not 6. 077 * </blockquote> 078 * <p> 079 * There is an interesting side effect possible if the requested number 080 * is a value smaller than the increment between valid values:</p> 081 * <blockquote> 082 * Using the set of valid totals from the previous example, 083 * let the currently owned number be the illegal value of 6. 084 * (This is possible when the properties of the owner change without 085 * this pool's awareness.) 086 * If pairCount is 1, the desired new total is 7. However, 7 is 087 * not a valid value. The largest valid number that is less than 088 * or equal to 7 is 4, thus the value allocated, and returned by 089 * this method, is -2, not 1. 090 * </blockquote> 091 * 092 * @param owner 093 * the proud new owner of some baseline board pairs. 094 * 095 * @param addlPairCount 096 * the desired number of <i>additional</i> BLBPs to allocate to 097 * {@code owner}. Negative values will be treated the same as a 098 * value of zero. 099 * 100 * @return 101 * the number of additional pairs actually allocated. 102 * This number could be less than {@code pairCount} if this pool 103 * is unable to meet the owner's request. 104 */ 105 int allocateAdditionalPairsTo(WidarCorrelationProductGroup owner, int addlPairCount) 106 { 107 int allocated = 0; 108 109 if (addlPairCount < 0) 110 addlPairCount = 0; 111 112 int currentlyOwned = getBlbpsOwnedBy(owner); 113 int newDesiredTotal = currentlyOwned + addlPairCount; 114 115 List<Integer> validTotals = getValidBlbpCounts(owner); 116 117 if (validTotals.contains(newDesiredTotal)) 118 { 119 allocated = addlPairCount; 120 } 121 else 122 { 123 //Find largest value <= desired 124 for (int i=validTotals.size()-1; i >= 0; i--) 125 { 126 int validTot = validTotals.get(i); 127 if (validTot <= newDesiredTotal) 128 allocated = validTot - currentlyOwned; 129 } 130 } 131 132 blbpOwners.put(owner.getUUID(), currentlyOwned + allocated); 133 134 return allocated; 135 } 136 137 /** 138 * Reclaims the given number of BLBPs currently held by {@code owner}. 139 * <p> 140 * The number of BLBPs reclaimed will be such that the total number of 141 * BLBPs owned by {@code owner} after reclamation will be the largest 142 * valid number that is less than or equal to the desired new total. 143 * This is best explained via an example:</p> 144 * <blockquote> 145 * Let the valid total number of boards for owner be in the set 146 * {0, 4, 8, 12, 16}. Let the currently owned number be 12. 147 * If pairCount is 5, the desired new total is 7. However, 7 is 148 * not a valid value. The largest valid number that is less than 149 * or equal to 7 is 4, thus the value reclaimed, and returned by 150 * this method, is 8, not 5. 151 * </blockquote> 152 * <p> 153 * There is an interesting side effect possible if the requested number 154 * is a value smaller than the increment between valid values:</p> 155 * <blockquote> 156 * Using the set of valid totals from the previous example, 157 * let the currently owned number be the illegal value of 11. 158 * (This is possible when the properties of the owner change without 159 * this pool's awareness.) 160 * If pairCount is 0, the desired new total is 11. However, 11 is 161 * not a valid value. The largest valid number that is less than 162 * or equal to 11 is 8, thus the value reclaimed, and returned by 163 * this method, is 3, not 0. 164 * </blockquote> 165 * 166 * @param owner 167 * a current owner of baseline board pairs. 168 * 169 * @param pairCount 170 * the number of BLBPs to reclaim. 171 * Negative values will be treated the same as a value of zero. 172 * 173 * @return 174 * the number of BLBPs reclaimed. This number could be more 175 * than {@code pairCount} if the desired new total is not a 176 * valid number. 177 */ 178 int reclaimPairsFrom(WidarCorrelationProductGroup owner, int pairCount) 179 { 180 int reclaimed = 0; 181 182 if (pairCount <= 0) 183 pairCount = 0; 184 185 int currentlyOwned = getBlbpsOwnedBy(owner); 186 int newDesiredTotal = currentlyOwned - pairCount; 187 188 if (newDesiredTotal <= 0) 189 { 190 reclaimed = reclaimPairsFrom(owner); 191 } 192 else 193 { 194 List<Integer> validTotals = getValidBlbpCounts(owner); 195 196 if (validTotals.contains(newDesiredTotal)) 197 { 198 reclaimed = pairCount; 199 } 200 else 201 { 202 //Find largest value <= desired 203 for (int i=validTotals.size()-1; i >= 0; i--) 204 { 205 int validTot = validTotals.get(i); 206 if (validTot <= newDesiredTotal) 207 reclaimed = currentlyOwned - validTot; 208 } 209 } 210 211 int newTotal = currentlyOwned - reclaimed; 212 213 if (newTotal <= 0) 214 blbpOwners.remove(owner.getUUID()); 215 else 216 blbpOwners.put(owner.getUUID(), newTotal); 217 } 218 219 return reclaimed; 220 } 221 222 /** 223 * Reclaims all the BLBPs currently held by {@code owner}. 224 * 225 * @param owner 226 * a current owner of baseline board pairs. 227 * 228 * @return 229 * the number of BLBPs reclaimed. 230 */ 231 int reclaimPairsFrom(WidarCorrelationProductGroup owner) 232 { 233 int reclaimed = getBlbpsOwnedBy(owner); 234 235 blbpOwners.remove(owner.getUUID()); 236 237 return reclaimed; 238 } 239 240 /** 241 * Compares the owners of the BLBPs to the set of valid potential owners 242 * and frees any fraudulently owned pairs. The set of valid owners 243 * comes from the owner of this pool. This method is useful when it 244 * appears that dead owners of BLBPs did not get a chance to release 245 * their BLBPs. 246 */ 247 public void clean() 248 { 249 if (poolOwner != null) 250 { 251 HashSet<String> validOwners = new HashSet<String>(); 252 253 //Put together a set of valid owner IDs 254 for (CorrelatorBaseband bb : poolOwner.getBasebands()) 255 for (CorrelatorSubband sb : bb.getSubbands()) 256 for (CorrelationProductGroup cpg : sb.getCorrelationProductGroups()) 257 validOwners.add(cpg.getUUID()); 258 259 //If a BLBP's owner is not in valid set, free it 260 for (String currOwner : blbpOwners.keySet()) 261 if (!validOwners.contains(currOwner)) 262 blbpOwners.remove(currOwner); 263 } 264 265 //TODO perhaps this method should also make sure the current totals 266 // are valid. Beware: if 64 SBs all went from 4-bit to 7-bit 267 // RQ, then pool is overallocated 268 } 269 270 //============================================================================ 271 // OWNERSHIP QUERIES 272 //============================================================================ 273 274 /** 275 * Returns a list of the number of BLBPs that may be owned by {@code owner}. 276 * Often the returned list will contain the integers zero through the number 277 * of unowned BLBPs. However, depending on the properties of {@code owner}, 278 * not all integral values in that range may be valid, and the maximum number 279 * might be something less than the total available. 280 * <p> 281 * The returned list is sorted from lowest to highest.</p> 282 * 283 * @param owner 284 * a potential owner of baseline board pairs. 285 * 286 * @return 287 * a list containing the valid numbers of BLBPs for the given owner. 288 */ 289 List<Integer> getValidBlbpCounts(WidarCorrelationProductGroup owner) 290 { 291 List<Integer> valid = new ArrayList<Integer>(); 292 293 //TODO temp simple logic here 294 // Need to: 295 // 1. DONE (was: add # owned by this group to total unowned) 296 // 2. consider amt owned by other groups in same baseband 297 // Rem: if > 4 BLBPs for 1 SB, sacrifice SBOIDs 298 int incr = getBlbpIncrement(owner); 299 int max = getBlbpsUnowned() + getBlbpsOwnedBy(owner); 300 for (int i = 0; i <= max; i += incr) 301 valid.add(i); 302 303 return valid; 304 } 305 306 /** 307 * Returns the smallest number of BLBPs that can be added to a subband 308 * that has the given requantization. 309 * 310 * @param rqBits 311 * the number of bits for the requantized signal. 312 * 313 * @return 314 * the BLBP increment for a subband with <tt>rqBits</tt>. 315 */ 316 private int getBlbpIncr(int rqBits) 317 { 318 int incr = 1; 319 320 if (rqBits == 7 && poolOwner != null && poolOwner.getMaxAntennaCount() > 16) 321 incr = 4; 322 323 return incr; 324 } 325 326 /** 327 * Returns the smallest number of BLBPs that should be added to <tt>owner's</tt> 328 * collection. For most owners this value is <i>one</i>. However, for owners 329 * who are part of a subband using 7-bit RQ and part of a configuration with 330 * more than 16 antennas, this value is <i>four</i>. 331 */ 332 int getBlbpIncrement(WidarCorrelationProductGroup owner) 333 { 334 WidarSubband sb = owner.getSubband(); 335 336 return sb == null ? 1 : getBlbpIncr(sb.getRequantization()); 337 } 338 339 /** 340 * Returns the number of baseline board pairs owned by {@code owner}. 341 * 342 * @param owner 343 * a potential owner of baseline board pairs. 344 * 345 * @return 346 * the number of baseline board pairs owned by {@code owner}. 347 */ 348 public int getBlbpsOwnedBy(WidarCorrelationProductGroup owner) 349 { 350 String key = owner.getUUID(); 351 352 return blbpOwners.containsKey(key) ? blbpOwners.get(key) : 0; 353 } 354 355 /** 356 * Returns the number of baseline board pairs owned by subbands. 357 * @return the number of BLBPs owned by subbands 358 */ 359 public int getBlbpsOwned() 360 { 361 clean(); 362 363 return tallyBlbpsOwned(); 364 } 365 366 private int tallyBlbpsOwned() 367 { 368 int owned = 0; 369 for (int i : blbpOwners.values()) 370 owned += i; 371 372 return owned; 373 } 374 375 /** 376 * Returns the number of baseline boards pairs currently unowned. 377 * @return the free number of BLBPs. 378 */ 379 public int getBlbpsUnowned() 380 { 381 return WIDAR_BLBP_COUNT - getBlbpsOwned(); 382 } 383 384 //============================================================================ 385 // PERSISTENCE HELPERS 386 //============================================================================ 387 388 @XmlElement(name="owner") 389 @SuppressWarnings("unused") //Used by JAXB 390 private PoolMember[] getOwners() 391 { 392 clean(); 393 394 int valueCount = blbpOwners.size(); 395 if (valueCount == 0) 396 return null; 397 398 PoolMember[] result = new PoolMember[valueCount]; 399 400 int e=0; 401 for (Map.Entry<String, Integer> owner : blbpOwners.entrySet()) 402 result[e++] = new PoolMember(owner.getKey(), owner.getValue()); 403 404 return result; 405 } 406 @SuppressWarnings("unused") //Used by JAXB 407 private void setOwners(PoolMember[] replacements) 408 { 409 blbpOwners.clear(); 410 for (PoolMember pm : replacements) 411 blbpOwners.put(pm.id, pm.blbpCount); 412 } 413 414 static class PoolMember 415 { 416 @XmlAttribute int blbpCount; 417 @XmlAttribute String id; 418 419 PoolMember() { this("",0); } 420 421 PoolMember(String key, int value) 422 { 423 this.id = key; 424 this.blbpCount = value; 425 } 426 } 427 428 //============================================================================ 429 // 430 //============================================================================ 431 /* 432 public static void main(String... args) throws Exception 433 { 434 BlbpPool pool = new BlbpPool(); 435 436 edu.nrao.sss.util.JaxbUtility jaxbUtil = new edu.nrao.sss.util.JaxbUtility(); 437 javax.xml.validation.Schema schema = jaxbUtil.getSchemaFor(BlbpPool.class); 438 java.io.Writer writer = new java.io.PrintWriter(System.out); 439 440 for (char c='a'; c <= 'm'; c++) 441 pool.blbpOwners.put(""+c, (int)(1+4*Math.random())); 442 443 try 444 { 445 jaxbUtil.writeObjectAsXmlTo(writer, pool, schema); 446 } 447 catch (Exception ex) 448 { 449 System.out.println("Trouble w/ src.toXml. Msg:"); 450 System.out.println(ex.getMessage()); 451 ex.printStackTrace(); 452 453 System.out.println("Attempting to write XML w/out schema verification:"); 454 jaxbUtil.setLookForDefaultSchema(false); 455 try 456 { 457 jaxbUtil.writeObjectAsXmlTo(writer, pool, null); 458 } 459 catch (javax.xml.bind.JAXBException ex2) 460 { 461 System.out.println("Still had trouble w/ src.toXml. Msg:"); 462 System.out.println(ex.getMessage()); 463 ex.printStackTrace(); 464 } 465 } 466 } 467 */ 468 }