diff --git a/CHANGELOG.md b/CHANGELOG.md index 74aca9a..fdd37ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/). memoises decoded column arrays per block, so each is decoded once. ~50% less time on a wide `-r … --tsv` over a 1 M-row file; output byte-identical. The cache is region-mode only, so a sequential full scan is unaffected. +- **Tabix range queries reuse the line buffer.** `TabixInputStream` allocated and + freed an htslib `kstring` per record; it now keeps one buffer for the whole + scan (htslib reallocs only when a line outgrows it). Output unchanged. ### Fixed - **bigWig/bigBed misaligned read (aarch64 correctness).** libBigWig read each diff --git a/main.cpp b/main.cpp index a199bba..bd7da29 100644 --- a/main.cpp +++ b/main.cpp @@ -1640,6 +1640,10 @@ class TabixInputStream : public arrow::io::InputStream { size_t pos_ = 0; bool eof_ = false; bool closed_ = false; + // Reused across records: htslib's line reader (bgzf_getline) resets `l` and + // reallocs `s` only when a line outgrows it, so keeping one buffer for the + // whole scan avoids a malloc+free per record. Freed once in the destructor. + kstring_t ks_ = {0, 0, nullptr}; public: static std::string open(const std::string& path, const std::string& region, @@ -1697,6 +1701,7 @@ class TabixInputStream : public arrow::io::InputStream { for (auto* it : iters_) if (it) tbx_itr_destroy(it); if (tbx_) tbx_destroy(tbx_); if (fp_) hts_close(fp_); + if (ks_.s) free(ks_.s); } arrow::Status Close() override { closed_ = true; return arrow::Status::OK(); } @@ -1727,19 +1732,16 @@ class TabixInputStream : public arrow::io::InputStream { } private: bool fetch_next_line() { - kstring_t s = {0, 0, nullptr}; while (cur_iter_ < iters_.size()) { - int r = tbx_itr_next(fp_, tbx_, iters_[cur_iter_], &s); + int r = tbx_itr_next(fp_, tbx_, iters_[cur_iter_], &ks_); if (r >= 0) { - buf_.assign(s.s, s.l); + buf_.assign(ks_.s, ks_.l); buf_ += '\n'; pos_ = 0; - if (s.s) free(s.s); return true; } ++cur_iter_; } - if (s.s) free(s.s); eof_ = true; return false; }