This is an automated email from the ASF dual-hosted git repository.
changchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-gluten.git
The following commit(s) were added to refs/heads/main by this push:
new 735781ac00 [GLUTEN-7482][CH] Remove redundant head object operation of
s3 (#7565)
735781ac00 is described below
commit 735781ac00404e5e07fcf3a5f560afde3b134bed
Author: Shuai li <[email protected]>
AuthorDate: Thu Oct 17 13:12:03 2024 +0800
[GLUTEN-7482][CH] Remove redundant head object operation of s3 (#7565)
* remove head
* add set_read_util_position
---
.../commands/GlutenCacheFilesCommand.scala | 6 +-
.../execution/tpch/GlutenClickHouseHDFSSuite.scala | 47 +++-
.../Storages/SubstraitSource/ReadBufferBuilder.cpp | 239 ++++++---------------
3 files changed, 106 insertions(+), 186 deletions(-)
diff --git
a/backends-clickhouse/src/main/scala/org/apache/spark/sql/execution/commands/GlutenCacheFilesCommand.scala
b/backends-clickhouse/src/main/scala/org/apache/spark/sql/execution/commands/GlutenCacheFilesCommand.scala
index aec414f055..44d8cf196c 100644
---
a/backends-clickhouse/src/main/scala/org/apache/spark/sql/execution/commands/GlutenCacheFilesCommand.scala
+++
b/backends-clickhouse/src/main/scala/org/apache/spark/sql/execution/commands/GlutenCacheFilesCommand.scala
@@ -101,6 +101,7 @@ case class GlutenCacheFilesCommand(
val paths = new JArrayList[String]()
val starts = new JArrayList[JLong]()
val lengths = new JArrayList[JLong]()
+ val modificationTimes = new JArrayList[JLong]()
val partitionColumns = new JArrayList[JMap[String, String]]
fileStatusArray.foreach(
@@ -108,6 +109,7 @@ case class GlutenCacheFilesCommand(
paths.add(fileStatus.getPath.toUri.toASCIIString)
starts.add(JLong.valueOf(0))
lengths.add(JLong.valueOf(fileStatus.getLen))
+
modificationTimes.add(JLong.valueOf(fileStatus.getModificationTime))
partitionColumns.add(new JHashMap[String, String]())
})
@@ -116,8 +118,8 @@ case class GlutenCacheFilesCommand(
paths,
starts,
lengths,
- lengths,
- new JArrayList[JLong](),
+ lengths, /* fileSizes */
+ modificationTimes,
partitionColumns,
new JArrayList[JMap[String, String]](),
ReadFileFormat.ParquetReadFormat, // ignore format in backend
diff --git
a/backends-clickhouse/src/test/scala/org/apache/gluten/execution/tpch/GlutenClickHouseHDFSSuite.scala
b/backends-clickhouse/src/test/scala/org/apache/gluten/execution/tpch/GlutenClickHouseHDFSSuite.scala
index e18242dde3..7a1bba0f1b 100644
---
a/backends-clickhouse/src/test/scala/org/apache/gluten/execution/tpch/GlutenClickHouseHDFSSuite.scala
+++
b/backends-clickhouse/src/test/scala/org/apache/gluten/execution/tpch/GlutenClickHouseHDFSSuite.scala
@@ -144,11 +144,11 @@ class GlutenClickHouseHDFSSuite
test("GLUTEN-7542: Fix cache refresh") {
withSQLConf("spark.sql.hive.manageFilesourcePartitions" -> "false") {
- val file_path = s"$tablesPath/issue_7542/"
- val targetDirs = new Path(file_path)
+ val filePath = s"$tablesPath/issue_7542/"
+ val targetDirs = new Path(filePath)
val fs = targetDirs.getFileSystem(spark.sessionState.newHadoopConf())
fs.mkdirs(targetDirs)
- val out = fs.create(new Path(s"$file_path/00000_0"))
+ val out = fs.create(new Path(s"$filePath/00000_0"))
IOUtils.write("1\n2\n3\n4\n5", out, Charset.defaultCharset())
out.close()
sql(s"""
@@ -156,12 +156,12 @@ class GlutenClickHouseHDFSSuite
| `c_custkey` int )
|using CSV
|LOCATION
- | '$file_path/'
+ | '$filePath/'
|""".stripMargin)
sql(s"""select * from issue_7542""").collect()
- fs.delete(new Path(s"$file_path/00000_0"), false)
- val out2 = fs.create(new Path(s"$file_path/00000_0"))
+ fs.delete(new Path(s"$filePath/00000_0"), false)
+ val out2 = fs.create(new Path(s"$filePath/00000_0"))
IOUtils.write("1\n2\n3\n4\n3\n3\n3", out2, Charset.defaultCharset())
out2.close()
val df = sql(s"""select count(*) from issue_7542 where c_custkey=3""")
@@ -176,4 +176,39 @@ class GlutenClickHouseHDFSSuite
sql("drop table issue_7542")
}
}
+
+ test("test set_read_util_position") {
+ val tableName = "read_until_test"
+ val tablePath = s"$tablesPath/$tableName/"
+ val targetFile = new Path(tablesPath)
+ val fs = targetFile.getFileSystem(spark.sessionState.newHadoopConf())
+ fs.delete(new Path(tablePath), true)
+ sql(s"""
+ | CREATE TABLE $tableName
+ | USING csv
+ | LOCATION '$tablePath'
+ | as
+ | select * from lineitem
+ |""".stripMargin)
+
+ val sql_str =
+ s"""
+ |SELECT
+ | sum(l_extendedprice * l_discount) AS revenue
+ |FROM
+ | $tableName
+ |WHERE
+ | l_shipdate >= date'1994-01-01'
+ | AND l_shipdate < date'1994-01-01' + interval 1 year
+ | AND l_discount BETWEEN 0.06 - 0.01 AND 0.06 + 0.01
+ | AND l_quantity < 24;
+ |
+ |""".stripMargin
+
+ withSQLConf("spark.sql.files.maxPartitionBytes" -> "1M") {
+ compareResultsAgainstVanillaSpark(sql_str, compareResult = true, _ => {})
+ }
+
+ fs.delete(new Path(tablePath), true)
+ }
}
diff --git a/cpp-ch/local-engine/Storages/SubstraitSource/ReadBufferBuilder.cpp
b/cpp-ch/local-engine/Storages/SubstraitSource/ReadBufferBuilder.cpp
index 0e2d8f41be..56205f224a 100644
--- a/cpp-ch/local-engine/Storages/SubstraitSource/ReadBufferBuilder.cpp
+++ b/cpp-ch/local-engine/Storages/SubstraitSource/ReadBufferBuilder.cpp
@@ -31,14 +31,12 @@
#include <IO/ReadSettings.h>
#include <IO/S3/getObjectInfo.h>
#include <IO/S3Common.h>
-#include <IO/S3Settings.h>
#include <IO/SeekableReadBuffer.h>
#include <Interpreters/Cache/FileCache.h>
#include <Interpreters/Cache/FileCacheFactory.h>
#include <Interpreters/Cache/FileCacheSettings.h>
#include <Interpreters/Context.h>
#include <Storages/ObjectStorage/HDFS/AsynchronousReadBufferFromHDFS.h>
-#include <Storages/ObjectStorage/HDFS/HDFSCommon.h>
#include <Storages/ObjectStorage/HDFS/ReadBufferFromHDFS.h>
#include <Storages/SubstraitSource/ReadBufferBuilder.h>
#include <Storages/SubstraitSource/SubstraitFileSource.h>
@@ -92,7 +90,7 @@ template <class key_type, class value_type>
class ConcurrentLRU
{
public:
- ConcurrentLRU(size_t size) : cache(size) { }
+ explicit ConcurrentLRU(size_t size) : cache(size) { }
boost::optional<value_type> get(const key_type & key)
{
std::shared_lock<std::shared_mutex> lock(rwLock);
@@ -117,12 +115,13 @@ private:
std::shared_mutex rwLock;
};
-std::pair<size_t, size_t> adjustFileReadPosition(DB::ReadBufferFromFileBase &
buffer, size_t read_start_pos, size_t read_end_pos)
+static std::pair<size_t, size_t>
adjustFileReadPosition(DB::ReadBufferFromFileBase & buffer, size_t
read_start_pos, size_t read_end_pos)
{
auto get_next_line_pos = [&](DB::ReadBufferFromFileBase & buf) -> size_t
{
while (!buf.eof())
{
+ /// Search for \n or \r\n or \n\r or \r in buffer.
if (*buf.position() == '\r')
{
++buf.position();
@@ -137,6 +136,12 @@ std::pair<size_t, size_t>
adjustFileReadPosition(DB::ReadBufferFromFileBase & bu
else if (*buf.position() == '\n')
{
++buf.position();
+
+ if (!buf.eof() && *buf.position() == '\r')
+ {
+ ++buf.position();
+ }
+
return buf.getPosition();
}
@@ -167,6 +172,26 @@ std::pair<size_t, size_t>
adjustFileReadPosition(DB::ReadBufferFromFileBase & bu
return result;
}
+static std::unique_ptr<DB::ReadBufferFromFileBase>
+resetOffset(std::unique_ptr<DB::ReadBufferFromFileBase> read_buffer, const
substrait::ReadRel::LocalFiles::FileOrFiles & file_info)
+{
+ auto start_end_pos = adjustFileReadPosition(*read_buffer,
file_info.start(), file_info.start() + file_info.length());
+ LOG_DEBUG(
+ &Poco::Logger::get("ReadBufferBuilder"),
+ "File read start and end position adjusted from {},{} to {},{}",
+ file_info.start(),
+ file_info.start() + file_info.length(),
+ start_end_pos.first,
+ start_end_pos.second);
+
+ if (dynamic_cast<DB::ReadBufferFromHDFS *>(read_buffer.get()) ||
dynamic_cast<DB::ReadBufferFromFile *>(read_buffer.get()))
+ read_buffer =
std::make_unique<DB::BoundedReadBuffer>(std::move(read_buffer));
+
+ read_buffer->seek(start_end_pos.first, SEEK_SET);
+ read_buffer->setReadUntilPosition(start_end_pos.second);
+ return read_buffer;
+}
+
class LocalFileReadBufferBuilder : public ReadBufferBuilder
{
public:
@@ -188,22 +213,8 @@ public:
else
read_buffer = std::make_unique<DB::ReadBufferFromFile>(file_path);
-
if (set_read_util_position)
- {
- read_buffer =
std::make_unique<DB::BoundedReadBuffer>(std::move(read_buffer));
- auto start_end_pos = adjustFileReadPosition(*read_buffer,
file_info.start(), file_info.start() + file_info.length());
- LOG_DEBUG(
- &Poco::Logger::get("ReadBufferBuilder"),
- "File read start and end position adjusted from {},{} to
{},{}",
- file_info.start(),
- file_info.start() + file_info.length(),
- start_end_pos.first,
- start_end_pos.second);
-
- read_buffer->seek(start_end_pos.first, SEEK_SET);
- read_buffer->setReadUntilPosition(start_end_pos.second);
- }
+ return resetOffset(std::move(read_buffer), file_info);
return read_buffer;
}
@@ -228,25 +239,6 @@ public:
if (file_uri.getPort())
uri_path += ":" +
std::to_string(static_cast<unsigned>(file_uri.getPort()));
- size_t read_util_position = 0;
- size_t read_begin = 0;
- if (set_read_util_position)
- {
- std::pair<size_t, size_t> start_end_pos
- = adjustFileReadStartAndEndPos(file_info.start(),
file_info.start() + file_info.length(), uri_path, file_uri.getPath());
-
- LOG_DEBUG(
- &Poco::Logger::get("ReadBufferBuilder"),
- "File read start and end position adjusted from {},{} to
{},{}",
- file_info.start(),
- file_info.start() + file_info.length(),
- start_end_pos.first,
- start_end_pos.second);
-
- read_begin = start_end_pos.first;
- read_util_position = start_end_pos.second;
- }
-
size_t file_size = 0;
size_t modified_time = 0;
if (file_info.has_properties())
@@ -255,7 +247,7 @@ public:
modified_time = file_info.properties().modificationtime();
}
- std::unique_ptr<DB::ReadBuffer> read_buffer;
+ std::unique_ptr<DB::ReadBufferFromFileBase> read_buffer;
if (hdfs_config.hdfs_async)
{
@@ -263,10 +255,13 @@ public:
if (file_size)
size = file_size;
- auto read_buffer_impl = std::make_shared<DB::ReadBufferFromHDFS>(
- uri_path, file_uri.getPath(), config,
read_settings, read_util_position, true, size);
- auto & pool_reader =
context->getThreadPoolReader(DB::FilesystemReaderType::ASYNCHRONOUS_REMOTE_FS_READER);
- read_buffer =
std::make_unique<DB::AsynchronousReadBufferFromHDFS>(pool_reader,
read_settings, std::move(read_buffer_impl));
+ read_buffer
+ = std::make_unique<DB::ReadBufferFromHDFS>(uri_path,
file_uri.getPath(), config, read_settings, file_size, true, size);
+ if (read_settings.remote_fs_prefetch)
+ {
+ auto & pool_reader =
context->getThreadPoolReader(DB::FilesystemReaderType::ASYNCHRONOUS_REMOTE_FS_READER);
+ read_buffer =
std::make_unique<DB::AsynchronousBoundedReadBuffer>(std::move(read_buffer),
pool_reader, read_settings);
+ }
}
else
{
@@ -275,16 +270,16 @@ public:
// only for spark3.2 file partition not contained file size
// so first compute file size first
auto read_buffer_impl =
std::make_unique<DB::ReadBufferFromHDFS>(
- uri_path, file_uri.getPath(), config, read_settings,
read_util_position, true);
+ uri_path, file_uri.getPath(), config, read_settings, 0,
true);
file_size = read_buffer_impl->getFileSize();
}
ReadBufferCreator hdfs_read_buffer_creator
- = [this, hdfs_uri = uri_path, hdfs_file_path =
file_uri.getPath(), read_settings, &config, read_util_position](
+ = [this, hdfs_uri = uri_path, hdfs_file_path =
file_uri.getPath(), read_settings, &config](
bool /* restricted_seek */, const DB::StoredObject &
object) -> std::unique_ptr<DB::ReadBufferFromHDFS>
{
return std::make_unique<DB::ReadBufferFromHDFS>(
- hdfs_uri, hdfs_file_path, config, read_settings,
read_util_position, true, object.bytes_size);
+ hdfs_uri, hdfs_file_path, config, read_settings, 0, true,
object.bytes_size);
};
auto remote_path = file_uri.getPath().substr(1);
@@ -292,122 +287,15 @@ public:
auto cache_creator = wrapWithCache(hdfs_read_buffer_creator,
read_settings, remote_path, modified_time, file_size);
auto cache_hdfs_read =
std::make_unique<DB::ReadBufferFromRemoteFSGather>(
std::move(cache_creator), stored_objects, read_settings,
nullptr, /* use_external_buffer */ false);
- cache_hdfs_read->setReadUntilPosition(read_util_position);
read_buffer = std::move(cache_hdfs_read);
}
- if (set_read_util_position && read_begin)
- if (auto * seekable_in = dynamic_cast<DB::SeekableReadBuffer
*>(read_buffer.get()))
- seekable_in->seek(read_begin, SEEK_SET);
+ if (set_read_util_position)
+ return resetOffset(std::move(read_buffer), file_info);
return read_buffer;
}
- std::pair<size_t, size_t>
- adjustFileReadStartAndEndPos(size_t read_start_pos, size_t read_end_pos,
const std::string & uri_path, const std::string & file_path)
- {
- auto builder = DB::createHDFSBuilder(uri_path,
context->getConfigRef());
- auto fs = DB::createHDFSFS(builder.get());
- hdfsFile fin = hdfsOpenFile(fs.get(), file_path.c_str(), O_RDONLY, 0,
0, 0);
- std::string hdfs_file_path = uri_path + file_path;
- if (!fin)
- throw DB::Exception(
- DB::ErrorCodes::CANNOT_OPEN_FILE, "Cannot open hdfs file:{},
error: {}", hdfs_file_path, std::string(hdfsGetLastError()));
-
- /// Always close hdfs file before exit function.
- SCOPE_EXIT({ hdfsCloseFile(fs.get(), fin); });
-
- auto hdfs_file_info = hdfsGetPathInfo(fs.get(), file_path.c_str());
- if (!hdfs_file_info)
- throw DB::Exception(
- DB::ErrorCodes::UNKNOWN_FILE_SIZE,
- "Cannot find out file size for :{}, error: {}",
- hdfs_file_path,
- std::string(hdfsGetLastError()));
- size_t hdfs_file_size = hdfs_file_info->mSize;
-
- /// initial_pos maybe in the middle of a row, so we need to find the
next row start position.
- auto get_next_line_pos = [&](hdfsFS hdfs_fs, hdfsFile file, size_t
initial_pos, size_t file_size) -> size_t
- {
- if (initial_pos == 0 || initial_pos == file_size)
- return initial_pos;
-
- int seek_ret = hdfsSeek(hdfs_fs, file, initial_pos);
- if (seek_ret < 0)
- throw DB::Exception(
- DB::ErrorCodes::CANNOT_SEEK_THROUGH_FILE,
- "Fail to seek HDFS file: {}, error: {}",
- file_path,
- std::string(hdfsGetLastError()));
-
- static constexpr size_t buf_size = 1024;
- char buf[buf_size];
-
- auto do_read = [&]() -> int
- {
- auto n = hdfsRead(hdfs_fs, file, buf, buf_size);
- if (n < 0)
- throw DB::Exception(
- DB::ErrorCodes::CANNOT_READ_FROM_FILE_DESCRIPTOR,
- "Fail to read HDFS file: {}, error: {}",
- file_path,
- std::string(hdfsGetLastError()));
-
- return n;
- };
-
- auto pos = initial_pos;
- while (true)
- {
- auto n = do_read();
-
- /// If read to the end of file, return directly.
- if (n == 0)
- return pos;
-
- /// Search for \n or \r\n or \n\r in buffer.
- int i = 0;
- while (i < n)
- {
- if (buf[i] == '\n')
- {
- if (i + 1 < n)
- return buf[i + 1] == '\r' ? pos + i + 2 : pos + i
+ 1;
-
- /// read again if buffer is not enough.
- auto m = do_read();
- if (m == 0)
- return pos + i + 1;
-
- return buf[0] == '\r' ? pos + i + 2 : pos + i + 1;
- }
- else if (buf[i] == '\r')
- {
- if (i + 1 < n)
- return buf[i + 1] == '\n' ? pos + i + 2 : pos + i
+ 1;
-
- /// read again if buffer is not enough.
- auto m = do_read();
- if (m == 0)
- return pos + i + 1;
-
- return buf[0] == '\n' ? pos + i + 2 : pos + i + 1;
- }
- else
- ++i;
- }
-
- /// Can't find \n or \r\n or \n\r in current buffer, read
again.
- pos += n;
- }
- };
-
- std::pair<size_t, size_t> result;
- result.first = get_next_line_pos(fs.get(), fin, read_start_pos,
hdfs_file_size);
- result.second = get_next_line_pos(fs.get(), fin, read_end_pos,
hdfs_file_size);
- return result;
- }
-
private:
DB::ContextPtr context;
};
@@ -450,9 +338,20 @@ public:
const std::string& bucket = file_uri.getHost();
const auto client = getClient(bucket);
std::string pathKey = file_uri.getPath().substr(1);
- DB::S3::ObjectInfo object_info = DB::S3::getObjectInfo(*client,
bucket, pathKey, "");
- size_t object_size = object_info.size;
- Int64 object_modified_time = object_info.last_modification_time;
+
+ size_t object_size = 0;
+ size_t object_modified_time = 0;
+ if (file_info.has_properties())
+ {
+ object_size = file_info.properties().filesize();
+ object_modified_time = file_info.properties().modificationtime();
+ }
+ else
+ {
+ DB::S3::ObjectInfo object_info = DB::S3::getObjectInfo(*client,
bucket, pathKey, "");
+ object_size = object_info.size;
+ object_modified_time = object_info.last_modification_time;
+ }
auto read_buffer_creator
= [bucket, client, read_settings, this](bool restricted_seek,
const DB::StoredObject & object) -> std::unique_ptr<DB::ReadBufferFromFileBase>
@@ -478,30 +377,14 @@ public:
auto & pool_reader =
context->getThreadPoolReader(DB::FilesystemReaderType::ASYNCHRONOUS_REMOTE_FS_READER);
auto async_reader
- =
std::make_unique<DB::AsynchronousBoundedReadBuffer>(std::move(s3_impl),
pool_reader, read_settings, nullptr, nullptr);
-
- if (set_read_util_position)
- {
- auto start_end_pos = adjustFileReadPosition(*async_reader,
file_info.start(), file_info.start() + file_info.length());
- LOG_DEBUG(
- &Poco::Logger::get("ReadBufferBuilder"),
- "File read start and end position adjusted from {},{} to
{},{}",
- file_info.start(),
- file_info.start() + file_info.length(),
- start_end_pos.first,
- start_end_pos.second);
-
- async_reader->seek(start_end_pos.first, SEEK_SET);
- async_reader->setReadUntilPosition(start_end_pos.second);
- }
- else
- {
- async_reader->setReadUntilEnd();
- }
+ =
std::make_unique<DB::AsynchronousBoundedReadBuffer>(std::move(s3_impl),
pool_reader, read_settings);
if (read_settings.remote_fs_prefetch)
async_reader->prefetch(Priority{});
+ if (set_read_util_position)
+ return resetOffset(std::move(async_reader), file_info);
+
return async_reader;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]