| 1215 | } |
| 1216 | |
| 1217 | void createRegularFile(const CanonPath & path, fun<void(CreateRegularFileSink &)> func) override |
| 1218 | { |
| 1219 | checkInterrupt(); |
| 1220 | |
| 1221 | /* Multithreaded blob writing. We read the incoming file data into memory and asynchronously write it to a Git |
| 1222 | blob object. However, to avoid unbounded memory usage, if the amount of data in flight exceeds a threshold, |
| 1223 | we switch to writing directly to a Git write stream. */ |
| 1224 | |
| 1225 | using WriteStream = std::unique_ptr<::git_writestream, decltype([](::git_writestream * stream) { |
| 1226 | if (stream) |
| 1227 | stream->free(stream); |
| 1228 | })>; |
| 1229 | |
| 1230 | struct CRF : CreateRegularFileSink |
| 1231 | { |
| 1232 | CanonPath path; |
| 1233 | GitFileSystemObjectSinkImpl & parent; |
| 1234 | WriteStream stream; |
| 1235 | std::optional<decltype(parent.repoPool)::Handle> repo; |
| 1236 | |
| 1237 | std::string contents; |
| 1238 | bool executable = false; |
| 1239 | |
| 1240 | CRF(CanonPath path, GitFileSystemObjectSinkImpl & parent) |
| 1241 | : path(std::move(path)) |
| 1242 | , parent(parent) |
| 1243 | { |
| 1244 | } |
| 1245 | |
| 1246 | ~CRF() |
| 1247 | { |
| 1248 | parent.totalBufSize -= contents.size(); |
| 1249 | } |
| 1250 | |
| 1251 | void operator()(std::string_view data) override |
| 1252 | { |
| 1253 | if (!stream) { |
| 1254 | contents.append(data); |
| 1255 | parent.totalBufSize += data.size(); |
| 1256 | |
| 1257 | if (parent.totalBufSize > parent.maxBufSize) { |
| 1258 | repo.emplace(parent.repoPool.get()); |
| 1259 | |
| 1260 | if (git_blob_create_from_stream(Setter(stream), **repo, nullptr)) |
| 1261 | throw GitError("creating a blob stream object"); |
| 1262 | |
| 1263 | if (stream->write(stream.get(), contents.data(), contents.size())) |
| 1264 | throw GitError("writing a blob for tarball member '%s'", path); |
| 1265 | |
| 1266 | parent.totalBufSize -= contents.size(); |
| 1267 | contents.clear(); |
| 1268 | } |
| 1269 | } else { |
| 1270 | if (stream->write(stream.get(), data.data(), data.size())) |
| 1271 | throw GitError("writing a blob for tarball member '%s'", path); |
| 1272 | } |
| 1273 | } |
| 1274 | |