1 /**
2  * @file   reader_base.h
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  * @section DESCRIPTION
29  *
30  * This file defines class ReaderBase.
31  */
32 
33 #ifndef TILEDB_READER_BASE_H
34 #define TILEDB_READER_BASE_H
35 
36 #include <queue>
37 #include "strategy_base.h"
38 #include "tiledb/common/status.h"
39 #include "tiledb/sm/array_schema/dimension.h"
40 #include "tiledb/sm/array_schema/tile_domain.h"
41 #include "tiledb/sm/misc/types.h"
42 #include "tiledb/sm/query/query_condition.h"
43 #include "tiledb/sm/query/result_cell_slab.h"
44 #include "tiledb/sm/query/result_space_tile.h"
45 #include "tiledb/sm/subarray/subarray_partitioner.h"
46 
47 namespace tiledb {
48 namespace sm {
49 
50 class Array;
51 class ArraySchema;
52 class StorageManager;
53 class Subarray;
54 
55 /** Processes read queries. */
56 class ReaderBase : public StrategyBase {
57  public:
58   /* ********************************* */
59   /*          TYPE DEFINITIONS         */
60   /* ********************************* */
61 
62   /** The state for a read query. */
63   struct ReadState {
64     /**
65      * True if the query led to a result that does not fit in
66      * the user buffers.
67      */
68     bool overflowed_ = false;
69 
70     /** The subarray partitioner. */
71     SubarrayPartitioner partitioner_;
72 
73     /**
74      * ``true`` if the next partition cannot be retrieved from the
75      * partitioner, because it reaches a partition that is unsplittable.
76      */
77     bool unsplittable_ = false;
78 
79     /** True if the reader has been initialized. */
80     bool initialized_ = false;
81 
82     /** ``true`` if there are no more partitions. */
doneReadState83     bool done() const {
84       return partitioner_.done();
85     }
86 
87     /** Retrieves the next partition from the partitioner. */
nextReadState88     Status next() {
89       return partitioner_.next(&unsplittable_);
90     }
91 
92     /**
93      * Splits the current partition and updates the state, retrieving
94      * a new current partition. This function is typically called
95      * by the reader when the current partition was estimated to fit
96      * the results, but that was not eventually true.
97      */
split_currentReadState98     Status split_current() {
99       return partitioner_.split_current(&unsplittable_);
100     }
101   };
102 
103   /* ********************************* */
104   /*     CONSTRUCTORS & DESTRUCTORS    */
105   /* ********************************* */
106 
107   /** Constructor. */
108   ReaderBase(
109       stats::Stats* stats,
110       tdb_shared_ptr<Logger> logger,
111       StorageManager* storage_manager,
112       Array* array,
113       Config& config,
114       std::unordered_map<std::string, QueryBuffer>& buffers,
115       Subarray& subarray,
116       Layout layout,
117       QueryCondition& condition);
118 
119   /** Destructor. */
120   ~ReaderBase() = default;
121 
122   /* ********************************* */
123   /*          STATIC FUNCTIONS         */
124   /* ********************************* */
125 
126   /**
127    * Computes a mapping (tile coordinates) -> (result space tile).
128    * The produced result space tiles will contain information only
129    * about fragments that will contribute results. Specifically, if
130    * a fragment is completely covered by a more recent fragment
131    * in a particular space tile, then it will certainly not contribute
132    * results and, thus, no information about that fragment is included
133    * in the space tile.
134    *
135    * @tparam T The datatype of the tile domains.
136    * @param domain The array domain
137    * @param tile_coords The unique coordinates of the tiles that intersect
138    *     a subarray.
139    * @param array_tile_domain The array tile domain.
140    * @param frag_tile_domains The tile domains of each fragment. These
141    *     are assumed to be ordered from the most recent to the oldest
142    *     fragment.
143    * @param result_space_tiles The result space tiles to be produced
144    *     by the function.
145    */
146   template <class T>
147   static void compute_result_space_tiles(
148       const Domain* domain,
149       const std::vector<std::vector<uint8_t>>& tile_coords,
150       const TileDomain<T>& array_tile_domain,
151       const std::vector<TileDomain<T>>& frag_tile_domains,
152       std::map<const T*, ResultSpaceTile<T>>* result_space_tiles);
153 
154  protected:
155   /* ********************************* */
156   /*        PROTECTED DATATYPES        */
157   /* ********************************* */
158 
159   /** Bitflags for individual dimension/attributes in `process_tiles()`. */
160   typedef uint8_t ProcessTileFlags;
161 
162   /** Bitflag values applicable to `ProcessTileFlags`. */
163   enum ProcessTileFlag { READ = 1, COPY = 2 };
164 
165   typedef std::
166       unordered_map<ResultTile*, std::vector<std::pair<uint64_t, uint64_t>>>
167           ResultCellSlabsIndex;
168 
169   /* ********************************* */
170   /*       PROTECTED ATTRIBUTES        */
171   /* ********************************* */
172 
173   /** The query condition. */
174   QueryCondition& condition_;
175 
176   /** The fragment metadata that the reader will focus on. */
177   std::vector<tdb_shared_ptr<FragmentMetadata>> fragment_metadata_;
178 
179   /** Protects result tiles. */
180   mutable std::mutex result_tiles_mutex_;
181 
182   /** Try to fix overflows on var sized copies. */
183   bool fix_var_sized_overflows_;
184 
185   /** Clear the coordinates tiles after copies. */
186   bool clear_coords_tiles_on_copy_;
187 
188   /** Was there an overflow during copying tiles. */
189   bool copy_overflowed_;
190 
191   /**
192    * Used to specify where in the result cell slabs to end the copy
193    * operations. First is the size of the result cell slabs, second is
194    * the length of the last result cell slab.
195    */
196   std::pair<uint64_t, uint64_t> copy_end_;
197 
198   /* ********************************* */
199   /*         PROTECTED METHODS         */
200   /* ********************************* */
201 
202   /**
203    * Deletes the tiles on the input attribute/dimension from the result tiles.
204    *
205    * @param name The attribute/dimension name.
206    * @param result_tiles The result tiles to delete from.
207    * @return void
208    */
209   void clear_tiles(
210       const std::string& name,
211       const std::vector<ResultTile*>* result_tiles) const;
212 
213   /**
214    * Resets the buffer sizes to the original buffer sizes. This is because
215    * the read query may alter the buffer sizes to reflect the size of
216    * the useful data (results) written in the buffers.
217    */
218   void reset_buffer_sizes();
219 
220   /** Zeroes out the user buffer sizes, indicating an empty result. */
221   void zero_out_buffer_sizes();
222 
223   /** Correctness checks for `subarray_`. */
224   Status check_subarray() const;
225 
226   /** Correctness checks validity buffer sizes in `buffers_`. */
227   Status check_validity_buffer_sizes() const;
228 
229   /**
230    * Loads tile offsets for each attribute/dimension name into
231    * their associated element in `fragment_metadata_`.
232    *
233    * @param subarray The subarray to load tiles for.
234    * @param names The attribute/dimension names.
235    * @return Status
236    */
237   Status load_tile_offsets(
238       Subarray* subarray, const std::vector<std::string>* names);
239 
240   /**
241    * Loads tile var sizes for each attribute/dimension name into
242    * their associated element in `fragment_metadata_`.
243    *
244    * @param subarray The subarray to load tiles for.
245    * @param names The attribute/dimension names.
246    * @return Status
247    */
248   Status load_tile_var_sizes(
249       Subarray* subarray, const std::vector<std::string>* names);
250 
251   /**
252    * Initializes a fixed-sized tile.
253    *
254    * @param format_version The format version of the tile.
255    * @param name The attribute/dimension the tile belongs to.
256    * @param tile The tile to be initialized.
257    * @return Status
258    */
259   Status init_tile(
260       uint32_t format_version, const std::string& name, Tile* tile) const;
261 
262   /**
263    * Initializes a var-sized tile.
264    *
265    * @param format_version The format version of the tile.
266    * @param name The attribute/dimension the tile belongs to.
267    * @param tile The offsets tile to be initialized.
268    * @param tile_var The var-sized data tile to be initialized.
269    * @return Status
270    */
271   Status init_tile(
272       uint32_t format_version,
273       const std::string& name,
274       Tile* tile,
275       Tile* tile_var) const;
276 
277   /**
278    * Initializes a fixed-sized tile.
279    *
280    * @param format_version The format version of the tile.
281    * @param name The attribute/dimension the tile belongs to.
282    * @param tile The tile to be initialized.
283    * @param tile_validity The validity tile to be initialized.
284    * @return Status
285    */
286   Status init_tile_nullable(
287       uint32_t format_version,
288       const std::string& name,
289       Tile* tile,
290       Tile* tile_validity) const;
291 
292   /**
293    * Initializes a var-sized tile.
294    *
295    * @param format_version The format version of the tile.
296    * @param name The attribute/dimension the tile belongs to.
297    * @param tile The offsets tile to be initialized.
298    * @param tile_var The var-sized data tile to be initialized.
299    * @param tile_validity The validity tile to be initialized.
300    * @return Status
301    */
302   Status init_tile_nullable(
303       uint32_t format_version,
304       const std::string& name,
305       Tile* tile,
306       Tile* tile_var,
307       Tile* tile_validity) const;
308 
309   /**
310    * Concurrently executes `read_tiles` for each name in `names`. This
311    * must be the entry point for reading attribute tiles because it
312    * generates stats for reading attributes.
313    *
314    * @param names The attribute names.
315    * @param result_tiles The retrieved tiles will be stored inside the
316    *     `ResultTile` instances in this vector.
317    * @return Status
318    */
319   Status read_attribute_tiles(
320       const std::vector<std::string>* names,
321       const std::vector<ResultTile*>* result_tiles) const;
322 
323   /**
324    * Concurrently executes `read_tiles` for each name in `names`. This
325    * must be the entry point for reading coordinate tiles because it
326    * generates stats for reading coordinates.
327    *
328    * @param names The coordinate/dimension names.
329    * @param result_tiles The retrieved tiles will be stored inside the
330    *     `ResultTile` instances in this vector.
331    * @return Status
332    */
333   Status read_coordinate_tiles(
334       const std::vector<std::string>* names,
335       const std::vector<ResultTile*>* result_tiles) const;
336 
337   /**
338    * Concurrently executes `read_tiles` for each name in `names`.
339    *
340    * @param names The attribute/dimension names.
341    * @param result_tiles The retrieved tiles will be stored inside the
342    *     `ResultTile` instances in this vector.
343    * @return Status
344    */
345   Status read_tiles(
346       const std::vector<std::string>* names,
347       const std::vector<ResultTile*>* result_tiles) const;
348 
349   /**
350    * Retrieves the tiles on a particular attribute or dimension and stores it
351    * in the appropriate result tile.
352    *
353    * @param name The attribute/dimension name.
354    * @param result_tiles The retrieved tiles will be stored inside the
355    *     `ResultTile` instances in this vector.
356    * @return Status
357    */
358   Status read_tiles(
359       const std::string& name,
360       const std::vector<ResultTile*>* result_tiles) const;
361 
362   /**
363    * Retrieves the tiles on a particular attribute or dimension and stores it
364    * in the appropriate result tile.
365    *
366    * The reads are done asynchronously, and futures for each read operation are
367    * added to the output parameter.
368    *
369    * @param name The attribute/dimension name.
370    * @param result_tiles The retrieved tiles will be stored inside the
371    *     `ResultTile` instances in this vector.
372    * @param tasks Vector to hold futures for the read tasks.
373    * @return Status
374    */
375   Status read_tiles(
376       const std::string& name,
377       const std::vector<ResultTile*>* result_tiles,
378       std::vector<ThreadPool::Task>* tasks) const;
379 
380   /**
381    * Filters the tiles on a particular attribute/dimension from all input
382    * fragments based on the tile info in `result_tiles`.
383    *
384    * @param name Attribute/dimension whose tiles will be unfiltered.
385    * @param result_tiles Vector containing the tiles to be unfiltered.
386    * @return Status
387    */
388   Status unfilter_tiles(
389       const std::string& name,
390       const std::vector<ResultTile*>* result_tiles) const;
391 
392   /**
393    * Runs the input fixed-sized tile for the input attribute or dimension
394    * through the filter pipeline. The tile buffer is modified to contain the
395    * output of the pipeline.
396    *
397    * @param name The attribute/dimension the tile belong to.
398    * @param tile The tile to be unfiltered.
399    * @return Status
400    */
401   Status unfilter_tile(const std::string& name, Tile* tile) const;
402 
403   /**
404    * Runs the input var-sized tile for the input attribute or dimension through
405    * the filter pipeline. The tile buffer is modified to contain the output of
406    * the pipeline.
407    *
408    * @param name The attribute/dimension the tile belong to.
409    * @param tile The offsets tile to be unfiltered.
410    * @param tile_var The value tile to be unfiltered.
411    * @return Status
412    */
413   Status unfilter_tile(
414       const std::string& name, Tile* tile, Tile* tile_var) const;
415 
416   /**
417    * Runs the input fixed-sized tile for the input nullable attribute
418    * through the filter pipeline. The tile buffer is modified to contain the
419    * output of the pipeline.
420    *
421    * @param name The attribute/dimension the tile belong to.
422    * @param tile The tile to be unfiltered.
423    * @param tile_validity The validity tile to be unfiltered.
424    * @return Status
425    */
426   Status unfilter_tile_nullable(
427       const std::string& name, Tile* tile, Tile* tile_validity) const;
428 
429   /**
430    * Runs the input var-sized tile for the input nullable attribute through
431    * the filter pipeline. The tile buffer is modified to contain the output of
432    * the pipeline.
433    *
434    * @param name The attribute/dimension the tile belong to.
435    * @param tile The offsets tile to be unfiltered.
436    * @param tile_var The value tile to be unfiltered.
437    * @param tile_validity The validity tile to be unfiltered.
438    * @return Status
439    */
440   Status unfilter_tile_nullable(
441       const std::string& name,
442       Tile* tile,
443       Tile* tile_var,
444       Tile* tile_validity) const;
445 
446   /**
447    * Copies the result coordinates to the user buffers.
448    * It also appropriately cleans up the used result tiles.
449    */
450   Status copy_coordinates(
451       const std::vector<ResultTile*>* result_tiles,
452       std::vector<ResultCellSlab>* result_cell_slabs);
453 
454   /**
455    * Copies the result attribute values to the user buffers.
456    * It also appropriately cleans up the used result tiles.
457    */
458   Status copy_attribute_values(
459       uint64_t stride,
460       std::vector<ResultTile*>* result_tiles,
461       std::vector<ResultCellSlab>* result_cell_slabs,
462       Subarray& subarray,
463       uint64_t memory_budget = UINT64_MAX,
464       bool include_dim = false);
465 
466   /**
467    * Copies the cells for the input **fixed-sized** attribute/dimension and
468    * result cell slabs into the corresponding result buffers.
469    *
470    * @param name The targeted attribute/dimension.
471    * @param stride If it is `UINT64_MAX`, then the cells in the result
472    *     cell slabs are all contiguous. Otherwise, each cell in the
473    *     result cell slabs are `stride` cells apart from each other.
474    * @param result_cell_slabs The result cell slabs to copy cells for.
475    * @param fixed_cs_partitions The cell slab partitions.
476    * @return Status
477    */
478   Status copy_fixed_cells(
479       const std::string& name,
480       uint64_t stride,
481       const std::vector<ResultCellSlab>* result_cell_slabs,
482       std::vector<size_t>* fixed_cs_partitions);
483 
484   /**
485    * Compute cs partitions for fixed-sized cell copying.
486    *
487    * @param result_cell_slabs The result cell slabs to copy cells for.
488    * @param fixed_cs_partitions The output partitions.
489    */
490   void compute_fixed_cs_partitions(
491       const std::vector<ResultCellSlab>* result_cell_slabs,
492       std::vector<size_t>* fixed_cs_partitions);
493 
494   /**
495    * Returns the configured bytesize for var-sized attribute offsets
496    */
497   uint64_t offsets_bytesize() const;
498 
499   /**
500    * Copies the cells for the input **fixed-sized** attribute/dimension and
501    * result cell slabs into the corresponding result buffers for the
502    * partition in `ctx_cache` at index `partition_idx`.
503    *
504    * @param name The partition index.
505    * @param name The targeted attribute/dimension.
506    * @param stride If it is `UINT64_MAX`, then the cells in the result
507    *     cell slabs are all contiguous. Otherwise, each cell in the
508    *     result cell slabs are `stride` cells apart from each other.
509    * @param result_cell_slabs The result cell slabs to copy cells for.
510    * @param cs_offsets The cell slab offsets.
511    * @param cs_partitions The cell slab partitions to operate on.
512    * @return Status
513    */
514   Status copy_partitioned_fixed_cells(
515       size_t partition_idx,
516       const std::string* name,
517       uint64_t stride,
518       const std::vector<ResultCellSlab>* result_cell_slabs,
519       const std::vector<uint64_t>* cs_offsets,
520       const std::vector<size_t>* cs_partitions);
521 
522   /**
523    * Copies the cells for the input **var-sized** attribute/dimension and result
524    * cell slabs into the corresponding result buffers.
525    *
526    * @param name The targeted attribute/dimension.
527    * @param stride If it is `UINT64_MAX`, then the cells in the result
528    *     cell slabs are all contiguous. Otherwise, each cell in the
529    *     result cell slabs are `stride` cells apart from each other.
530    * @param result_cell_slabs The result cell slabs to copy cells for.
531    * @param var_cs_partitions The cell slab partitions.
532    * @param total_cs_length The total cell slab length.
533    * @return Status
534    */
535   Status copy_var_cells(
536       const std::string& name,
537       uint64_t stride,
538       std::vector<ResultCellSlab>* result_cell_slabs,
539       std::vector<std::pair<size_t, size_t>>* var_cs_partitions,
540       size_t total_var_cs_length);
541 
542   /**
543    * Compute cs partitions for var-sized cell copying.
544    *
545    * @param result_cell_slabs The result cell slabs to copy cells for.
546    * @param var_cs_partitions The output partitions.
547    * @param total_var_cs_length The total cell slab length.
548    */
549   void compute_var_cs_partitions(
550       const std::vector<ResultCellSlab>* result_cell_slabs,
551       std::vector<std::pair<size_t, size_t>>* var_cs_partitions,
552       size_t* total_var_cs_length);
553 
554   /**
555    * Computes offsets into destination buffers for the given
556    * attribute/dimensions's offset and variable-length data, for the given list
557    * of result cell slabs.
558    *
559    * @param name The variable-length attribute/dimension.
560    * @param stride If it is `UINT64_MAX`, then the cells in the result
561    *     cell slabs are all contiguous. Otherwise, each cell in the
562    *     result cell slabs are `stride` cells apart from each other.
563    * @param result_cell_slabs The result cell slabs to compute destinations for.
564    * @param offset_offsets_per_cs Output to hold one vector per result cell
565    *    slab, and one element per cell in the slab. The elements are the
566    *    destination offsets for the attribute's offsets.
567    * @param var_offsets_per_cs Output to hold one vector per result cell slab,
568    *    and one element per cell in the slab. The elements are the destination
569    *    offsets for the attribute's variable-length data.
570    * @param total_offset_size Output set to the total size in bytes of the
571    *    offsets in the given list of result cell slabs.
572    * @param total_var_size Output set to the total size in bytes of the
573    *    attribute's variable-length in the given list of result cell slabs.
574    * @param total_validity_size Output set to the total size in bytes of the
575    *    attribute's validity vector in the given list of result cell slabs.
576    * @return Status
577    */
578   Status compute_var_cell_destinations(
579       const std::string& name,
580       uint64_t stride,
581       std::vector<ResultCellSlab>* result_cell_slabs,
582       std::vector<uint64_t>* offset_offsets_per_cs,
583       std::vector<uint64_t>* var_offsets_per_cs,
584       uint64_t* total_offset_size,
585       uint64_t* total_var_size,
586       uint64_t* total_validity_size);
587 
588   /**
589    * Copies the cells for the input **var-sized** attribute/dimension and result
590    * cell slabs into the corresponding result buffers for the
591    * partition in `cs_partitions` at index `partition_idx`.
592    *
593    * @param name The partition index.
594    * @param name The targeted attribute/dimension.
595    * @param stride If it is `UINT64_MAX`, then the cells in the result
596    *     cell slabs are all contiguous. Otherwise, each cell in the
597    *     result cell slabs are `stride` cells apart from each other.
598    * @param result_cell_slabs The result cell slabs to copy cells for.
599    * @param offset_offsets_per_cs Maps each cell slab to its offset
600    *     for its attribute offsets.
601    * @param var_offsets_per_cs Maps each cell slab to its offset
602    *     for its variable-length data.
603    * @param cs_partitions The cell slab partitions to operate on.
604    * @return Status
605    */
606   Status copy_partitioned_var_cells(
607       size_t partition_idx,
608       const std::string* name,
609       uint64_t stride,
610       const std::vector<ResultCellSlab>* result_cell_slabs,
611       const std::vector<uint64_t>* offset_offsets_per_cs,
612       const std::vector<uint64_t>* var_offsets_per_cs,
613       const std::vector<std::pair<size_t, size_t>>* cs_partitions);
614 
615   /**
616    * For each dimension/attribute in `names`, performs the actions
617    * defined in the `ProcessTileFlags`.
618    *
619    * @param names The dimension/attribute names to process.
620    * @param result_tiles The retrieved tiles will be stored inside the
621    *   `ResultTile` instances in this vector.
622    * @param result_cell_slabs The cell slabs to process.
623    * @param subarray Specifies the current subarray.
624    * @param stride The stride between cells, UINT64_MAX for contiguous.
625    * @param memory_budget The memory budget, UINT64_MAX for unlimited.
626    * @param memory_used_for_tiles The memory used for tiles that will not be
627    * unloaded.
628    */
629   Status process_tiles(
630       const std::unordered_map<std::string, ProcessTileFlags>* names,
631       std::vector<ResultTile*>* result_tiles,
632       std::vector<ResultCellSlab>* result_cell_slabs,
633       Subarray* subarray,
634       uint64_t stride,
635       uint64_t memory_budget,
636       uint64_t* memory_used_for_tiles);
637 
638   /**
639    * Builds and returns an association from each tile in `result_cell_slabs`
640    * to the cell slabs it contains.
641    */
642   tdb_unique_ptr<ResultCellSlabsIndex> compute_rcs_index(
643       const std::vector<ResultCellSlab>* result_cell_slabs) const;
644 
645   /**
646    * Applies the query condition, `condition_`, to filter cell indexes
647    * within `result_cell_slabs`. This mutates `result_cell_slabs`.
648    *
649    * @param result_cell_slabs The unfiltered cell slabs.
650    * @param result_tiles The result tiles that must contain values for
651    *   attributes within `condition_`.
652    * @param subarray Specifies the current subarray.
653    * @param stride The stride between cells, defaulting to UINT64_MAX
654    *   for contiguous cells.
655    * @param memory_budget_rcs The memory budget for tiles, defaulting
656    *   to UINT64_MAX for unlimited budget.
657    * @param memory_budget_tiles The memory budget for result cell slabs,
658    *   defaulting to UINT64_MAX for unlimited budget.
659    * @param memory_used_for_tiles The memory used for tiles that will
660    *   not be unloaded.
661    * @return Status
662    */
663   Status apply_query_condition(
664       std::vector<ResultCellSlab>* result_cell_slabs,
665       std::vector<ResultTile*>* result_tiles,
666       Subarray* subarray,
667       uint64_t stride = UINT64_MAX,
668       uint64_t memory_budget_rcs = UINT64_MAX,
669       uint64_t memory_budget_tiles = UINT64_MAX,
670       uint64_t* memory_used_for_tiles = nullptr);
671 
672   /**
673    * Get the size of an attribute tile.
674    *
675    * @param name The attribute name.
676    * @param f The fragment idx.
677    * @param t The tile idx.
678    * @param tile_size The return tile size.
679    * @return Status
680    */
681   Status get_attribute_tile_size(
682       const std::string& name, unsigned f, uint64_t t, uint64_t* tile_size);
683 
684   /**
685    * Computes the result space tiles based on the current partition.
686    *
687    * @tparam T The domain datatype.
688    * @param subarray The input subarray.
689    * @param partitioner_subarray The partitioner subarray.
690    * @param result_space_tiles The result space tiles to be computed.
691    */
692   template <class T>
693   void compute_result_space_tiles(
694       const Subarray* subarray,
695       const Subarray* partitioner_subarray,
696       std::map<const T*, ResultSpaceTile<T>>* result_space_tiles) const;
697 
698   /** Returns `true` if the coordinates are included in the attributes. */
699   bool has_coords() const;
700 
701   /**
702    * Fills the coordinate buffer with coordinates. Applicable only to dense
703    * arrays when the user explicitly requests the coordinates to be
704    * materialized.
705    *
706    * @tparam T The domain type.
707    * @param subarray The input subarray.
708    * @return Status
709    */
710   template <class T>
711   Status fill_dense_coords(const Subarray& subarray);
712 
713   /**
714    * Fills the coordinate buffers with coordinates. Applicable only to dense
715    * arrays when the user explicitly requests the coordinates to be
716    * materialized. Also applicable only to global order.
717    *
718    * @tparam T The domain type.
719    * @param subarray The input subarray.
720    * @param dim_idx The dimension indices of the corresponding `buffers`.
721    *     For the special zipped coordinates, `dim_idx`, `buffers` and `offsets`
722    *     contain a single element and `dim_idx` contains `dim_num` as
723    *     the dimension index.
724    * @param buffers The buffers to copy from. It could be the special
725    *     zipped coordinates or separate coordinate buffers.
726    * @param offsets The offsets that will be used eventually to update
727    *     the buffer sizes, determining the useful results written in
728    *     the buffers.
729    * @return Status
730    */
731   template <class T>
732   Status fill_dense_coords_global(
733       const Subarray& subarray,
734       const std::vector<unsigned>& dim_idx,
735       const std::vector<QueryBuffer*>& buffers,
736       std::vector<uint64_t>* offsets);
737 
738   /**
739    * Fills the coordinate buffers with coordinates. Applicable only to dense
740    * arrays when the user explicitly requests the coordinates to be
741    * materialized. Also applicable only to row-/col-major order.
742    *
743    * @tparam T The domain type.
744    * @param subarray The input subarray.
745    * @param dim_idx The dimension indices of the corresponding `buffers`.
746    *     For the special zipped coordinates, `dim_idx`, `buffers` and `offsets`
747    *     contain a single element and `dim_idx` contains `dim_num` as
748    *     the dimension index.
749    * @param buffers The buffers to copy from. It could be the special
750    *     zipped coordinates or separate coordinate buffers.
751    * @param offsets The offsets that will be used eventually to update
752    *     the buffer sizes, determining the useful results written in
753    *     the buffers.
754    * @return Status
755    */
756   template <class T>
757   Status fill_dense_coords_row_col(
758       const Subarray& subarray,
759       const std::vector<unsigned>& dim_idx,
760       const std::vector<QueryBuffer*>& buffers,
761       std::vector<uint64_t>* offsets);
762 
763   /**
764    * Fills coordinates in the input buffers for a particular cell slab,
765    * following a row-major layout. For instance, if the starting coordinate are
766    * [3, 1] and the number of coords to be written is 3, this function will
767    * write to the input buffer (starting at the input offset) coordinates
768    * [3, 1], [3, 2], and [3, 3].
769    *
770    * @tparam T The domain type.
771    * @param start The starting coordinates in the slab.
772    * @param num The number of coords to be written.
773    * @param dim_idx The dimension indices of the corresponding `buffers`.
774    *     For the special zipped coordinates, `dim_idx`, `buffers` and `offsets`
775    *     contain a single element and `dim_idx` contains `dim_num` as
776    *     the dimension index.
777    * @param buffers The buffers to copy from. It could be the special
778    *     zipped coordinates or separate coordinate buffers.
779    * @param offsets The offsets that will be used eventually to update
780    *     the buffer sizes, determining the useful results written in
781    *     the buffers.
782    */
783   template <class T>
784   void fill_dense_coords_row_slab(
785       const T* start,
786       uint64_t num,
787       const std::vector<unsigned>& dim_idx,
788       const std::vector<QueryBuffer*>& buffers,
789       std::vector<uint64_t>* offsets) const;
790 
791   /**
792    * Fills coordinates in the input buffers for a particular cell slab,
793    * following a col-major layout. For instance, if the starting coordinate are
794    * [3, 1] and the number of coords to be written is 3, this function will
795    * write to the input buffer (starting at the input offset) coordinates
796    * [4, 1], [5, 1], and [6, 1].
797    *
798    * @tparam T The domain type.
799    * @param start The starting coordinates in the slab.
800    * @param num The number of coords to be written.
801    * @param dim_idx The dimension indices of the corresponding `buffers`.
802    *     For the special zipped coordinates, `dim_idx`, `buffers` and `offsets`
803    *     contain a single element and `dim_idx` contains `dim_num` as
804    *     the dimension index.
805    * @param buffers The buffers to copy from. It could be the special
806    *     zipped coordinates or separate coordinate buffers.
807    * @param offsets The offsets that will be used eventually to update
808    *     the buffer sizes, determining the useful results written in
809    *     the buffers.
810    */
811   template <class T>
812   void fill_dense_coords_col_slab(
813       const T* start,
814       uint64_t num,
815       const std::vector<unsigned>& dim_idx,
816       const std::vector<QueryBuffer*>& buffers,
817       std::vector<uint64_t>* offsets) const;
818 };
819 
820 }  // namespace sm
821 }  // namespace tiledb
822 
823 #endif  // TILEDB_READER_BASE_H