|
15 | 15 | */
|
16 | 16 |
|
17 | 17 | #include <fcntl.h>
|
| 18 | +#include <folly/executors/CPUThreadPoolExecutor.h> |
18 | 19 |
|
19 | 20 | #include "velox/common/base/tests/GTestUtils.h"
|
20 | 21 | #include "velox/common/file/File.h"
|
@@ -66,7 +67,10 @@ void writeDataWithOffset(WriteFile* writeFile) {
|
66 | 67 | ASSERT_EQ(writeFile->size(), 15 + kOneMB);
|
67 | 68 | }
|
68 | 69 |
|
69 |
| -void readData(ReadFile* readFile, bool checkFileSize = true) { |
| 70 | +void readData( |
| 71 | + ReadFile* readFile, |
| 72 | + bool checkFileSize = true, |
| 73 | + bool testReadAsync = false) { |
70 | 74 | if (checkFileSize) {
|
71 | 75 | ASSERT_EQ(readFile->size(), 15 + kOneMB);
|
72 | 76 | }
|
@@ -105,6 +109,30 @@ void readData(ReadFile* readFile, bool checkFileSize = true) {
|
105 | 109 | ASSERT_EQ(std::string_view(head, sizeof(head)), "aaaaabbbbbcc");
|
106 | 110 | ASSERT_EQ(std::string_view(middle, sizeof(middle)), "cccc");
|
107 | 111 | ASSERT_EQ(std::string_view(tail, sizeof(tail)), "ccddddd");
|
| 112 | + if (testReadAsync) { |
| 113 | + std::vector<folly::Range<char*>> buffers1 = { |
| 114 | + folly::Range<char*>(head, sizeof(head)), |
| 115 | + folly::Range<char*>(nullptr, (char*)(uint64_t)500000)}; |
| 116 | + auto future1 = readFile->preadvAsync(0, buffers1); |
| 117 | + const auto offset1 = sizeof(head) + 500000; |
| 118 | + std::vector<folly::Range<char*>> buffers2 = { |
| 119 | + folly::Range<char*>(middle, sizeof(middle)), |
| 120 | + folly::Range<char*>( |
| 121 | + nullptr, |
| 122 | + (char*)(uint64_t)(15 + kOneMB - offset1 - sizeof(middle) - |
| 123 | + sizeof(tail)))}; |
| 124 | + auto future2 = readFile->preadvAsync(offset1, buffers2); |
| 125 | + std::vector<folly::Range<char*>> buffers3 = { |
| 126 | + folly::Range<char*>(tail, sizeof(tail))}; |
| 127 | + const auto offset2 = 15 + kOneMB - sizeof(tail); |
| 128 | + auto future3 = readFile->preadvAsync(offset2, buffers3); |
| 129 | + ASSERT_EQ(offset1, future1.wait().value()); |
| 130 | + ASSERT_EQ(offset2 - offset1, future2.wait().value()); |
| 131 | + ASSERT_EQ(sizeof(tail), future3.wait().value()); |
| 132 | + ASSERT_EQ(std::string_view(head, sizeof(head)), "aaaaabbbbbcc"); |
| 133 | + ASSERT_EQ(std::string_view(middle, sizeof(middle)), "cccc"); |
| 134 | + ASSERT_EQ(std::string_view(tail, sizeof(tail)), "ccddddd"); |
| 135 | + } |
108 | 136 | }
|
109 | 137 |
|
110 | 138 | // We could templated this test, but that's kinda overkill for how simple it is.
|
@@ -157,6 +185,13 @@ class LocalFileTest : public ::testing::TestWithParam<bool> {
|
157 | 185 | }
|
158 | 186 |
|
159 | 187 | const bool useFaultyFs_;
|
| 188 | + const std::unique_ptr<folly::CPUThreadPoolExecutor> executor_ = |
| 189 | + std::make_unique<folly::CPUThreadPoolExecutor>( |
| 190 | + std::max( |
| 191 | + 1, |
| 192 | + static_cast<int32_t>(std::thread::hardware_concurrency() / 2)), |
| 193 | + std::make_shared<folly::NamedThreadFactory>( |
| 194 | + "LocalFileReadAheadTest")); |
160 | 195 | };
|
161 | 196 |
|
162 | 197 | TEST_P(LocalFileTest, writeAndRead) {
|
@@ -185,6 +220,14 @@ TEST_P(LocalFileTest, writeAndRead) {
|
185 | 220 | writeFile->close();
|
186 | 221 | ASSERT_EQ(writeFile->size(), 15 + kOneMB);
|
187 | 222 | }
|
| 223 | + // Test read async. |
| 224 | + if (!useFaultyFs_) { |
| 225 | + auto readFile = |
| 226 | + std::make_shared<LocalReadFile>(filename, executor_.get()); |
| 227 | + readData(readFile.get(), true, true); |
| 228 | + auto readFileWithoutExecutor = std::make_shared<LocalReadFile>(filename); |
| 229 | + readData(readFileWithoutExecutor.get(), true, true); |
| 230 | + } |
188 | 231 | auto readFile = fs->openFileForRead(filename);
|
189 | 232 | readData(readFile.get());
|
190 | 233 | }
|
|
0 commit comments