This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 50fd9971b03 [Opt](orc)Optimize the merge io when orc reader read 
multiple tiny stripes. (#42004)
50fd9971b03 is described below

commit 50fd9971b0380f5a4f360067b60c24a381e224f3
Author: daidai <[email protected]>
AuthorDate: Thu Nov 7 22:54:23 2024 +0800

    [Opt](orc)Optimize the merge io when orc reader read multiple tiny stripes. 
(#42004)
    
    ### What problem does this PR solve?
    
    When reading orc files, we may encounter a scenario where the stripe
    byte size is very small but the number of stripes is very large.
    
    This pr introduces three session variables
    `orc_tiny_stripe_threshold_bytes`, `orc_once_max_read_bytes`, and
    `orc_max_merge_distance_bytes` to optimize io reading for the above
    scenarios.
    
    If a stripe byte size is less than `orc_tiny_stripe_threshold_bytes`, we
    will consider it as a tiny stripe. For multiple tiny stripes, we will
    perform IO merge reading according to the `orc_once_max_read_bytes` and
    `orc_max_merge_distance_bytes` parameters. Among them,
    `orc_once_max_read_bytes` indicates the maximum size of the merged IO.
    You should not set `orc_once_max_read_bytes` less than
    `orc_tiny_stripe_threshold_bytes`, although we will not force an error.
    When using tiny stripe reading optimization, since tiny stripes are not
    necessarily continuous, when the distance between two tiny stripes is
    greater than `orc_max_merge_distance_bytes`, we will not merge them into
    one IO.
    
    If you don't want to use this optimization, you can `set
    orc_tiny_stripe_threshold_bytes = 0`.
    
    
    Default parameters:
    ```mysql
    orc_tiny_stripe_threshold_bytes = 8388608 (8M)
    orc_once_max_read_bytes = 8388608 (8M)
    orc_max_merge_distance_bytes = 1048576 (1M)
    ```
    
    We also add relevant profiles for this purpose so that parameters can be
    adjusted to optimize reading.
    `RangeCacheFileReader`:
    1. `CacheRefreshCount`: how many IOs are merged
    2. `ReadToCacheBytes`: how much data is actually read after merging
    3. `ReadToCacheTime`: how long it takes to read data after merging
    4. `RequestBytes`: how many bytes does the apache-orc library actually
    need to read the orc file
    5. `RequestIO`: how many times the apache-orc library calls this read
    interface
    6. `RequestTime`: how long it takes the apache-orc library to call this
    read interface
    
    It should be noted that `RangeCacheFileReader` is a wrapper of the
    reader that actually reads data, such as the hdfs reader, so strictly
    speaking, `CacheRefreshCount` is not equal to how many IOs are initiated
    to hdfs, because each time the hdfs reader is requested, the hdfs reader
    may not be able to read all the data at once.
    
    This pr also involves changes to the apache-orc third-party library:
    https://github.com/apache/doris-thirdparty/pull/244.
    Reference implementation:
    
https://github.com/trinodb/trino/blob/master/lib/trino-orc/src/main/java/io/trino/orc/OrcDataSourceUtils.java#L36
    
    #### Summary:
    ```mysql
    set orc_tiny_stripe_threshold_bytes = xxx;
    set orc_once_max_read_bytes = xxx;
    set orc_max_merge_distance_bytes = xxx;
    
    # xxx is the size in bytes
    ```
    
    ### Release note
    Introduces three session variables `orc_tiny_stripe_threshold_bytes`,
    `orc_once_max_read_bytes`, and `orc_max_merge_distance_bytes` to
    optimize io reading of scenarios where the orc stripe byte size is very
    small but the number of stripes is very large.
    
    
    Co-authored-by: kaka11chen <[email protected]>
    Co-authored-by: daidai <[email protected]>
---
 be/src/apache-orc                                  |    2 +-
 be/src/io/fs/buffered_reader.cpp                   |  102 +
 be/src/io/fs/buffered_reader.h                     |  141 ++
 be/src/vec/exec/format/orc/vorc_reader.cpp         |   80 +-
 be/src/vec/exec/format/orc/vorc_reader.h           |   15 +-
 be/test/io/fs/buffered_reader_test.cpp             |  108 +
 .../scripts/create_preinstalled_scripts/run67.hql  |   11 +
 .../orc/orc_tiny_stripes/output_60_3.orc           |  Bin 0 -> 19688 bytes
 .../orc/orc_tiny_stripes/output_6_1.orc            |  Bin 0 -> 1902 bytes
 .../orc/orc_tiny_stripes/random_output_60_3.orc    |  Bin 0 -> 24248 bytes
 .../orc/orc_tiny_stripes/random_output_6_1.orc     |  Bin 0 -> 2293 bytes
 .../java/org/apache/doris/qe/SessionVariable.java  |   77 +
 gensrc/thrift/PaloInternalService.thrift           |    4 +
 .../hive/test_orc_tiny_stripes.out                 | 2311 ++++++++++++++++++++
 .../hive/test_orc_tiny_stripes.groovy              |  203 ++
 15 files changed, 3038 insertions(+), 16 deletions(-)

diff --git a/be/src/apache-orc b/be/src/apache-orc
index 903ea6ccdc4..db01184f765 160000
--- a/be/src/apache-orc
+++ b/be/src/apache-orc
@@ -1 +1 @@
-Subproject commit 903ea6ccdc463b8a17af2604975107ba7d895380
+Subproject commit db01184f765c03496e4107bd3ac37c077ac4bc5f
diff --git a/be/src/io/fs/buffered_reader.cpp b/be/src/io/fs/buffered_reader.cpp
index 20d5684734e..7fd85caa43b 100644
--- a/be/src/io/fs/buffered_reader.cpp
+++ b/be/src/io/fs/buffered_reader.cpp
@@ -869,5 +869,107 @@ Result<io::FileReaderSPtr> 
DelegateReader::create_file_reader(
                 return reader;
             });
 }
+
+Status LinearProbeRangeFinder::get_range_for(int64_t desired_offset,
+                                             io::PrefetchRange& result_range) {
+    while (index < _ranges.size()) {
+        io::PrefetchRange& range = _ranges[index];
+        if (range.end_offset > desired_offset) {
+            if (range.start_offset > desired_offset) [[unlikely]] {
+                return Status::InvalidArgument("Invalid desiredOffset");
+            }
+            result_range = range;
+            return Status::OK();
+        }
+        ++index;
+    }
+    return Status::InvalidArgument("Invalid desiredOffset");
+}
+
+RangeCacheFileReader::RangeCacheFileReader(RuntimeProfile* profile, 
io::FileReaderSPtr inner_reader,
+                                           std::shared_ptr<RangeFinder> 
range_finder)
+        : _profile(profile),
+          _inner_reader(std::move(inner_reader)),
+          _range_finder(std::move(range_finder)) {
+    _size = _inner_reader->size();
+    uint64_t max_cache_size =
+            std::max((uint64_t)4096, 
(uint64_t)_range_finder->get_max_range_size());
+    _cache = OwnedSlice(max_cache_size);
+
+    if (_profile != nullptr) {
+        const char* random_profile = "RangeCacheFileReader";
+        ADD_TIMER_WITH_LEVEL(_profile, random_profile, 1);
+        _request_io =
+                ADD_CHILD_COUNTER_WITH_LEVEL(_profile, "RequestIO", 
TUnit::UNIT, random_profile, 1);
+        _request_bytes = ADD_CHILD_COUNTER_WITH_LEVEL(_profile, 
"RequestBytes", TUnit::BYTES,
+                                                      random_profile, 1);
+        _request_time = ADD_CHILD_TIMER_WITH_LEVEL(_profile, "RequestTime", 
random_profile, 1);
+        _read_to_cache_time =
+                ADD_CHILD_TIMER_WITH_LEVEL(_profile, "ReadToCacheTime", 
random_profile, 1);
+        _cache_refresh_count = ADD_CHILD_COUNTER_WITH_LEVEL(_profile, 
"CacheRefreshCount",
+                                                            TUnit::UNIT, 
random_profile, 1);
+        _read_to_cache_bytes = ADD_CHILD_COUNTER_WITH_LEVEL(_profile, 
"ReadToCacheBytes",
+                                                            TUnit::BYTES, 
random_profile, 1);
+    }
+}
+
+Status RangeCacheFileReader::read_at_impl(size_t offset, Slice result, size_t* 
bytes_read,
+                                          const IOContext* io_ctx) {
+    auto request_size = result.size;
+
+    _cache_statistics.request_io++;
+    _cache_statistics.request_bytes += request_size;
+    SCOPED_RAW_TIMER(&_cache_statistics.request_time);
+
+    PrefetchRange range;
+    if (_range_finder->get_range_for(offset, range)) [[likely]] {
+        if (_current_start_offset != range.start_offset) { // need read new 
range to cache.
+            auto range_size = range.end_offset - range.start_offset;
+
+            _cache_statistics.cache_refresh_count++;
+            _cache_statistics.read_to_cache_bytes += range_size;
+            SCOPED_RAW_TIMER(&_cache_statistics.read_to_cache_time);
+
+            Slice cache_slice = {_cache.data(), range_size};
+            RETURN_IF_ERROR(
+                    _inner_reader->read_at(range.start_offset, cache_slice, 
bytes_read, io_ctx));
+
+            if (*bytes_read != range_size) [[unlikely]] {
+                return Status::InternalError(
+                        "RangeCacheFileReader use inner reader read bytes {} 
not eq expect size {}",
+                        *bytes_read, range_size);
+            }
+
+            _current_start_offset = range.start_offset;
+        }
+
+        int64_t buffer_offset = offset - _current_start_offset;
+        memcpy(result.data, _cache.data() + buffer_offset, request_size);
+        *bytes_read = request_size;
+
+        return Status::OK();
+    } else {
+        return Status::InternalError("RangeCacheFileReader read  not in 
Ranges. Offset = {}",
+                                     offset);
+        //                RETURN_IF_ERROR(_inner_reader->read_at(offset, 
result , bytes_read, io_ctx));
+        //                return Status::OK();
+        // think return error is ok,otherwise it will cover up the error.
+    }
+}
+
+void RangeCacheFileReader::_collect_profile_before_close() {
+    if (_profile != nullptr) {
+        COUNTER_UPDATE(_request_io, _cache_statistics.request_io);
+        COUNTER_UPDATE(_request_bytes, _cache_statistics.request_bytes);
+        COUNTER_UPDATE(_request_time, _cache_statistics.request_time);
+        COUNTER_UPDATE(_read_to_cache_time, 
_cache_statistics.read_to_cache_time);
+        COUNTER_UPDATE(_cache_refresh_count, 
_cache_statistics.cache_refresh_count);
+        COUNTER_UPDATE(_read_to_cache_bytes, 
_cache_statistics.read_to_cache_bytes);
+        if (_inner_reader != nullptr) {
+            _inner_reader->collect_profile_before_close();
+        }
+    }
+}
+
 } // namespace io
 } // namespace doris
diff --git a/be/src/io/fs/buffered_reader.h b/be/src/io/fs/buffered_reader.h
index 907ea11b216..67e07665fbf 100644
--- a/be/src/io/fs/buffered_reader.h
+++ b/be/src/io/fs/buffered_reader.h
@@ -53,6 +53,147 @@ struct PrefetchRange {
             : start_offset(start_offset), end_offset(end_offset) {}
 
     PrefetchRange() : start_offset(0), end_offset(0) {}
+
+    bool operator==(const PrefetchRange& other) const {
+        return (start_offset == other.start_offset) && (end_offset == 
other.end_offset);
+    }
+
+    bool operator!=(const PrefetchRange& other) const { return !(*this == 
other); }
+
+    PrefetchRange span(const PrefetchRange& other) const {
+        return {std::min(start_offset, other.end_offset), 
std::max(start_offset, other.end_offset)};
+    }
+    PrefetchRange seq_span(const PrefetchRange& other) const {
+        return {start_offset, other.end_offset};
+    }
+
+    //Ranges needs to be sorted.
+    static std::vector<PrefetchRange> merge_adjacent_seq_ranges(
+            const std::vector<PrefetchRange>& seq_ranges, int64_t 
max_merge_distance_bytes,
+            int64_t once_max_read_bytes) {
+        if (seq_ranges.empty()) {
+            return {};
+        }
+        // Merge overlapping ranges
+        std::vector<PrefetchRange> result;
+        PrefetchRange last = seq_ranges.front();
+        for (size_t i = 1; i < seq_ranges.size(); ++i) {
+            PrefetchRange current = seq_ranges[i];
+            PrefetchRange merged = last.seq_span(current);
+            if (merged.end_offset <= once_max_read_bytes + merged.start_offset 
&&
+                last.end_offset + max_merge_distance_bytes >= 
current.start_offset) {
+                last = merged;
+            } else {
+                result.push_back(last);
+                last = current;
+            }
+        }
+        result.push_back(last);
+        return result;
+    }
+};
+
+class RangeFinder {
+public:
+    virtual ~RangeFinder() = default;
+    virtual Status get_range_for(int64_t desired_offset, io::PrefetchRange& 
result_range) = 0;
+    virtual size_t get_max_range_size() const = 0;
+};
+
+class LinearProbeRangeFinder : public RangeFinder {
+public:
+    LinearProbeRangeFinder(std::vector<io::PrefetchRange>&& ranges) : 
_ranges(std::move(ranges)) {}
+
+    Status get_range_for(int64_t desired_offset, io::PrefetchRange& 
result_range) override;
+
+    size_t get_max_range_size() const override {
+        size_t max_range_size = 0;
+        for (const auto& range : _ranges) {
+            max_range_size = std::max(max_range_size, range.end_offset - 
range.start_offset);
+        }
+        return max_range_size;
+    }
+
+    ~LinearProbeRangeFinder() override = default;
+
+private:
+    std::vector<io::PrefetchRange> _ranges;
+    size_t index {0};
+};
+
+/**
+ * The reader provides a solution to read one range at a time. You can 
customize RangeFinder to meet your scenario.
+ * For me, since there will be tiny stripes when reading orc files, in order 
to reduce the requests to hdfs,
+ * I first merge the access to the orc files to be read (of course there is a 
problem of read amplification,
+ * but in my scenario, compared with reading hdfs multiple times, it is faster 
to read more data on hdfs at one time),
+ * and then because the actual reading of orc files is in order from front to 
back, I provide LinearProbeRangeFinder.
+ */
+class RangeCacheFileReader : public io::FileReader {
+    struct RangeCacheReaderStatistics {
+        int64_t request_io = 0;
+        int64_t request_bytes = 0;
+        int64_t request_time = 0;
+        int64_t read_to_cache_time = 0;
+        int64_t cache_refresh_count = 0;
+        int64_t read_to_cache_bytes = 0;
+    };
+
+public:
+    RangeCacheFileReader(RuntimeProfile* profile, io::FileReaderSPtr 
inner_reader,
+                         std::shared_ptr<RangeFinder> range_finder);
+
+    ~RangeCacheFileReader() override = default;
+
+    Status close() override {
+        if (!_closed) {
+            _closed = true;
+        }
+        return Status::OK();
+    }
+
+    const io::Path& path() const override { return _inner_reader->path(); }
+
+    size_t size() const override { return _size; }
+
+    bool closed() const override { return _closed; }
+
+protected:
+    Status read_at_impl(size_t offset, Slice result, size_t* bytes_read,
+                        const IOContext* io_ctx) override;
+
+    void _collect_profile_before_close() override;
+
+private:
+    RuntimeProfile* _profile = nullptr;
+    io::FileReaderSPtr _inner_reader;
+    std::shared_ptr<RangeFinder> _range_finder;
+
+    OwnedSlice _cache;
+    int64_t _current_start_offset = -1;
+
+    size_t _size;
+    bool _closed = false;
+
+    RuntimeProfile::Counter* _request_io = nullptr;
+    RuntimeProfile::Counter* _request_bytes = nullptr;
+    RuntimeProfile::Counter* _request_time = nullptr;
+    RuntimeProfile::Counter* _read_to_cache_time = nullptr;
+    RuntimeProfile::Counter* _cache_refresh_count = nullptr;
+    RuntimeProfile::Counter* _read_to_cache_bytes = nullptr;
+    RangeCacheReaderStatistics _cache_statistics;
+    /**
+     * `RangeCacheFileReader`:
+     *   1. `CacheRefreshCount`: how many IOs are merged
+     *   2. `ReadToCacheBytes`: how much data is actually read after merging
+     *   3. `ReadToCacheTime`: how long it takes to read data after merging
+     *   4. `RequestBytes`: how many bytes does the apache-orc library 
actually need to read the orc file
+     *   5. `RequestIO`: how many times the apache-orc library calls this read 
interface
+     *   6. `RequestTime`: how long it takes the apache-orc library to call 
this read interface
+     *
+     *   It should be noted that `RangeCacheFileReader` is a wrapper of the 
reader that actually reads data,such as
+     *   the hdfs reader, so strictly speaking, `CacheRefreshCount` is not 
equal to how many IOs are initiated to hdfs,
+     *  because each time the hdfs reader is requested, the hdfs reader may 
not be able to read all the data at once.
+     */
 };
 
 /**
diff --git a/be/src/vec/exec/format/orc/vorc_reader.cpp 
b/be/src/vec/exec/format/orc/vorc_reader.cpp
index 6b6639f2feb..e2161d8a6dc 100644
--- a/be/src/vec/exec/format/orc/vorc_reader.cpp
+++ b/be/src/vec/exec/format/orc/vorc_reader.cpp
@@ -857,28 +857,79 @@ Status OrcReader::set_fill_columns(
     if (_colname_to_value_range == nullptr || 
!_init_search_argument(_colname_to_value_range)) {
         _lazy_read_ctx.can_lazy_read = false;
     }
+    try {
+        _row_reader_options.range(_range_start_offset, _range_size);
+        _row_reader_options.setTimezoneName(_ctz == "CST" ? "Asia/Shanghai" : 
_ctz);
+        _row_reader_options.include(_read_cols);
+        _row_reader_options.setEnableLazyDecoding(true);
 
-    if (!_lazy_read_ctx.can_lazy_read) {
-        for (auto& kv : _lazy_read_ctx.predicate_partition_columns) {
-            _lazy_read_ctx.partition_columns.emplace(kv.first, kv.second);
+        uint64_t number_of_stripes = _reader->getNumberOfStripes();
+        auto all_stripes_needed = 
_reader->getNeedReadStripes(_row_reader_options);
+
+        int64_t range_end_offset = _range_start_offset + _range_size;
+
+        // If you set "orc_tiny_stripe_threshold_bytes" = 0, the use tiny 
stripes merge io optimization will not be used.
+        int64_t orc_tiny_stripe_threshold_bytes = 8L * 1024L * 1024L;
+        int64_t orc_once_max_read_bytes = 8L * 1024L * 1024L;
+        int64_t orc_max_merge_distance_bytes = 1L * 1024L * 1024L;
+
+        if (_state != nullptr) {
+            orc_tiny_stripe_threshold_bytes =
+                    _state->query_options().orc_tiny_stripe_threshold_bytes;
+            orc_once_max_read_bytes = 
_state->query_options().orc_once_max_read_bytes;
+            orc_max_merge_distance_bytes = 
_state->query_options().orc_max_merge_distance_bytes;
         }
-        for (auto& kv : _lazy_read_ctx.predicate_missing_columns) {
-            _lazy_read_ctx.missing_columns.emplace(kv.first, kv.second);
+
+        bool all_tiny_stripes = true;
+        std::vector<io::PrefetchRange> tiny_stripe_ranges;
+
+        for (uint64_t i = 0; i < number_of_stripes; i++) {
+            std::unique_ptr<orc::StripeInformation> strip_info = 
_reader->getStripe(i);
+            uint64_t strip_start_offset = strip_info->getOffset();
+            uint64_t strip_end_offset = strip_start_offset + 
strip_info->getLength();
+
+            if (strip_start_offset >= range_end_offset || strip_end_offset < 
_range_start_offset ||
+                !all_stripes_needed[i]) {
+                continue;
+            }
+            if (strip_info->getLength() > orc_tiny_stripe_threshold_bytes) {
+                all_tiny_stripes = false;
+                break;
+            }
+
+            tiny_stripe_ranges.emplace_back(strip_start_offset, 
strip_end_offset);
         }
-    }
+        if (all_tiny_stripes && number_of_stripes > 0) {
+            std::vector<io::PrefetchRange> prefetch_merge_ranges =
+                    
io::PrefetchRange::merge_adjacent_seq_ranges(tiny_stripe_ranges,
+                                                                 
orc_max_merge_distance_bytes,
+                                                                 
orc_once_max_read_bytes);
+            auto range_finder =
+                    
std::make_shared<io::LinearProbeRangeFinder>(std::move(prefetch_merge_ranges));
 
-    _fill_all_columns = true;
+            auto* orc_input_stream_ptr = 
static_cast<ORCFileInputStream*>(_reader->getStream());
+            orc_input_stream_ptr->set_all_tiny_stripes();
+            auto& orc_file_reader = orc_input_stream_ptr->get_file_reader();
+            auto orc_inner_reader = orc_input_stream_ptr->get_inner_reader();
+            orc_file_reader = 
std::make_shared<io::RangeCacheFileReader>(_profile, orc_inner_reader,
+                                                                         
range_finder);
+        }
 
-    // create orc row reader
-    try {
-        _row_reader_options.range(_range_start_offset, _range_size);
-        _row_reader_options.setTimezoneName(_ctz == "CST" ? "Asia/Shanghai" : 
_ctz);
-        _row_reader_options.include(_read_cols);
+        if (!_lazy_read_ctx.can_lazy_read) {
+            for (auto& kv : _lazy_read_ctx.predicate_partition_columns) {
+                _lazy_read_ctx.partition_columns.emplace(kv.first, kv.second);
+            }
+            for (auto& kv : _lazy_read_ctx.predicate_missing_columns) {
+                _lazy_read_ctx.missing_columns.emplace(kv.first, kv.second);
+            }
+        }
+
+        _fill_all_columns = true;
+        // create orc row reader
         if (_lazy_read_ctx.can_lazy_read) {
             _row_reader_options.filter(_lazy_read_ctx.predicate_orc_columns);
             _orc_filter = std::unique_ptr<ORCFilterImpl>(new 
ORCFilterImpl(this));
         }
-        _row_reader_options.setEnableLazyDecoding(true);
         if (!_lazy_read_ctx.conjuncts.empty()) {
             _string_dict_filter = std::make_unique<StringDictFilterImpl>(this);
         }
@@ -2415,6 +2466,9 @@ MutableColumnPtr 
OrcReader::_convert_dict_column_to_string_column(
 void ORCFileInputStream::beforeReadStripe(
         std::unique_ptr<orc::StripeInformation> current_strip_information,
         std::vector<bool> selected_columns) {
+    if (_is_all_tiny_stripes) {
+        return;
+    }
     if (_file_reader != nullptr) {
         _file_reader->collect_profile_before_close();
     }
diff --git a/be/src/vec/exec/format/orc/vorc_reader.h 
b/be/src/vec/exec/format/orc/vorc_reader.h
index 4aad5637ef5..0807f4949e5 100644
--- a/be/src/vec/exec/format/orc/vorc_reader.h
+++ b/be/src/vec/exec/format/orc/vorc_reader.h
@@ -34,6 +34,7 @@
 #include "common/status.h"
 #include "exec/olap_common.h"
 #include "io/file_factory.h"
+#include "io/fs/buffered_reader.h"
 #include "io/fs/file_reader.h"
 #include "io/fs/file_reader_writer_fwd.h"
 #include "olap/olap_common.h"
@@ -642,7 +643,11 @@ public:
               _io_ctx(io_ctx),
               _profile(profile) {}
 
-    ~ORCFileInputStream() override = default;
+    ~ORCFileInputStream() override {
+        if (_file_reader != nullptr) {
+            _file_reader->collect_profile_before_close();
+        }
+    }
 
     uint64_t getLength() const override { return _file_reader->size(); }
 
@@ -655,6 +660,12 @@ public:
     void beforeReadStripe(std::unique_ptr<orc::StripeInformation> 
current_strip_information,
                           std::vector<bool> selected_columns) override;
 
+    void set_all_tiny_stripes() { _is_all_tiny_stripes = true; }
+
+    io::FileReaderSPtr& get_file_reader() { return _file_reader; }
+
+    io::FileReaderSPtr& get_inner_reader() { return _inner_reader; }
+
 protected:
     void _collect_profile_at_runtime() override {};
     void _collect_profile_before_close() override;
@@ -663,10 +674,10 @@ private:
     const std::string& _file_name;
     io::FileReaderSPtr _inner_reader;
     io::FileReaderSPtr _file_reader;
+    bool _is_all_tiny_stripes = false;
     // Owned by OrcReader
     OrcReader::Statistics* _statistics = nullptr;
     const io::IOContext* _io_ctx = nullptr;
     RuntimeProfile* _profile = nullptr;
 };
-
 } // namespace doris::vectorized
diff --git a/be/test/io/fs/buffered_reader_test.cpp 
b/be/test/io/fs/buffered_reader_test.cpp
index d0a504162d3..658c98ba514 100644
--- a/be/test/io/fs/buffered_reader_test.cpp
+++ b/be/test/io/fs/buffered_reader_test.cpp
@@ -114,6 +114,34 @@ private:
     io::Path _path = "/tmp/mock";
 };
 
+class TestingRangeCacheFileReader : public io::FileReader {
+public:
+    TestingRangeCacheFileReader(std::shared_ptr<io::FileReader> delegate) : 
_delegate(delegate) {};
+
+    ~TestingRangeCacheFileReader() override = default;
+
+    Status close() override { return _delegate->close(); }
+
+    const io::Path& path() const override { return _delegate->path(); }
+
+    size_t size() const override { return _delegate->size(); }
+
+    bool closed() const override { return _delegate->closed(); }
+
+    const io::PrefetchRange& last_read_range() const { return 
*_last_read_range; }
+
+protected:
+    Status read_at_impl(size_t offset, Slice result, size_t* bytes_read,
+                        const io::IOContext* io_ctx) override {
+        _last_read_range = std::make_unique<io::PrefetchRange>(offset, offset 
+ result.size);
+        return _delegate->read_at_impl(offset, result, bytes_read, io_ctx);
+    }
+
+private:
+    std::shared_ptr<io::FileReader> _delegate;
+    std::unique_ptr<io::PrefetchRange> _last_read_range;
+};
+
 TEST_F(BufferedReaderTest, normal_use) {
     // buffered_reader_test_file 950 bytes
     io::FileReaderSPtr local_reader;
@@ -398,4 +426,84 @@ TEST_F(BufferedReaderTest, test_merged_io) {
     }
 }
 
+TEST_F(BufferedReaderTest, test_range_cache_file_reader) {
+    io::FileReaderSPtr offset_reader = 
std::make_shared<MockOffsetFileReader>(128 * 1024 * 1024);
+    auto testing_reader = 
std::make_shared<TestingRangeCacheFileReader>(offset_reader);
+
+    int64_t orc_max_merge_distance = 1L * 1024L * 1024L;
+    int64_t orc_once_max_read_size = 8L * 1024L * 1024L;
+
+    {
+        std::vector<io::PrefetchRange> tiny_stripe_ranges = {
+                io::PrefetchRange(3, 33),
+                io::PrefetchRange(33, 63),
+                io::PrefetchRange(63, 8L * 1024L * 1024L + 63),
+        };
+        std::vector<io::PrefetchRange> prefetch_merge_ranges =
+                io::PrefetchRange::merge_adjacent_seq_ranges(
+                        tiny_stripe_ranges, orc_max_merge_distance, 
orc_once_max_read_size);
+        auto range_finder =
+                
std::make_shared<io::LinearProbeRangeFinder>(std::move(prefetch_merge_ranges));
+        io::RangeCacheFileReader range_cache_file_reader(nullptr, 
testing_reader, range_finder);
+        char data[1];
+        Slice result(data, 1);
+        size_t bytes_read;
+        EXPECT_TRUE(range_cache_file_reader.read_at(3, result, &bytes_read, 
nullptr).ok());
+        EXPECT_EQ(io::PrefetchRange(3, 63), testing_reader->last_read_range());
+
+        EXPECT_TRUE(range_cache_file_reader.read_at(63, result, &bytes_read, 
nullptr).ok());
+        EXPECT_EQ(io::PrefetchRange(63, 8 * 1024L * 1024L + 63), 
testing_reader->last_read_range());
+        EXPECT_TRUE(range_cache_file_reader.close().ok());
+    }
+
+    {
+        std::vector<io::PrefetchRange> tiny_stripe_ranges = {
+                io::PrefetchRange(3, 33),
+                io::PrefetchRange(33, 63),
+                io::PrefetchRange(63, 8L * 1024L * 1024L + 63),
+        };
+        std::vector<io::PrefetchRange> prefetch_merge_ranges =
+                io::PrefetchRange::merge_adjacent_seq_ranges(
+                        tiny_stripe_ranges, orc_max_merge_distance, 
orc_once_max_read_size);
+        auto range_finder =
+                
std::make_shared<io::LinearProbeRangeFinder>(std::move(prefetch_merge_ranges));
+        io::RangeCacheFileReader range_cache_file_reader(nullptr, 
testing_reader, range_finder);
+        char data[1];
+        Slice result(data, 1);
+        size_t bytes_read;
+        EXPECT_TRUE(range_cache_file_reader.read_at(62, result, &bytes_read, 
nullptr).ok());
+        EXPECT_EQ(io::PrefetchRange(3, 63), testing_reader->last_read_range());
+
+        EXPECT_TRUE(range_cache_file_reader.read_at(63, result, &bytes_read, 
nullptr).ok());
+        EXPECT_EQ(io::PrefetchRange(63, 8L * 1024L * 1024L + 63),
+                  testing_reader->last_read_range());
+        EXPECT_TRUE(range_cache_file_reader.close().ok());
+    }
+
+    {
+        std::vector<io::PrefetchRange> tiny_stripe_ranges = {
+                io::PrefetchRange(3, 3),
+                io::PrefetchRange(4, 1048576L * 5L + 4),
+                io::PrefetchRange(1048576L * 5L + 4, 1048576L * 3L + 1048576L 
* 5L + 4),
+        };
+        std::vector<io::PrefetchRange> prefetch_merge_ranges =
+                io::PrefetchRange::merge_adjacent_seq_ranges(
+                        tiny_stripe_ranges, orc_max_merge_distance, 
orc_once_max_read_size);
+        auto range_finder =
+                
std::make_shared<io::LinearProbeRangeFinder>(std::move(prefetch_merge_ranges));
+        io::RangeCacheFileReader range_cache_file_reader(nullptr, 
testing_reader, range_finder);
+        char data[1];
+        Slice result(data, 1);
+        size_t bytes_read;
+        EXPECT_TRUE(range_cache_file_reader.read_at(3, result, &bytes_read, 
nullptr).ok());
+        EXPECT_EQ(io::PrefetchRange(3, 1 + 1048576 * 5 + 3), 
testing_reader->last_read_range());
+
+        EXPECT_TRUE(range_cache_file_reader.read_at(4 + 1048576 * 5, result, 
&bytes_read, nullptr)
+                            .ok());
+        EXPECT_EQ(io::PrefetchRange(4 + 1048576 * 5, 3 * 1048576 + 4 + 1048576 
* 5),
+                  testing_reader->last_read_range());
+        EXPECT_TRUE(range_cache_file_reader.close().ok());
+    }
+}
+
 } // end namespace doris
diff --git 
a/docker/thirdparties/docker-compose/hive/scripts/create_preinstalled_scripts/run67.hql
 
b/docker/thirdparties/docker-compose/hive/scripts/create_preinstalled_scripts/run67.hql
new file mode 100644
index 00000000000..f84cc11f040
--- /dev/null
+++ 
b/docker/thirdparties/docker-compose/hive/scripts/create_preinstalled_scripts/run67.hql
@@ -0,0 +1,11 @@
+use `default`;
+
+CREATE TABLE `orc_tiny_stripes`(
+    col1 bigint,
+    col2 string,
+    col3 bigint
+)
+STORED AS orc
+LOCATION '/user/doris/preinstalled_data/orc/orc_tiny_stripes';
+
+msck repair table orc_tiny_stripes;
diff --git 
a/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/output_60_3.orc
 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/output_60_3.orc
new file mode 100644
index 00000000000..34c95840549
Binary files /dev/null and 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/output_60_3.orc
 differ
diff --git 
a/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/output_6_1.orc
 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/output_6_1.orc
new file mode 100644
index 00000000000..2735240826b
Binary files /dev/null and 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/output_6_1.orc
 differ
diff --git 
a/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/random_output_60_3.orc
 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/random_output_60_3.orc
new file mode 100644
index 00000000000..6a3d16f9b44
Binary files /dev/null and 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/random_output_60_3.orc
 differ
diff --git 
a/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/random_output_6_1.orc
 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/random_output_6_1.orc
new file mode 100644
index 00000000000..7fce353b526
Binary files /dev/null and 
b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/orc/orc_tiny_stripes/random_output_6_1.orc
 differ
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index 45df14a6e6f..922f55bd537 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -470,6 +470,12 @@ public class SessionVariable implements Serializable, 
Writable {
 
     public static final String ENABLE_ORC_LAZY_MAT = 
"enable_orc_lazy_materialization";
 
+    public static final String ORC_TINY_STRIPE_THRESHOLD_BYTES = 
"orc_tiny_stripe_threshold_bytes";
+
+    public static final String ORC_ONCE_MAX_READ_BYTES = 
"orc_once_max_read_bytes";
+
+    public static final String ORC_MAX_MERGE_DISTANCE_BYTES = 
"orc_max_merge_distance_bytes";
+
     public static final String ENABLE_PARQUET_FILTER_BY_MIN_MAX = 
"enable_parquet_filter_by_min_max";
 
     public static final String ENABLE_ORC_FILTER_BY_MIN_MAX = 
"enable_orc_filter_by_min_max";
@@ -1719,6 +1725,46 @@ public class SessionVariable implements Serializable, 
Writable {
     public boolean enableOrcLazyMat = true;
 
 
+    @VariableMgr.VarAttr(
+            name = ORC_TINY_STRIPE_THRESHOLD_BYTES,
+            description = 
{"在orc文件中如果一个stripe的字节大小小于`orc_tiny_stripe_threshold`,"
+                    + "我们认为该stripe为 tiny stripe。对于多个连续的tiny 
stripe我们会进行读取优化,即一次性读多个tiny stripe."
+                    + "如果你不想使用该优化,可以将该值设置为0。默认为 8M。",
+                    "In an orc file, if the byte size of a stripe is less than 
`orc_tiny_stripe_threshold`,"
+                            + "we consider the stripe to be a tiny stripe. For 
multiple consecutive tiny stripes,"
+                            + "we will perform read optimization, that is, 
read multiple tiny stripes at a time."
+                            + "If you do not want to use this optimization, 
you can set this value to 0."
+                            + "The default is 8M."},
+            needForward = true,
+            setter = "setOrcTinyStripeThresholdBytes")
+    public long orcTinyStripeThresholdBytes  = 8L * 1024L * 1024L;
+
+
+    @VariableMgr.VarAttr(
+            name = ORC_ONCE_MAX_READ_BYTES,
+            description = {"在使用tiny stripe读取优化的时候,会对多个tiny stripe合并成一次IO,"
+                    + 
"该参数用来控制每次IO请求的最大字节大小。你不应该将值设置的小于`orc_tiny_stripe_threshold`。默认为 8M。",
+                    "When using tiny stripe read optimization, multiple tiny 
stripes will be merged into one IO."
+                            + "This parameter is used to control the maximum 
byte size of each IO request."
+                            + "You should not set the value less than 
`orc_tiny_stripe_threshold`."
+                            + "The default is 8M."},
+            needForward = true,
+            setter = "setOrcOnceMaxReadBytes")
+    public long orcOnceMaxReadBytes = 8L * 1024L * 1024L;
+
+
+    @VariableMgr.VarAttr(
+            name = ORC_MAX_MERGE_DISTANCE_BYTES,
+            description = {"在使用tiny stripe读取优化的时候,由于tiny stripe并不一定连续。"
+                    + "当两个tiny stripe之间距离大于该参数时,我们不会将其合并成一次IO。默认为 1M。",
+                    "When using tiny stripe read optimization, since tiny 
stripes are not necessarily continuous,"
+                            + "when the distance between two tiny stripes is 
greater than this parameter,"
+                            + "we will not merge them into one IO. The default 
value is 1M."},
+            needForward = true,
+            setter = "setOrcMaxMergeDistanceBytes")
+    public long orcMaxMergeDistanceBytes = 1024L * 1024L;
+
+
     @VariableMgr.VarAttr(
             name = ENABLE_PARQUET_FILTER_BY_MIN_MAX,
             description = {"控制 parquet reader 是否启用 min-max 值过滤。默认为 true。",
@@ -2799,6 +2845,32 @@ public class SessionVariable implements Serializable, 
Writable {
         this.parallelExecInstanceNum = val;
     }
 
+    public void setOrcTinyStripeThresholdBytes(String value) throws Exception {
+        long val = checkFieldLongValue(ORC_TINY_STRIPE_THRESHOLD_BYTES, 0, 
value);
+        this.orcTinyStripeThresholdBytes = val;
+    }
+
+    public void setOrcOnceMaxReadBytes(String value)  throws Exception {
+        long val = checkFieldLongValue(ORC_ONCE_MAX_READ_BYTES, 0, value);
+        this.orcOnceMaxReadBytes = val;
+    }
+
+    public void setOrcMaxMergeDistanceBytes(String value)  throws Exception {
+        long val = checkFieldLongValue(ORC_MAX_MERGE_DISTANCE_BYTES, 0, value);
+        this.orcMaxMergeDistanceBytes = val;
+    }
+
+    private long checkFieldLongValue(String variableName, long minValue, 
String value) throws Exception {
+        long val = Long.parseLong(value);
+        if (val < minValue) {
+            throw new Exception(
+                    variableName + " value should greater than or equal " + 
String.valueOf(minValue)
+                            + ", you set value is: " + value);
+        }
+        return val;
+    }
+
+
     private int checkFieldValue(String variableName, int minValue, String 
value) throws Exception {
         int val = Integer.valueOf(value);
         if (val < minValue) {
@@ -3867,6 +3939,11 @@ public class SessionVariable implements Serializable, 
Writable {
         tResult.setInListValueCountThreshold(inListValueCountThreshold);
         
tResult.setEnablePhraseQuerySequentialOpt(enablePhraseQuerySequentialOpt);
         
tResult.setEnableAutoCreateWhenOverwrite(enableAutoCreateWhenOverwrite);
+
+        tResult.setOrcTinyStripeThresholdBytes(orcTinyStripeThresholdBytes);
+        tResult.setOrcMaxMergeDistanceBytes(orcMaxMergeDistanceBytes);
+        tResult.setOrcOnceMaxReadBytes(orcOnceMaxReadBytes);
+
         return tResult;
     }
 
diff --git a/gensrc/thrift/PaloInternalService.thrift 
b/gensrc/thrift/PaloInternalService.thrift
index f531db30282..29fecc27539 100644
--- a/gensrc/thrift/PaloInternalService.thrift
+++ b/gensrc/thrift/PaloInternalService.thrift
@@ -352,6 +352,10 @@ struct TQueryOptions {
   136: optional bool enable_phrase_query_sequential_opt = true;
 
   137: optional bool enable_auto_create_when_overwrite = false;
+
+  138: optional i64 orc_tiny_stripe_threshold_bytes = 8388608;
+  139: optional i64 orc_once_max_read_bytes = 8388608;
+  140: optional i64 orc_max_merge_distance_bytes = 1048576;
   // For cloud, to control if the content would be written into file cache
   // In write path, to control if the content would be written into file cache.
   // In read path, read from file cache or remote storage when execute query.
diff --git 
a/regression-test/data/external_table_p0/hive/test_orc_tiny_stripes.out 
b/regression-test/data/external_table_p0/hive/test_orc_tiny_stripes.out
new file mode 100644
index 00000000000..d08eb7c8872
--- /dev/null
+++ b/regression-test/data/external_table_p0/hive/test_orc_tiny_stripes.out
@@ -0,0 +1,2311 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
+-- !test_1 --
+372
+
+-- !test_2 --
+1      str_1   10000000001
+1      str_1   10000000001
+
+-- !test_3 --
+0      str_0   10000000000
+0      str_0   10000000000
+100    9DPJaFc00euBteqiW1f1    10000000027
+100    str_100 10000000100
+2200   tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800   TaWGgh4iZ       10000000115
+5700   SwOaGJj9fVbk5j0Np       10000000050
+
+-- !test_4 --
+4      str_4   10000000004
+4      str_4   10000000004
+
+-- !test_5 --
+348
+
+-- !test_6 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_7 --
+5      str_5   10000000005
+5      str_5   10000000005
+53     str_53  10000000053
+146    str_146 10000000146
+3961   hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129   qwPIwtkTZb      10000000005
+4942   vAdLpLUN3VkGNmTjvuPv    10000000053
+5349   koTeYPr2Qaqqnlk07X      10000000146
+5745   1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573   e3lIPwNnbG6DPmog        10000000005
+8614   TtyopDvRptLB5   10000000005
+
+-- !test_8 --
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+
+-- !test_9 --
+10
+
+-- !test_10 --
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+
+-- !test_11 --
+0      str_0   10000000000
+0      str_0   10000000000
+1      str_1   10000000001
+1      str_1   10000000001
+2      str_2   10000000002
+2      str_2   10000000002
+3      str_3   10000000003
+3      str_3   10000000003
+4      str_4   10000000004
+4      str_4   10000000004
+5      str_5   10000000005
+5      str_5   10000000005
+6      str_6   10000000006
+7      str_7   10000000007
+8      str_8   10000000008
+9      str_9   10000000009
+
+-- !test_12 --
+0
+0
+6
+
+-- !test_13 --
+20
+60
+
+-- !test_14 --
+0
+0
+40
+
diff --git 
a/regression-test/suites/external_table_p0/hive/test_orc_tiny_stripes.groovy 
b/regression-test/suites/external_table_p0/hive/test_orc_tiny_stripes.groovy
new file mode 100644
index 00000000000..bc585340fcc
--- /dev/null
+++ b/regression-test/suites/external_table_p0/hive/test_orc_tiny_stripes.groovy
@@ -0,0 +1,203 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_orc_tiny_stripes", 
"p0,external,hive,external_docker,external_docker_hive") {
+
+    String enabled = context.config.otherConfigs.get("enableHiveTest")
+    if (enabled == null || !enabled.equalsIgnoreCase("true")) {
+        logger.info("diable Hive test.")
+        return;
+
+    }
+
+    for (String hivePrefix : ["hive2"]) {
+        try {
+            String hms_port = context.config.otherConfigs.get(hivePrefix + 
"HmsPort")
+            String catalog_name = "${hivePrefix}_test_orc_tiny_stripes"
+            String externalEnvIp = 
context.config.otherConfigs.get("externalEnvIp")
+
+            sql """drop catalog if exists ${catalog_name}"""
+            sql """create catalog if not exists ${catalog_name} properties (
+                "type"="hms",
+                'hive.metastore.uris' = 'thrift://${externalEnvIp}:${hms_port}'
+            );"""
+            sql """use `${catalog_name}`.`default`"""
+
+
+
+            
+            def orc_configs = [
+                [0,0,0],
+                [0,10230,1024],
+                [1,1,1],
+                [201,130,0],
+                [1024,1024,0],
+                [1024,1024,1024],
+                [4096,1024,0],    
+                [1024,4096,0],
+                [1,10240,10000000],
+                [1000000,888888888,0],
+                [1000000000000,1000000000000,100000000000]
+            ]
+            def li = [ "set enable_orc_lazy_materialization=true;","set 
enable_orc_lazy_materialization=false;"] 
+
+
+            li.each  { it1 -> 
+                sql it1 
+
+                orc_configs.each { it2 ->
+                    def value1 = it2[0].toString()
+                    def value2 = it2[1].toString()
+                    def value3 = it2[2].toString()
+
+                    sql "set orc_tiny_stripe_threshold_bytes = " + value1 + ";"
+                    sql "set orc_once_max_read_bytes = " + value2 + ";"
+                    sql "set orc_max_merge_distance_bytes = " + value3 + ";"
+
+
+                    qt_test_1 """ select count(*) from orc_tiny_stripes; """  
//372
+
+/*
+*/
+
+                    qt_test_2 """ select * from orc_tiny_stripes where col1 = 
1 order by col1,col2,col3; """  
+/*
+1       str_1   10000000001
+1       str_1   10000000001
+*/                    
+                    qt_test_3 """ select * from orc_tiny_stripes where 
col1%100 = 0 order by col1,col2,col3 ; """
+/*
+0       str_0   10000000000
+0       str_0   10000000000
+100     9DPJaFc00euBteqiW1f1    10000000027
+100     str_100 10000000100
+2200    tQ7BRFEuf8h56kahqsLPa1vu        10000000034
+4800    TaWGgh4iZ       10000000115
+5700    SwOaGJj9fVbk5j0Np       10000000050
+*/
+
+                    qt_test_4 """ select * from orc_tiny_stripes where col2 = 
"str_4" order by col1,col2,col3; """
+/*
+4       str_4   10000000004
+4       str_4   10000000004
+*/ 
+                    qt_test_5 """ select count(*) from orc_tiny_stripes  where 
col3 > 10000000005; """ //348
+                    qt_test_6 """ select * from orc_tiny_stripes  where col3 
in ( 10000000005,10000000053,10000000146) order by col1,col2,col3 ; """ 
+/*
+5       str_5   10000000005
+5       str_5   10000000005
+53      str_53  10000000053
+146     str_146 10000000146
+3961    hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129    qwPIwtkTZb      10000000005
+4942    vAdLpLUN3VkGNmTjvuPv    10000000053
+5349    koTeYPr2Qaqqnlk07X      10000000146
+5745    1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573    e3lIPwNnbG6DPmog        10000000005
+8614    TtyopDvRptLB5   10000000005                    
+*/                  
+                    
+                    qt_test_7 """ select * from orc_tiny_stripes  where col3 
in ( 10000000005,10000000053,10000000146) order by col1,col2,col3 ; """ 
+/*
+5       str_5   10000000005
+5       str_5   10000000005
+53      str_53  10000000053
+146     str_146 10000000146
+3961    hMgIY4oui0MHYgaIFg4zz5Ti3p      10000000053
+4129    qwPIwtkTZb      10000000005
+4942    vAdLpLUN3VkGNmTjvuPv    10000000053
+5349    koTeYPr2Qaqqnlk07X      10000000146
+5745    1cx1jZ6QGRWAkskiOgURj6dscYxDOl  10000000005
+7573    e3lIPwNnbG6DPmog        10000000005
+8614    TtyopDvRptLB5   10000000005
+*/                  
+                    
+                    qt_test_8 """ select col3 from orc_tiny_stripes  where 
col3 in ( 10000000005,10000000053,10000000146) order by col3 ; """ 
+/*
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000005
+10000000053
+10000000053
+10000000053
+10000000146
+10000000146
+*/
+
+                    qt_test_9 """ select col1 from orc_tiny_stripes  where 
col1 in (10,1000) order by col1 ; """ // 10 
+                    qt_test_10 """ select col2 from orc_tiny_stripes  where 
length(col2) > 29 order by col2  ; """
+/*
+1cx1jZ6QGRWAkskiOgURj6dscYxDOl
+Asn3tnIg1xYm8Lbgey8baqw3EmooFm
+MSBtFURjtMu3LyDTLYx9FBM23UQdZ1
+e8e7xgwaSI2JKI65FEThzSQBVmKeAZ
+w3xAirHLO1tvjon2jgr7y9tBtrGfMS
+zABBLCkowUIqfONQOAjir8YPkFqfDW
+*/
+                    qt_test_11 """ select * from orc_tiny_stripes  where col1 
< 10 order by col1,col2,col3; """ 
+/*
+0       str_0   10000000000
+0       str_0   10000000000
+1       str_1   10000000001
+1       str_1   10000000001
+2       str_2   10000000002
+2       str_2   10000000002
+3       str_3   10000000003
+3       str_3   10000000003
+4       str_4   10000000004
+4       str_4   10000000004
+5       str_5   10000000005
+5       str_5   10000000005
+6       str_6   10000000006
+7       str_7   10000000007
+8       str_8   10000000008
+9       str_9   10000000009
+*/
+
+                    qt_test_12 """ select col1 from orc_tiny_stripes  where 
col1 in(0,6 ) order by  col1; """ 
+/*
+0
+0
+6
+*/
+ 
+                    qt_test_13 """ select col1 from orc_tiny_stripes  where 
col1 in(20,60 ) order by  col1; """ 
+ /*
+20
+60
+*/
+ 
+                    qt_test_14 """ select col1 from orc_tiny_stripes  where 
col1 in(40,0 ) order by col1; """ 
+/*
+0
+0
+40
+*/
+
+
+                }
+            }
+
+            sql """drop catalog if exists ${catalog_name}"""
+        } finally {
+        }
+    }
+}
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to