annotate base/StorageAdviser.cpp @ 1078:ce82bcdc95d0

Fail upfront if the file is going to be too large. We expect the caller to split up large data sets into several MatrixFiles
author Chris Cannam
date Wed, 10 Jun 2015 13:10:26 +0100
parents cc27f35aa75c
children 329ddaf7415d
rev   line source
Chris@168 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@168 2
Chris@168 3 /*
Chris@168 4 Sonic Visualiser
Chris@168 5 An audio file viewer and annotation editor.
Chris@168 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 QMUL.
Chris@168 8
Chris@168 9 This program is free software; you can redistribute it and/or
Chris@168 10 modify it under the terms of the GNU General Public License as
Chris@168 11 published by the Free Software Foundation; either version 2 of the
Chris@168 12 License, or (at your option) any later version. See the file
Chris@168 13 COPYING included with this distribution for more information.
Chris@168 14 */
Chris@168 15
Chris@168 16 #include "StorageAdviser.h"
Chris@168 17
Chris@168 18 #include "Exceptions.h"
Chris@168 19 #include "TempDirectory.h"
Chris@168 20
Chris@168 21 #include "system/System.h"
Chris@168 22
Chris@168 23 #include <iostream>
Chris@168 24
Chris@436 25 //#define DEBUG_STORAGE_ADVISER 1
Chris@374 26
Chris@1038 27 size_t StorageAdviser::m_discPlanned = 0;
Chris@1038 28 size_t StorageAdviser::m_memoryPlanned = 0;
Chris@205 29
Chris@168 30 StorageAdviser::Recommendation
Chris@411 31 StorageAdviser::m_baseRecommendation = StorageAdviser::NoRecommendation;
Chris@411 32
Chris@411 33 StorageAdviser::Recommendation
Chris@168 34 StorageAdviser::recommend(Criteria criteria,
Chris@1038 35 size_t minimumSize,
Chris@1038 36 size_t maximumSize)
Chris@168 37 {
Chris@374 38 #ifdef DEBUG_STORAGE_ADVISER
Chris@690 39 SVDEBUG << "StorageAdviser::recommend: Criteria " << criteria
Chris@170 40 << ", minimumSize " << minimumSize
Chris@687 41 << ", maximumSize " << maximumSize << endl;
Chris@374 42 #endif
Chris@170 43
Chris@411 44 if (m_baseRecommendation != NoRecommendation) {
Chris@411 45 return m_baseRecommendation; // for now
Chris@411 46 }
Chris@411 47
Chris@541 48 QString path;
Chris@541 49 try {
Chris@541 50 path = TempDirectory::getInstance()->getPath();
Chris@541 51 } catch (std::exception e) {
Chris@843 52 cerr << "StorageAdviser::recommend: ERROR: Failed to get temporary directory path: " << e.what() << endl;
Chris@541 53 return Recommendation(UseMemory | ConserveSpace);
Chris@541 54 }
Chris@1038 55 ssize_t discFree = GetDiscSpaceMBAvailable(path.toLocal8Bit());
Chris@1038 56 ssize_t memoryFree, memoryTotal;
Chris@170 57 GetRealMemoryMBAvailable(memoryFree, memoryTotal);
Chris@168 58
Chris@1038 59 if (discFree > ssize_t(m_discPlanned / 1024 + 1)) {
Chris@205 60 discFree -= m_discPlanned / 1024 + 1;
Chris@205 61 } else if (discFree > 0) { // can also be -1 for unknown
Chris@205 62 discFree = 0;
Chris@205 63 }
Chris@205 64
Chris@1038 65 if (memoryFree > ssize_t(m_memoryPlanned / 1024 + 1)) {
Chris@205 66 memoryFree -= m_memoryPlanned / 1024 + 1;
Chris@205 67 } else if (memoryFree > 0) { // can also be -1 for unknown
Chris@205 68 memoryFree = 0;
Chris@205 69 }
Chris@205 70
Chris@374 71 #ifdef DEBUG_STORAGE_ADVISER
Chris@843 72 cerr << "Disc space: " << discFree << ", memory free: " << memoryFree << ", memory total: " << memoryTotal << ", min " << minimumSize << ", max " << maximumSize << endl;
Chris@374 73 #endif
Chris@168 74
Chris@192 75 //!!! We have a potentially serious problem here if multiple
Chris@192 76 //recommendations are made in advance of any of the resulting
Chris@192 77 //allocations, as the allocations that have been recommended for
Chris@192 78 //won't be taken into account in subsequent recommendations.
Chris@192 79
Chris@170 80 enum StorageStatus {
Chris@170 81 Unknown,
Chris@170 82 Insufficient,
Chris@170 83 Marginal,
Chris@170 84 Sufficient
Chris@170 85 };
Chris@168 86
Chris@170 87 StorageStatus memoryStatus = Unknown;
Chris@170 88 StorageStatus discStatus = Unknown;
Chris@170 89
Chris@1038 90 ssize_t minmb = ssize_t(minimumSize / 1024 + 1);
Chris@1038 91 ssize_t maxmb = ssize_t(maximumSize / 1024 + 1);
Chris@170 92
Chris@170 93 if (memoryFree == -1) memoryStatus = Unknown;
Chris@415 94 else if (memoryFree < memoryTotal / 3) memoryStatus = Insufficient;
Chris@170 95 else if (minmb > (memoryFree * 3) / 4) memoryStatus = Insufficient;
Chris@170 96 else if (maxmb > (memoryFree * 3) / 4) memoryStatus = Marginal;
Chris@170 97 else if (minmb > (memoryFree / 3)) memoryStatus = Marginal;
Chris@170 98 else if (memoryTotal == -1 ||
Chris@170 99 minmb > (memoryTotal / 10)) memoryStatus = Marginal;
Chris@170 100 else memoryStatus = Sufficient;
Chris@170 101
Chris@170 102 if (discFree == -1) discStatus = Unknown;
Chris@170 103 else if (minmb > (discFree * 3) / 4) discStatus = Insufficient;
Chris@173 104 else if (maxmb > (discFree / 4)) discStatus = Marginal;
Chris@173 105 else if (minmb > (discFree / 10)) discStatus = Marginal;
Chris@170 106 else discStatus = Sufficient;
Chris@170 107
Chris@374 108 #ifdef DEBUG_STORAGE_ADVISER
Chris@843 109 cerr << "Memory status: " << memoryStatus << ", disc status "
Chris@843 110 << discStatus << endl;
Chris@374 111 #endif
Chris@170 112
Chris@170 113 int recommendation = NoRecommendation;
Chris@170 114
Chris@170 115 if (memoryStatus == Insufficient || memoryStatus == Unknown) {
Chris@170 116
Chris@170 117 recommendation |= UseDisc;
Chris@170 118
Chris@170 119 if (discStatus == Insufficient && minmb > discFree) {
Chris@170 120 throw InsufficientDiscSpace(path, minmb, discFree);
Chris@170 121 }
Chris@170 122
Chris@170 123 if (discStatus == Insufficient || discStatus == Marginal) {
Chris@170 124 recommendation |= ConserveSpace;
Chris@170 125 } else if (discStatus == Unknown && !(criteria & PrecisionCritical)) {
Chris@170 126 recommendation |= ConserveSpace;
Chris@170 127 } else {
Chris@170 128 recommendation |= UseAsMuchAsYouLike;
Chris@170 129 }
Chris@170 130
Chris@170 131 } else if (memoryStatus == Marginal) {
Chris@170 132
Chris@170 133 if (((criteria & SpeedCritical) ||
Chris@170 134 (criteria & FrequentLookupLikely)) &&
Chris@170 135 !(criteria & PrecisionCritical) &&
Chris@170 136 !(criteria & LongRetentionLikely)) {
Chris@170 137
Chris@170 138 // requirements suggest a preference for memory
Chris@170 139
Chris@170 140 if (discStatus != Insufficient) {
Chris@170 141 recommendation |= PreferMemory;
Chris@170 142 } else {
Chris@170 143 recommendation |= UseMemory;
Chris@170 144 }
Chris@170 145
Chris@170 146 recommendation |= ConserveSpace;
Chris@170 147
Chris@170 148 } else {
Chris@170 149
Chris@170 150 if (discStatus == Insufficient) {
Chris@170 151 recommendation |= (UseMemory | ConserveSpace);
Chris@170 152 } else if (discStatus == Marginal) {
Chris@170 153 recommendation |= (PreferMemory | ConserveSpace);
Chris@170 154 } else if (discStatus == Unknown) {
Chris@170 155 recommendation |= (PreferDisc | ConserveSpace);
Chris@170 156 } else {
Chris@170 157 recommendation |= (UseDisc | UseAsMuchAsYouLike);
Chris@170 158 }
Chris@170 159 }
Chris@170 160
Chris@170 161 } else {
Chris@170 162
Chris@170 163 if (discStatus == Insufficient) {
Chris@170 164 recommendation |= (UseMemory | ConserveSpace);
Chris@170 165 } else if (discStatus != Sufficient) {
Chris@170 166 recommendation |= (PreferMemory | ConserveSpace);
Chris@170 167 } else {
Chris@170 168
Chris@170 169 if ((criteria & SpeedCritical) ||
Chris@170 170 (criteria & FrequentLookupLikely)) {
Chris@170 171 recommendation |= PreferMemory;
Chris@170 172 if (criteria & PrecisionCritical) {
Chris@170 173 recommendation |= UseAsMuchAsYouLike;
Chris@170 174 } else {
Chris@170 175 recommendation |= ConserveSpace;
Chris@170 176 }
Chris@170 177 } else {
Chris@170 178 recommendation |= PreferDisc;
Chris@170 179 recommendation |= UseAsMuchAsYouLike;
Chris@170 180 }
Chris@170 181 }
Chris@170 182 }
Chris@170 183
Chris@170 184 return Recommendation(recommendation);
Chris@168 185 }
Chris@168 186
Chris@205 187 void
Chris@1038 188 StorageAdviser::notifyPlannedAllocation(AllocationArea area, size_t size)
Chris@205 189 {
Chris@205 190 if (area == MemoryAllocation) m_memoryPlanned += size;
Chris@205 191 else if (area == DiscAllocation) m_discPlanned += size;
Chris@843 192 // cerr << "storage planned up: memory: " << m_memoryPlanned << ", disc "
Chris@843 193 // << m_discPlanned << endl;
Chris@205 194 }
Chris@205 195
Chris@205 196 void
Chris@1038 197 StorageAdviser::notifyDoneAllocation(AllocationArea area, size_t size)
Chris@205 198 {
Chris@205 199 if (area == MemoryAllocation) {
Chris@205 200 if (m_memoryPlanned > size) m_memoryPlanned -= size;
Chris@205 201 else m_memoryPlanned = 0;
Chris@205 202 } else if (area == DiscAllocation) {
Chris@205 203 if (m_discPlanned > size) m_discPlanned -= size;
Chris@205 204 else m_discPlanned = 0;
Chris@205 205 }
Chris@843 206 // cerr << "storage planned down: memory: " << m_memoryPlanned << ", disc "
Chris@843 207 // << m_discPlanned << endl;
Chris@205 208 }
Chris@205 209
Chris@411 210 void
Chris@411 211 StorageAdviser::setFixedRecommendation(Recommendation recommendation)
Chris@411 212 {
Chris@411 213 m_baseRecommendation = recommendation;
Chris@411 214 }
Chris@411 215