mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-18 12:22:12 +00:00
Http temporary buffer integration with fs cache
This commit is contained in:
parent
5c5aaeca6d
commit
92d0d9d4ff
@ -19,12 +19,14 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <Disks/DiskFactory.h>
|
#include <Disks/DiskFactory.h>
|
||||||
|
#include <Disks/IO/WriteBufferFromTemporaryFile.h>
|
||||||
|
|
||||||
#include <Common/randomSeed.h>
|
#include <Common/randomSeed.h>
|
||||||
#include <IO/ReadHelpers.h>
|
#include <IO/ReadHelpers.h>
|
||||||
#include <IO/WriteBufferFromTemporaryFile.h>
|
|
||||||
#include <IO/WriteHelpers.h>
|
#include <IO/WriteHelpers.h>
|
||||||
#include <Common/logger_useful.h>
|
#include <Common/logger_useful.h>
|
||||||
|
|
||||||
|
|
||||||
namespace CurrentMetrics
|
namespace CurrentMetrics
|
||||||
{
|
{
|
||||||
extern const Metric DiskSpaceReservedForMerge;
|
extern const Metric DiskSpaceReservedForMerge;
|
||||||
@ -588,7 +590,7 @@ try
|
|||||||
static DiskWriteCheckData data;
|
static DiskWriteCheckData data;
|
||||||
String tmp_template = fs::path(disk_path) / "";
|
String tmp_template = fs::path(disk_path) / "";
|
||||||
{
|
{
|
||||||
auto buf = WriteBufferFromTemporaryFile::create(tmp_template);
|
auto buf = std::make_unique<WriteBufferFromTemporaryFile>(tmp_template);
|
||||||
buf->write(data.data, data.PAGE_SIZE_IN_BYTES);
|
buf->write(data.data, data.PAGE_SIZE_IN_BYTES);
|
||||||
buf->sync();
|
buf->sync();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <IO/WriteBufferFromTemporaryFile.h>
|
#include <Disks/IO/WriteBufferFromTemporaryFile.h>
|
||||||
#include <IO/ReadBufferFromFile.h>
|
#include <IO/ReadBufferFromFile.h>
|
||||||
|
#include <Disks/TemporaryFileOnDisk.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
@ -12,18 +13,18 @@ namespace ErrorCodes
|
|||||||
extern const int CANNOT_SEEK_THROUGH_FILE;
|
extern const int CANNOT_SEEK_THROUGH_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WriteBufferFromTemporaryFile::WriteBufferFromTemporaryFile(TemporaryFileOnDiskHolder && tmp_file_)
|
||||||
WriteBufferFromTemporaryFile::WriteBufferFromTemporaryFile(std::unique_ptr<PocoTemporaryFile> && tmp_file_)
|
: WriteBufferFromFile(tmp_file_->getPath(), DBMS_DEFAULT_BUFFER_SIZE, O_RDWR | O_TRUNC | O_CREAT, /* throttler= */ {}, 0600)
|
||||||
: WriteBufferFromFile(tmp_file_->path(), DBMS_DEFAULT_BUFFER_SIZE, O_RDWR | O_TRUNC | O_CREAT, /* throttler= */ {}, 0600), tmp_file(std::move(tmp_file_))
|
, tmp_file(std::move(tmp_file_))
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
WriteBufferFromTemporaryFile::Ptr WriteBufferFromTemporaryFile::create(const std::string & tmp_dir)
|
|
||||||
{
|
{
|
||||||
return Ptr{new WriteBufferFromTemporaryFile(createTemporaryFile(tmp_dir))};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WriteBufferFromTemporaryFile::WriteBufferFromTemporaryFile(const String & tmp_file_path)
|
||||||
|
: WriteBufferFromFile(tmp_file_path, DBMS_DEFAULT_BUFFER_SIZE, O_RDWR | O_TRUNC | O_CREAT, /* throttler= */ {}, 0600)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
class ReadBufferFromTemporaryWriteBuffer : public ReadBufferFromFile
|
class ReadBufferFromTemporaryWriteBuffer : public ReadBufferFromFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -40,11 +41,11 @@ public:
|
|||||||
return std::make_shared<ReadBufferFromTemporaryWriteBuffer>(fd, file_name, std::move(origin->tmp_file));
|
return std::make_shared<ReadBufferFromTemporaryWriteBuffer>(fd, file_name, std::move(origin->tmp_file));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadBufferFromTemporaryWriteBuffer(int fd_, const std::string & file_name_, std::unique_ptr<PocoTemporaryFile> && tmp_file_)
|
ReadBufferFromTemporaryWriteBuffer(int fd_, const std::string & file_name_, TemporaryFileOnDiskHolder && tmp_file_)
|
||||||
: ReadBufferFromFile(fd_, file_name_), tmp_file(std::move(tmp_file_))
|
: ReadBufferFromFile(fd_, file_name_), tmp_file(std::move(tmp_file_))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::unique_ptr<PocoTemporaryFile> tmp_file;
|
TemporaryFileOnDiskHolder tmp_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class TemporaryFileOnDisk;
|
||||||
|
using TemporaryFileOnDiskHolder = std::unique_ptr<TemporaryFileOnDisk>;
|
||||||
|
|
||||||
/// Rereadable WriteBuffer, could be used as disk buffer
|
/// Rereadable WriteBuffer, could be used as disk buffer
|
||||||
/// Creates unique temporary in directory (and directory itself)
|
/// Creates unique temporary in directory (and directory itself)
|
||||||
class WriteBufferFromTemporaryFile : public WriteBufferFromFile, public IReadableWriteBuffer
|
class WriteBufferFromTemporaryFile : public WriteBufferFromFile, public IReadableWriteBuffer
|
||||||
@ -15,16 +18,15 @@ class WriteBufferFromTemporaryFile : public WriteBufferFromFile, public IReadabl
|
|||||||
public:
|
public:
|
||||||
using Ptr = std::shared_ptr<WriteBufferFromTemporaryFile>;
|
using Ptr = std::shared_ptr<WriteBufferFromTemporaryFile>;
|
||||||
|
|
||||||
static Ptr create(const std::string & tmp_dir);
|
explicit WriteBufferFromTemporaryFile(TemporaryFileOnDiskHolder && tmp_file_);
|
||||||
|
explicit WriteBufferFromTemporaryFile(const String & tmp_file_path);
|
||||||
|
|
||||||
~WriteBufferFromTemporaryFile() override;
|
~WriteBufferFromTemporaryFile() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit WriteBufferFromTemporaryFile(std::unique_ptr<PocoTemporaryFile> && tmp_file);
|
|
||||||
|
|
||||||
std::shared_ptr<ReadBuffer> getReadBufferImpl() override;
|
std::shared_ptr<ReadBuffer> getReadBufferImpl() override;
|
||||||
|
|
||||||
std::unique_ptr<PocoTemporaryFile> tmp_file;
|
TemporaryFileOnDiskHolder tmp_file;
|
||||||
|
|
||||||
friend class ReadBufferFromTemporaryWriteBuffer;
|
friend class ReadBufferFromTemporaryWriteBuffer;
|
||||||
};
|
};
|
@ -3,11 +3,11 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <IO/CascadeWriteBuffer.h>
|
#include <IO/CascadeWriteBuffer.h>
|
||||||
#include <IO/MemoryReadWriteBuffer.h>
|
#include <IO/MemoryReadWriteBuffer.h>
|
||||||
#include <IO/WriteBufferFromTemporaryFile.h>
|
|
||||||
#include <IO/WriteBufferFromString.h>
|
#include <IO/WriteBufferFromString.h>
|
||||||
#include <IO/ConcatReadBuffer.h>
|
#include <IO/ConcatReadBuffer.h>
|
||||||
#include <IO/copyData.h>
|
#include <IO/copyData.h>
|
||||||
#include <Common/typeid_cast.h>
|
#include <Common/typeid_cast.h>
|
||||||
|
#include <Disks/IO/WriteBufferFromTemporaryFile.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@ -214,7 +214,7 @@ try
|
|||||||
std::string tmp_template = "tmp/TemporaryFileWriteBuffer/";
|
std::string tmp_template = "tmp/TemporaryFileWriteBuffer/";
|
||||||
std::string data = makeTestArray(s);
|
std::string data = makeTestArray(s);
|
||||||
|
|
||||||
auto buf = WriteBufferFromTemporaryFile::create(tmp_template);
|
auto buf = std::make_shared<WriteBufferFromTemporaryFile>(tmp_template);
|
||||||
buf->write(data.data(), data.size());
|
buf->write(data.data(), data.size());
|
||||||
|
|
||||||
std::string tmp_filename = buf->getFileName();
|
std::string tmp_filename = buf->getFileName();
|
||||||
@ -253,7 +253,7 @@ try
|
|||||||
testCascadeBufferRedability(makeTestArray(s),
|
testCascadeBufferRedability(makeTestArray(s),
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
[=] (auto) { return WriteBufferFromTemporaryFile::create(tmp_template); }
|
[=] (auto) { return std::make_shared<WriteBufferFromTemporaryFile>(tmp_template); }
|
||||||
});
|
});
|
||||||
|
|
||||||
testCascadeBufferRedability(makeTestArray(s),
|
testCascadeBufferRedability(makeTestArray(s),
|
||||||
@ -261,7 +261,7 @@ try
|
|||||||
std::make_shared<MemoryWriteBuffer>(std::max(1ul, s/3ul), 2, 1.5),
|
std::make_shared<MemoryWriteBuffer>(std::max(1ul, s/3ul), 2, 1.5),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[=] (auto) { return WriteBufferFromTemporaryFile::create(tmp_template); }
|
[=] (auto) { return std::make_shared<WriteBufferFromTemporaryFile>(tmp_template); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
#include <Interpreters/Cache/WriteBufferToFileSegment.h>
|
#include <Interpreters/Cache/WriteBufferToFileSegment.h>
|
||||||
#include <Interpreters/Cache/FileSegment.h>
|
#include <Interpreters/Cache/FileSegment.h>
|
||||||
#include <IO/SwapHelper.h>
|
#include <IO/SwapHelper.h>
|
||||||
|
#include <IO/ReadBufferFromFile.h>
|
||||||
|
|
||||||
#include <base/scope_guard.h>
|
#include <base/scope_guard.h>
|
||||||
|
|
||||||
@ -11,11 +12,23 @@ namespace DB
|
|||||||
|
|
||||||
namespace ErrorCodes
|
namespace ErrorCodes
|
||||||
{
|
{
|
||||||
|
extern const int LOGICAL_ERROR;
|
||||||
extern const int NOT_ENOUGH_SPACE;
|
extern const int NOT_ENOUGH_SPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteBufferToFileSegment::WriteBufferToFileSegment(FileSegment * file_segment_)
|
WriteBufferToFileSegment::WriteBufferToFileSegment(FileSegment * file_segment_)
|
||||||
: WriteBufferFromFileDecorator(file_segment_->detachWriter()), file_segment(file_segment_)
|
: WriteBufferFromFileDecorator(file_segment_->detachWriter())
|
||||||
|
, file_segment(file_segment_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteBufferToFileSegment::WriteBufferToFileSegment(FileSegmentsHolder && segment_holder_)
|
||||||
|
: WriteBufferFromFileDecorator(
|
||||||
|
segment_holder_.file_segments.size() == 1
|
||||||
|
? segment_holder_.file_segments.front()->detachWriter()
|
||||||
|
: throw Exception(ErrorCodes::LOGICAL_ERROR, "WriteBufferToFileSegment can be created only from single segment"))
|
||||||
|
, file_segment(segment_holder_.file_segments.front().get())
|
||||||
|
, segment_holder(std::move(segment_holder_))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +65,11 @@ void WriteBufferToFileSegment::nextImpl()
|
|||||||
file_segment->setDownloadedSize(bytes_to_write);
|
file_segment->setDownloadedSize(bytes_to_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ReadBuffer> WriteBufferToFileSegment::getReadBufferImpl()
|
||||||
|
{
|
||||||
|
finalize();
|
||||||
|
return std::make_shared<ReadBufferFromFile>(file_segment->getPathInLocalCache());
|
||||||
|
}
|
||||||
|
|
||||||
WriteBufferToFileSegment::~WriteBufferToFileSegment()
|
WriteBufferToFileSegment::~WriteBufferToFileSegment()
|
||||||
{
|
{
|
||||||
|
@ -1,23 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <IO/WriteBufferFromFileDecorator.h>
|
#include <IO/WriteBufferFromFileDecorator.h>
|
||||||
|
#include <Interpreters/Cache/FileSegment.h>
|
||||||
|
#include <IO/IReadableWriteBuffer.h>
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
class FileSegment;
|
class FileSegment;
|
||||||
|
|
||||||
class WriteBufferToFileSegment : public WriteBufferFromFileDecorator
|
class WriteBufferToFileSegment : public WriteBufferFromFileDecorator, public IReadableWriteBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit WriteBufferToFileSegment(FileSegment * file_segment_);
|
explicit WriteBufferToFileSegment(FileSegment * file_segment_);
|
||||||
|
explicit WriteBufferToFileSegment(FileSegmentsHolder && segment_holder);
|
||||||
|
|
||||||
void nextImpl() override;
|
void nextImpl() override;
|
||||||
|
|
||||||
~WriteBufferToFileSegment() override;
|
~WriteBufferToFileSegment() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::shared_ptr<ReadBuffer> getReadBufferImpl() override;
|
||||||
|
|
||||||
|
/// Reference to the file segment in segment_holder if owned by this WriteBufferToFileSegment
|
||||||
|
/// or to the external file segment passed to the constructor
|
||||||
FileSegment * file_segment;
|
FileSegment * file_segment;
|
||||||
|
|
||||||
|
/// Empty if file_segment is not owned by this WriteBufferToFileSegment
|
||||||
|
FileSegmentsHolder segment_holder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <Core/ProtocolDefines.h>
|
#include <Core/ProtocolDefines.h>
|
||||||
#include <Disks/SingleDiskVolume.h>
|
#include <Disks/SingleDiskVolume.h>
|
||||||
#include <Disks/DiskLocal.h>
|
#include <Disks/DiskLocal.h>
|
||||||
|
#include <Disks/IO/WriteBufferFromTemporaryFile.h>
|
||||||
|
|
||||||
#include <Common/logger_useful.h>
|
#include <Common/logger_useful.h>
|
||||||
#include <Interpreters/Cache/WriteBufferToFileSegment.h>
|
#include <Interpreters/Cache/WriteBufferToFileSegment.h>
|
||||||
@ -54,29 +55,52 @@ TemporaryDataOnDisk::TemporaryDataOnDisk(TemporaryDataOnDiskScopePtr parent_, Cu
|
|||||||
, current_metric_scope(metric_scope)
|
, current_metric_scope(metric_scope)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TemporaryFileStream & TemporaryDataOnDisk::createStream(const Block & header, size_t max_file_size)
|
WriteBufferPtr TemporaryDataOnDisk::createRawStream(size_t max_file_size)
|
||||||
{
|
{
|
||||||
if (file_cache)
|
if (file_cache)
|
||||||
return createStreamToCacheFile(header, max_file_size);
|
{
|
||||||
|
auto holder = createCacheFile(max_file_size);
|
||||||
|
return std::make_shared<WriteBufferToFileSegment>(std::move(holder));
|
||||||
|
}
|
||||||
else if (volume)
|
else if (volume)
|
||||||
return createStreamToRegularFile(header, max_file_size);
|
{
|
||||||
|
auto tmp_file = createRegularFile(max_file_size);
|
||||||
|
return std::make_shared<WriteBufferFromTemporaryFile>(std::move(tmp_file));
|
||||||
|
}
|
||||||
|
|
||||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no cache and no volume");
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no cache and no volume");
|
||||||
}
|
}
|
||||||
|
|
||||||
TemporaryFileStream & TemporaryDataOnDisk::createStreamToCacheFile(const Block & header, size_t max_file_size)
|
TemporaryFileStream & TemporaryDataOnDisk::createStream(const Block & header, size_t max_file_size)
|
||||||
{
|
{
|
||||||
if (!file_cache)
|
if (file_cache)
|
||||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no cache");
|
{
|
||||||
|
auto holder = createCacheFile(max_file_size);
|
||||||
auto holder = file_cache->set(FileSegment::Key::random(), 0, std::max(10_MiB, max_file_size), CreateFileSegmentSettings(FileSegmentKind::Temporary, /* unbounded */ true));
|
|
||||||
|
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
TemporaryFileStreamPtr & tmp_stream = streams.emplace_back(std::make_unique<TemporaryFileStream>(std::move(holder), header, this));
|
TemporaryFileStreamPtr & tmp_stream = streams.emplace_back(std::make_unique<TemporaryFileStream>(std::move(holder), header, this));
|
||||||
return *tmp_stream;
|
return *tmp_stream;
|
||||||
|
}
|
||||||
|
else if (volume)
|
||||||
|
{
|
||||||
|
auto tmp_file = createRegularFile(max_file_size);
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
TemporaryFileStreamPtr & tmp_stream = streams.emplace_back(std::make_unique<TemporaryFileStream>(std::move(tmp_file), header, this));
|
||||||
|
return *tmp_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no cache and no volume");
|
||||||
}
|
}
|
||||||
|
|
||||||
TemporaryFileStream & TemporaryDataOnDisk::createStreamToRegularFile(const Block & header, size_t max_file_size)
|
FileSegmentsHolder TemporaryDataOnDisk::createCacheFile(size_t max_file_size)
|
||||||
|
{
|
||||||
|
if (!file_cache)
|
||||||
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no cache");
|
||||||
|
|
||||||
|
return file_cache->set(FileSegment::Key::random(), 0, std::max(10_MiB, max_file_size), CreateFileSegmentSettings(FileSegmentKind::Temporary, /* unbounded */ true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFileOnDiskHolder TemporaryDataOnDisk::createRegularFile(size_t max_file_size)
|
||||||
{
|
{
|
||||||
if (!volume)
|
if (!volume)
|
||||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no volume");
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryDataOnDiskScope has no volume");
|
||||||
@ -94,11 +118,7 @@ TemporaryFileStream & TemporaryDataOnDisk::createStreamToRegularFile(const Block
|
|||||||
disk = volume->getDisk();
|
disk = volume->getDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tmp_file = std::make_unique<TemporaryFileOnDisk>(disk, current_metric_scope);
|
return std::make_unique<TemporaryFileOnDisk>(disk, current_metric_scope);
|
||||||
|
|
||||||
std::lock_guard lock(mutex);
|
|
||||||
TemporaryFileStreamPtr & tmp_stream = streams.emplace_back(std::make_unique<TemporaryFileStream>(std::move(tmp_file), header, this));
|
|
||||||
return *tmp_stream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TemporaryFileStream *> TemporaryDataOnDisk::getStreams() const
|
std::vector<TemporaryFileStream *> TemporaryDataOnDisk::getStreams() const
|
||||||
@ -119,22 +139,11 @@ bool TemporaryDataOnDisk::empty() const
|
|||||||
|
|
||||||
struct TemporaryFileStream::OutputWriter
|
struct TemporaryFileStream::OutputWriter
|
||||||
{
|
{
|
||||||
OutputWriter(const String & path, const Block & header_)
|
OutputWriter(std::unique_ptr<WriteBuffer> out_buf_, const Block & header_)
|
||||||
: out_buf(std::make_unique<WriteBufferFromFile>(path))
|
|
||||||
, out_compressed_buf(*out_buf)
|
|
||||||
, out_writer(out_compressed_buf, DBMS_TCP_PROTOCOL_VERSION, header_)
|
|
||||||
{
|
|
||||||
LOG_TEST(&Poco::Logger::get("TemporaryFileStream"), "Writing to temporary file {}", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputWriter(std::unique_ptr<WriteBufferToFileSegment> out_buf_, const Block & header_)
|
|
||||||
: out_buf(std::move(out_buf_))
|
: out_buf(std::move(out_buf_))
|
||||||
, out_compressed_buf(*out_buf)
|
, out_compressed_buf(*out_buf)
|
||||||
, out_writer(out_compressed_buf, DBMS_TCP_PROTOCOL_VERSION, header_)
|
, out_writer(out_compressed_buf, DBMS_TCP_PROTOCOL_VERSION, header_)
|
||||||
{
|
{
|
||||||
LOG_TEST(&Poco::Logger::get("TemporaryFileStream"),
|
|
||||||
"Writing to temporary file {}",
|
|
||||||
static_cast<const WriteBufferToFileSegment *>(out_buf.get())->getFileName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(const Block & block)
|
size_t write(const Block & block)
|
||||||
@ -223,8 +232,9 @@ TemporaryFileStream::TemporaryFileStream(TemporaryFileOnDiskHolder file_, const
|
|||||||
: parent(parent_)
|
: parent(parent_)
|
||||||
, header(header_)
|
, header(header_)
|
||||||
, file(std::move(file_))
|
, file(std::move(file_))
|
||||||
, out_writer(std::make_unique<OutputWriter>(file->getPath(), header))
|
, out_writer(std::make_unique<OutputWriter>(std::make_unique<WriteBufferFromFile>(file->getPath()), header))
|
||||||
{
|
{
|
||||||
|
LOG_TEST(&Poco::Logger::get("TemporaryFileStream"), "Writing to temporary file {}", file->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
TemporaryFileStream::TemporaryFileStream(FileSegmentsHolder && segments_, const Block & header_, TemporaryDataOnDisk * parent_)
|
TemporaryFileStream::TemporaryFileStream(FileSegmentsHolder && segments_, const Block & header_, TemporaryDataOnDisk * parent_)
|
||||||
@ -236,6 +246,8 @@ TemporaryFileStream::TemporaryFileStream(FileSegmentsHolder && segments_, const
|
|||||||
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryFileStream can be created only from single segment");
|
throw Exception(ErrorCodes::LOGICAL_ERROR, "TemporaryFileStream can be created only from single segment");
|
||||||
auto & segment = segment_holder.file_segments.front();
|
auto & segment = segment_holder.file_segments.front();
|
||||||
auto out_buf = std::make_unique<WriteBufferToFileSegment>(segment.get());
|
auto out_buf = std::make_unique<WriteBufferToFileSegment>(segment.get());
|
||||||
|
|
||||||
|
LOG_TEST(&Poco::Logger::get("TemporaryFileStream"), "Writing to temporary file {}", out_buf->getFileName());
|
||||||
out_writer = std::make_unique<OutputWriter>(std::move(out_buf), header);
|
out_writer = std::make_unique<OutputWriter>(std::move(out_buf), header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,14 +90,20 @@ public:
|
|||||||
/// If max_file_size > 0, then check that there's enough space on the disk and throw an exception in case of lack of free space
|
/// If max_file_size > 0, then check that there's enough space on the disk and throw an exception in case of lack of free space
|
||||||
TemporaryFileStream & createStream(const Block & header, size_t max_file_size = 0);
|
TemporaryFileStream & createStream(const Block & header, size_t max_file_size = 0);
|
||||||
|
|
||||||
|
/// Write raw data directly into buffer.
|
||||||
|
/// Differences from `createStream`:
|
||||||
|
/// 1) it doesn't account data in parent scope
|
||||||
|
/// 2) returned buffer owns resources (instead of TemporaryDataOnDisk itself)
|
||||||
|
WriteBufferPtr createRawStream(size_t max_file_size = 0);
|
||||||
|
|
||||||
std::vector<TemporaryFileStream *> getStreams() const;
|
std::vector<TemporaryFileStream *> getStreams() const;
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
const StatAtomic & getStat() const { return stat; }
|
const StatAtomic & getStat() const { return stat; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TemporaryFileStream & createStreamToCacheFile(const Block & header, size_t max_file_size);
|
FileSegmentsHolder createCacheFile(size_t max_file_size);
|
||||||
TemporaryFileStream & createStreamToRegularFile(const Block & header, size_t max_file_size);
|
TemporaryFileOnDiskHolder createRegularFile(size_t max_file_size);
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
mutable std::mutex mutex;
|
||||||
std::vector<TemporaryFileStreamPtr> streams TSA_GUARDED_BY(mutex);
|
std::vector<TemporaryFileStreamPtr> streams TSA_GUARDED_BY(mutex);
|
||||||
|
@ -708,6 +708,27 @@ TEST_F(FileCacheTest, temporaryData)
|
|||||||
|
|
||||||
ASSERT_EQ(file_cache.getUsedCacheSize(), used_size_before_attempt);
|
ASSERT_EQ(file_cache.getUsedCacheSize(), used_size_before_attempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t before_used_size = file_cache.getUsedCacheSize();
|
||||||
|
auto tmp_data = std::make_unique<TemporaryDataOnDisk>(tmp_data_scope);
|
||||||
|
|
||||||
|
auto write_buf_stream = tmp_data->createRawStream();
|
||||||
|
|
||||||
|
write_buf_stream->write("1234567890", 10);
|
||||||
|
write_buf_stream->write("abcde", 5);
|
||||||
|
auto read_buf = dynamic_cast<IReadableWriteBuffer *>(write_buf_stream.get())->tryGetReadBuffer();
|
||||||
|
|
||||||
|
ASSERT_GT(file_cache.getUsedCacheSize(), before_used_size + 10);
|
||||||
|
|
||||||
|
char buf[15];
|
||||||
|
size_t read_size = read_buf->read(buf, 15);
|
||||||
|
ASSERT_EQ(read_size, 15);
|
||||||
|
ASSERT_EQ(std::string(buf, 15), "1234567890abcde");
|
||||||
|
read_size = read_buf->read(buf, 15);
|
||||||
|
ASSERT_EQ(read_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto tmp_data = std::make_unique<TemporaryDataOnDisk>(tmp_data_scope);
|
auto tmp_data = std::make_unique<TemporaryDataOnDisk>(tmp_data_scope);
|
||||||
auto & stream = tmp_data->createStream(generateBlock());
|
auto & stream = tmp_data->createStream(generateBlock());
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
#include <IO/ConcatReadBuffer.h>
|
#include <IO/ConcatReadBuffer.h>
|
||||||
#include <IO/MemoryReadWriteBuffer.h>
|
#include <IO/MemoryReadWriteBuffer.h>
|
||||||
#include <IO/ReadBufferFromString.h>
|
#include <IO/ReadBufferFromString.h>
|
||||||
#include <IO/WriteBufferFromTemporaryFile.h>
|
|
||||||
#include <IO/WriteHelpers.h>
|
#include <IO/WriteHelpers.h>
|
||||||
#include <IO/copyData.h>
|
#include <IO/copyData.h>
|
||||||
#include <Interpreters/Context.h>
|
#include <Interpreters/Context.h>
|
||||||
|
#include <Interpreters/TemporaryDataOnDisk.h>
|
||||||
#include <Parsers/QueryParameterVisitor.h>
|
#include <Parsers/QueryParameterVisitor.h>
|
||||||
#include <Interpreters/executeQuery.h>
|
#include <Interpreters/executeQuery.h>
|
||||||
#include <Interpreters/Session.h>
|
#include <Interpreters/Session.h>
|
||||||
@ -623,12 +623,11 @@ void HTTPHandler::processQuery(
|
|||||||
|
|
||||||
if (buffer_until_eof)
|
if (buffer_until_eof)
|
||||||
{
|
{
|
||||||
const std::string tmp_path(server.context()->getGlobalTemporaryVolume()->getDisk()->getPath());
|
auto tmp_data = std::make_shared<TemporaryDataOnDisk>(server.context()->getTempDataOnDisk());
|
||||||
const std::string tmp_path_template(fs::path(tmp_path) / "http_buffers/");
|
|
||||||
|
|
||||||
auto create_tmp_disk_buffer = [tmp_path_template] (const WriteBufferPtr &)
|
auto create_tmp_disk_buffer = [tmp_data] (const WriteBufferPtr &) -> WriteBufferPtr
|
||||||
{
|
{
|
||||||
return WriteBufferFromTemporaryFile::create(tmp_path_template);
|
return tmp_data->createRawStream(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
cascade_buffer2.emplace_back(std::move(create_tmp_disk_buffer));
|
cascade_buffer2.emplace_back(std::move(create_tmp_disk_buffer));
|
||||||
|
Loading…
Reference in New Issue
Block a user