Queued buffering for downloads.

This commit is contained in:
J-D-K 2025-09-21 22:49:16 -04:00
parent b5d7b90c0e
commit c5d7464679
5 changed files with 33 additions and 65 deletions

View File

@ -39,7 +39,7 @@ INCLUDES := include ./Libraries/FsLib/Switch/FsLib/include ./Libraries/SDLLib/SD
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 09.13.2025
APP_VERSION := 09.21.2025
ROMFS := romfs
ICON := icon.jpg

View File

@ -3,21 +3,13 @@
#include "sys/sys.hpp"
#include <array>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <semaphore>
#include <vector>
namespace curl
{
inline constexpr size_t SHARED_BUFFER_SIZE = 0x500000;
// This is for synchronizing the buffer.
enum class BufferState
{
Empty,
Full
};
using DownloadPair = std::pair<std::unique_ptr<sys::Byte[]>, ssize_t>;
// clang-format off
struct DownloadStruct : sys::threadpool::DataStruct
@ -25,14 +17,8 @@ namespace curl
/// @brief Buffer mutex.
std::mutex lock{};
/// @brief Conditional for when the buffer is full.
std::condition_variable condition{};
/// @brief Shared buffer that is read into.
std::vector<sys::Byte> sharedBuffer{};
/// @brief Bool to signal when the buffer is ready/empty.
BufferState bufferState{};
/// @brief Queue of buffers to write.
std::queue<DownloadPair> bufferQueue{};
/// @brief Destination file to write to.
fslib::File *dest{};
@ -40,9 +26,6 @@ namespace curl
/// @brief Optional. Task to update with progress.
sys::ProgressTask *task{};
/// @brief Current offset in the file.
size_t offset{};
/// @brief Size of the file being downloaded.
int64_t fileSize{};
@ -59,7 +42,6 @@ namespace curl
downloadStruct->dest = &dest;
downloadStruct->task = task;
downloadStruct->fileSize = fileSize;
downloadStruct->sharedBuffer.reserve(SHARED_BUFFER_SIZE);
return downloadStruct;
}
}

View File

@ -32,7 +32,7 @@ namespace
/// @brief Build month.
constexpr uint8_t BUILD_MON = 9;
/// @brief Build day.
constexpr uint8_t BUILD_DAY = 13;
constexpr uint8_t BUILD_DAY = 21;
/// @brief Year.
constexpr uint16_t BUILD_YEAR = 2025;

View File

@ -4,6 +4,7 @@
#include "logging/logger.hpp"
#include "stringutil.hpp"
#include <condition_variable>
#include <cstring>
namespace
@ -67,33 +68,19 @@ size_t curl::write_data_to_file(const char *buffer, size_t size, size_t count, f
size_t curl::download_file_threaded(const char *buffer, size_t size, size_t count, curl::DownloadStruct *download)
{
std::mutex &lock = download->lock;
std::condition_variable &condition = download->condition;
auto &sharedBuffer = download->sharedBuffer;
curl::BufferState &bufferState = download->bufferState;
sys::ProgressTask *task = download->task;
size_t &offset = download->offset;
int64_t fileSize = download->fileSize;
std::mutex &lock = download->lock;
auto &bufferQueue = download->bufferQueue;
const size_t downloadSize = size * count;
auto chunkBuffer = std::make_unique<sys::Byte[]>(downloadSize);
std::copy(buffer, buffer + downloadSize, chunkBuffer.get());
{
std::unique_lock<std::mutex> bufferLock{lock};
condition.wait(bufferLock, [&]() { return bufferState == curl::BufferState::Empty; });
sharedBuffer.insert(sharedBuffer.end(), buffer, buffer + downloadSize);
const int64_t nextOffset = offset + downloadSize;
if (sharedBuffer.size() >= SIZE_DOWNLOAD_THRESHOLD || nextOffset >= fileSize)
{
bufferState = curl::BufferState::Full;
condition.notify_one();
}
offset += downloadSize;
std::lock_guard queueGuard{lock};
auto queuePair = std::make_pair(std::move(chunkBuffer), downloadSize);
bufferQueue.push(std::move(queuePair));
}
if (task) { task->increase_current(static_cast<double>(downloadSize)); }
return downloadSize;
}
@ -101,33 +88,31 @@ void curl::download_write_thread_function(sys::threadpool::JobData jobData)
{
auto castData = std::static_pointer_cast<curl::DownloadStruct>(jobData);
std::mutex &lock = castData->lock;
std::condition_variable &condition = castData->condition;
auto &sharedBuffer = castData->sharedBuffer;
curl::BufferState &bufferState = castData->bufferState;
fslib::File &dest = *castData->dest;
int64_t fileSize = castData->fileSize;
auto &writeComplete = castData->writeComplete;
std::vector<sys::Byte> localBuffer{};
localBuffer.reserve(curl::SHARED_BUFFER_SIZE);
std::mutex &lock = castData->lock;
auto &bufferQueue = castData->bufferQueue;
fslib::File &dest = *castData->dest;
sys::ProgressTask *task = castData->task;
int64_t fileSize = castData->fileSize;
auto &writeComplete = castData->writeComplete;
for (int64_t i = 0; i < fileSize;)
{
curl::DownloadPair downloadPair{};
{
std::unique_lock<std::mutex> bufferLock{lock};
condition.wait(bufferLock, [&]() { return bufferState == curl::BufferState::Full; });
std::lock_guard queueGuard{lock};
if (bufferQueue.empty()) { continue; }
// Copy and reset the offset.
localBuffer.assign_range(sharedBuffer);
sharedBuffer.clear();
bufferState = curl::BufferState::Empty;
condition.notify_one();
downloadPair = std::move(bufferQueue.front());
bufferQueue.pop();
}
dest.write(localBuffer.data(), localBuffer.size());
i += localBuffer.size();
auto &[chunkBuffer, bufferSize] = downloadPair;
dest.write(chunkBuffer.get(), bufferSize);
i += bufferSize;
if (task) { task->update_current(static_cast<double>(i)); }
}
writeComplete.release();

View File

@ -9,6 +9,7 @@
#include "sys/sys.hpp"
#include "ui/PopMessageManager.hpp"
#include <condition_variable>
#include <cstring>
#include <memory>
#include <mutex>