svcore  1.9
StorageAdviser.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "StorageAdviser.h"
00017 
00018 #include "Exceptions.h"
00019 #include "TempDirectory.h"
00020 
00021 #include "system/System.h"
00022 
00023 #include <iostream>
00024 
00025 //#define DEBUG_STORAGE_ADVISER 1
00026 
00027 long StorageAdviser::m_discPlanned = 0;
00028 long StorageAdviser::m_memoryPlanned = 0;
00029 
00030 StorageAdviser::Recommendation
00031 StorageAdviser::m_baseRecommendation = StorageAdviser::NoRecommendation;
00032 
00033 StorageAdviser::Recommendation
00034 StorageAdviser::recommend(Criteria criteria,
00035                           int minimumSize,
00036                           int maximumSize)
00037 {
00038 #ifdef DEBUG_STORAGE_ADVISER
00039     SVDEBUG << "StorageAdviser::recommend: Criteria " << criteria 
00040               << ", minimumSize " << minimumSize
00041               << ", maximumSize " << maximumSize << endl;
00042 #endif
00043 
00044     if (m_baseRecommendation != NoRecommendation) {
00045         return m_baseRecommendation; // for now
00046     }
00047 
00048     QString path;
00049     try {
00050         path = TempDirectory::getInstance()->getPath();
00051     } catch (std::exception e) {
00052         cerr << "StorageAdviser::recommend: ERROR: Failed to get temporary directory path: " << e.what() << endl;
00053         return Recommendation(UseMemory | ConserveSpace);
00054     }
00055     int discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit());
00056     int memoryFree, memoryTotal;
00057     GetRealMemoryMBAvailable(memoryFree, memoryTotal);
00058 
00059     if (discFree > m_discPlanned / 1024 + 1) {
00060         discFree -= m_discPlanned / 1024 + 1;
00061     } else if (discFree > 0) { // can also be -1 for unknown
00062         discFree = 0;
00063     }
00064 
00065     if (memoryFree > m_memoryPlanned / 1024 + 1) {
00066         memoryFree -= m_memoryPlanned / 1024 + 1;
00067     } else if (memoryFree > 0) { // can also be -1 for unknown
00068         memoryFree = 0;
00069     }
00070 
00071 #ifdef DEBUG_STORAGE_ADVISER
00072     cerr << "Disc space: " << discFree << ", memory free: " << memoryFree << ", memory total: " << memoryTotal << ", min " << minimumSize << ", max " << maximumSize << endl;
00073 #endif
00074 
00076     //recommendations are made in advance of any of the resulting
00077     //allocations, as the allocations that have been recommended for
00078     //won't be taken into account in subsequent recommendations.
00079 
00080     enum StorageStatus {
00081         Unknown,
00082         Insufficient,
00083         Marginal,
00084         Sufficient
00085     };
00086 
00087     StorageStatus memoryStatus = Unknown;
00088     StorageStatus discStatus = Unknown;
00089 
00090     int minmb = minimumSize / 1024 + 1;
00091     int maxmb = maximumSize / 1024 + 1;
00092 
00093     if (memoryFree == -1) memoryStatus = Unknown;
00094     else if (memoryFree < memoryTotal / 3) memoryStatus = Insufficient;
00095     else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
00096     else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
00097     else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
00098     else if (memoryTotal == -1 ||
00099              minmb > (memoryTotal / 10)) memoryStatus = Marginal;
00100     else memoryStatus = Sufficient;
00101 
00102     if (discFree == -1) discStatus = Unknown;
00103     else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
00104     else if (maxmb > (discFree / 4)) discStatus = Marginal;
00105     else if (minmb > (discFree / 10)) discStatus = Marginal;
00106     else discStatus = Sufficient;
00107 
00108 #ifdef DEBUG_STORAGE_ADVISER
00109     cerr << "Memory status: " << memoryStatus << ", disc status "
00110               << discStatus << endl;
00111 #endif
00112 
00113     int recommendation = NoRecommendation;
00114 
00115     if (memoryStatus == Insufficient || memoryStatus == Unknown) {
00116 
00117         recommendation |= UseDisc;
00118 
00119         if (discStatus == Insufficient && minmb > discFree) {
00120             throw InsufficientDiscSpace(path, minmb, discFree);
00121         }
00122 
00123         if (discStatus == Insufficient || discStatus == Marginal) {
00124             recommendation |= ConserveSpace;
00125         } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
00126             recommendation |= ConserveSpace;
00127         } else {
00128             recommendation |= UseAsMuchAsYouLike;
00129         }
00130 
00131     } else if (memoryStatus == Marginal) {
00132 
00133         if (((criteria & SpeedCritical) ||
00134              (criteria & FrequentLookupLikely)) &&
00135             !(criteria & PrecisionCritical) &&
00136             !(criteria & LongRetentionLikely)) {
00137 
00138             // requirements suggest a preference for memory
00139 
00140             if (discStatus != Insufficient) {
00141                 recommendation |= PreferMemory;
00142             } else {
00143                 recommendation |= UseMemory;
00144             }
00145 
00146             recommendation |= ConserveSpace;
00147 
00148         } else {
00149 
00150             if (discStatus == Insufficient) {
00151                 recommendation |= (UseMemory | ConserveSpace);
00152             } else if (discStatus == Marginal) {
00153                 recommendation |= (PreferMemory | ConserveSpace);
00154             } else if (discStatus == Unknown) {
00155                 recommendation |= (PreferDisc | ConserveSpace);
00156             } else {
00157                 recommendation |= (UseDisc | UseAsMuchAsYouLike);
00158             }
00159         }    
00160 
00161     } else {
00162 
00163         if (discStatus == Insufficient) {
00164             recommendation |= (UseMemory | ConserveSpace);
00165         } else if (discStatus != Sufficient) {
00166             recommendation |= (PreferMemory | ConserveSpace);
00167         } else {
00168 
00169             if ((criteria & SpeedCritical) ||
00170                 (criteria & FrequentLookupLikely)) {
00171                 recommendation |= PreferMemory;
00172                 if (criteria & PrecisionCritical) {
00173                     recommendation |= UseAsMuchAsYouLike;
00174                 } else {
00175                     recommendation |= ConserveSpace;
00176                 }
00177             } else {
00178                 recommendation |= PreferDisc;
00179                 recommendation |= UseAsMuchAsYouLike;
00180             }
00181         }
00182     }
00183 
00184     return Recommendation(recommendation);
00185 }
00186 
00187 void
00188 StorageAdviser::notifyPlannedAllocation(AllocationArea area, int size)
00189 {
00190     if (area == MemoryAllocation) m_memoryPlanned += size;
00191     else if (area == DiscAllocation) m_discPlanned += size;
00192 //    cerr << "storage planned up: memory: " << m_memoryPlanned << ", disc "
00193 //              << m_discPlanned << endl;
00194 }
00195 
00196 void
00197 StorageAdviser::notifyDoneAllocation(AllocationArea area, int size)
00198 {
00199     if (area == MemoryAllocation) {
00200         if (m_memoryPlanned > size) m_memoryPlanned -= size;
00201         else m_memoryPlanned = 0;
00202     } else if (area == DiscAllocation) {
00203         if (m_discPlanned > size) m_discPlanned -= size; 
00204         else m_discPlanned = 0;
00205     }
00206 //    cerr << "storage planned down: memory: " << m_memoryPlanned << ", disc "
00207 //              << m_discPlanned << endl;
00208 }
00209 
00210 void
00211 StorageAdviser::setFixedRecommendation(Recommendation recommendation)
00212 {
00213     m_baseRecommendation = recommendation;
00214 }
00215