Skip to content

Commit 694a036

Browse files
authored
Improve export run-time performance by caching sample headers (#881)
* Updated TileDBVCFDataset::SampleHeaders to support caching parsed, sample-specific headers This functionality is implemented via TileDBVCFDataset::SampleHeaders::get_sample_header_shared(), which returns a shared_ptr with the option for SampleHeaders to cache a copy of the shared_ptr. * Updated Reader::report_cell() to cache headers when exporting records This significantly reduces run-time by reducing time spent parsing header strings and (de)allocating header objects.
1 parent 9783d70 commit 694a036

4 files changed

Lines changed: 53 additions & 7 deletions

File tree

libtiledbvcf/src/dataset/tiledbvcfdataset.cc

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,10 +1374,11 @@ void TileDBVCFDataset::SampleHeaders::set_sample_header(
13741374
}
13751375

13761376
// Save the sample's unique header index and insertion order
1377-
sample_index_lookup.emplace(sample_name, Indexes{hdr_idx, sample_idx});
1377+
sample_index_lookup.emplace(
1378+
sample_name, Indexes{hdr_idx, sample_idx, nullptr});
13781379
}
13791380

1380-
SafeBCFHdr TileDBVCFDataset::SampleHeaders::get_sample_header(
1381+
bcf_hdr_t* TileDBVCFDataset::SampleHeaders::parse_sample_header(
13811382
const std::string& sample) const {
13821383
bcf_hdr_t* hdr = bcf_hdr_init("r");
13831384
if (!hdr) {
@@ -1411,9 +1412,30 @@ SafeBCFHdr TileDBVCFDataset::SampleHeaders::get_sample_header(
14111412
"bcftools: failed to update VCF header.");
14121413
}
14131414

1415+
return hdr;
1416+
}
1417+
1418+
SafeBCFHdr TileDBVCFDataset::SampleHeaders::get_sample_header(
1419+
const std::string& sample) const {
1420+
bcf_hdr_t* hdr = parse_sample_header(sample);
14141421
return SafeBCFHdr(hdr, bcf_hdr_destroy);
14151422
}
14161423

1424+
SafeSharedBCFHdr TileDBVCFDataset::SampleHeaders::get_sample_header_shared(
1425+
std::string& sample, bool cache) {
1426+
Indexes& indexes = sample_index_lookup.at(sample);
1427+
if (cache) {
1428+
if (indexes.cached_header == nullptr) {
1429+
bcf_hdr_t* hdr = parse_sample_header(sample);
1430+
indexes.cached_header.reset(hdr);
1431+
}
1432+
return indexes.cached_header;
1433+
}
1434+
1435+
bcf_hdr_t* hdr = parse_sample_header(sample);
1436+
return SafeSharedBCFHdr(hdr);
1437+
}
1438+
14171439
std::vector<std::string>
14181440
TileDBVCFDataset::SampleHeaders::header_ordered_samples() const {
14191441
auto samples = samples_view();

libtiledbvcf/src/dataset/tiledbvcfdataset.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ class TileDBVCFDataset {
220220
struct Indexes {
221221
size_t header_idx; // index in unique_headers
222222
size_t tiledb_idx; // index in TileDB header array
223+
SafeSharedBCFHdr cached_header;
223224
};
224225
// Save unique headers as strings for on-demand bcf_hdr_t parsing
225226
std::vector<std::string> unique_headers;
@@ -240,6 +241,14 @@ class TileDBVCFDataset {
240241
void set_sample_header(
241242
const char* hdr_str, const std::string& sample_name, size_t sample_idx);
242243

244+
/**
245+
* Parses the header for the given sample name and returns a raw pointer.
246+
*
247+
* @param sample The name of the sample to get the header for
248+
* @return The header for the sample
249+
*/
250+
bcf_hdr_t* parse_sample_header(const std::string& sample) const;
251+
243252
public:
244253
friend class TileDBVCFDataset;
245254

@@ -275,13 +284,24 @@ class TileDBVCFDataset {
275284
SafeBCFHdr first() const;
276285

277286
/**
278-
* Gets the header for the given sample name.
287+
* Gets the header for the given sample name and returns a unique pointer.
279288
*
280289
* @param sample The name of the sample to get the header for
281-
* @return The first header
290+
* @return The header for the sample
282291
*/
283292
SafeBCFHdr get_sample_header(const std::string& sample) const;
284293

294+
/**
295+
* Gets the header for the given sample name and returns a shared pointer,
296+
* with optional caching.
297+
*
298+
* @param sample The name of the sample to get the header for
299+
* @param cache If the shared pointer should be cached
300+
* @return The header for the sample
301+
*/
302+
SafeSharedBCFHdr get_sample_header_shared(
303+
std::string& sample, bool cache = true);
304+
285305
/**
286306
* Returns the sample names stored as a view of the internal lookup map.
287307
*

libtiledbvcf/src/read/reader.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,12 +1686,13 @@ bool Reader::report_cell(
16861686
sample = SampleAndId{std::string(sample_name, size)};
16871687
}
16881688

1689-
SafeBCFHdr hdr(nullptr, bcf_hdr_destroy);
1689+
bcf_hdr_t* hdr = nullptr;
16901690
if (read_state_.need_headers) {
1691-
hdr = read_state_.current_hdrs.get_sample_header(sample.sample_name);
1691+
hdr = read_state_.current_hdrs.get_sample_header_shared(sample.sample_name)
1692+
.get();
16921693
}
16931694
if (!exporter_->export_record(
1694-
sample, hdr.get(), region, contig_offset, results, cell_idx))
1695+
sample, hdr, region, contig_offset, results, cell_idx))
16951696
return false;
16961697

16971698
// If no overflow, increment num records count.

libtiledbvcf/src/vcf/vcf_utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ namespace vcf {
4646
/** Alias for unique_ptr to bcf_hdr_t. */
4747
typedef std::unique_ptr<bcf_hdr_t, decltype(&bcf_hdr_destroy)> SafeBCFHdr;
4848

49+
/** Alias for unique_ptr to bcf_hdr_t. */
50+
typedef std::shared_ptr<bcf_hdr_t> SafeSharedBCFHdr;
51+
4952
/** Alias for unique_ptr to bcf1_t. */
5053
typedef std::unique_ptr<bcf1_t, decltype(&bcf_destroy)> SafeBCFRec;
5154

0 commit comments

Comments
 (0)