| 176 | } |
| 177 | |
| 178 | Future<Void> AsyncFileCached::changeFileSize(int64_t size) { |
| 179 | ++countFileCacheWrites; |
| 180 | ++countCacheWrites; |
| 181 | |
| 182 | std::vector<Future<Void>> actors; |
| 183 | int64_t oldLength = length; |
| 184 | |
| 185 | int offsetInPage = size % pageCache->pageSize; |
| 186 | int64_t pageOffset = size - offsetInPage; |
| 187 | |
| 188 | if (offsetInPage == 0 && size == length) { |
| 189 | return Void(); |
| 190 | } |
| 191 | |
| 192 | length = size; |
| 193 | prevLength = size; |
| 194 | |
| 195 | if (offsetInPage) { |
| 196 | CODE_PROBE(true, "Truncating to the middle of a page"); |
| 197 | auto p = pages.find(pageOffset); |
| 198 | if (p != pages.end()) { |
| 199 | auto f = p->second->flush(); |
| 200 | if (!f.isReady() || f.isError()) |
| 201 | actors.push_back(f); |
| 202 | } else { |
| 203 | CODE_PROBE(true, "Truncating to the middle of a page that isn't in cache"); |
| 204 | } |
| 205 | |
| 206 | pageOffset += pageCache->pageSize; |
| 207 | } |
| 208 | |
| 209 | // if this call to truncate results in a larger file, there is no |
| 210 | // need to erase any pages |
| 211 | if (oldLength > pageOffset) { |
| 212 | // Iterating through all pages results in better cache locality than |
| 213 | // looking up pages one by one in the hash table. However, if we only need |
| 214 | // to truncate a small portion of data, looking up pages one by one should |
| 215 | // be faster. So for now we do single key lookup for each page if it results |
| 216 | // in less than a fixed percentage of the unordered map being accessed. |
| 217 | int64_t numLookups = (oldLength + (pageCache->pageSize - 1) - pageOffset) / pageCache->pageSize; |
| 218 | if (numLookups < pages.size() * FLOW_KNOBS->PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION) { |
| 219 | for (int64_t offset = pageOffset; offset < oldLength; offset += pageCache->pageSize) { |
| 220 | auto iter = pages.find(offset); |
| 221 | if (iter != pages.end()) { |
| 222 | auto f = iter->second->truncate(); |
| 223 | if (!f.isReady() || f.isError()) { |
| 224 | actors.push_back(f); |
| 225 | } |
| 226 | pages.erase(iter); |
| 227 | } |
| 228 | } |
| 229 | } else { |
| 230 | for (auto p = pages.begin(); p != pages.end();) { |
| 231 | if (p->first >= pageOffset) { |
| 232 | auto f = p->second->truncate(); |
| 233 | if (!f.isReady() || f.isError()) { |
| 234 | actors.push_back(f); |
| 235 | } |
no test coverage detected