StorageAdviser.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "StorageAdviser.h"
17 
18 #include "Exceptions.h"
19 #include "TempDirectory.h"
20 
21 #include "system/System.h"
22 
23 #include <iostream>
24 
25 QString
27 {
28  QStringList labels;
29  if (criteria & SpeedCritical) labels.push_back("SpeedCritical");
30  if (criteria & PrecisionCritical) labels.push_back("PrecisionCritical");
31  if (criteria & LongRetentionLikely) labels.push_back("LongRetentionLikely");
32  if (criteria & FrequentLookupLikely) labels.push_back("FrequentLookupLikely");
33  if (labels.empty()) return "None";
34  else return labels.join("+");
35 }
36 
37 QString
39 {
40  QStringList labels;
41  if (recommendation & UseMemory) labels.push_back("UseMemory");
42  if (recommendation & PreferMemory) labels.push_back("PreferMemory");
43  if (recommendation & PreferDisc) labels.push_back("PreferDisc");
44  if (recommendation & UseDisc) labels.push_back("UseDisc");
45  if (recommendation & ConserveSpace) labels.push_back("ConserveSpace");
46  if (recommendation & UseAsMuchAsYouLike) labels.push_back("UseAsMuchAsYouLike");
47  if (labels.empty()) return "None";
48  else return labels.join("+");
49 }
50 
51 QString
53 {
54  if (status == Insufficient) return "Insufficient";
55  if (status == Marginal) return "Marginal";
56  if (status == Sufficient) return "Sufficient";
57  return "Unknown";
58 }
59 
62 
65 
68  size_t minimumSize,
69  size_t maximumSize)
70 {
71  SVDEBUG << "StorageAdviser::recommend: criteria " << criteria
72  << " (" + criteriaToString(criteria) + ")"
73  << ", minimumSize " << minimumSize
74  << ", maximumSize " << maximumSize << endl;
75 
77  SVDEBUG << "StorageAdviser::recommend: Returning fixed recommendation "
78  << m_baseRecommendation << " ("
80  return m_baseRecommendation; // for now
81  }
82 
83  QString path;
84  try {
86  } catch (const std::exception &e) {
87  SVDEBUG << "StorageAdviser::recommend: ERROR: Failed to get temporary directory path: " << e.what() << endl;
88  int r = UseMemory | ConserveSpace;
89  SVDEBUG << "StorageAdviser: returning fallback " << r
90  << " (" << recommendationToString(r) << ")" << endl;
91  return Recommendation(r);
92  }
93  ssize_t discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit());
94  ssize_t memoryFree, memoryTotal;
95  GetRealMemoryMBAvailable(memoryFree, memoryTotal);
96 
97  SVDEBUG << "StorageAdviser: disc space: " << discFree
98  << "M, memory free: " << memoryFree
99  << "M, memory total: " << memoryTotal << "M" << endl;
100 
101  // In 32-bit addressing mode we can't address more than 4Gb.
102  // If the total memory is reported as more than 4Gb, we should
103  // reduce the available amount by the difference between 4Gb
104  // and the total. This won't give us an accurate idea of the
105  // amount of memory available any more, but it should be enough
106  // to prevent us from trying to allocate more for our own use
107  // than can be addressed at all!
108  if (sizeof(void *) < 8) {
109  if (memoryTotal > 4096) {
110  ssize_t excess = memoryTotal - 4096;
111  if (memoryFree > excess) {
112  memoryFree -= excess;
113  } else {
114  memoryFree = 0;
115  }
116  SVDEBUG << "StorageAdviser: more real memory found than we "
117  << "can address in a 32-bit process, reducing free "
118  << "estimate to " << memoryFree << "M accordingly" << endl;
119  }
120  }
121 
122  SVDEBUG << "StorageAdviser: disc planned: " << (m_discPlanned / 1024)
123  << "K, memory planned: " << (m_memoryPlanned / 1024) << "K" << endl;
124  SVDEBUG << "StorageAdviser: min requested: " << minimumSize
125  << "K, max requested: " << maximumSize << "K" << endl;
126 
127  if (discFree > ssize_t(m_discPlanned / 1024 + 1)) {
128  discFree -= m_discPlanned / 1024 + 1;
129  } else if (discFree > 0) { // can also be -1 for unknown
130  discFree = 0;
131  }
132 
133  if (memoryFree > ssize_t(m_memoryPlanned / 1024 + 1)) {
134  memoryFree -= m_memoryPlanned / 1024 + 1;
135  } else if (memoryFree > 0) { // can also be -1 for unknown
136  memoryFree = 0;
137  }
138 
140  //recommendations are made in advance of any of the resulting
141  //allocations, as the allocations that have been recommended for
142  //won't be taken into account in subsequent recommendations.
143 
144  StorageStatus memoryStatus = Unknown;
145  StorageStatus discStatus = Unknown;
146 
147  ssize_t minmb = ssize_t(minimumSize / 1024 + 1);
148  ssize_t maxmb = ssize_t(maximumSize / 1024 + 1);
149 
150  if (memoryFree == -1) memoryStatus = Unknown;
151  else if (memoryFree < memoryTotal / 3 && memoryFree < 512) memoryStatus = Insufficient;
152  else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
153  else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
154  else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
155  else if (memoryTotal == -1 ||
156  minmb > (memoryTotal / 10)) memoryStatus = Marginal;
157  else memoryStatus = Sufficient;
158 
159  if (discFree == -1) discStatus = Unknown;
160  else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
161  else if (maxmb > (discFree / 4)) discStatus = Marginal;
162  else if (minmb > (discFree / 10)) discStatus = Marginal;
163  else discStatus = Sufficient;
164 
165  SVDEBUG << "StorageAdviser: memory status: " << memoryStatus
166  << " (" << storageStatusToString(memoryStatus) << ")"
167  << ", disc status " << discStatus
168  << " (" << storageStatusToString(discStatus) << ")" << endl;
169 
170  int recommendation = NoRecommendation;
171 
172  if (memoryStatus == Insufficient || memoryStatus == Unknown) {
173 
174  recommendation |= UseDisc;
175 
176  if (discStatus == Insufficient && minmb > discFree) {
177  throw InsufficientDiscSpace(path, minmb, discFree);
178  }
179 
180  if (discStatus == Insufficient || discStatus == Marginal) {
181  recommendation |= ConserveSpace;
182  } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
183  recommendation |= ConserveSpace;
184  } else {
185  recommendation |= UseAsMuchAsYouLike;
186  }
187 
188  } else if (memoryStatus == Marginal) {
189 
190  if (((criteria & SpeedCritical) ||
191  (criteria & FrequentLookupLikely)) &&
192  !(criteria & PrecisionCritical) &&
193  !(criteria & LongRetentionLikely)) {
194 
195  // requirements suggest a preference for memory
196 
197  if (discStatus != Insufficient) {
198  recommendation |= PreferMemory;
199  } else {
200  recommendation |= UseMemory;
201  }
202 
203  recommendation |= ConserveSpace;
204 
205  } else {
206 
207  if (discStatus == Insufficient) {
208  recommendation |= (UseMemory | ConserveSpace);
209  } else if (discStatus == Marginal) {
210  recommendation |= (PreferMemory | ConserveSpace);
211  } else if (discStatus == Unknown) {
212  recommendation |= (PreferDisc | ConserveSpace);
213  } else {
214  recommendation |= (UseDisc | UseAsMuchAsYouLike);
215  }
216  }
217 
218  } else {
219 
220  if (discStatus == Insufficient) {
221  recommendation |= (UseMemory | ConserveSpace);
222  } else if (discStatus != Sufficient) {
223  recommendation |= (PreferMemory | ConserveSpace);
224  } else {
225 
226  if ((criteria & SpeedCritical) ||
227  (criteria & FrequentLookupLikely)) {
228  recommendation |= PreferMemory;
229  if (criteria & PrecisionCritical) {
230  recommendation |= UseAsMuchAsYouLike;
231  } else {
232  recommendation |= ConserveSpace;
233  }
234  } else {
235  recommendation |= PreferDisc;
236  recommendation |= UseAsMuchAsYouLike;
237  }
238  }
239  }
240 
241  SVDEBUG << "StorageAdviser: returning recommendation " << recommendation
242  << " (" << recommendationToString(recommendation) << ")" << endl;
243 
244  return Recommendation(recommendation);
245 }
246 
247 void
249 {
250  if (area == MemoryAllocation) m_memoryPlanned += size;
251  else if (area == DiscAllocation) m_discPlanned += size;
252  SVDEBUG << "StorageAdviser: storage planned up: now memory: " << m_memoryPlanned << ", disc "
253  << m_discPlanned << endl;
254 }
255 
256 void
258 {
259  if (area == MemoryAllocation) {
260  if (m_memoryPlanned > size) m_memoryPlanned -= size;
261  else m_memoryPlanned = 0;
262  } else if (area == DiscAllocation) {
263  if (m_discPlanned > size) m_discPlanned -= size;
264  else m_discPlanned = 0;
265  }
266  SVDEBUG << "StorageAdviser: storage planned down: now memory: " << m_memoryPlanned << ", disc "
267  << m_discPlanned << endl;
268 }
269 
270 void
272 {
273  m_baseRecommendation = recommendation;
274 }
275 
void GetRealMemoryMBAvailable(ssize_t &available, ssize_t &total)
Definition: System.cpp:126
ssize_t GetDiscSpaceMBAvailable(const char *path)
Definition: System.cpp:262
static Recommendation recommend(Criteria criteria, size_t minimumSize, size_t maximumSize)
Recommend where to store some data, given certain storage and recall criteria.
QString getPath()
Create the root temporary directory if necessary, and return its path.
static QString criteriaToString(int)
static Recommendation m_baseRecommendation
static TempDirectory * getInstance()
static void notifyPlannedAllocation(AllocationArea area, size_t size)
Specify that we are planning to use a given amount of storage (in kilobytes), but haven&#39;t allocated i...
static void notifyDoneAllocation(AllocationArea area, size_t size)
Specify that we have now allocated, or abandoned the allocation of, the given amount (in kilobytes) o...
#define SVDEBUG
Definition: Debug.h:106
static void setFixedRecommendation(Recommendation recommendation)
Force all subsequent recommendations to use the (perhaps partial) specification given here...
static size_t m_discPlanned
static size_t m_memoryPlanned
static QString recommendationToString(int)
static QString storageStatusToString(StorageStatus)