/* * [StatsForSender.java] * * Summary: Track statistics. * * Copyright: (c) 2003-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2003-10-05 */ package com.mindprod.replicatorsender; import com.mindprod.fastcat.FastCat; import com.mindprod.replicatorcommon.Config; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.TimeUnit; /** * Track statistics. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2003-10-05 * @since 2003-10-05 */ final class StatsForSender { /** * HowToProcess many files are actively being distributed. */ static int activeFilesCount; /** * what is the highest zip number in use. The first file is z1.zip. */ static int highestZip; /** * newest file deleted in this session, null if none */ static MaxiFD newestRecentlyDeletedFile; /** * newest file updated in this session, null if none */ static MaxiFD newestRecentlyPackagedFile; /** * newest file redeleted in this session, null if none */ static MaxiFD newestRedeletedFile; /** * newest file repackaged in this session, null if none */ static MaxiFD newestRepackagedFile; /** * oldest file deleted in this session, null if none */ static MaxiFD oldestRecentlyDeletedFile; /** * oldest file updated in this session, null if none */ static MaxiFD oldestRecentlyPackagedFile; /** * oldest file redeleted in this session, null if none */ static MaxiFD oldestRedeletedFile; /** * oldest file repackaged in this session, null if none */ static MaxiFD oldestRepackagedFile; /** * HowToProcess many files deleted since the last distribution. */ static int recentDeletedFilesCount; /** * HowToProcess many new files since the last distribution. */ static int recentNewFilesCount; /** * count of files repackaged into new zips. */ static int recentRepackedFilesCount; /** * HowToProcess many files were unchanged since the last distribution. */ static int recentUnchangedFilesCount; /** * HowToProcess many files were updated since the last distribution. */ static int recentUpdatedFilesCount; /** * HowToProcess many zips are in active distribution. */ static int recentZipsCreated; /** * HowToProcess many zip files were deleted since the last distribution. */ static int recentZipsDeleted; /** * HowToProcess many zips were emaciated, (shrunk to 0 bytes) since the last distribution. */ static int recentZipsEmaciated; /** * HowToProcess many zips were retired since the last distribution. */ static int recentZipsRetired; /** * number of zip files containing files to distribute, not counting retired or emaciated zips. */ private static int activeZipsCount; /** * How many zips have now been deleted from the distribution, not counting retired but including emaciated. */ private static int deletedZipsCount; /** * number of deletions in the distribution */ private static int distributionDeletedFilesCount; /** * HowToProcess many zips are emaciated, (shrunk to 0 bytes) */ private static int emaciatedZipsCount; /** * latest how many minutes until we next emaciate a retired zip. 0 if none. */ private static int minutesTillEmaciationHigh; /** * earliest how many minutes until we next emaciate a retired zip. 0 if none. */ private static int minutesTillEmaciationLow; /** * HowToProcess many zips are retired */ private static int retiredZipsCount; /** * Calc time until a zip is emaciated.. * * @param whenRetired timestamp when a zip was retired * * @return time is minutes until that zip will be emaciated.. */ private static int calcTimeToEmaciation( long whenRetired ) { int minutesTillEmaciation; if ( retiredZipsCount > 0 ) { final long millisTillEmaciation = ( whenRetired + TimeUnit.MINUTES.toMillis( ConfigForSender.RETIREMENT ) - System .currentTimeMillis() ); minutesTillEmaciation = ( int ) TimeUnit.MILLISECONDS.toMinutes( millisTillEmaciation ); if ( minutesTillEmaciation < 0 ) { minutesTillEmaciation = 0; } } else { minutesTillEmaciation = 0; } return minutesTillEmaciation; } /** * compute some of the zip stats that don't get computed as a side effect. */ static void computeZipsStats() { activeZipsCount = 0; long whenOldestZipRetired = Long.MAX_VALUE; long whenYoungestZipRetired = Config.NULL_TIMESTAMP; for ( MaxiZD maxiZD : ReplicatorSender.allZips ) { switch ( maxiZD.status ) { case A_UNCREATED: case B_CREATED: activeZipsCount++; break; case C_DECOMMISSIONED: case D_RETIRED: retiredZipsCount++; if ( maxiZD.retiredOnTimestamp < whenOldestZipRetired ) { whenOldestZipRetired = maxiZD.retiredOnTimestamp; } if ( maxiZD.retiredOnTimestamp > whenYoungestZipRetired ) { whenYoungestZipRetired = maxiZD.retiredOnTimestamp; } break; case E_EMACIATED: emaciatedZipsCount++; break; case F_DELETED: // are no deleted zips, so this will be 0. break; } } deletedZipsCount = highestZip - activeZipsCount - retiredZipsCount; // include emaciatedZipsCount as deleted activeFilesCount = ReplicatorSender.filesToDistribute.size(); distributionDeletedFilesCount = ReplicatorSender.filesToDelete.size(); minutesTillEmaciationLow = calcTimeToEmaciation( whenOldestZipRetired ); minutesTillEmaciationHigh = calcTimeToEmaciation( whenYoungestZipRetired ); } /** * Display elapsed minutes in hours and minutes. * * @param minutes cannot be negative. * * @return string xx hours and xx minutes */ private static String displayElapsedMinutes( int minutes ) { assert minutes >= 0 : "negative minutes display"; final FastCat sb = new FastCat( 7 ); final int hh = minutes / 60; final int mm = minutes % 60; if ( hh > 0 ) { sb.append( hh ); sb.append( " hour" ); if ( hh != 1 ) { sb.append( "s" ); } if ( mm > 0 ) { sb.append( " and " ); } } if ( mm > 0 || hh == 0 ) { sb.append( mm ); sb.append( " minute" ); if ( mm != 1 ) { sb.append( "s" ); } } return sb.toString(); } /** * Display the statistics. * * @return string describing all the statistics. */ static String dump() { final FastCat sb = new FastCat( 84 ); sb.append( "\n" ); sb.append( "S T A T I S T I C S\n" ); sb.append( "\n" ); sb.append( "FILES\n" ); sb.append( activeFilesCount ); sb.append( " active files distributed\n" ); sb.append( recentUnchangedFilesCount ); sb.append( " unchanged files\n" ); sb.append( recentRepackedFilesCount ); sb.append( " recently repackaged files\n" ); sb.append( recentUpdatedFilesCount ); sb.append( " recently updated files\n" ); sb.append( recentNewFilesCount ); sb.append( " new files\n" ); sb.append( "\n" ); sb.append( "DELETIONS\n" ); sb.append( distributionDeletedFilesCount ); sb.append( " deleted files\n" ); sb.append( recentDeletedFilesCount ); sb.append( " recently deleted files\n" ); sb.append( "\n" ); sb.append( "ZIPS\n" ); sb.append( highestZip ); sb.append( " highest zip number used\n" ); sb.append( activeZipsCount ); sb.append( " active zips\n" ); sb.append( retiredZipsCount ); sb.append( " retired zips" ); if ( minutesTillEmaciationHigh > 0 ) { sb.append( " to be deleted in " ); if ( minutesTillEmaciationLow > 0 && minutesTillEmaciationLow != minutesTillEmaciationHigh ) { sb.append( displayElapsedMinutes( minutesTillEmaciationLow ) ); sb.append( " to " ); } sb.append( displayElapsedMinutes( minutesTillEmaciationHigh ) ); sb.append( "." ); } sb.append( "\n" ); sb.append( deletedZipsCount ); sb.append( " deleted zips\n" ); sb.append( recentZipsCreated ); sb.append( " recently created zips\n" ); sb.append( recentZipsRetired ); sb.append( " recently retired zips\n" ); // since we will delete emaciated files later in same run, we treat emaciated as deleted and don't report // deleted. sb.append( recentZipsEmaciated ); sb.append( " recently deleted zips\n" ); sb.append( "\nPACKING\n" ); // arrange that stats come out in date order, with nothing for null entries. ArrayList al = new ArrayList<>( 8 ); if ( oldestRepackagedFile != null ) { al.add( new DescribedMaxiFD( oldestRepackagedFile, "oldest repackaged file" ) ); } if ( oldestRedeletedFile != null ) { al.add( new DescribedMaxiFD( oldestRedeletedFile, "oldest redeleted file" ) ); } if ( newestRepackagedFile != null ) { al.add( new DescribedMaxiFD( newestRepackagedFile, "newest repackaged file" ) ); } if ( newestRedeletedFile != null ) { al.add( new DescribedMaxiFD( newestRedeletedFile, "newest redeleted file" ) ); } if ( oldestRecentlyPackagedFile != null ) { al.add( new DescribedMaxiFD( oldestRecentlyPackagedFile, "oldest recently packaged file" ) ); } if ( oldestRecentlyDeletedFile != null ) { al.add( new DescribedMaxiFD( oldestRecentlyDeletedFile, "oldest recently deleted file" ) ); } if ( newestRecentlyPackagedFile != null ) { al.add( new DescribedMaxiFD( newestRecentlyPackagedFile, "newest recently packaged file" ) ); } if ( newestRecentlyDeletedFile != null ) { al.add( new DescribedMaxiFD( newestRecentlyDeletedFile, "newest recently deleted file" ) ); } Collections.sort( al ); for ( DescribedMaxiFD item : al ) { sb.append( item.displayFDNameAndTime() ); } return sb.toString(); } }