From b94196d74593b165c5df0a06d90dad26723fd419 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 3 Aug 2016 16:46:30 -0400 Subject: [PATCH 01/57] Enhancing the array read modes to encompass the two sorted read modes --- core/include/array/array.h | 16 +++-- core/include/c_api/constants.h | 8 ++- core/include/fragment/book_keeping.h | 6 ++ core/include/fragment/fragment.h | 6 ++ core/include/misc/utils.h | 6 ++ .../include/storage_manager/storage_manager.h | 12 +++- core/src/array/array.cc | 58 +++++++++++-------- core/src/fragment/book_keeping.cc | 12 +++- core/src/fragment/fragment.cc | 27 ++++++--- core/src/misc/utils.cc | 11 ++++ core/src/storage_manager/storage_manager.cc | 29 ++++++---- 11 files changed, 136 insertions(+), 55 deletions(-) diff --git a/core/include/array/array.h b/core/include/array/array.h index 73fe2829..8fc75e17 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -160,8 +160,8 @@ class Array { bool overflow(int attribute_id) const; /** - * Performs a read operation in an array, which must be initialized with mode - * TILEDB_ARRAY_READ. The function retrieves the result cells that lie inside + * Performs a read operation in an array, which must be initialized in read + * mode. The function retrieves the result cells that lie inside * the subarray specified in init() or reset_subarray(). The results are * written in input buffers provided by the user, which are also allocated by * the user. Note that the results are written in the buffers in the same @@ -187,9 +187,15 @@ class Array { */ int read(void** buffers, size_t* buffer_sizes); + /** Returns true if the array is in read mode. */ + bool read_mode() const; + /** Returns the subarray in which the array is constrained. */ const void* subarray() const; + /** Returns true if the array is in write mode. */ + bool write_mode() const; + @@ -199,7 +205,7 @@ class Array { /** * Consolidates all fragments into a new single one, on a per-attribute basis. - * Returns the new fragment (which has to be finalized outside this functions), + * Returns the new fragment (which has to be finalized outside this function), * along with the names of the old (consolidated) fragments (which also have * to be deleted outside this function). * @@ -240,6 +246,8 @@ class Array { * - TILEDB_ARRAY_WRITE * - TILEDB_ARRAY_WRITE_UNSORTED * - TILEDB_ARRAY_READ + * - TILEDB_ARRAY_READ_SORTED_COL + * - TILEDB_ARRAY_READ_SORTED_ROW * @param subarray The subarray in which the array read/write will be * constrained on. If it is NULL, then the subarray is set to the entire * array domain. For the case of writes, this is meaningful only for @@ -433,7 +441,7 @@ class Array { std::string new_fragment_name() const; /** - * Opens the existing fragments in TILEDB_ARRAY_READ_MODE. + * Opens the existing fragments. * * @param fragment_names The vector with the fragment names. * @param book_keeping The book-keeping of the array fragments. diff --git a/core/include/c_api/constants.h b/core/include/c_api/constants.h index f183fe8f..ac4b258f 100644 --- a/core/include/c_api/constants.h +++ b/core/include/c_api/constants.h @@ -47,9 +47,11 @@ /**@{*/ /** Array mode. */ -#define TILEDB_ARRAY_READ 0 -#define TILEDB_ARRAY_WRITE 1 -#define TILEDB_ARRAY_WRITE_UNSORTED 2 +#define TILEDB_ARRAY_READ 0 +#define TILEDB_ARRAY_READ_SORTED_COL 1 +#define TILEDB_ARRAY_READ_SORTED_ROW 2 +#define TILEDB_ARRAY_WRITE 3 +#define TILEDB_ARRAY_WRITE_UNSORTED 4 /**@}*/ /**@{*/ diff --git a/core/include/fragment/book_keeping.h b/core/include/fragment/book_keeping.h index 2d6ceea2..fe948cac 100644 --- a/core/include/fragment/book_keeping.h +++ b/core/include/fragment/book_keeping.h @@ -121,6 +121,9 @@ class BookKeeping { /** Returns the non-empty domain in which the fragment is constrained. */ const void* non_empty_domain() const; + /** Returns true if the array is in read mode. */ + bool read_mode() const; + /** Returns the number of tiles in the fragment. */ int64_t tile_num() const; @@ -133,6 +136,9 @@ class BookKeeping { /** Returns the variable tile sizes. */ const std::vector >& tile_var_sizes() const; + /** Returns true if the array is in write mode. */ + bool write_mode() const; + diff --git a/core/include/fragment/fragment.h b/core/include/fragment/fragment.h index 8d3df148..1b186dad 100644 --- a/core/include/fragment/fragment.h +++ b/core/include/fragment/fragment.h @@ -112,6 +112,9 @@ class Fragment { /** Returns the mode of the fragment. */ int mode() const; + /** Returns true if the array is in read mode. */ + bool read_mode() const; + /** Returns the read state of the fragment. */ ReadState* read_state() const; @@ -121,6 +124,9 @@ class Fragment { */ size_t tile_size(int attribute_id) const; + /** Returns true if the array is in write mode. */ + bool write_mode() const; + diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index e7255ae4..704f203d 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -80,6 +80,12 @@ extern std::string tiledb_ut_errmsg; */ void adjacent_slashes_dedup(std::string& value); +/** Returns true if the input is an array read mode. */ +bool array_read_mode(int mode); + +/** Returns true if the input is an array write mode. */ +bool array_write_mode(int mode); + /** * Checks if both inputs represent the '/' character. This is an auxiliary * function to adjacent_slashes_dedup(). diff --git a/core/include/storage_manager/storage_manager.h b/core/include/storage_manager/storage_manager.h index 2a084cef..b12bf9df 100755 --- a/core/include/storage_manager/storage_manager.h +++ b/core/include/storage_manager/storage_manager.h @@ -250,6 +250,8 @@ class StorageManager { * - TILEDB_ARRAY_WRITE * - TILEDB_ARRAY_WRITE_UNSORTED * - TILEDB_ARRAY_READ + * - TILEDB_ARRAY_READ_SORTED_COL + * - TILEDB_ARRAY_READ_SORTED_ROW * @param subarray The subarray in which the array read/write will be * constrained on. If it is NULL, then the subarray is set to the entire * array domain. For the case of writes, this is meaningful only for @@ -591,12 +593,14 @@ class StorageManager { * @param array_schema The array schema. * @param fragment_names The names of the fragments of the array. * @param book_keeping The book-keeping structures to be returned. + * @param mode The array mode * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. */ int array_load_book_keeping( const ArraySchema* array_schema, const std::vector& fragment_names, - std::vector& book_keeping); + std::vector& book_keeping, + int mode); /** * Moves a TileDB array. @@ -613,16 +617,18 @@ class StorageManager { * Opens an array. This creates or updates an OpenArray entry for this array, * and loads the array schema and book-keeping if it is the first time this * array is being initialized. The book-keeping structures are loaded only - * if the input mode is TILEDB_ARRAY_READ. + * if the input mode is a read mode. * * @param array_name The array name (must be absolute path). * @param mode The mode in which the array is being initialized. * @param open_array The open array entry that is retrieved. + * @param mode The array mode. * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ int array_open( const std::string& array_name, - OpenArray*& open_array); + OpenArray*& open_array, + int mode); /** * Stores the input array schema into the input array directory (serializing diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 91b1d0ad..fc6aea7e 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -160,7 +160,7 @@ void Array::aio_handle_requests() { int Array::aio_read(AIO_Request* aio_request) { // Sanity checks - if(mode_ != TILEDB_ARRAY_READ) { + if(!read_mode()) { std::string errmsg = "Cannot (async) read from array; Invalid mode"; PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; @@ -182,8 +182,7 @@ int Array::aio_read(AIO_Request* aio_request) { int Array::aio_write(AIO_Request* aio_request) { // Sanity checks - if(mode_ != TILEDB_ARRAY_WRITE && - mode_ != TILEDB_ARRAY_WRITE_UNSORTED) { + if(!write_mode()) { std::string errmsg = "Cannot (async) write to array; Invalid mode"; PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; @@ -229,7 +228,7 @@ int Array::mode() const { bool Array::overflow() const { // Not applicable to writes - if(mode_ != TILEDB_ARRAY_READ) + if(!read_mode()) return false; for(int i=0; i attributes_vec; if(attributes == NULL) { // Default: all attributes attributes_vec = array_schema->attributes(); + // TODO: revisit this for sorted writes if(array_schema->dense() && mode != TILEDB_ARRAY_WRITE_UNSORTED) // Remove coordinates attribute for dense arrays, // unless in TILEDB_WRITE_UNSORTED mode @@ -540,15 +552,11 @@ int Array::init( return TILEDB_AR_ERR; } - // Set mode - mode_ = mode; - // Set array schema array_schema_ = array_schema; // Initialize new fragment if needed - if(mode_ == TILEDB_ARRAY_WRITE || - mode_ == TILEDB_ARRAY_WRITE_UNSORTED) { + if(write_mode()) { // WRITE MODE // Get new fragment name std::string new_fragment_name = this->new_fragment_name(); if(new_fragment_name == "") { @@ -566,13 +574,13 @@ int Array::init( tiledb_ar_errmsg = tiledb_fg_errmsg; return TILEDB_AR_ERR; } - } else if(mode_ == TILEDB_ARRAY_READ) { + } else { // READ MODE if(open_fragments(fragment_names, book_keeping) != TILEDB_AR_OK) { array_schema_ = NULL; return TILEDB_AR_ERR; } array_read_state_ = new ArrayReadState(this); - } + } // Initialize the AIO-related members aio_cond_ = PTHREAD_COND_INITIALIZER; @@ -639,11 +647,14 @@ int Array::reset_attributes( } int Array::reset_subarray(const void* subarray) { + // Sanity check + assert(read_mode() || write_mode()); + // For easy referencd int fragment_num = fragments_.size(); // Finalize fragments if in write mode - if(mode_ != TILEDB_ARRAY_READ) { + if(write_mode()) { // Finalize and delete fragments for(int i=0; ifinalize(); @@ -662,7 +673,7 @@ int Array::reset_subarray(const void* subarray) { memcpy(subarray_, subarray, subarray_size); // Re-set of re-initialize fragments - if(mode_ != TILEDB_ARRAY_READ) { // WRITE MODE + if(write_mode()) { // WRITE MODE // Get new fragment name std::string new_fragment_name = this->new_fragment_name(); if(new_fragment_name == "") { @@ -679,7 +690,7 @@ int Array::reset_subarray(const void* subarray) { tiledb_ar_errmsg = tiledb_fg_errmsg; return TILEDB_AR_ERR; } - } else if(mode_ == TILEDB_ARRAY_READ) { // READ MODE + } else { // READ MODE // Re-initialize the read state of the fragments for(int i=0; ireset_read_state(); @@ -698,8 +709,7 @@ int Array::reset_subarray(const void* subarray) { int Array::write(const void** buffers, const size_t* buffer_sizes) { // Sanity checks - if(mode_ != TILEDB_ARRAY_WRITE && - mode_ != TILEDB_ARRAY_WRITE_UNSORTED) { + if(!write_mode()) { std::string errmsg = "Cannot write to array; Invalid mode"; PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; @@ -733,6 +743,7 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { } // In WRITE_UNSORTED mode, the fragment must be finalized + // TODO: revisit this for sorted writes if(mode_ == TILEDB_ARRAY_WRITE_UNSORTED) { if(fragments_[0]->finalize() != TILEDB_FG_OK) { tiledb_ar_errmsg = tiledb_fg_errmsg; @@ -755,7 +766,7 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { void Array::aio_handle_next_request(AIO_Request* aio_request) { int rc = TILEDB_AR_OK; - if(mode_ == TILEDB_ARRAY_READ) { // READ + if(read_mode()) { // READ MODE // Reset the subarray only if this request does not continue from the last if(aio_last_handled_request_ != aio_request->id_) rc = reset_subarray(aio_request->subarray_); @@ -763,7 +774,7 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { // Invoke the read if(rc == TILEDB_AR_OK) rc = read(aio_request->buffers_, aio_request->buffer_sizes_); - } else { // WRITE + } else { // WRITE MODE rc = write( (const void**) aio_request->buffers_, (const size_t*) aio_request->buffer_sizes_); @@ -926,7 +937,6 @@ int Array::open_fragments( // Sanity check assert(fragment_names.size() == book_keeping.size()); - // Create a fragment object for each fragment directory int fragment_num = fragment_names.size(); for(int i=0; itile_num(domain_); @@ -162,6 +167,11 @@ const std::vector >& BookKeeping::tile_var_sizes() const { return tile_var_sizes_; } +inline +bool BookKeeping::write_mode() const { + return array_write_mode(mode_); +} + @@ -240,7 +250,7 @@ void BookKeeping::append_tile_var_size( */ int BookKeeping::finalize() { // Nothing to do in READ mode - if(mode_ == TILEDB_ARRAY_READ) + if(read_mode()) return TILEDB_BK_OK; // Do nothing if the fragment directory does not exist (fragment empty) diff --git a/core/src/fragment/fragment.cc b/core/src/fragment/fragment.cc index 8c8103a6..0ad8d7fd 100644 --- a/core/src/fragment/fragment.cc +++ b/core/src/fragment/fragment.cc @@ -82,7 +82,7 @@ Fragment::~Fragment() { if(read_state_ != NULL) delete read_state_; - if(book_keeping_ != NULL && mode_ != TILEDB_ARRAY_READ) + if(book_keeping_ != NULL && !read_mode()) delete book_keeping_; } @@ -114,6 +114,11 @@ int Fragment::mode() const { return mode_; } +inline +bool Fragment::read_mode() const { + return array_read_mode(mode_); +} + ReadState* Fragment::read_state() const { return read_state_; } @@ -132,6 +137,11 @@ size_t Fragment::tile_size(int attribute_id) const { cell_num_per_tile * array_schema->cell_size(attribute_id); } +inline +bool Fragment::write_mode() const { + return array_write_mode(mode_); +} + @@ -179,19 +189,18 @@ int Fragment::init( const std::string& fragment_name, int mode, const void* subarray) { + // Set fragment name and mode + fragment_name_ = fragment_name; + mode_ = mode; + // Sanity check - if(mode != TILEDB_ARRAY_WRITE && - mode != TILEDB_ARRAY_WRITE_UNSORTED) { + if(!write_mode()) { std::string errmsg = "Cannot initialize fragment; Invalid mode"; PRINT_ERROR(errmsg); tiledb_fg_errmsg = TILEDB_FG_ERRMSG + errmsg; return TILEDB_FG_ERR; } - // Set fragment name and mode - fragment_name_ = fragment_name; - mode_ = mode; - // Check if the fragment is dense or not dense_ = true; const std::vector& attribute_ids = array_->attribute_ids(); @@ -230,7 +239,7 @@ int Fragment::init( BookKeeping* book_keeping) { // Set member attributes fragment_name_ = fragment_name; - mode_ = TILEDB_ARRAY_READ; + mode_ = array_->mode(); book_keeping_ = book_keeping; dense_ = book_keeping_->dense(); write_state_ = NULL; @@ -267,7 +276,7 @@ int Fragment::write(const void** buffers, const size_t* buffer_sizes) { int Fragment::rename_fragment() { // Do nothing in READ mode - if(mode_ == TILEDB_ARRAY_READ) + if(read_mode()) return TILEDB_FG_OK; std::string parent_dir = ::parent_dir(fragment_name_); diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 63ef039a..0473b2bc 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -79,6 +79,17 @@ void adjacent_slashes_dedup(std::string& value) { value.end()); } +bool array_read_mode(int mode) { + return mode == TILEDB_ARRAY_READ || + mode == TILEDB_ARRAY_READ_SORTED_COL || + mode == TILEDB_ARRAY_READ_SORTED_ROW; +} + +bool array_write_mode(int mode) { + return mode == TILEDB_ARRAY_WRITE || + mode == TILEDB_ARRAY_WRITE_UNSORTED; +} + bool both_slashes(char a, char b) { return a == '/' && b == '/'; } diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 1b5ce420..9f9ca15d 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -433,7 +433,8 @@ void StorageManager::array_get_fragment_names( int StorageManager::array_load_book_keeping( const ArraySchema* array_schema, const std::vector& fragment_names, - std::vector& book_keeping) { + std::vector& book_keeping, + int mode) { // For easy reference int fragment_num = fragment_names.size(); @@ -452,7 +453,7 @@ int StorageManager::array_load_book_keeping( array_schema, dense, fragment_names[i], - TILEDB_ARRAY_READ); + mode); // Load book-keeping if(f_book_keeping->load() != TILEDB_BK_OK) { @@ -563,8 +564,8 @@ int StorageManager::array_init( // Open the array OpenArray* open_array = NULL; - if(mode == TILEDB_ARRAY_READ) { - if(array_open(real_dir(array_dir), open_array) != TILEDB_SM_OK) + if(array_read_mode(mode)) { + if(array_open(real_dir(array_dir), open_array, mode) != TILEDB_SM_OK) return TILEDB_SM_ERR; } @@ -596,10 +597,9 @@ int StorageManager::array_finalize(Array* array) { return TILEDB_SM_OK; // Finalize and close the array - int mode = array->mode(); int rc_finalize = array->finalize(); int rc_close = TILEDB_SM_OK; - if(mode == TILEDB_ARRAY_READ) + if(array->read_mode()) rc_close = array_close(array->array_schema()->array_name()); // Clean up @@ -630,6 +630,7 @@ int StorageManager::array_iterator_init( if(array_init( array, array_dir, + // TODO: revisit this and pass the mode as input - change also the website TILEDB_ARRAY_READ, subarray, attributes, @@ -950,7 +951,10 @@ int StorageManager::metadata_init( // Open the array that implements the metadata OpenArray* open_array = NULL; if(mode == TILEDB_METADATA_READ) { - if(array_open(real_dir(metadata_dir), open_array) != TILEDB_SM_OK) + if(array_open( + real_dir(metadata_dir), + open_array, + TILEDB_ARRAY_READ) != TILEDB_SM_OK) return TILEDB_SM_ERR; } @@ -1367,8 +1371,9 @@ int StorageManager::array_close(const std::string& array) { if(it->second->cnt_ == 0) { // Clean up book-keeping std::vector::iterator bit = it->second->book_keeping_.begin(); - for(; bit != it->second->book_keeping_.end(); ++bit) + for(; bit != it->second->book_keeping_.end(); ++bit) { delete *bit; + } // Unlock and destroy mutexes it->second->mutex_unlock(); @@ -1377,7 +1382,7 @@ int StorageManager::array_close(const std::string& array) { // Unlock consolidation filelock rc_filelock = consolidation_filelock_unlock( it->second->consolidation_filelock_); - + // Delete array schema if(it->second->array_schema_ != NULL) delete it->second->array_schema_; @@ -1525,7 +1530,8 @@ int StorageManager::array_move( int StorageManager::array_open( const std::string& array_name, - OpenArray*& open_array) { + OpenArray*& open_array, + int mode) { // Get the open array entry if(array_get_open_array_entry(array_name, open_array) != TILEDB_SM_OK) return TILEDB_SM_ERR; @@ -1565,7 +1571,8 @@ int StorageManager::array_open( if(array_load_book_keeping( open_array->array_schema_, open_array->fragment_names_, - open_array->book_keeping_) != TILEDB_SM_OK) { + open_array->book_keeping_, + mode) != TILEDB_SM_OK) { delete open_array->array_schema_; open_array->array_schema_ = NULL; open_array->mutex_unlock(); From 474f3e7bc495f12411ddd0193a0aaebf44306747 Mon Sep 17 00:00:00 2001 From: spapadop Date: Thu, 22 Sep 2016 19:18:26 -0400 Subject: [PATCH 02/57] Substantial progress on sorted reads. --- core/include/array/array.h | 39 +- core/include/array/array_schema.h | 52 + core/include/array/array_sorted_read_state.h | 539 ++++++++++ core/include/c_api/constants.h | 3 + core/include/fragment/read_state.h | 2 +- core/src/array/array.cc | 73 +- core/src/array/array_schema.cc | 136 ++- core/src/array/array_sorted_read_state.cc | 932 ++++++++++++++++++ .../src/tiledb_array_read_sorted_dense.cc | 85 ++ 9 files changed, 1845 insertions(+), 16 deletions(-) create mode 100644 core/include/array/array_sorted_read_state.h create mode 100644 core/src/array/array_sorted_read_state.cc create mode 100644 examples/src/tiledb_array_read_sorted_dense.cc diff --git a/core/include/array/array.h b/core/include/array/array.h index 8fc75e17..c9a42ba6 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -35,6 +35,7 @@ #include "aio_request.h" #include "array_read_state.h" +#include "array_sorted_read_state.h" #include "array_schema.h" #include "book_keeping.h" #include "config.h" @@ -71,6 +72,7 @@ extern std::string tiledb_ar_errmsg; class ArrayReadState; +class ArraySortedReadState; class Fragment; @@ -165,7 +167,7 @@ class Array { * the subarray specified in init() or reset_subarray(). The results are * written in input buffers provided by the user, which are also allocated by * the user. Note that the results are written in the buffers in the same - * order they appear on the disk, which leads to maximum performance. + * order as that specified by the user in the init() function. * * @param buffers An array of buffers, one for each attribute. These must be * provided in the same order as the attributes specified in @@ -187,6 +189,34 @@ class Array { */ int read(void** buffers, size_t* buffer_sizes); + /** + * Performs a read operation in an array, which must be initialized in read + * mode. The function retrieves the result cells that lie inside + * the subarray specified in init() or reset_subarray(). The results are + * written in input buffers provided by the user, which are also allocated by + * the user. Note that the results are written in the buffers in the same + * order they appear on the disk, which leads to maximum performance. + * + * @param buffers An array of buffers, one for each attribute. These must be + * provided in the same order as the attributes specified in + * init() or reset_attributes(). The case of variable-sized attributes is + * special. Instead of providing a single buffer for such an attribute, + * **two** must be provided: the second will hold the variable-sized cell + * values, whereas the first holds the start offsets of each cell in the + * second buffer. + * @param buffer_sizes The sizes (in bytes) allocated by the user for the + * input buffers (there is a one-to-one correspondence). The function will + * attempt to write as many results as can fit in the buffers, and + * potentially alter the buffer size to indicate the size of the *useful* + * data written in the buffer. If a buffer cannot hold all results, the + * function will still succeed, writing as much data as it can and turning + * on an overflow flag which can be checked with function overflow(). The + * next invocation will resume for the point the previous one stopped, + * without inflicting a considerable performance penalty due to overflow. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ + int read_default(void** buffers, size_t* buffer_sizes); + /** Returns true if the array is in read mode. */ bool read_mode() const; @@ -348,7 +378,7 @@ class Array { pthread_mutex_t aio_mtx_; /** The queue that stores the pending AIO requests. */ std::queue aio_queue_; - /** The thread tha handles all the AIO reads and writes in the background. */ + /** The thread that handles all the AIO reads and writes in the background. */ pthread_t aio_thread_; /** Indicates whether the AIO thread was canceled or not. */ bool aio_thread_canceled_; @@ -358,6 +388,8 @@ class Array { const ArraySchema* array_schema_; /** The read state of the array. */ ArrayReadState* array_read_state_; + /** The sorted read state of the array. */ + ArraySortedReadState* array_sorted_read_state_; /** * The ids of the attributes the array is initialized with. Note that the * array may be initialized with a subset of attributes when writing or @@ -402,13 +434,14 @@ class Array { * Function called by the AIO thread. * * @param context This is practically the Array object for which the function - * is called (typically *this* is passed to ths argument by the caller). + * is called (typically *this* is passed to this argument by the caller). */ static void *aio_handler(void* context); /** * Pusghes an AIO request into the AIO queue. * + * @param aio_request The AIO request. * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. */ int aio_push_request(AIO_Request* aio_request); diff --git a/core/include/array/array_schema.h b/core/include/array/array_schema.h index 292aa363..28fc9d21 100644 --- a/core/include/array/array_schema.h +++ b/core/include/array/array_schema.h @@ -170,6 +170,42 @@ class ArraySchema { const std::vector& attributes, std::vector& attribute_ids) const; + /** + * Returns true if the input range is contained fully in a single + * column of tiles. + */ + bool is_contained_in_tile_slab_col(const void* range) const; + + /** + * Returns true if the input range is contained fully in a single + * column of tiles. + * + * @template T The coordinates type. + * @param range The input range. + * @return True if the input range is contained fully in a single + * column of tiles. + */ + template + bool is_contained_in_tile_slab_col(const T* range) const; + + /** + * Returns true if the input range is contained fully in a single + * row of tiles. + */ + bool is_contained_in_tile_slab_row(const void* range) const; + + /** + * Returns true if the input range is contained fully in a single + * row of tiles. + * + * @template T The coordinates type. + * @param range The input range. + * @return True if the input range is contained fully in a single + * row of tiles. + */ + template + bool is_contained_in_tile_slab_row(const T* range) const; + /** Prints information about the array schema to stdout. */ void print() const; @@ -243,6 +279,14 @@ class ArraySchema { template int64_t tile_num(const T* domain) const; + /** Returns the tile order. */ + int tile_order() const; + + /** Return the number of cells in a column tile slab of an input subarray. */ + int64_t tile_slab_col_cell_num(const void* subarray) const; + + /** Return the number of cells in a row tile slab of an input subarray. */ + int64_t tile_slab_row_cell_num(const void* subarray) const; /** Returns the type of the i-th attribute, or NULL if 'i' is invalid. */ int type(int i) const; @@ -1007,6 +1051,14 @@ class ArraySchema { /** Initializes a Hilbert curve. */ void init_hilbert_curve(); + + /** Return the number of cells in a column tile slab of an input subarray. */ + template + int64_t tile_slab_col_cell_num(const T* subarray) const; + + /** Return the number of cells in a row tile slab of an input subarray. */ + template + int64_t tile_slab_row_cell_num(const T* subarray) const; }; #endif diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h new file mode 100644 index 00000000..48b9b2fe --- /dev/null +++ b/core/include/array/array_sorted_read_state.h @@ -0,0 +1,539 @@ +/** + * @file array_sorted_read_state.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file defines class ArraySortedReadState. + */ + +#ifndef __ARRAY_SORTED_READ_STATE_H__ +#define __ARRAY_SORTED_READ_STATE_H__ + +#include "array.h" +#include +#include +#include + + +/* ********************************* */ +/* CONSTANTS */ +/* ********************************* */ + +/**@{*/ +/** Return code. */ +#define TILEDB_ASRS_OK 0 +#define TILEDB_ASRS_ERR -1 +/**@}*/ + +/** Default error message. */ +#define TILEDB_ASRS_ERRMSG std::string("[TileDB::ArraySortedReadState] Error: ") + + + + +/* ********************************* */ +/* GLOBAL VARIABLES */ +/* ********************************* */ + +extern std::string tiledb_asrs_errmsg; + + +class Array; + +/** + * Stores the state necessary when reading cells from the array fragments, + * sorted in a way different to the global cell order. + */ +class ArraySortedReadState { + public: + + /* ********************************* */ + /* TYPE DEFINITIONS */ + /* ********************************* */ + + /** Simple struct used for an AIO or copy request. */ + struct ASRS_Request { + /** The id of the targeted tile slab. */ + int id_; + /** The calling object. */ + ArraySortedReadState* asrs_; + }; + + /** Info about a tile slab. It is used by the copy_tile_slab() function. */ + struct TileSlabInfo { + /** + * Number of cell slabs to be copied in as tile pass, + * per attribute per tile. + */ + int64_t** cell_slab_num_in_pass_; + /** The multi-dimensional range of cell slabs per tile. */ + int64_t** cell_slab_range_; + /** Cell slab size per attribute per tile. */ + size_t** cell_slab_size_; + /** + * Bytes to jump after copying a cell slab, per attribute, per tile, + * per dimension. + */ + size_t*** offsets_per_dim_; + /** Number of tiles in the tile slab. */ + int64_t tile_num_; + /** Offset of each starting result cell per attribute per tile. */ + size_t** tile_offsets_; + }; + + /** The state for a tile slab copy. */ + struct TileSlabState { + /** The current tile per attribute. */ + int64_t* current_tile_; + /** The cell slab in the current pass per attribute per tile. */ + int64_t** current_cell_slab_in_pass_; + /** The offset of the next cell slab to be copied per attribute per tile. */ + size_t** current_offset_; + }; + + + /* ********************************* */ + /* CONSTRUCTORS & DESTRUCTORS */ + /* ********************************* */ + + /** + * Constructor. + * + * @param array The array this array sorted read state belongs to. + */ + ArraySortedReadState(Array* array); + + /** Destructor. */ + ~ArraySortedReadState(); + + + + + /* ********************************* */ + /* ACCESSORS */ + /* ********************************* */ + + /** Returns true if copying into the user buffers resulted in overflow. */ + bool overflow() const; + + /** + * Same as Array::read(), but it sorts the cells in the buffers based on the + * order the user specified in Array::init(). Note that this function will + * fail if there is not enough system memory to hold the cells of a + * 'tile slab' overlapping with the selected subarray. + * + * @param buffers An array of buffers, one for each attribute. These must be + * provided in the same order as the attributes specified in + * Array::init() or Array::reset_attributes(). The case of variable-sized + * attributes is special. Instead of providing a single buffer for such + * an attribute, **two** must be provided: the second will hold the + * variable-sized cell values, whereas the first holds the start offsets + * of each cell in the second buffer. + * @param buffer_sizes The sizes (in bytes) allocated by the user for the + * input buffers (there is a one-to-one correspondence). The function will + * attempt to write as many results as can fit in the buffers, and + * potentially alter the buffer size to indicate the size of the *useful* + * data written in the buffer. If a buffer cannot hold all results, the + * function will still succeed, writing as much data as it can and turning + * on an overflow flag which can be checked with function overflow(). The + * next invocation will resume for the point the previous one stopped, + * without inflicting a considerable performance penalty due to overflow. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int read(void** buffers, size_t* buffer_sizes); + + + + + /* ********************************* */ + /* MUTATORS */ + /* ********************************* */ + + + /** + * Initialized the array sorted read state. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int init(); + + + private: + /* ********************************* */ + /* PRIVATE ATTRIBUTES */ + /* ********************************* */ + + /** The AIO mutex conditions (one for each buffer). */ + pthread_cond_t aio_cond_[2]; + + /** The current id of the buffers the next AIO will occur into. */ + int aio_id_; + + /** The AIO mutex. */ + pthread_mutex_t aio_mtx_; + + /** The array this sorted read state belongs to. */ + Array* array_; + + /** The ids of the attributes the array was initialized with. */ + const std::vector& attribute_ids_; + + /** Number of allocated buffers. */ + int buffer_num_; + + /** Allocated sizes for buffers_ (similar to those used in Array::read). */ + size_t* buffer_sizes_[2]; + + /** Local buffers (similar to those used in Array::read). */ + void** buffers_[2]; + + /** The copy mutex conditions (one for each buffer). */ + pthread_cond_t copy_cond_[2]; + + /** The current id of the buffers the next copy will occur from. */ + int copy_id_; + + /** The copy mutex. */ + pthread_mutex_t copy_mtx_; + + /** The thread tha handles all the copying in the background. */ + pthread_t copy_thread_; + + /** True if the read is done. */ + bool done_; + + /** The overflow mutex condition. */ + pthread_cond_t overflow_cond_; + + /** The overflow mutex. */ + pthread_mutex_t overflow_mtx_; + + /** Overflow flag for each attribute. */ + std::vector overflow_; + + /** True if a copy must be resumed. */ + bool resume_copy_; + + /** True if an AIO must be resumed. */ + bool resume_aio_; + + /** The query subarray. */ + const void* subarray_; + + /** The tile slab to be read for the first and second buffers. */ + void* tile_slab_[2]; + + /** The info for each of the two tile slabs under investigation. */ + TileSlabInfo tile_slab_info_[2]; + + /** User buffer sizes. */ + size_t* user_buffer_sizes_; + + /** User buffers. */ + void** user_buffers_; + + /** Wait for copy flags, one for each local buffer. */ + bool wait_copy_[2]; + + /** Wait for AIO flags, one for each local buffer. */ + bool wait_aio_[2]; + + /* ********************************* */ + /* PRIVATE METHODS */ + /* ********************************* */ + + /** + * Called when an AIO completes. + * + * @param data A ASRS_Request object. + * @return void + */ + static void *aio_done(void* data); + + /** Sets the flag of wait_aio_[id] to true. */ + void block_aio(int id); + + /** Sets the flag of wait_copy_[id] to true. */ + void block_copy(int id); + + /** Sets the flag of resume_copy_ to true. */ + void block_overflow(); + + /** + * Calculates the number of buffers to be allocated, based on the number + * of attributes initialized for the array. + * + * @return void + */ + void calculate_buffer_num(); + + /** + * Calculates the buffer sizes based on the subarray and the number of cells + * in a (full) tile slab. + * + * @return void + */ + void calculate_buffer_sizes(); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of column-major order. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_col(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of row-major order. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_row(int id); + + /** + * Function called by the copy thread. + * + * @param context This is practically the ArraySortedReadState object for + * which the function is called (typically *this* is passed to this + * argument by the caller). + */ + static void *copy_handler(void* context); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order. + * + * @return void. + */ + void copy_tile_slab(); + + /** + * Creates the buffers based on the calculated buffer sizes. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int create_buffers(); + + /** Frees the tile slab info. */ + void free_tile_slab_info(); + + /** Frees the tile slab state. */ + void free_tile_slab_state(); + + /** Handles the copy requests. */ + void handle_copy_requests(); + + /** Initializes the tile slab info. */ + void init_tile_slab_info(); + + /** Initializes the tile slab state. */ + void init_tile_slab_state(); + + /** + * Locks the AIO mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int lock_aio_mtx(); + + /** + * Locks the copy mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int lock_copy_mtx(); + + /** + * Locks the overflow mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int lock_overflow_mtx(); + + /** + * Retrieves the next column tile slab to be processed. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ + template + bool next_tile_slab_col(); + + /** + * Retrieves the next row tile slab to be processed. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ + template + bool next_tile_slab_row(); + + /** + * Same as Array::read(), but it sorts the cells in the buffers based on the + * order the user specified in Array::init(). Note that this function will + * fail if there is not enough system memory to hold the cells of a + * 'tile slab' overlapping with the selected subarray. + * + * @template T The domain type. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + template + int read(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * column-major order with respect to the selected subarray. + * Applicable only to dense arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ + template + int read_dense_sorted_col(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * row-major order with respect to the selected subarray. + * Applicable only to dense arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ + template + int read_dense_sorted_row(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * column-major order with respect to the selected subarray. + * Applicable only to sparse arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ + template + int read_sparse_sorted_col(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * row-major order with respect to the selected subarray. + * Applicable only to sparse arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ + template + int read_sparse_sorted_row(); + + /** + * Reads the current tile slab into the input buffers. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int read_tile_slab(); + + /** + * Signals an AIO condition. + * + * @param id The id of the AIO condition to be signaled. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int release_aio(int id); + + /** + * Signals a copy condition. + * + * @param id The id of the copy condition to be signaled. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int release_copy(int id); + + /** + * Signals the overflow condition. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int release_overflow(); + + /** Resets the oveflow flags to **false**. */ + void reset_overflow(); + + /** Resets the state of the tile slab with the input id. */ + void reset_tile_slab_state(int id); + + /** + * Unlocks the AIO mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int unlock_aio_mtx(); + + /** + * Unlocks the copy mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int unlock_copy_mtx(); + + /** + * Unlocks the overflow mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int unlock_overflow_mtx(); + + /** + * Waits on a copy operation for the buffer with input id to finish. + * + * @param id The id of the buffer the copy operation must be completed. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int wait_copy(int id); + + /** + * Waits on a AIO operation for the buffer with input id to finish. + * + * @param id The id of the buffer the AIO operation must be completed. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int wait_aio(int id); + + /** + * Waits until there is no buffer overflow. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int wait_overflow(); +}; + +#endif diff --git a/core/include/c_api/constants.h b/core/include/c_api/constants.h index ac4b258f..3d80056f 100644 --- a/core/include/c_api/constants.h +++ b/core/include/c_api/constants.h @@ -165,4 +165,7 @@ #define TILEDB_SORTED_BUFFER_VAR_SIZE 10000000 // ~10MB /**@}*/ +/** The alignment to assist vectorization. */ +#define ALIGNMENT 64 + #endif diff --git a/core/include/fragment/read_state.h b/core/include/fragment/read_state.h index 971fa375..0dd1dd57 100644 --- a/core/include/fragment/read_state.h +++ b/core/include/fragment/read_state.h @@ -463,7 +463,7 @@ class ReadState { std::vector tiles_sizes_; /** Local variable tile buffers (one per attribute). */ std::vector tiles_var_; - /** Allocated sizes for the local varible tile buffers. */ + /** Allocated sizes for the local variable tile buffers. */ std::vector tiles_var_allocated_size_; /** Current offsets in tiles_var_ (one per attribute). */ std::vector tiles_var_offsets_; diff --git a/core/src/array/array.cc b/core/src/array/array.cc index fc6aea7e..817c7715 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -110,7 +110,6 @@ void Array::aio_handle_requests() { return; } - // Wait for AIO requests while(aio_queue_.size() == 0) { // If the thread is canceled, unblock and exit @@ -258,8 +257,22 @@ int Array::read(void** buffers, size_t* buffer_sizes) { return TILEDB_AR_ERR; } - // TODO: distinguish between the read modes + // Handle sorted modes + if(mode_ == TILEDB_ARRAY_READ_SORTED_COL || + mode_ == TILEDB_ARRAY_READ_SORTED_ROW) { + int rc = array_sorted_read_state_->read(buffers, buffer_sizes); + if(rc == TILEDB_ASRS_OK) { + return TILEDB_AR_OK; + } else { + // TODO: propagate error message + return TILEDB_AR_ERR; + } + } else { // mode_ == TILDB_ARRAY_READ + return read_default(buffers, buffer_sizes); + } +} +int Array::read_default(void** buffers, size_t* buffer_sizes) { int buffer_i = 0; int attribute_id_num = attribute_ids_.size(); @@ -273,6 +286,11 @@ int Array::read(void** buffers, size_t* buffer_sizes) { else buffer_i += 2; } + success = true; + } else { + if(array_read_state_->read(buffers, buffer_sizes) == TILEDB_ARS_OK) + success = true; + } // Success return TILEDB_AR_OK; @@ -547,7 +565,7 @@ int Array::init( // Set attribute ids if(array_schema->get_attribute_ids(attributes_vec, attribute_ids_) - == TILEDB_AS_ERR) { + != TILEDB_AS_OK) tiledb_ar_errmsg = tiledb_as_errmsg; return TILEDB_AR_ERR; } @@ -575,11 +593,27 @@ int Array::init( return TILEDB_AR_ERR; } } else { // READ MODE + // Open fragments if(open_fragments(fragment_names, book_keeping) != TILEDB_AR_OK) { array_schema_ = NULL; return TILEDB_AR_ERR; } + + // Create ArrayReadState array_read_state_ = new ArrayReadState(this); + + // Create ArraySortedReadState + if(mode_ != TILEDB_ARRAY_READ) { + array_sorted_read_state_ = new ArraySortedReadState(this); + if(array_sorted_read_state_->init() != TILEDB_ASRS_OK) { + // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asrs_errmsg + delete array_sorted_read_state_; + array_sorted_read_state_ = NULL; + return TILEDB_AR_ERR; + } + } else { + array_sorted_read_state_ = NULL; + } } // Initialize the AIO-related members @@ -637,9 +671,13 @@ int Array::reset_attributes( // Set attribute ids if(array_schema_->get_attribute_ids(attributes_vec, attribute_ids_) - == TILEDB_AS_ERR) { + != TILEDB_AS_OK) tiledb_ar_errmsg = tiledb_as_errmsg; return TILEDB_AR_ERR; + + // Reset subarray so that the read/write states are flushed + if(reset_subarray(subarray_) != TILEDB_AR_OK) + return TILEDB_AR_ERR; } // Success @@ -701,6 +739,21 @@ int Array::reset_subarray(const void* subarray) { array_read_state_ = NULL; } array_read_state_ = new ArrayReadState(this); + + // Re-initialize ArraySortedReadState + if(array_sorted_read_state_ != NULL) + delete array_sorted_read_state_; + if(mode_ != TILEDB_ARRAY_READ) { + array_sorted_read_state_ = new ArraySortedReadState(this); + if(array_sorted_read_state_->init() != TILEDB_ASRS_OK) { + // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asrs_errmsg + delete array_sorted_read_state_; + array_sorted_read_state_ = NULL; + return TILEDB_AR_ERR; + } + } else { + array_sorted_read_state_ = NULL; + } } // Success @@ -824,17 +877,17 @@ int Array::aio_push_request(AIO_Request* aio_request) { // Push request aio_queue_.push(aio_request); - // Unlock AIO mutext - if(pthread_mutex_unlock(&aio_mtx_)) { - std::string errmsg = "Cannot unlock AIO mutex"; + // Signal AIO thread + if(pthread_cond_signal(&aio_cond_)) { + std::string errmsg = "Cannot signal AIO thread"; PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; return TILEDB_AR_ERR; } - // Signal AIO thread - if(pthread_cond_signal(&aio_cond_)) { - std::string errmsg = "Cannot signal AIO thread"; + // Unlock AIO mutext + if(pthread_mutex_unlock(&aio_mtx_)) { + std::string errmsg = "Cannot unlock AIO mutex"; PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; return TILEDB_AR_ERR; diff --git a/core/src/array/array_schema.cc b/core/src/array/array_schema.cc index bb81b2f1..37c8043c 100644 --- a/core/src/array/array_schema.cc +++ b/core/src/array/array_schema.cc @@ -109,7 +109,6 @@ const std::string& ArraySchema::array_name() const { return array_name_; } - void ArraySchema::array_schema_export(ArraySchemaC* array_schema_c) const { // Set array name size_t array_name_len = array_name_.size(); @@ -332,6 +331,32 @@ int ArraySchema::get_attribute_ids( return TILEDB_AS_OK; } +bool ArraySchema::is_contained_in_tile_slab_col(const void* range) const { + if(types_[attribute_num_] == TILEDB_INT32) + return is_contained_in_tile_slab_col(static_cast(range)); + else if(types_[attribute_num_] == TILEDB_INT64) + return is_contained_in_tile_slab_col(static_cast(range)); + else if(types_[attribute_num_] == TILEDB_FLOAT32) + return is_contained_in_tile_slab_col(static_cast(range)); + else if(types_[attribute_num_] == TILEDB_FLOAT64) + return is_contained_in_tile_slab_col(static_cast(range)); + else + return false; +} + +bool ArraySchema::is_contained_in_tile_slab_row(const void* range) const { + if(types_[attribute_num_] == TILEDB_INT32) + return is_contained_in_tile_slab_row(static_cast(range)); + else if(types_[attribute_num_] == TILEDB_INT64) + return is_contained_in_tile_slab_row(static_cast(range)); + else if(types_[attribute_num_] == TILEDB_FLOAT32) + return is_contained_in_tile_slab_row(static_cast(range)); + else if(types_[attribute_num_] == TILEDB_FLOAT64) + return is_contained_in_tile_slab_row(static_cast(range)); + else + return false; +} + void ArraySchema::print() const { // Array name std::cout << "Array name:\n\t" << array_name_ << "\n"; @@ -677,7 +702,6 @@ int ArraySchema::subarray_overlap( return overlap; } - const void* ArraySchema::tile_domain() const { return tile_domain_; } @@ -744,6 +768,39 @@ int64_t ArraySchema::tile_num(const T* domain) const { return ret; } +int ArraySchema::tile_order() const { + return tile_order_; +} + +int64_t ArraySchema::tile_slab_col_cell_num(const void* subarray) const { + // Invoke the proper templated function + if(types_[attribute_num_] == TILEDB_INT32) + return tile_slab_col_cell_num(static_cast(subarray)); + else if(types_[attribute_num_] == TILEDB_INT64) + return tile_slab_col_cell_num(static_cast(subarray)); + else if(types_[attribute_num_] == TILEDB_FLOAT32) + return tile_slab_col_cell_num(static_cast(subarray)); + else if(types_[attribute_num_] == TILEDB_FLOAT64) + return tile_slab_col_cell_num(static_cast(subarray)); + else + return TILEDB_AS_ERR; +} + +int64_t ArraySchema::tile_slab_row_cell_num(const void* subarray) const { + // Invoke the proper templated function + if(types_[attribute_num_] == TILEDB_INT32) + return tile_slab_row_cell_num(static_cast(subarray)); + else if(types_[attribute_num_] == TILEDB_INT64) + return tile_slab_row_cell_num(static_cast(subarray)); + else if(types_[attribute_num_] == TILEDB_FLOAT32) + return tile_slab_row_cell_num(static_cast(subarray)); + else if(types_[attribute_num_] == TILEDB_FLOAT64) + return tile_slab_row_cell_num(static_cast(subarray)); + else + return TILEDB_AS_ERR; + +} + int ArraySchema::type(int i) const { if(i<0 || i>attribute_num_) { std::string errmsg = "Cannot retrieve type; Invalid attribute id"; @@ -2473,6 +2530,81 @@ void ArraySchema::init_hilbert_curve() { hilbert_curve_ = new HilbertCurve(hilbert_bits_, dim_num_); } +template +bool ArraySchema::is_contained_in_tile_slab_col(const T* range) const { + // For easy reference + const T* domain = static_cast(domain_); + const T* tile_extents = static_cast(tile_extents_); + int64_t tile_l, tile_h; + + // Check if range is not contained in a column tile slab + for(int i=1; i +bool ArraySchema::is_contained_in_tile_slab_row(const T* range) const { + // For easy reference + const T* domain = static_cast(domain_); + const T* tile_extents = static_cast(tile_extents_); + int64_t tile_l, tile_h; + + // Check if range is not contained in a row tile slab + for(int i=0; i +int64_t ArraySchema::tile_slab_col_cell_num(const T* subarray) const { + // For easy reference + const T* tile_extents = static_cast(tile_extents_); + + // Initialize the cell num to be returned to the maximum number of rows + // in the slab + int64_t cell_num = + std::min( + tile_extents[dim_num_-1], + subarray[2*(dim_num_-1)+1] - subarray[2*(dim_num_-1)] + 1); + + // Calculate the number of cells in the slab + for(int i=0; i +int64_t ArraySchema::tile_slab_row_cell_num(const T* subarray) const { + // For easy reference + const T* tile_extents = static_cast(tile_extents_); + + // Initialize the cell num to be returned to the maximum number of rows + // in the slab + int64_t cell_num = std::min(tile_extents[0], subarray[1] - subarray[0] + 1); + + // Calculate the number of cells in the slab + for(int i=1; i + + + + +/* ****************************** */ +/* MACROS */ +/* ****************************** */ + +#ifdef VERBOSE +# define PRINT_ERROR(x) std::cerr << TILEDB_ASRS_ERRMSG << x << ".\n" +#else +# define PRINT_ERROR(x) do { } while(0) +#endif + + + + +/* ****************************** */ +/* GLOBAL VARIABLES */ +/* ****************************** */ + +std::string tiledb_asrs_errmsg = ""; + + + + +/* ****************************** */ +/* CONSTRUCTORS & DESTRUCTORS */ +/* ****************************** */ + +ArraySortedReadState::ArraySortedReadState( + Array* array) + : array_(array), + attribute_ids_(array->attribute_ids()), + subarray_(array->subarray()) { + // Initializations + copy_id_ = 0; + aio_id_ = 0; + done_ = false; + resume_copy_ = false; + resume_aio_ = false; + for(int i=0; i<2; ++i) { + buffer_sizes_[i] = NULL; + buffers_[i] = NULL; + tile_slab_[i] = NULL; + wait_copy_[i] = false; + wait_aio_[i] = true; + } + overflow_.resize(attribute_ids_.size()); + for(int i=0; (int) attribute_ids_.size(); ++i) + overflow_[i] = false; + + // Calculate number of buffers + calculate_buffer_num(); + + // Calculate buffer sizes + calculate_buffer_sizes(); + + // Initialize tile slab info and state + init_tile_slab_info(); + init_tile_slab_state(); +} + +ArraySortedReadState::~ArraySortedReadState() { + // Clean up + for(int i=0; i<2; ++i) { + if(buffer_sizes_[i] != NULL) + delete [] buffer_sizes_[i]; + if(buffers_[i] != NULL) { + for(int b=0; barray_schema()->coords_type(); + if(type == TILEDB_INT32) + return read(); + else if(type == TILEDB_INT64) + return read(); + else if(type == TILEDB_FLOAT32) + return read(); + else if(type == TILEDB_FLOAT64) + return read(); + else + assert(0); +} + + + + +/* ****************************** */ +/* MUTATORS */ +/* ****************************** */ + +int ArraySortedReadState::init() { + // Create buffers + if(create_buffers() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Create the thread that will be handling all the copying + if(pthread_create( + ©_thread_, + NULL, + ArraySortedReadState::copy_handler, + this)) { + std::string errmsg = "Cannot create AIO thread"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Initialize the mutexes and conditions + if(pthread_mutex_init(&aio_mtx_, NULL)) { + std::string errmsg = "Cannot initialize IO mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + if(pthread_mutex_init(©_mtx_, NULL)) { + std::string errmsg = "Cannot initialize copy mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + if(pthread_mutex_init(&overflow_mtx_, NULL)) { + std::string errmsg = "Cannot initialize overflow mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + for(int i=0; i<2; ++i) { + aio_cond_[i] = PTHREAD_COND_INITIALIZER; + if(pthread_cond_init(&(aio_cond_[i]), NULL)) { + std::string errmsg = "Cannot initialize IO mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + copy_cond_[i] = PTHREAD_COND_INITIALIZER; + if(pthread_cond_init(&(copy_cond_[i]), NULL)) { + std::string errmsg = "Cannot initialize copy mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + overflow_cond_ = PTHREAD_COND_INITIALIZER; + if(pthread_cond_init(&overflow_cond_, NULL)) { + std::string errmsg = "Cannot initialize overflow mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + + +/* ****************************** */ +/* PRIVATE METHODS */ +/* ****************************** */ + +void *ArraySortedReadState::aio_done(void* data) { + ArraySortedReadState* asrs = ((ASRS_Request*) data)->asrs_; + int id = ((ASRS_Request*) data)->id_; + asrs->block_copy(id); + asrs->release_aio(id); + + return NULL; +} + +void ArraySortedReadState::block_aio(int id) { + lock_copy_mtx(); + wait_copy_[id] = true; + unlock_copy_mtx(); +} + +void ArraySortedReadState::block_copy(int id) { + lock_aio_mtx(); + wait_aio_[id] = true; + unlock_aio_mtx(); +} + +void ArraySortedReadState::block_overflow() { + lock_overflow_mtx(); + resume_copy_ = true; + unlock_overflow_mtx(); +} + +void ArraySortedReadState::calculate_buffer_num() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Calculate number of buffers + buffer_num_ = 0; + int attribute_id_num = (int) attribute_ids_.size(); + for(int i=0; ivar_size(attribute_ids_[i])) + ++buffer_num_; + else // Variable-sized attribute + buffer_num_ += 2; + } +} + +void ArraySortedReadState::calculate_buffer_sizes() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Get cell number in a (full) tile slab + int64_t tile_slab_cell_num; + if(array_->mode() == TILEDB_ARRAY_READ_SORTED_ROW) + tile_slab_cell_num = array_schema->tile_slab_row_cell_num(subarray_); + else // TILEDB_ARRAY_READ_SORTED_COL + tile_slab_cell_num = array_schema->tile_slab_col_cell_num(subarray_); + + // Calculate buffer sizes + int attribute_id_num = (int) attribute_ids_.size(); + for(int j=0; j<2; ++j) { + buffer_sizes_[j] = new size_t[buffer_num_]; + for(int i=0, b=0; ivar_size(attribute_ids_[i])) { + buffer_sizes_[j][b] = + tile_slab_cell_num * array_schema->cell_size(attribute_ids_[i]); + ++b; + } else { // Variable-sized attribute + buffer_sizes_[j][b] = tile_slab_cell_num * sizeof(size_t); + ++b; + buffer_sizes_[j][b] = 2 * tile_slab_cell_num * sizeof(size_t); + ++b; + } + } + } +} + +template +void ArraySortedReadState::calculate_tile_slab_info_col(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_row(int id) { + // TODO +} + +void *ArraySortedReadState::copy_handler(void* context) { + // This will enter an indefinite loop that will handle all incoming copy + // requests + ((ArraySortedReadState*) context)->handle_copy_requests(); + + // Return + return NULL; +} + +void ArraySortedReadState::copy_tile_slab() { + // TODO +} + +int ArraySortedReadState::create_buffers() { + for(int j=0; j<2; ++j) { + buffers_[j] = (void**) malloc(buffer_num_ * sizeof(void*)); + if(buffers_[j] == NULL) { + std::string errmsg = "Cannot create local buffers"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + for(int b=0; b < buffer_num_; ++b) { + buffers_[j][b] = aligned_alloc(ALIGNMENT, buffer_sizes_[j][b]); + if(buffers_[j][b] == NULL) { + std::string errmsg = "Cannot allocate local buffer"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + } + + // Success + return TILEDB_ASRS_OK; +} + +void ArraySortedReadState::free_tile_slab_info() { + // TODO +} + +void ArraySortedReadState::free_tile_slab_state() { + // TODO +} + +void ArraySortedReadState::handle_copy_requests() { + // Handle copy requests indefinitely + for(;;) { + // Wait for AIO + wait_aio(copy_id_); + + // Start the copy + copy_tile_slab(); + + // Wait in case of overflow + if(overflow()) { + block_overflow(); + block_aio(copy_id_); + release_copy(copy_id_); + wait_overflow(); + continue; + } + + // Copy is done + block_aio(copy_id_); + release_copy(copy_id_); + copy_id_ = (copy_id_ + 1) % 2; + } +} + +void ArraySortedReadState::init_tile_slab_info() { + // TODO +} + +void ArraySortedReadState::init_tile_slab_state() { + // TODO +} + +int ArraySortedReadState::lock_aio_mtx() { + if(pthread_mutex_lock(&aio_mtx_)) { + std::string errmsg = "Cannot lock AIO mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::lock_copy_mtx() { + if(pthread_mutex_lock(©_mtx_)) { + std::string errmsg = "Cannot lock copy mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::lock_overflow_mtx() { + if(pthread_mutex_lock(&overflow_mtx_)) { + std::string errmsg = "Cannot lock overflow mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +template +bool ArraySortedReadState::next_tile_slab_col() { + // Quick check if done + if(done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // Allocate space for the tile slab if necessary + if(tile_slab_[aio_id_] == NULL) + tile_slab_[aio_id_] = malloc(2*array_->array_schema()->coords_size()); + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + int dim_num = array_schema->dim_num(); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_-1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab[prev_id] != NULL && + tile_slab[prev_id][2*(dim_num-1) + 1] == subarray[2*(dim_num-1) + 1]) { + done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(tile_slab[prev_id] == NULL) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num-1)] = subarray[2*(dim_num-1)]; + T upper = subarray[2*(dim_num-1)] + tile_extents[dim_num-1]; + T cropped_upper = + (upper - domain[2*(dim_num-1)]) / tile_extents[dim_num-1] * + tile_extents[dim_num-1] + domain[2*(dim_num-1)]; + tile_slab[aio_id_][2*(dim_num-1)+1] = + std::min(cropped_upper - 1, subarray[2*(dim_num-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; iarray_schema()->coords_size()); + + // Advance tile slab + tile_slab[aio_id_][2*(dim_num-1)] = tile_slab[aio_id_][2*(dim_num-1)+1] + 1; + tile_slab[aio_id_][2*(dim_num-1)+1] = + std::min( + tile_slab[aio_id_][2*(dim_num-1)+1] + tile_extents[dim_num-1] - 1, + subarray[2*(dim_num-1)+1]); + } + + // Calculate tile slab info and reset tile slab state + calculate_tile_slab_info_col(aio_id_); + reset_tile_slab_state(aio_id_); + + // Success + return true; +} + +template +bool ArraySortedReadState::next_tile_slab_row() { + // Quick check if done + if(done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // Allocate space for the tile slab if necessary + if(tile_slab_[aio_id_] == NULL) + tile_slab_[aio_id_] = malloc(2*array_->array_schema()->coords_size()); + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + int dim_num = array_schema->dim_num(); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_-1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab[prev_id] != NULL && + tile_slab[prev_id][1] == subarray[1]) { + done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(tile_slab[prev_id] == NULL) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + T upper = subarray[0] + tile_extents[0]; + T cropped_upper = + (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; iarray_schema()->coords_size()); + + // Advance tile slab + tile_slab[aio_id_][0] = tile_slab[aio_id_][1] + 1; + tile_slab[aio_id_][1] = std::min( + tile_slab[aio_id_][1] + tile_extents[0] - 1, + subarray[1]); + } + + // Calculate tile slab info and reset tile slab state + calculate_tile_slab_info_row(aio_id_); + reset_tile_slab_state(aio_id_); + + // Success + return true; +} + +template +int ArraySortedReadState::read() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int mode = array_->mode(); + + if(mode == TILEDB_ARRAY_READ_SORTED_COL) { + if(array_schema->dense()) + return read_dense_sorted_col(); + else + return read_sparse_sorted_col(); + } else if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(array_schema->dense()) + return read_dense_sorted_row(); + else + return read_sparse_sorted_row(); + } else { + assert(0); // The code should never reach here + } +} + +template +int ArraySortedReadState::read_dense_sorted_col() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_COL_MAJOR && + array_schema->is_contained_in_tile_slab_row(subarray)) + return array_->read_default(user_buffers_, user_buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_col()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy to finish + for(int i=0; i<2; ++i) + wait_copy(i); + + // Success + return TILEDB_ASRS_OK; +} + +template +int ArraySortedReadState::read_dense_sorted_row() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_ROW_MAJOR && + array_schema->is_contained_in_tile_slab_col(subarray)) + return array_->read_default(user_buffers_, user_buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_row()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy to finish + for(int i=0; i<2; ++i) + wait_copy(i); + + // Success + return TILEDB_ASRS_OK; +} + +template +int ArraySortedReadState::read_sparse_sorted_col() { + // TODO + + // Success + return TILEDB_ASRS_OK; +} + +template +int ArraySortedReadState::read_sparse_sorted_row() { + // TODO + + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::read_tile_slab() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // We need to exit if the copy did no complete (due to overflow) + if(resume_copy_) { + resume_aio_ = true; + return TILEDB_ASRS_OK; + } + + // TODO: This has to go in a loop to capture the case a variable-length + // TODO: attribute overflows + + // Prepare AIO request + ASRS_Request asrs_request = { aio_id_, this }; + AIO_Request aio_request = {}; + aio_request.buffers_ = buffers_[aio_id_]; + aio_request.buffer_sizes_ = buffer_sizes_[aio_id_]; + aio_request.subarray_ = tile_slab_[aio_id_]; + aio_request.completion_handle_ = aio_done; + aio_request.completion_data_ = &asrs_request; + + // Send the AIO request + if(array_->aio_read(&aio_request) != TILEDB_AR_OK) { + // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; + return TILEDB_ASRS_ERR; + } + + // Change aio_id_ + aio_id_ = (aio_id_ + 1) % 2; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::release_aio(int id) { + // Lock the AIO mutex + if(lock_aio_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Set AIO flag + wait_aio_[id] = false; + + // Signal condition + if(pthread_cond_signal(&(aio_cond_[id]))) { + std::string errmsg = "Cannot signal AIO condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Unlock the AIO mutex + if(unlock_aio_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::release_copy(int id) { + // Lock the copy mutex + if(lock_copy_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Set copy flag + wait_copy_[id] = false; + + // Signal condition + if(pthread_cond_signal(©_cond_[id])) { + std::string errmsg = "Cannot signal copy condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Unlock the copy mutex + if(unlock_copy_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::release_overflow() { + // Lock the overflow mutex + if(lock_overflow_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Set copy flag + resume_copy_ = false; + + // Signal condition + if(pthread_cond_signal(&overflow_cond_)) { + std::string errmsg = "Cannot signal overflow condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Unlock the overflow mutex + if(unlock_overflow_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +void ArraySortedReadState::reset_overflow() { + for(int i=0; (int) attribute_ids_.size(); ++i) + overflow_[i] = false; +} + +int ArraySortedReadState::unlock_aio_mtx() { + if(pthread_mutex_unlock(&aio_mtx_)) { + std::string errmsg = "Cannot unlock AIO mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +void ArraySortedReadState::reset_tile_slab_state(int id) { + // TODO +} + +int ArraySortedReadState::unlock_copy_mtx() { + if(pthread_mutex_unlock(©_mtx_)) { + std::string errmsg = "Cannot unlock copy mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::unlock_overflow_mtx() { + if(pthread_mutex_unlock(&overflow_mtx_)) { + std::string errmsg = "Cannot unlock overflow mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::wait_aio(int id) { + // Lock AIO mutex + if(lock_aio_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Wait to be signaled + while(wait_aio_[id]) { + if(pthread_cond_wait(&(aio_cond_[id]), &aio_mtx_)) { + std::string errmsg = "Cannot wait on IO mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + + // Unlock AIO mutex + if(unlock_aio_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::wait_copy(int id) { + // Lock copy mutex + if(lock_copy_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Wait to be signaled + while(wait_copy_[id]) { + if(pthread_cond_wait(&(copy_cond_[id]), ©_mtx_)) { + std::string errmsg = "Cannot wait on copy mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + + // Unlock copy mutex + if(unlock_copy_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::wait_overflow() { + // Wait to be signaled + while(overflow()) { + if(pthread_cond_wait(&overflow_cond_, &overflow_mtx_)) { + std::string errmsg = "Cannot wait on IO mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + + // Success + return TILEDB_ASRS_OK; +} diff --git a/examples/src/tiledb_array_read_sorted_dense.cc b/examples/src/tiledb_array_read_sorted_dense.cc new file mode 100644 index 00000000..2a4d95b6 --- /dev/null +++ b/examples/src/tiledb_array_read_sorted_dense.cc @@ -0,0 +1,85 @@ +/** + * @file tiledb_array_read_sorted_dense.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * It shows how to read from a dense array, constraining the read + * to a specific subarray and subset of attributes. The cells are copied to the + * input buffers sorted in row-major order within the selected subarray. + */ + +#include "c_api.h" +#include + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Subarray and attributes + int64_t subarray[] = { 1, 4, 1, 2 }; + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + "my_workspace/dense_arrays/my_array_A", // Array name + TILEDB_ARRAY_READ_SORTED_ROW, // Mode + subarray, // Constrain in subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Prepare cell buffers + int buffer_a1[3]; + void* buffers[] = { buffer_a1 }; + size_t buffer_sizes[] = { sizeof(buffer_a1) }; + + + // Loop until no overflow + printf(" a1\n----\n"); + do { + printf("Reading cells...\n"); + + // Read from array + tiledb_array_read(tiledb_array, buffers, buffer_sizes); + + // Print cell values + int64_t result_num = buffer_sizes[0] / sizeof(int); + for(int i=0; i Date: Mon, 26 Sep 2016 19:12:16 -0400 Subject: [PATCH 03/57] More progress on sorted reads --- core/include/array/array_schema.h | 6 +- core/include/array/array_sorted_read_state.h | 138 ++++- core/src/array/array_schema.cc | 17 +- core/src/array/array_sorted_read_state.cc | 572 ++++++++++++++++++- 4 files changed, 681 insertions(+), 52 deletions(-) diff --git a/core/include/array/array_schema.h b/core/include/array/array_schema.h index 28fc9d21..ad4a67e2 100644 --- a/core/include/array/array_schema.h +++ b/core/include/array/array_schema.h @@ -263,10 +263,10 @@ class ArraySchema { int64_t tile_num() const; /** - * Returns the number of tiles in the input domain (applicable only to dense - * arrays). + * Returns the number of tiles overlapping with the input range + * (applicable only to dense arrays). */ - int64_t tile_num(const void* domain) const; + int64_t tile_num(const void* range) const; /** * Returns the number of tiles in the input domain (applicable only to dense diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 48b9b2fe..7e7f1dbb 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -75,6 +75,24 @@ class ArraySortedReadState { /* TYPE DEFINITIONS */ /* ********************************* */ + /** Used in advance_cell_slab(). */ + struct AdvanceCellSlabInfo { + /** The id of the targeted attribute id in attribute_ids_. */ + int aid_; + /** The calling object. */ + ArraySortedReadState* asrs_; + }; + + /** Stores state about the current read/copy request. */ + struct CopyState { + /** Current offsets in user buffers. */ + size_t* buffer_offsets_; + /** User buffer sizes. */ + size_t* buffer_sizes_; + /** User buffers. */ + void** buffers_; + }; + /** Simple struct used for an AIO or copy request. */ struct ASRS_Request { /** The id of the targeted tile slab. */ @@ -99,20 +117,24 @@ class ArraySortedReadState { * per dimension. */ size_t*** offsets_per_dim_; + /** Offset of first result cell slab per attribute per tile. */ + size_t** start_offsets_; /** Number of tiles in the tile slab. */ int64_t tile_num_; - /** Offset of each starting result cell per attribute per tile. */ - size_t** tile_offsets_; }; /** The state for a tile slab copy. */ struct TileSlabState { /** The current tile per attribute. */ int64_t* current_tile_; + /** The current coordinates in the slab range per attribute per tile. */ + int64_t*** current_cell_slab_coords_; /** The cell slab in the current pass per attribute per tile. */ int64_t** current_cell_slab_in_pass_; /** The offset of the next cell slab to be copied per attribute per tile. */ - size_t** current_offset_; + size_t** current_offsets_; + /** Keeps track of whether a tile slab copy for an attribute id done. */ + bool* copy_tile_slab_done_; }; @@ -137,6 +159,12 @@ class ArraySortedReadState { /* ACCESSORS */ /* ********************************* */ + /** Returns true if the current slab is finished being copied. */ + bool copy_tile_slab_done() const; + + /** True if read is done for all attributes. */ + bool done() const; + /** Returns true if copying into the user buffers resulted in overflow. */ bool overflow() const; @@ -187,6 +215,9 @@ class ArraySortedReadState { /* PRIVATE ATTRIBUTES */ /* ********************************* */ + /** Function for advancing a cell slab during a copy operation. */ + void *(*advance_cell_slab_) (void*); + /** The AIO mutex conditions (one for each buffer). */ pthread_cond_t aio_cond_[2]; @@ -217,14 +248,17 @@ class ArraySortedReadState { /** The current id of the buffers the next copy will occur from. */ int copy_id_; + /** The copy state. */ + CopyState copy_state_; + /** The copy mutex. */ pthread_mutex_t copy_mtx_; /** The thread tha handles all the copying in the background. */ pthread_t copy_thread_; - /** True if the read is done. */ - bool done_; + /** True if the copy thread is running. */ + bool copy_thread_running_; /** The overflow mutex condition. */ pthread_cond_t overflow_cond_; @@ -235,6 +269,9 @@ class ArraySortedReadState { /** Overflow flag for each attribute. */ std::vector overflow_; + /** True if no more tile slabs to read. */ + bool read_tile_slabs_done_; + /** True if a copy must be resumed. */ bool resume_copy_; @@ -250,11 +287,8 @@ class ArraySortedReadState { /** The info for each of the two tile slabs under investigation. */ TileSlabInfo tile_slab_info_[2]; - /** User buffer sizes. */ - size_t* user_buffer_sizes_; - - /** User buffers. */ - void** user_buffers_; + /** The state for the current tile slab being copied. */ + TileSlabState tile_slab_state_; /** Wait for copy flags, one for each local buffer. */ bool wait_copy_[2]; @@ -266,6 +300,42 @@ class ArraySortedReadState { /* PRIVATE METHODS */ /* ********************************* */ + /** + * Advances a cell slab focusing on column-major order, and updates + * the CopyState and TileSlabState. + * Used in copy_tile_slab(). + * + * @param data Essentially a pointer to a AdvanceCellSlabInfo object. + * @return void + */ + static void *advance_cell_slab_col(void* data); + + /** + * Advances a cell slab focusing on row-major order, and updates + * the CopyState and TileSlabState. + * Used in copy_tile_slab(). + * + * @param data Essentially a pointer to a AdvanceCellSlabInfo object. + * @return void + */ + static void *advance_cell_slab_row(void* data); + + /** + * Advances a cell slab when the requested order is column-major. + * + * @param aid The id of the attribute in attribute_ids_ to focus on. + * @return void + */ + void advance_cell_slab_col(int aid); + + /** + * Advances a cell slab when the requested order is row-major. + * + * @param aid The id of the attribute in attribute_ids_ to focus on. + * @return void + */ + void advance_cell_slab_row(int aid); + /** * Called when an AIO completes. * @@ -321,6 +391,13 @@ class ArraySortedReadState { template void calculate_tile_slab_info_row(int id); + /** + * Kills the copy thread (if it is still running). + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int cancel_copy_thread(); + /** * Function called by the copy thread. * @@ -338,6 +415,28 @@ class ArraySortedReadState { */ void copy_tile_slab(); + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular fixed-length attribute. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ + void copy_tile_slab(int aid, int bid); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular variable-length attribute. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ + void copy_tile_slab_var(int aid, int bid); + /** * Creates the buffers based on the calculated buffer sizes. * @@ -345,6 +444,9 @@ class ArraySortedReadState { */ int create_buffers(); + /** Frees the copy state. */ + void free_copy_state(); + /** Frees the tile slab info. */ void free_tile_slab_info(); @@ -354,9 +456,18 @@ class ArraySortedReadState { /** Handles the copy requests. */ void handle_copy_requests(); + /** Initializes the copy state. */ + void init_copy_state(); + /** Initializes the tile slab info. */ void init_tile_slab_info(); + /** + * Initializes the tile slab info for a particular tile slab, using the + * input tile number. + */ + void init_tile_slab_info(int id, int64_t tile_num); + /** Initializes the tile slab state. */ void init_tile_slab_state(); @@ -485,11 +596,14 @@ class ArraySortedReadState { */ int release_overflow(); + /** Resets the copy state using the input buffer info. */ + void reset_copy_state(void** buffers, size_t* buffer_sizes); + /** Resets the oveflow flags to **false**. */ void reset_overflow(); - /** Resets the state of the tile slab with the input id. */ - void reset_tile_slab_state(int id); + /** Resets the tile slab state. */ + void reset_tile_slab_state(); /** * Unlocks the AIO mutex. diff --git a/core/src/array/array_schema.cc b/core/src/array/array_schema.cc index 37c8043c..2ddf231f 100644 --- a/core/src/array/array_schema.cc +++ b/core/src/array/array_schema.cc @@ -739,12 +739,12 @@ int64_t ArraySchema::tile_num() const { return ret; } -int64_t ArraySchema::tile_num(const void* domain) const { +int64_t ArraySchema::tile_num(const void* range) const { // Invoke the proper template function if(types_[attribute_num_] == TILEDB_INT32) - return tile_num(static_cast(domain)); + return tile_num(static_cast(range)); else if(types_[attribute_num_] == TILEDB_INT64) - return tile_num(static_cast(domain)); + return tile_num(static_cast(range)); assert(0); @@ -757,13 +757,18 @@ int64_t ArraySchema::tile_num(const void* domain) const { } template -int64_t ArraySchema::tile_num(const T* domain) const { +int64_t ArraySchema::tile_num(const T* range) const { // For easy reference const T* tile_extents = static_cast(tile_extents_); + const T* domain = static_cast(domain_); int64_t ret = 1; - for(int i=0; iarray_schema()->coords_type(); if(type == TILEDB_INT32) @@ -225,6 +241,7 @@ int ArraySortedReadState::init() { tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; return TILEDB_ASRS_ERR; } + copy_thread_running_ = true; // Initialize the mutexes and conditions if(pthread_mutex_init(&aio_mtx_, NULL)) { @@ -269,6 +286,13 @@ int ArraySortedReadState::init() { return TILEDB_ASRS_ERR; } + // Determine the advance_cell_slab_ method + int mode = array_->mode(); + if(mode == TILEDB_ARRAY_READ_SORTED_ROW) + advance_cell_slab_ = advance_cell_slab_row; + else // mode == TILEDB_ARRAY_READ_SORTED_COL + advance_cell_slab_ = advance_cell_slab_col; + // Success return TILEDB_ASRS_OK; } @@ -278,6 +302,100 @@ int ArraySortedReadState::init() { /* PRIVATE METHODS */ /* ****************************** */ +void *ArraySortedReadState::advance_cell_slab_col(void* data) { + ArraySortedReadState* asrs = ((AdvanceCellSlabInfo*) data)->asrs_; + int aid = ((AdvanceCellSlabInfo*) data)->aid_; + asrs->advance_cell_slab_col(aid); + return NULL; +} + +void *ArraySortedReadState::advance_cell_slab_row(void* data) { + ArraySortedReadState* asrs = ((AdvanceCellSlabInfo*) data)->asrs_; + int aid = ((AdvanceCellSlabInfo*) data)->aid_; + asrs->advance_cell_slab_row(aid); + return NULL; +} + +void ArraySortedReadState::advance_cell_slab_col(int aid) { + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; + int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; + int dim_num = array_->array_schema()->dim_num(); + + // Advance cell slab + ++(tile_slab_state_.current_cell_slab_in_pass_[aid][tid]); + + // Advance cell slab coordinates and offsets + int d = 0; + ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][d]); + tile_slab_state_.current_offsets_[aid][tid] += + tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; + while(d < dim_num-1 && + tile_slab_state_.current_cell_slab_coords_[aid][tid][d] > + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d+1]) { + tile_slab_state_.current_cell_slab_coords_[aid][tid][d] = + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d]; + ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][++d]); + tile_slab_state_.current_offsets_[aid][tid] += + tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; + } + + // Check if tile slab is done + if(tile_slab_state_.current_cell_slab_coords_[aid][tid][dim_num-1] > + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*(dim_num-1)+1]) { + tile_slab_state_.copy_tile_slab_done_[aid] = true; + return; + } + + // Check if pass is done and advance tile id + if(tile_slab_state_.current_cell_slab_in_pass_[aid][tid] == + tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid]) { + tile_slab_state_.current_cell_slab_in_pass_[aid][tid] = 0; + tid = (tid + 1) % tile_num; + return; + } +} + +void ArraySortedReadState::advance_cell_slab_row(int aid) { + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; + int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; + int dim_num = array_->array_schema()->dim_num(); + + // Advance cell slab + ++(tile_slab_state_.current_cell_slab_in_pass_[aid][tid]); + + // Advance cell slab coordinates and offsets + int d = dim_num-1; + ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][d]); + tile_slab_state_.current_offsets_[aid][tid] += + tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; + while(d > 0 && + tile_slab_state_.current_cell_slab_coords_[aid][tid][d] > + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d+1]) { + tile_slab_state_.current_cell_slab_coords_[aid][tid][d] = + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d]; + ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][++d]); + tile_slab_state_.current_offsets_[aid][tid] += + tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; + } + + // Check if tile slab is done + if(tile_slab_state_.current_cell_slab_coords_[aid][tid][0] > + tile_slab_info_[copy_id_].cell_slab_range_[tid][1]) { + tile_slab_state_.copy_tile_slab_done_[aid] = true; + return; + } + + // Check if pass is done and advance tile id + if(tile_slab_state_.current_cell_slab_in_pass_[aid][tid] == + tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid]) { + tile_slab_state_.current_cell_slab_in_pass_[aid][tid] = 0; + tid = (tid + 1) % tile_num; + return; + } +} + void *ArraySortedReadState::aio_done(void* data) { ArraySortedReadState* asrs = ((ASRS_Request*) data)->asrs_; int id = ((ASRS_Request*) data)->id_; @@ -354,14 +472,40 @@ void ArraySortedReadState::calculate_buffer_sizes() { template void ArraySortedReadState::calculate_tile_slab_info_col(int id) { + // Calculate number of tiles, if they are not already calculated + if(tile_slab_info_[id].tile_num_ == -1) + init_tile_slab_info(id, array_->array_schema()->tile_num(subarray_)); + // TODO } template void ArraySortedReadState::calculate_tile_slab_info_row(int id) { + // Calculate number of tiles, if they are not already calculated + if(tile_slab_info_[id].tile_num_ == -1) + init_tile_slab_info(id, array_->array_schema()->tile_num(subarray_)); + // TODO } +int ArraySortedReadState::cancel_copy_thread() { + // If the thread is not running, exit with success + if(!copy_thread_running_) + return TILEDB_ASRS_OK; + + // Kill copy thread + if(pthread_cancel(copy_thread_)) { + std::string errmsg = "Cannot destroy AIO thread"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + copy_thread_running_ = false; + + // Success + return TILEDB_ASRS_OK; +} + void *ArraySortedReadState::copy_handler(void* context) { // This will enter an indefinite loop that will handle all incoming copy // requests @@ -372,7 +516,161 @@ void *ArraySortedReadState::copy_handler(void* context) { } void ArraySortedReadState::copy_tile_slab() { - // TODO + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Copy tile slab for each attribute separately + for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { + if(!array_schema->var_size(attribute_ids_[i])) { + copy_tile_slab(i, b); + ++b; + } else { + copy_tile_slab_var(i, b); + b += 2; + } + } +} + +void ArraySortedReadState::copy_tile_slab(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + return; + } + + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* local_buffer = (char*) buffers_[copy_id_][bid]; + + // For all overlapping tiles, in a round-robin fashion + for(;;) { + // For easy reference + int64_t snum = + tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid]; // Slab num + int64_t& sid = + tile_slab_state_.current_cell_slab_in_pass_[aid][tid]; // Slab + size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; + size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid][tid]; + + // For all cell slabs in a pass + while(sid < snum) { + // Handle overflow + if(buffer_offset + cell_slab_size > buffer_size) { + overflow_[aid] = true; + break; + } + + // Copy cell slab + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_slab_size); + + // Update buffer offset + buffer_offset += cell_slab_size; + + // Prepare for new slab + AdvanceCellSlabInfo acsi = { aid, this }; + (*advance_cell_slab_)(&acsi); + } + + // Terminating condition + if(tile_slab_state_.copy_tile_slab_done_[aid]) + break; + } + + // Set user buffer size + buffer_size = buffer_offset; +} + +void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + copy_state_.buffer_sizes_[bid+1] = 0; // Nothing written + return; + } + + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile + size_t cell_slab_size_var; + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t& buffer_offset_var = copy_state_.buffer_offsets_[bid+1]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + size_t buffer_size_var = copy_state_.buffer_sizes_[bid+1]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* buffer_var = (char*) copy_state_.buffers_[bid+1]; + char* local_buffer = (char*) buffers_[copy_id_][bid]; + char* local_buffer_var = (char*) buffers_[copy_id_][bid+1]; + size_t local_buffer_size = buffer_sizes_[copy_id_][bid]; + size_t local_buffer_var_size = buffer_sizes_[copy_id_][bid+1]; + size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; + int64_t cell_num_in_buffer = local_buffer_size / sizeof(size_t); + + // For all overlapping tiles, in a round-robin fashion + for(;;) { + // For easy reference + int64_t snum = + tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid];// Slab num + size_t cell_slab_size = + tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; + int64_t cell_num_in_slab = cell_slab_size / sizeof(size_t); + size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid][tid]; + int64_t& sid = + tile_slab_state_.current_cell_slab_in_pass_[aid][tid]; // Slab + + // For all cell slabs in a pass + while(sid < snum) { + // Handle overflow + if(buffer_offset + cell_slab_size > buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate variable cell slab size + int64_t cell_start = local_buffer_offset / sizeof(size_t); + int64_t cell_end = cell_start + cell_num_in_slab; + cell_slab_size_var = + (cell_end == cell_num_in_buffer) ? + local_buffer_var_size - local_buffer_s[cell_start] : + local_buffer_s[cell_end] - local_buffer_s[cell_start]; + + // Handle overflow for the the variable-length buffer + if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { + overflow_[aid] = true; + break; + } + + // Copy cell slabs + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_slab_size); + memcpy( + buffer_var + buffer_offset_var, + local_buffer_var + local_buffer_s[cell_start], + cell_slab_size_var); + + // Update buffer offsets + buffer_offset += cell_slab_size; + buffer_offset_var += cell_slab_size_var; + + // Prepare for new slab + AdvanceCellSlabInfo acsi = { aid, this }; + (*advance_cell_slab_)(&acsi); + } + + // Terminating condition + if(tile_slab_state_.copy_tile_slab_done_[aid]) + break; + } + + // Set user buffer sizes + buffer_size = buffer_offset; + buffer_size_var = buffer_offset_var; } int ArraySortedReadState::create_buffers() { @@ -400,12 +698,103 @@ int ArraySortedReadState::create_buffers() { return TILEDB_ASRS_OK; } +void ArraySortedReadState::free_copy_state() { + if(copy_state_.buffer_offsets_ != NULL) + delete [] copy_state_.buffer_offsets_; +} + void ArraySortedReadState::free_tile_slab_info() { - // TODO + // For easy reference + int anum = (int) attribute_ids_.size(); + + // Initialize + for(int i=0; i<2; ++i) { + int64_t tile_num = tile_slab_info_[i].tile_num_; + + if(tile_slab_info_[i].cell_slab_range_ != NULL) { + for(int j=0; jarray_schema()->dim_num(); + + tile_slab_info_[id].cell_slab_range_ = new int64_t*[tile_num]; + for(int64_t i=0; i bool ArraySortedReadState::next_tile_slab_col() { // Quick check if done - if(done_) + if(read_tile_slabs_done_) return false; // If the AIO needs to be resumed, exit (no need for a new tile slab) @@ -507,7 +969,7 @@ bool ArraySortedReadState::next_tile_slab_col() { // Check again if done, this time based on the tile slab and subarray if(tile_slab[prev_id] != NULL && tile_slab[prev_id][2*(dim_num-1) + 1] == subarray[2*(dim_num-1) + 1]) { - done_ = true; + read_tile_slabs_done_ = true; return false; } @@ -544,7 +1006,6 @@ bool ArraySortedReadState::next_tile_slab_col() { // Calculate tile slab info and reset tile slab state calculate_tile_slab_info_col(aio_id_); - reset_tile_slab_state(aio_id_); // Success return true; @@ -553,7 +1014,7 @@ bool ArraySortedReadState::next_tile_slab_col() { template bool ArraySortedReadState::next_tile_slab_row() { // Quick check if done - if(done_) + if(read_tile_slabs_done_) return false; // If the AIO needs to be resumed, exit (no need for a new tile slab) @@ -580,7 +1041,7 @@ bool ArraySortedReadState::next_tile_slab_row() { // Check again if done, this time based on the tile slab and subarray if(tile_slab[prev_id] != NULL && tile_slab[prev_id][1] == subarray[1]) { - done_ = true; + read_tile_slabs_done_ = true; return false; } @@ -614,7 +1075,6 @@ bool ArraySortedReadState::next_tile_slab_row() { // Calculate tile slab info and reset tile slab state calculate_tile_slab_info_row(aio_id_); - reset_tile_slab_state(aio_id_); // Success return true; @@ -650,7 +1110,9 @@ int ArraySortedReadState::read_dense_sorted_col() { // Check if this can be satisfied with a default read if(array_schema->cell_order() == TILEDB_COL_MAJOR && array_schema->is_contained_in_tile_slab_row(subarray)) - return array_->read_default(user_buffers_, user_buffer_sizes_); + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); // Iterate over each tile slab while(next_tile_slab_col()) { @@ -667,6 +1129,10 @@ int ArraySortedReadState::read_dense_sorted_col() { for(int i=0; i<2; ++i) wait_copy(i); + // If done, kill the copy thread + if(done() && cancel_copy_thread() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + // Success return TILEDB_ASRS_OK; } @@ -680,7 +1146,9 @@ int ArraySortedReadState::read_dense_sorted_row() { // Check if this can be satisfied with a default read if(array_schema->cell_order() == TILEDB_ROW_MAJOR && array_schema->is_contained_in_tile_slab_col(subarray)) - return array_->read_default(user_buffers_, user_buffer_sizes_); + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); // Iterate over each tile slab while(next_tile_slab_row()) { @@ -697,6 +1165,10 @@ int ArraySortedReadState::read_dense_sorted_row() { for(int i=0; i<2; ++i) wait_copy(i); + // If done, kill the copy thread + if(done() && cancel_copy_thread() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + // Success return TILEDB_ASRS_OK; } @@ -825,11 +1297,53 @@ int ArraySortedReadState::release_overflow() { return TILEDB_ASRS_OK; } +void ArraySortedReadState::reset_copy_state( + void** buffers, + size_t* buffer_sizes) { + copy_state_.buffers_ = buffers; + copy_state_.buffer_sizes_ = buffer_sizes; + for(int i=0; iarray_schema()->dim_num(); + int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; + + // Perform proper allocations if it is the first time + if(tile_slab_state_.current_cell_slab_coords_[0] == NULL) { + for(int i=0; i Date: Tue, 27 Sep 2016 18:13:39 -0400 Subject: [PATCH 04/57] More changes on sorted reads. --- core/include/array/array_sorted_read_state.h | 124 +++++- core/src/array/array.cc | 2 - core/src/array/array_schema.cc | 19 + core/src/array/array_sorted_read_state.cc | 406 +++++++++++++------ 4 files changed, 421 insertions(+), 130 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 7e7f1dbb..c98b9dd8 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -103,15 +103,12 @@ class ArraySortedReadState { /** Info about a tile slab. It is used by the copy_tile_slab() function. */ struct TileSlabInfo { - /** - * Number of cell slabs to be copied in as tile pass, - * per attribute per tile. - */ - int64_t** cell_slab_num_in_pass_; /** The multi-dimensional range of cell slabs per tile. */ int64_t** cell_slab_range_; /** Cell slab size per attribute per tile. */ size_t** cell_slab_size_; + /** first dimension to advance when advancing the cell slab coordinates. */ + int first_dim_to_advance_; /** * Bytes to jump after copying a cell slab, per attribute, per tile, * per dimension. @@ -119,8 +116,12 @@ class ArraySortedReadState { size_t*** offsets_per_dim_; /** Offset of first result cell slab per attribute per tile. */ size_t** start_offsets_; + /** The normalized tile domain of the tile slab. */ + void* tile_domain_; /** Number of tiles in the tile slab. */ int64_t tile_num_; + /** Tiles to jump when a tile is done. */ + int64_t tiles_to_advance_; }; /** The state for a tile slab copy. */ @@ -129,8 +130,6 @@ class ArraySortedReadState { int64_t* current_tile_; /** The current coordinates in the slab range per attribute per tile. */ int64_t*** current_cell_slab_coords_; - /** The cell slab in the current pass per attribute per tile. */ - int64_t** current_cell_slab_in_pass_; /** The offset of the next cell slab to be copied per attribute per tile. */ size_t** current_offsets_; /** Keeps track of whether a tile slab copy for an attribute id done. */ @@ -233,6 +232,12 @@ class ArraySortedReadState { /** The ids of the attributes the array was initialized with. */ const std::vector& attribute_ids_; + /** + * The sizes of the attributes. For variable-length attributes, sizeof(size_t) + * is stored. + */ + std::vector attribute_sizes_; + /** Number of allocated buffers. */ int buffer_num_; @@ -284,6 +289,9 @@ class ArraySortedReadState { /** The tile slab to be read for the first and second buffers. */ void* tile_slab_[2]; + /** Normalized tile slab. */ + void* tile_slab_norm_[2]; + /** The info for each of the two tile slabs under investigation. */ TileSlabInfo tile_slab_info_[2]; @@ -380,6 +388,54 @@ class ArraySortedReadState { template void calculate_tile_slab_info_col(int id); + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of column-major order, when the array tile order is column-major and + * the array cell order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_col_cc(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of column-major order, when the array tile order is column-major and + * the array cell order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_col_cr(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of column-major order, when the array tile order is row-major and + * the array cell order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_col_rc(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of column-major order, when the array tile order is row-major and + * the array cell order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_col_rr(int id); + /** * Calculates the info used in the copy_tile_slab() function for the case * of row-major order. @@ -391,6 +447,54 @@ class ArraySortedReadState { template void calculate_tile_slab_info_row(int id); + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of row-major order, when the array tile order is column-major and + * the array cell order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_row_cc(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of row-major order, when the array tile order is column-major and + * the array cell order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_row_cr(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of row-major order, when the array tile order is row-major and + * the array cell order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_row_rc(int id); + + /** + * Calculates the info used in the copy_tile_slab() function for the case + * of row-major order, when the array tile order is row-major and + * the array cell order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info_row_rr(int id); + /** * Kills the copy thread (if it is still running). * @@ -465,7 +569,13 @@ class ArraySortedReadState { /** * Initializes the tile slab info for a particular tile slab, using the * input tile number. + * + * @template The domain type. + * @param id The slab id. + * @param tile_num The number of tiles overlapped by the tile slab. + * @return void. */ + template void init_tile_slab_info(int id, int64_t tile_num); /** Initializes the tile slab state. */ diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 817c7715..e42b4017 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -306,7 +306,6 @@ int Array::read_default(void** buffers, size_t* buffer_sizes) { return TILEDB_AR_OK; } -inline bool Array::read_mode() const { return array_read_mode(mode_); } @@ -315,7 +314,6 @@ const void* Array::subarray() const { return subarray_; } -inline bool Array::write_mode() const { return array_write_mode(mode_); } diff --git a/core/src/array/array_schema.cc b/core/src/array/array_schema.cc index 2ddf231f..5b2805b0 100644 --- a/core/src/array/array_schema.cc +++ b/core/src/array/array_schema.cc @@ -2718,6 +2718,24 @@ template int64_t ArraySchema::hilbert_id( template int64_t ArraySchema::hilbert_id( const double* coords) const; +template bool ArraySchema::is_contained_in_tile_slab_col( + const int* range) const; +template bool ArraySchema::is_contained_in_tile_slab_col( + const int64_t* range) const; +template bool ArraySchema::is_contained_in_tile_slab_col( + const float* range) const; +template bool ArraySchema::is_contained_in_tile_slab_col( + const double* range) const; + +template bool ArraySchema::is_contained_in_tile_slab_row( + const int* range) const; +template bool ArraySchema::is_contained_in_tile_slab_row( + const int64_t* range) const; +template bool ArraySchema::is_contained_in_tile_slab_row( + const float* range) const; +template bool ArraySchema::is_contained_in_tile_slab_row( + const double* range) const; + template int ArraySchema::subarray_overlap( const int* subarray_a, const int* subarray_b, @@ -2757,3 +2775,4 @@ template int64_t ArraySchema::tile_id( template int64_t ArraySchema::tile_id( const double* cell_coords) const; + diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 4f24d2d9..776eced0 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -67,6 +67,9 @@ ArraySortedReadState::ArraySortedReadState( : array_(array), attribute_ids_(array->attribute_ids()), subarray_(array->subarray()) { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + // Initializations copy_id_ = 0; aio_id_ = 0; @@ -78,12 +81,18 @@ ArraySortedReadState::ArraySortedReadState( buffer_sizes_[i] = NULL; buffers_[i] = NULL; tile_slab_[i] = NULL; + tile_slab_norm_[i] = NULL; wait_copy_[i] = false; wait_aio_[i] = true; } overflow_.resize(attribute_ids_.size()); - for(int i=0; (int) attribute_ids_.size(); ++i) + for(int i=0; (int) attribute_ids_.size(); ++i) { overflow_[i] = false; + if(array_schema->var_size(attribute_ids_[i])) + attribute_sizes_.push_back(sizeof(size_t)); + else + attribute_sizes_.push_back(array_schema->cell_size(attribute_ids_[i])); + } // Calculate number of buffers calculate_buffer_num(); @@ -109,6 +118,8 @@ ArraySortedReadState::~ArraySortedReadState() { } if(tile_slab_[i] != NULL) free(tile_slab_[i]); + if(tile_slab_norm_[i] != NULL) + free(tile_slab_norm_[i]); } // Destroy thread, conditions and mutexes @@ -321,12 +332,10 @@ void ArraySortedReadState::advance_cell_slab_col(int aid) { int64_t& tid = tile_slab_state_.current_tile_[aid]; int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; int dim_num = array_->array_schema()->dim_num(); - - // Advance cell slab - ++(tile_slab_state_.current_cell_slab_in_pass_[aid][tid]); + int64_t tiles_to_advance = tile_slab_info_[copy_id_].tiles_to_advance_; // Advance cell slab coordinates and offsets - int d = 0; + int d = tile_slab_info_[copy_id_].first_dim_to_advance_; ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][d]); tile_slab_state_.current_offsets_[aid][tid] += tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; @@ -342,17 +351,23 @@ void ArraySortedReadState::advance_cell_slab_col(int aid) { // Check if tile slab is done if(tile_slab_state_.current_cell_slab_coords_[aid][tid][dim_num-1] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*(dim_num-1)+1]) { + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*(dim_num-1)+1] && + tid == tile_num -1) { tile_slab_state_.copy_tile_slab_done_[aid] = true; return; } - // Check if pass is done and advance tile id - if(tile_slab_state_.current_cell_slab_in_pass_[aid][tid] == - tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid]) { - tile_slab_state_.current_cell_slab_in_pass_[aid][tid] = 0; - tid = (tid + 1) % tile_num; - return; + // Advance tile id + if((tid+1) % tiles_to_advance == 0) { + // Go back + tid -= (tiles_to_advance-1); + + // Check if the tile is done + if(tile_slab_state_.current_cell_slab_coords_[aid][tid][dim_num-1] > + tile_slab_info_[copy_id_].cell_slab_range_[tid][2*(dim_num-1)+1]) + tid += tiles_to_advance; + } else { + ++tid; } } @@ -360,13 +375,10 @@ void ArraySortedReadState::advance_cell_slab_row(int aid) { // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; - int dim_num = array_->array_schema()->dim_num(); - - // Advance cell slab - ++(tile_slab_state_.current_cell_slab_in_pass_[aid][tid]); + int64_t tiles_to_advance = tile_slab_info_[copy_id_].tiles_to_advance_; // Advance cell slab coordinates and offsets - int d = dim_num-1; + int d = tile_slab_info_[copy_id_].first_dim_to_advance_; ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][d]); tile_slab_state_.current_offsets_[aid][tid] += tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; @@ -375,24 +387,30 @@ void ArraySortedReadState::advance_cell_slab_row(int aid) { tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d+1]) { tile_slab_state_.current_cell_slab_coords_[aid][tid][d] = tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d]; - ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][++d]); + ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][--d]); tile_slab_state_.current_offsets_[aid][tid] += tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; } // Check if tile slab is done if(tile_slab_state_.current_cell_slab_coords_[aid][tid][0] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][1]) { + tile_slab_info_[copy_id_].cell_slab_range_[tid][1] && + tid == tile_num -1) { tile_slab_state_.copy_tile_slab_done_[aid] = true; return; } - // Check if pass is done and advance tile id - if(tile_slab_state_.current_cell_slab_in_pass_[aid][tid] == - tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid]) { - tile_slab_state_.current_cell_slab_in_pass_[aid][tid] = 0; - tid = (tid + 1) % tile_num; - return; + // Advance tile id + if((tid+1) % tiles_to_advance == 0) { + // Go back + tid -= (tiles_to_advance-1); + + // Check if the tile is done + if(tile_slab_state_.current_cell_slab_coords_[aid][tid][0] > + tile_slab_info_[copy_id_].cell_slab_range_[tid][1]) + tid += tiles_to_advance; + } else { + ++tid; } } @@ -473,19 +491,136 @@ void ArraySortedReadState::calculate_buffer_sizes() { template void ArraySortedReadState::calculate_tile_slab_info_col(int id) { // Calculate number of tiles, if they are not already calculated + int64_t tile_num = array_->array_schema()->tile_num(tile_slab_[id]); if(tile_slab_info_[id].tile_num_ == -1) - init_tile_slab_info(id, array_->array_schema()->tile_num(subarray_)); + init_tile_slab_info(id, tile_num); + + // Invoke the proper function based on the array tile and cell order + int cell_order = array_->array_schema()->cell_order(); + int tile_order = array_->array_schema()->tile_order(); + if(tile_order == TILEDB_ROW_MAJOR) { + if(cell_order == TILEDB_ROW_MAJOR) + calculate_tile_slab_info_col_rr(id); + else if(cell_order == TILEDB_COL_MAJOR) + calculate_tile_slab_info_col_rc(id); + else + assert(0); + } else if(tile_order == TILEDB_COL_MAJOR) { + if(cell_order == TILEDB_ROW_MAJOR) + calculate_tile_slab_info_col_cr(id); + else if(cell_order == TILEDB_COL_MAJOR) + calculate_tile_slab_info_col_cc(id); + else + assert(0); + } else { + assert(0); + } +} +template +void ArraySortedReadState::calculate_tile_slab_info_col_cc(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_col_cr(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_col_rc(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_col_rr(int id) { // TODO } template void ArraySortedReadState::calculate_tile_slab_info_row(int id) { // Calculate number of tiles, if they are not already calculated + int64_t tile_num = array_->array_schema()->tile_num(tile_slab_[id]); if(tile_slab_info_[id].tile_num_ == -1) - init_tile_slab_info(id, array_->array_schema()->tile_num(subarray_)); + init_tile_slab_info(id, tile_num); + + // Invoke the proper function based on the array tile and cell order + int cell_order = array_->array_schema()->cell_order(); + int tile_order = array_->array_schema()->tile_order(); + if(tile_order == TILEDB_ROW_MAJOR) { + if(cell_order == TILEDB_ROW_MAJOR) + calculate_tile_slab_info_row_rr(id); + else if(cell_order == TILEDB_COL_MAJOR) + calculate_tile_slab_info_row_rc(id); + else + assert(0); + } else if(tile_order == TILEDB_COL_MAJOR) { + if(cell_order == TILEDB_ROW_MAJOR) + calculate_tile_slab_info_row_cr(id); + else if(cell_order == TILEDB_COL_MAJOR) + calculate_tile_slab_info_row_cc(id); + else + assert(0); + } else { + assert(0); + } +} + +template +void ArraySortedReadState::calculate_tile_slab_info_row_cc(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_row_cr(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_row_rc(int id) { + // TODO +} + +template +void ArraySortedReadState::calculate_tile_slab_info_row_rr(int id) { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* domain = static_cast(array_schema->domain()); + // Initialize a running start offset + size_t start_offset = 0; + + // Calculate first dimension to advance + // TODO + + // Calculate tiles to advance + // TODO + + // Iterate over the tiles in tile domain in the array order // TODO + + // Calculate mapping to tile slab state tiles + // TODO + + // Calculate tile range + // TODO + + // Calculate cell slab range + // (i.e., the intersection between tile ranges and normalized tile slab) + // TODO + + // Calculate cell slab size + // TODO + + // Assign start offset + // TODO + + // Update start offset based on the cell slab range + // TODO + + // Calculate offsets per dimension + // TODO + } int ArraySortedReadState::cancel_copy_thread() { @@ -548,34 +683,27 @@ void ArraySortedReadState::copy_tile_slab(int aid, int bid) { // For all overlapping tiles, in a round-robin fashion for(;;) { // For easy reference - int64_t snum = - tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid]; // Slab num - int64_t& sid = - tile_slab_state_.current_cell_slab_in_pass_[aid][tid]; // Slab size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid][tid]; - // For all cell slabs in a pass - while(sid < snum) { - // Handle overflow - if(buffer_offset + cell_slab_size > buffer_size) { - overflow_[aid] = true; - break; - } + // Handle overflow + if(buffer_offset + cell_slab_size > buffer_size) { + overflow_[aid] = true; + break; + } - // Copy cell slab - memcpy( - buffer + buffer_offset, - local_buffer + local_buffer_offset, - cell_slab_size); - - // Update buffer offset - buffer_offset += cell_slab_size; + // Copy cell slab + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_slab_size); + + // Update buffer offset + buffer_offset += cell_slab_size; - // Prepare for new slab - AdvanceCellSlabInfo acsi = { aid, this }; - (*advance_cell_slab_)(&acsi); - } + // Prepare for new slab + AdvanceCellSlabInfo acsi = { aid, this }; + (*advance_cell_slab_)(&acsi); // Terminating condition if(tile_slab_state_.copy_tile_slab_done_[aid]) @@ -613,55 +741,48 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { // For all overlapping tiles, in a round-robin fashion for(;;) { // For easy reference - int64_t snum = - tile_slab_info_[copy_id_].cell_slab_num_in_pass_[aid][tid];// Slab num size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; int64_t cell_num_in_slab = cell_slab_size / sizeof(size_t); size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid][tid]; - int64_t& sid = - tile_slab_state_.current_cell_slab_in_pass_[aid][tid]; // Slab - - // For all cell slabs in a pass - while(sid < snum) { - // Handle overflow - if(buffer_offset + cell_slab_size > buffer_size) { - overflow_[aid] = true; - break; - } - // Calculate variable cell slab size - int64_t cell_start = local_buffer_offset / sizeof(size_t); - int64_t cell_end = cell_start + cell_num_in_slab; - cell_slab_size_var = - (cell_end == cell_num_in_buffer) ? - local_buffer_var_size - local_buffer_s[cell_start] : - local_buffer_s[cell_end] - local_buffer_s[cell_start]; - - // Handle overflow for the the variable-length buffer - if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { - overflow_[aid] = true; - break; - } + // Handle overflow + if(buffer_offset + cell_slab_size > buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate variable cell slab size + int64_t cell_start = local_buffer_offset / sizeof(size_t); + int64_t cell_end = cell_start + cell_num_in_slab; + cell_slab_size_var = + (cell_end == cell_num_in_buffer) ? + local_buffer_var_size - local_buffer_s[cell_start] : + local_buffer_s[cell_end] - local_buffer_s[cell_start]; + + // Handle overflow for the the variable-length buffer + if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { + overflow_[aid] = true; + break; + } - // Copy cell slabs - memcpy( - buffer + buffer_offset, - local_buffer + local_buffer_offset, - cell_slab_size); - memcpy( - buffer_var + buffer_offset_var, - local_buffer_var + local_buffer_s[cell_start], - cell_slab_size_var); - - // Update buffer offsets - buffer_offset += cell_slab_size; - buffer_offset_var += cell_slab_size_var; + // Copy cell slabs + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_slab_size); + memcpy( + buffer_var + buffer_offset_var, + local_buffer_var + local_buffer_s[cell_start], + cell_slab_size_var); + + // Update buffer offsets + buffer_offset += cell_slab_size; + buffer_offset_var += cell_slab_size_var; - // Prepare for new slab - AdvanceCellSlabInfo acsi = { aid, this }; - (*advance_cell_slab_)(&acsi); - } + // Prepare for new slab + AdvanceCellSlabInfo acsi = { aid, this }; + (*advance_cell_slab_)(&acsi); // Terminating condition if(tile_slab_state_.copy_tile_slab_done_[aid]) @@ -717,14 +838,6 @@ void ArraySortedReadState::free_tile_slab_info() { delete [] tile_slab_info_[i].cell_slab_range_; } - if(tile_slab_info_[i].cell_slab_num_in_pass_ != NULL) { - for(int j=0; j void ArraySortedReadState::init_tile_slab_info(int id, int64_t tile_num) { // For easy reference + const ArraySchema* array_schema = array_->array_schema(); int anum = (int) attribute_ids_.size(); - int dim_num = array_->array_schema()->dim_num(); + int dim_num = array_schema->dim_num(); + size_t coords_size = array_schema->coords_size(); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + const T* tile_slab = static_cast(tile_slab_[id]); tile_slab_info_[id].cell_slab_range_ = new int64_t*[tile_num]; for(int64_t i=0; i(tile_slab_info_[id].tile_domain_); + for(int i=0; iarray_schema()->coords_size(); + // Allocate space for the tile slab if necessary if(tile_slab_[aio_id_] == NULL) - tile_slab_[aio_id_] = malloc(2*array_->array_schema()->coords_size()); + tile_slab_[aio_id_] = malloc(2*coords_size); + if(tile_slab_norm_[aio_id_] == NULL) + tile_slab_norm_[aio_id_] = malloc(2*coords_size); // For easy reference const ArraySchema* array_schema = array_->array_schema(); @@ -962,6 +1085,7 @@ bool ArraySortedReadState::next_tile_slab_col() { const T* domain = static_cast(array_schema->domain()); const T* tile_extents = static_cast(array_schema->tile_extents()); T* tile_slab[2]; + T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); for(int i=0; i<2; ++i) tile_slab[i] = static_cast(tile_slab_[i]); int prev_id = (aio_id_-1)%2; @@ -983,18 +1107,28 @@ bool ArraySortedReadState::next_tile_slab_col() { tile_extents[dim_num-1] + domain[2*(dim_num-1)]; tile_slab[aio_id_][2*(dim_num-1)+1] = std::min(cropped_upper - 1, subarray[2*(dim_num-1)+1]); + tile_slab_norm[2*(dim_num-1)] = + tile_slab[aio_id_][2*(dim_num-1)] - domain[2*(dim_num-1)]; + tile_slab_norm[2*(dim_num-1)+1] = + tile_slab[aio_id_][2*(dim_num-1)+1] - domain[2*(dim_num-1)]; // Leave the rest of the subarray extents intact for(int i=0; iarray_schema()->coords_size()); + 2*coords_size); + memcpy( + tile_slab_norm_[aio_id_], + tile_slab_norm_[prev_id], + 2*coords_size); // Advance tile slab tile_slab[aio_id_][2*(dim_num-1)] = tile_slab[aio_id_][2*(dim_num-1)+1] + 1; @@ -1002,6 +1136,10 @@ bool ArraySortedReadState::next_tile_slab_col() { std::min( tile_slab[aio_id_][2*(dim_num-1)+1] + tile_extents[dim_num-1] - 1, subarray[2*(dim_num-1)+1]); + tile_slab_norm[2*(dim_num-1)] = + tile_slab[aio_id_][2*(dim_num-1)] - domain[2*(dim_num-1)]; + tile_slab_norm[2*(dim_num-1)+1] = + tile_slab[aio_id_][2*(dim_num-1)+1] - domain[2*(dim_num-1)]; } // Calculate tile slab info and reset tile slab state @@ -1023,9 +1161,14 @@ bool ArraySortedReadState::next_tile_slab_row() { return true; } + // For easy reference + size_t coords_size = array_->array_schema()->coords_size(); + // Allocate space for the tile slab if necessary if(tile_slab_[aio_id_] == NULL) - tile_slab_[aio_id_] = malloc(2*array_->array_schema()->coords_size()); + tile_slab_[aio_id_] = malloc(2*coords_size); + if(tile_slab_norm_[aio_id_] == NULL) + tile_slab_norm_[aio_id_] = malloc(2*coords_size); // For easy reference const ArraySchema* array_schema = array_->array_schema(); @@ -1034,6 +1177,7 @@ bool ArraySortedReadState::next_tile_slab_row() { const T* domain = static_cast(array_schema->domain()); const T* tile_extents = static_cast(array_schema->tile_extents()); T* tile_slab[2]; + T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); for(int i=0; i<2; ++i) tile_slab[i] = static_cast(tile_slab_[i]); int prev_id = (aio_id_-1)%2; @@ -1053,24 +1197,34 @@ bool ArraySortedReadState::next_tile_slab_row() { T cropped_upper = (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); + tile_slab_norm[0] = tile_slab[aio_id_][0] - domain[0]; + tile_slab_norm[1] = tile_slab[aio_id_][1] - domain[0]; // Leave the rest of the subarray extents intact for(int i=1; iarray_schema()->coords_size()); + 2*coords_size); + memcpy( + tile_slab_norm_[aio_id_], + tile_slab_norm_[prev_id], + 2*coords_size); // Advance tile slab tile_slab[aio_id_][0] = tile_slab[aio_id_][1] + 1; tile_slab[aio_id_][1] = std::min( tile_slab[aio_id_][1] + tile_extents[0] - 1, subarray[1]); + tile_slab_norm[0] = tile_slab[aio_id_][0] - domain[0]; + tile_slab_norm[1] = tile_slab[aio_id_][1] - domain[0]; } // Calculate tile slab info and reset tile slab state @@ -1323,7 +1477,6 @@ void ArraySortedReadState::reset_tile_slab_state() { tile_slab_state_.current_cell_slab_coords_[i] = new int64_t*[tile_num]; for(int64_t j=0; j(); +template int ArraySortedReadState::read_dense_sorted_col(); +template int ArraySortedReadState::read_dense_sorted_col(); +template int ArraySortedReadState::read_dense_sorted_col(); + +template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedReadState::read_dense_sorted_row(); From fe15abba1aa68bd73ec72f9ee4284e95a3d0ec19 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 28 Sep 2016 18:15:04 -0400 Subject: [PATCH 05/57] More progress on dense sorted reads --- core/include/array/array_sorted_read_state.h | 222 +++---- core/src/array/array_sorted_read_state.cc | 606 ++++++++----------- 2 files changed, 336 insertions(+), 492 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index c98b9dd8..4b6b01dc 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -75,10 +75,10 @@ class ArraySortedReadState { /* TYPE DEFINITIONS */ /* ********************************* */ - /** Used in advance_cell_slab(). */ - struct AdvanceCellSlabInfo { - /** The id of the targeted attribute id in attribute_ids_. */ - int aid_; + /** Used in functors. */ + struct ASRS_Data { + /** An id. */ + int id_; /** The calling object. */ ArraySortedReadState* asrs_; }; @@ -91,49 +91,48 @@ class ArraySortedReadState { size_t* buffer_sizes_; /** User buffers. */ void** buffers_; - }; - - /** Simple struct used for an AIO or copy request. */ - struct ASRS_Request { - /** The id of the targeted tile slab. */ - int id_; - /** The calling object. */ - ArraySortedReadState* asrs_; - }; + }; /** Info about a tile slab. It is used by the copy_tile_slab() function. */ struct TileSlabInfo { - /** The multi-dimensional range of cell slabs per tile. */ - int64_t** cell_slab_range_; + /** Used in calculations of cell ids, one vector per tile. */ + int64_t** cell_offset_per_dim_; /** Cell slab size per attribute per tile. */ size_t** cell_slab_size_; - /** first dimension to advance when advancing the cell slab coordinates. */ - int first_dim_to_advance_; + /** Number of cells in a cell slab per tile. */ + int64_t* cell_slab_num_; /** - * Bytes to jump after copying a cell slab, per attribute, per tile, - * per dimension. + * The range overlap of the **normalized** tile slab with each + * **normalized** tile range. + */ + void** range_overlap_; + /** + * Start offsets of each tile in the local buffer, per attribute per tile. */ - size_t*** offsets_per_dim_; - /** Offset of first result cell slab per attribute per tile. */ size_t** start_offsets_; - /** The normalized tile domain of the tile slab. */ - void* tile_domain_; + /** Tile mapping from the array order to the user order. */ + int64_t* tile_mapping_; /** Number of tiles in the tile slab. */ int64_t tile_num_; - /** Tiles to jump when a tile is done. */ - int64_t tiles_to_advance_; + /** Used in calculations of tile ids. */ + int64_t* tile_offset_per_dim_; }; /** The state for a tile slab copy. */ struct TileSlabState { - /** The current tile per attribute. */ - int64_t* current_tile_; - /** The current coordinates in the slab range per attribute per tile. */ - int64_t*** current_cell_slab_coords_; - /** The offset of the next cell slab to be copied per attribute per tile. */ - size_t** current_offsets_; /** Keeps track of whether a tile slab copy for an attribute id done. */ bool* copy_tile_slab_done_; + /** Current coordinates in tile slab per attribute. */ + void** current_coords_; + /** + * The offset in the local buffers of the next cell slab to be copied per + * attribute. Note that this applies only to fixed-sized attributes + * because the offsets of the variable-sized attributes can be derived from + * the buffers that hold the fixed-sized offsets. + */ + size_t* current_offsets_; + /** The current tile per attribute. */ + int64_t* current_tile_; }; @@ -247,6 +246,9 @@ class ArraySortedReadState { /** Local buffers (similar to those used in Array::read). */ void** buffers_[2]; + /** The coordinates size of the array. */ + size_t coords_size_; + /** The copy mutex conditions (one for each buffer). */ pthread_cond_t copy_cond_[2]; @@ -265,6 +267,9 @@ class ArraySortedReadState { /** True if the copy thread is running. */ bool copy_thread_running_; + /** The number of dimensions in the array. */ + int dim_num_; + /** The overflow mutex condition. */ pthread_cond_t overflow_cond_; @@ -313,9 +318,11 @@ class ArraySortedReadState { * the CopyState and TileSlabState. * Used in copy_tile_slab(). * + * @template T The domain type. * @param data Essentially a pointer to a AdvanceCellSlabInfo object. * @return void */ + template static void *advance_cell_slab_col(void* data); /** @@ -323,25 +330,31 @@ class ArraySortedReadState { * the CopyState and TileSlabState. * Used in copy_tile_slab(). * + * @template T The domain type. * @param data Essentially a pointer to a AdvanceCellSlabInfo object. * @return void */ + template static void *advance_cell_slab_row(void* data); /** * Advances a cell slab when the requested order is column-major. * + * @template T The domain type. * @param aid The id of the attribute in attribute_ids_ to focus on. * @return void */ + template void advance_cell_slab_col(int aid); /** * Advances a cell slab when the requested order is row-major. * + * @template T The domain type. * @param aid The id of the attribute in attribute_ids_ to focus on. * @return void */ + template void advance_cell_slab_row(int aid); /** @@ -388,54 +401,6 @@ class ArraySortedReadState { template void calculate_tile_slab_info_col(int id); - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of column-major order, when the array tile order is column-major and - * the array cell order is column-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_col_cc(int id); - - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of column-major order, when the array tile order is column-major and - * the array cell order is row-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_col_cr(int id); - - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of column-major order, when the array tile order is row-major and - * the array cell order is column-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_col_rc(int id); - - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of column-major order, when the array tile order is row-major and - * the array cell order is row-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_col_rr(int id); - /** * Calculates the info used in the copy_tile_slab() function for the case * of row-major order. @@ -447,54 +412,6 @@ class ArraySortedReadState { template void calculate_tile_slab_info_row(int id); - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of row-major order, when the array tile order is column-major and - * the array cell order is column-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_row_cc(int id); - - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of row-major order, when the array tile order is column-major and - * the array cell order is row-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_row_cr(int id); - - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of row-major order, when the array tile order is row-major and - * the array cell order is column-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_row_rc(int id); - - /** - * Calculates the info used in the copy_tile_slab() function for the case - * of row-major order, when the array tile order is row-major and - * the array cell order is row-major. - * - * @param T The domain type. - * @param id The tile slab id. - * @return void. - */ - template - void calculate_tile_slab_info_row_rr(int id); - /** * Kills the copy thread (if it is still running). * @@ -557,7 +474,35 @@ class ArraySortedReadState { /** Frees the tile slab state. */ void free_tile_slab_state(); - /** Handles the copy requests. */ + /** + * Returns the cell id along the **array** order for the current coordinates + * in the tile slab state for a particular attribute. + * + * @template T The domain type. + * @param aid The targeted attribute. + * @return The cell id. + */ + template + int64_t get_cell_id(int aid); + + /** + * Returns the tile id along the **array** order for the current coordinates + * in the tile slab state for a particular attribute. + * + * @template T The domain type. + * @param aid The targeted attribute. + * @return The tile id. + */ + template + int64_t get_tile_id(int aid); + + /** + * Handles the copy requests. + * + * @template T The domain type. + * @return void. + */ + template void handle_copy_requests(); /** Initializes the copy state. */ @@ -570,7 +515,7 @@ class ArraySortedReadState { * Initializes the tile slab info for a particular tile slab, using the * input tile number. * - * @template The domain type. + * @template T The domain type. * @param id The slab id. * @param tile_num The number of tiles overlapped by the tile slab. * @return void. @@ -712,7 +657,13 @@ class ArraySortedReadState { /** Resets the oveflow flags to **false**. */ void reset_overflow(); - /** Resets the tile slab state. */ + /** + * Resets the tile slab state. + * + * @template T The domain type. + * @return void. + */ + template void reset_tile_slab_state(); /** @@ -736,6 +687,17 @@ class ArraySortedReadState { */ int unlock_overflow_mtx(); + /** + * Calculates the new tile and local buffer offset for the new (already + * computed) current cell coordinates in the tile slab. + * + * @template T The domain type + * @param aid The attribute id to focus on. + * @return void. + */ + template + void update_current_tile_and_offset(int aid); + /** * Waits on a copy operation for the buffer with input id to finish. * diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 776eced0..e20bda90 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -69,9 +69,12 @@ ArraySortedReadState::ArraySortedReadState( subarray_(array->subarray()) { // For easy reference const ArraySchema* array_schema = array_->array_schema(); + int anum = (int) attribute_ids_.size(); // Initializations + coords_size_ = array_schema->coords_size(); copy_id_ = 0; + dim_num_ = array_schema->dim_num(); aio_id_ = 0; copy_thread_running_ = false; read_tile_slabs_done_ = false; @@ -85,8 +88,8 @@ ArraySortedReadState::ArraySortedReadState( wait_copy_[i] = false; wait_aio_[i] = true; } - overflow_.resize(attribute_ids_.size()); - for(int i=0; (int) attribute_ids_.size(); ++i) { + overflow_.resize(anum); + for(int i=0; ivar_size(attribute_ids_[i])) attribute_sizes_.push_back(sizeof(size_t)); @@ -297,12 +300,32 @@ int ArraySortedReadState::init() { return TILEDB_ASRS_ERR; } - // Determine the advance_cell_slab_ method + // Initialize functors int mode = array_->mode(); - if(mode == TILEDB_ARRAY_READ_SORTED_ROW) - advance_cell_slab_ = advance_cell_slab_row; - else // mode == TILEDB_ARRAY_READ_SORTED_COL - advance_cell_slab_ = advance_cell_slab_col; + int coords_type = array_->array_schema()->coords_type(); + if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(coords_type == TILEDB_INT32) + advance_cell_slab_ = advance_cell_slab_row; + else if(coords_type == TILEDB_INT64) + advance_cell_slab_ = advance_cell_slab_row; + else if(coords_type == TILEDB_FLOAT32) + advance_cell_slab_ = advance_cell_slab_row; + else if(coords_type == TILEDB_FLOAT64) + advance_cell_slab_ = advance_cell_slab_row; + else + assert(0); + } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + if(coords_type == TILEDB_INT32) + advance_cell_slab_ = advance_cell_slab_col; + else if(coords_type == TILEDB_INT64) + advance_cell_slab_ = advance_cell_slab_col; + else if(coords_type == TILEDB_FLOAT32) + advance_cell_slab_ = advance_cell_slab_col; + else if(coords_type == TILEDB_FLOAT64) + advance_cell_slab_ = advance_cell_slab_col; + else + assert(0); + } // Success return TILEDB_ASRS_OK; @@ -313,110 +336,77 @@ int ArraySortedReadState::init() { /* PRIVATE METHODS */ /* ****************************** */ +template void *ArraySortedReadState::advance_cell_slab_col(void* data) { - ArraySortedReadState* asrs = ((AdvanceCellSlabInfo*) data)->asrs_; - int aid = ((AdvanceCellSlabInfo*) data)->aid_; - asrs->advance_cell_slab_col(aid); + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int aid = ((ASRS_Data*) data)->id_; + asrs->advance_cell_slab_col(aid); return NULL; } +template void *ArraySortedReadState::advance_cell_slab_row(void* data) { - ArraySortedReadState* asrs = ((AdvanceCellSlabInfo*) data)->asrs_; - int aid = ((AdvanceCellSlabInfo*) data)->aid_; - asrs->advance_cell_slab_row(aid); + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int aid = ((ASRS_Data*) data)->id_; + asrs->advance_cell_slab_row(aid); return NULL; } +template void ArraySortedReadState::advance_cell_slab_col(int aid) { // For easy reference - int64_t& tid = tile_slab_state_.current_tile_[aid]; - int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; - int dim_num = array_->array_schema()->dim_num(); - int64_t tiles_to_advance = tile_slab_info_[copy_id_].tiles_to_advance_; - - // Advance cell slab coordinates and offsets - int d = tile_slab_info_[copy_id_].first_dim_to_advance_; - ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][d]); - tile_slab_state_.current_offsets_[aid][tid] += - tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; - while(d < dim_num-1 && - tile_slab_state_.current_cell_slab_coords_[aid][tid][d] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d+1]) { - tile_slab_state_.current_cell_slab_coords_[aid][tid][d] = - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d]; - ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][++d]); - tile_slab_state_.current_offsets_[aid][tid] += - tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; + int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile id + int64_t cell_slab_num = tile_slab_info_[copy_id_].cell_slab_num_[tid]; + T* current_coords = (T*) tile_slab_state_.current_coords_[aid]; + const T* tile_slab = (const T*) tile_slab_norm_[copy_id_]; + + // Advance cell slab coordinates + int d = 0; + current_coords[d] += cell_slab_num; + while(d < dim_num_-1 && current_coords[d] > tile_slab[2*d+1]) { + current_coords[d] = tile_slab[2*d]; + ++current_coords[++d]; } - // Check if tile slab is done - if(tile_slab_state_.current_cell_slab_coords_[aid][tid][dim_num-1] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*(dim_num-1)+1] && - tid == tile_num -1) { + // Check if done + if(current_coords[dim_num_-1] > tile_slab[2*(dim_num_-1)+1]) { tile_slab_state_.copy_tile_slab_done_[aid] = true; return; } - // Advance tile id - if((tid+1) % tiles_to_advance == 0) { - // Go back - tid -= (tiles_to_advance-1); - - // Check if the tile is done - if(tile_slab_state_.current_cell_slab_coords_[aid][tid][dim_num-1] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*(dim_num-1)+1]) - tid += tiles_to_advance; - } else { - ++tid; - } + // Calculate new tile and offset for the current coords + update_current_tile_and_offset(aid); } +template void ArraySortedReadState::advance_cell_slab_row(int aid) { // For easy reference - int64_t& tid = tile_slab_state_.current_tile_[aid]; - int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; - int64_t tiles_to_advance = tile_slab_info_[copy_id_].tiles_to_advance_; - - // Advance cell slab coordinates and offsets - int d = tile_slab_info_[copy_id_].first_dim_to_advance_; - ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][d]); - tile_slab_state_.current_offsets_[aid][tid] += - tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; - while(d > 0 && - tile_slab_state_.current_cell_slab_coords_[aid][tid][d] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d+1]) { - tile_slab_state_.current_cell_slab_coords_[aid][tid][d] = - tile_slab_info_[copy_id_].cell_slab_range_[tid][2*d]; - ++(tile_slab_state_.current_cell_slab_coords_[aid][tid][--d]); - tile_slab_state_.current_offsets_[aid][tid] += - tile_slab_info_[copy_id_].offsets_per_dim_[aid][tid][d]; + int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile id + int64_t cell_slab_num = tile_slab_info_[copy_id_].cell_slab_num_[tid]; + T* current_coords = (T*) tile_slab_state_.current_coords_[aid]; + const T* tile_slab = (const T*) tile_slab_norm_[copy_id_]; + + // Advance cell slab coordinates + int d = dim_num_-1; + current_coords[d] += cell_slab_num; + while(d > 0 && current_coords[d] > tile_slab[2*d+1]) { + current_coords[d] = tile_slab[2*d]; + ++current_coords[--d]; } - // Check if tile slab is done - if(tile_slab_state_.current_cell_slab_coords_[aid][tid][0] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][1] && - tid == tile_num -1) { + // Check if done + if(current_coords[0] > tile_slab[1]) { tile_slab_state_.copy_tile_slab_done_[aid] = true; return; } - // Advance tile id - if((tid+1) % tiles_to_advance == 0) { - // Go back - tid -= (tiles_to_advance-1); - - // Check if the tile is done - if(tile_slab_state_.current_cell_slab_coords_[aid][tid][0] > - tile_slab_info_[copy_id_].cell_slab_range_[tid][1]) - tid += tiles_to_advance; - } else { - ++tid; - } + // Calculate new tile and offset for the current coords + update_current_tile_and_offset(aid); } void *ArraySortedReadState::aio_done(void* data) { - ArraySortedReadState* asrs = ((ASRS_Request*) data)->asrs_; - int id = ((ASRS_Request*) data)->id_; + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; asrs->block_copy(id); asrs->release_aio(id); @@ -495,45 +485,6 @@ void ArraySortedReadState::calculate_tile_slab_info_col(int id) { if(tile_slab_info_[id].tile_num_ == -1) init_tile_slab_info(id, tile_num); - // Invoke the proper function based on the array tile and cell order - int cell_order = array_->array_schema()->cell_order(); - int tile_order = array_->array_schema()->tile_order(); - if(tile_order == TILEDB_ROW_MAJOR) { - if(cell_order == TILEDB_ROW_MAJOR) - calculate_tile_slab_info_col_rr(id); - else if(cell_order == TILEDB_COL_MAJOR) - calculate_tile_slab_info_col_rc(id); - else - assert(0); - } else if(tile_order == TILEDB_COL_MAJOR) { - if(cell_order == TILEDB_ROW_MAJOR) - calculate_tile_slab_info_col_cr(id); - else if(cell_order == TILEDB_COL_MAJOR) - calculate_tile_slab_info_col_cc(id); - else - assert(0); - } else { - assert(0); - } -} - -template -void ArraySortedReadState::calculate_tile_slab_info_col_cc(int id) { - // TODO -} - -template -void ArraySortedReadState::calculate_tile_slab_info_col_cr(int id) { - // TODO -} - -template -void ArraySortedReadState::calculate_tile_slab_info_col_rc(int id) { - // TODO -} - -template -void ArraySortedReadState::calculate_tile_slab_info_col_rr(int id) { // TODO } @@ -544,85 +495,9 @@ void ArraySortedReadState::calculate_tile_slab_info_row(int id) { if(tile_slab_info_[id].tile_num_ == -1) init_tile_slab_info(id, tile_num); - // Invoke the proper function based on the array tile and cell order - int cell_order = array_->array_schema()->cell_order(); - int tile_order = array_->array_schema()->tile_order(); - if(tile_order == TILEDB_ROW_MAJOR) { - if(cell_order == TILEDB_ROW_MAJOR) - calculate_tile_slab_info_row_rr(id); - else if(cell_order == TILEDB_COL_MAJOR) - calculate_tile_slab_info_row_rc(id); - else - assert(0); - } else if(tile_order == TILEDB_COL_MAJOR) { - if(cell_order == TILEDB_ROW_MAJOR) - calculate_tile_slab_info_row_cr(id); - else if(cell_order == TILEDB_COL_MAJOR) - calculate_tile_slab_info_row_cc(id); - else - assert(0); - } else { - assert(0); - } -} - -template -void ArraySortedReadState::calculate_tile_slab_info_row_cc(int id) { - // TODO -} - -template -void ArraySortedReadState::calculate_tile_slab_info_row_cr(int id) { // TODO } -template -void ArraySortedReadState::calculate_tile_slab_info_row_rc(int id) { - // TODO -} - -template -void ArraySortedReadState::calculate_tile_slab_info_row_rr(int id) { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const T* domain = static_cast(array_schema->domain()); - - // Initialize a running start offset - size_t start_offset = 0; - - // Calculate first dimension to advance - // TODO - - // Calculate tiles to advance - // TODO - - // Iterate over the tiles in tile domain in the array order - // TODO - - // Calculate mapping to tile slab state tiles - // TODO - - // Calculate tile range - // TODO - - // Calculate cell slab range - // (i.e., the intersection between tile ranges and normalized tile slab) - // TODO - - // Calculate cell slab size - // TODO - - // Assign start offset - // TODO - - // Update start offset based on the cell slab range - // TODO - - // Calculate offsets per dimension - // TODO - -} - int ArraySortedReadState::cancel_copy_thread() { // If the thread is not running, exit with success if(!copy_thread_running_) @@ -642,9 +517,22 @@ int ArraySortedReadState::cancel_copy_thread() { } void *ArraySortedReadState::copy_handler(void* context) { + // For easy reference + ArraySortedReadState* asrs = (ArraySortedReadState*) context; + // This will enter an indefinite loop that will handle all incoming copy // requests - ((ArraySortedReadState*) context)->handle_copy_requests(); + int coords_type = asrs->array_->array_schema()->coords_type(); + if(coords_type == TILEDB_INT32) + asrs->handle_copy_requests(); + else if(coords_type == TILEDB_INT64) + asrs->handle_copy_requests(); + else if(coords_type == TILEDB_FLOAT32) + asrs->handle_copy_requests(); + else if(coords_type == TILEDB_FLOAT64) + asrs->handle_copy_requests(); + else + assert(0); // Return return NULL; @@ -674,17 +562,17 @@ void ArraySortedReadState::copy_tile_slab(int aid, int bid) { } // For easy reference - int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile + int64_t& tid = tile_slab_state_.current_tile_[aid]; size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; size_t buffer_size = copy_state_.buffer_sizes_[bid]; char* buffer = (char*) copy_state_.buffers_[bid]; char* local_buffer = (char*) buffers_[copy_id_][bid]; - // For all overlapping tiles, in a round-robin fashion + // Iterate over the tile slab cells for(;;) { // For easy reference size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; - size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid][tid]; + size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; // Handle overflow if(buffer_offset + cell_slab_size > buffer_size) { @@ -702,8 +590,8 @@ void ArraySortedReadState::copy_tile_slab(int aid, int bid) { buffer_offset += cell_slab_size; // Prepare for new slab - AdvanceCellSlabInfo acsi = { aid, this }; - (*advance_cell_slab_)(&acsi); + ASRS_Data asrs_data = { aid, this }; + (*advance_cell_slab_)(&asrs_data); // Terminating condition if(tile_slab_state_.copy_tile_slab_done_[aid]) @@ -723,7 +611,7 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { } // For easy reference - int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile + int64_t& tid = tile_slab_state_.current_tile_[aid]; size_t cell_slab_size_var; size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; size_t& buffer_offset_var = copy_state_.buffer_offsets_[bid+1]; @@ -744,7 +632,7 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; int64_t cell_num_in_slab = cell_slab_size / sizeof(size_t); - size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid][tid]; + size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; // Handle overflow if(buffer_offset + cell_slab_size > buffer_size) { @@ -781,8 +669,8 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { buffer_offset_var += cell_slab_size_var; // Prepare for new slab - AdvanceCellSlabInfo acsi = { aid, this }; - (*advance_cell_slab_)(&acsi); + ASRS_Data asrs_data = { aid, this }; + (*advance_cell_slab_)(&asrs_data); // Terminating condition if(tile_slab_state_.copy_tile_slab_done_[aid]) @@ -828,83 +716,95 @@ void ArraySortedReadState::free_tile_slab_info() { // For easy reference int anum = (int) attribute_ids_.size(); - // Initialize + // Free for(int i=0; i<2; ++i) { int64_t tile_num = tile_slab_info_[i].tile_num_; - if(tile_slab_info_[i].cell_slab_range_ != NULL) { + if(tile_slab_info_[i].cell_offset_per_dim_ != NULL) { for(int j=0; j +int64_t ArraySortedReadState::get_cell_id(int aid) { + // For easy reference + const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; + int64_t tid = tile_slab_state_.current_tile_[aid]; + const T* range_overlap = + (const T*) tile_slab_info_[copy_id_].range_overlap_[tid]; + int64_t* cell_offset_per_dim = + tile_slab_info_[copy_id_].cell_offset_per_dim_[tid]; + + // Calculate cell id + int64_t cid = 0; + for(int i=0; i +int64_t ArraySortedReadState::get_tile_id(int aid) { + // For easy reference + const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + int64_t* tile_offset_per_dim = tile_slab_info_[copy_id_].tile_offset_per_dim_; + + // Calculate tile id + int64_t tid = 0; + for(int i=0; i void ArraySortedReadState::handle_copy_requests() { // Handle copy requests indefinitely for(;;) { @@ -913,7 +813,7 @@ void ArraySortedReadState::handle_copy_requests() { // Reset the tile slab state if(copy_tile_slab_done()) - reset_tile_slab_state(); + reset_tile_slab_state(); // Start the copy copy_tile_slab(); @@ -948,77 +848,61 @@ void ArraySortedReadState::init_tile_slab_info() { // Initialize for(int i=0; i<2; ++i) { - tile_slab_info_[i].cell_slab_range_ = new int64_t*[anum]; + tile_slab_info_[i].cell_offset_per_dim_ = NULL; tile_slab_info_[i].cell_slab_size_ = new size_t*[anum]; - tile_slab_info_[i].offsets_per_dim_ = new size_t**[anum]; + tile_slab_info_[i].cell_slab_num_ = NULL; + tile_slab_info_[i].range_overlap_ = NULL; tile_slab_info_[i].start_offsets_ = new size_t*[anum]; - tile_slab_info_[i].cell_slab_range_ = NULL; - tile_slab_info_[i].tile_domain_ = NULL; + tile_slab_info_[i].tile_mapping_ = NULL; + tile_slab_info_[i].tile_offset_per_dim_ = new int64_t[dim_num_]; for(int j=0; j void ArraySortedReadState::init_tile_slab_info(int id, int64_t tile_num) { // For easy reference - const ArraySchema* array_schema = array_->array_schema(); int anum = (int) attribute_ids_.size(); - int dim_num = array_schema->dim_num(); - size_t coords_size = array_schema->coords_size(); - const T* domain = static_cast(array_schema->domain()); - const T* tile_extents = static_cast(array_schema->tile_extents()); - const T* tile_slab = static_cast(tile_slab_[id]); - tile_slab_info_[id].cell_slab_range_ = new int64_t*[tile_num]; - for(int64_t i=0; i(tile_slab_info_[id].tile_domain_); - for(int i=0; iarray_schema()->coords_size(); - // Allocate space for the tile slab if necessary if(tile_slab_[aio_id_] == NULL) - tile_slab_[aio_id_] = malloc(2*coords_size); + tile_slab_[aio_id_] = malloc(2*coords_size_); if(tile_slab_norm_[aio_id_] == NULL) - tile_slab_norm_[aio_id_] = malloc(2*coords_size); + tile_slab_norm_[aio_id_] = malloc(2*coords_size_); // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); - int dim_num = array_schema->dim_num(); const T* domain = static_cast(array_schema->domain()); const T* tile_extents = static_cast(array_schema->tile_extents()); T* tile_slab[2]; @@ -1092,7 +972,7 @@ bool ArraySortedReadState::next_tile_slab_col() { // Check again if done, this time based on the tile slab and subarray if(tile_slab[prev_id] != NULL && - tile_slab[prev_id][2*(dim_num-1) + 1] == subarray[2*(dim_num-1) + 1]) { + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { read_tile_slabs_done_ = true; return false; } @@ -1100,20 +980,20 @@ bool ArraySortedReadState::next_tile_slab_col() { // If this is the first time this function is called, initialize if(tile_slab[prev_id] == NULL) { // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][2*(dim_num-1)] = subarray[2*(dim_num-1)]; - T upper = subarray[2*(dim_num-1)] + tile_extents[dim_num-1]; + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + T upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; T cropped_upper = - (upper - domain[2*(dim_num-1)]) / tile_extents[dim_num-1] * - tile_extents[dim_num-1] + domain[2*(dim_num-1)]; - tile_slab[aio_id_][2*(dim_num-1)+1] = - std::min(cropped_upper - 1, subarray[2*(dim_num-1)+1]); - tile_slab_norm[2*(dim_num-1)] = - tile_slab[aio_id_][2*(dim_num-1)] - domain[2*(dim_num-1)]; - tile_slab_norm[2*(dim_num-1)+1] = - tile_slab[aio_id_][2*(dim_num-1)+1] - domain[2*(dim_num-1)]; + (upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1] * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - 1, subarray[2*(dim_num_-1)+1]); + tile_slab_norm[2*(dim_num_-1)] = + tile_slab[aio_id_][2*(dim_num_-1)] - domain[2*(dim_num_-1)]; + tile_slab_norm[2*(dim_num_-1)+1] = + tile_slab[aio_id_][2*(dim_num_-1)+1] - domain[2*(dim_num_-1)]; // Leave the rest of the subarray extents intact - for(int i=0; iarray_schema()->coords_size(); - // Allocate space for the tile slab if necessary if(tile_slab_[aio_id_] == NULL) - tile_slab_[aio_id_] = malloc(2*coords_size); + tile_slab_[aio_id_] = malloc(2*coords_size_); if(tile_slab_norm_[aio_id_] == NULL) - tile_slab_norm_[aio_id_] = malloc(2*coords_size); + tile_slab_norm_[aio_id_] = malloc(2*coords_size_); // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); - int dim_num = array_schema->dim_num(); const T* domain = static_cast(array_schema->domain()); const T* tile_extents = static_cast(array_schema->tile_extents()); T* tile_slab[2]; @@ -1201,7 +1078,7 @@ bool ArraySortedReadState::next_tile_slab_row() { tile_slab_norm[1] = tile_slab[aio_id_][1] - domain[0]; // Leave the rest of the subarray extents intact - for(int i=1; iaio_read(&aio_request) != TILEDB_AR_OK) { @@ -1465,34 +1342,20 @@ void ArraySortedReadState::reset_overflow() { overflow_[i] = false; } +template void ArraySortedReadState::reset_tile_slab_state() { // For easy reference int anum = (int) attribute_ids_.size(); - int dim_num = array_->array_schema()->dim_num(); - int64_t tile_num = tile_slab_info_[copy_id_].tile_num_; - - // Perform proper allocations if it is the first time - if(tile_slab_state_.current_cell_slab_coords_[0] == NULL) { - for(int i=0; i +void ArraySortedReadState::update_current_tile_and_offset(int aid) { + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; + size_t& current_offset = tile_slab_state_.current_offsets_[aid]; + int64_t cid; + + // Calculate the new tile id + tid = tile_slab_info_[copy_id_].tile_mapping_[get_tile_id(aid)]; + + // Calculate the cell id + cid = get_cell_id(aid); + + // Calculate new offset + current_offset = + tile_slab_info_[copy_id_].start_offsets_[aid][tid] + + cid * attribute_sizes_[aid]; +} + int ArraySortedReadState::wait_aio(int id) { // Lock AIO mutex if(lock_aio_mtx() != TILEDB_ASRS_OK) From e6cd37528b2d4beaea80526530a363f6dc36a317 Mon Sep 17 00:00:00 2001 From: spapadop Date: Thu, 29 Sep 2016 15:33:42 -0400 Subject: [PATCH 06/57] More progress on dense sorted reads --- core/include/array/array_sorted_read_state.h | 192 +++++++- core/src/array/array_sorted_read_state.cc | 436 +++++++++++++++++-- 2 files changed, 582 insertions(+), 46 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 4b6b01dc..06696131 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -77,8 +77,10 @@ class ArraySortedReadState { /** Used in functors. */ struct ASRS_Data { - /** An id. */ + /** An id (typically an attribute id or a tile slab id. */ int id_; + /** Another id (typically a tile id). */ + int64_t id_2_; /** The calling object. */ ArraySortedReadState* asrs_; }; @@ -110,8 +112,6 @@ class ArraySortedReadState { * Start offsets of each tile in the local buffer, per attribute per tile. */ size_t** start_offsets_; - /** Tile mapping from the array order to the user order. */ - int64_t* tile_mapping_; /** Number of tiles in the tile slab. */ int64_t tile_num_; /** Used in calculations of tile ids. */ @@ -246,6 +246,12 @@ class ArraySortedReadState { /** Local buffers (similar to those used in Array::read). */ void** buffers_[2]; + /** Function for calculating cell slab info during a copy operation. */ + void *(*calculate_cell_slab_info_) (void*); + + /** Function for calculating tile slab info during a copy operation. */ + void *(*calculate_tile_slab_info_) (void*); + /** The coordinates size of the array. */ size_t coords_size_; @@ -291,6 +297,12 @@ class ArraySortedReadState { /** The query subarray. */ const void* subarray_; + /** Auxiliary variable used in calculate_tile_slab_info(). */ + void* tile_coords_; + + /** Auxiliary variable used in calculate_tile_slab_info(). */ + void* tile_domain_; + /** The tile slab to be read for the first and second buffers. */ void* tile_slab_[2]; @@ -319,11 +331,11 @@ class ArraySortedReadState { * Used in copy_tile_slab(). * * @template T The domain type. - * @param data Essentially a pointer to a AdvanceCellSlabInfo object. + * @param data Essentially a pointer to a ASRS_Data object. * @return void */ template - static void *advance_cell_slab_col(void* data); + static void *advance_cell_slab_col_s(void* data); /** * Advances a cell slab focusing on row-major order, and updates @@ -331,11 +343,11 @@ class ArraySortedReadState { * Used in copy_tile_slab(). * * @template T The domain type. - * @param data Essentially a pointer to a AdvanceCellSlabInfo object. + * @param data Essentially a pointer to a ASRS_Data object. * @return void */ template - static void *advance_cell_slab_row(void* data); + static void *advance_cell_slab_row_s(void* data); /** * Advances a cell slab when the requested order is column-major. @@ -391,8 +403,152 @@ class ArraySortedReadState { void calculate_buffer_sizes(); /** - * Calculates the info used in the copy_tile_slab() function for the case - * of column-major order. + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is column-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ + template + static void *calculate_cell_slab_info_col_col_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is row-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ + template + static void *calculate_cell_slab_info_col_row_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order in row-major and the **array** cell + * order is column-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ + template + static void *calculate_cell_slab_info_row_col_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is row-major and the **array** cell + * order is row-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ + template + static void *calculate_cell_slab_info_row_row_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ + template + void calculate_cell_slab_info_col_col(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ + template + void calculate_cell_slab_info_col_row(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is row-major and the **array** cell + * order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ + template + void calculate_cell_slab_info_row_row(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is row-major and the **array** cell + * order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ + template + void calculate_cell_slab_info_row_col(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **array** cell order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ + template + void calculate_cell_slab_info_row(int id, int64_t tid); + + /** + * Calculates the **normalized** tile domain overlapped by the input tile + * slab. Note that this domain is the same for all tile slabs + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_domain(int id); + + /** + * Calculates the info used in the copy_tile_slab() function. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ + template + void calculate_tile_slab_info(int id); + + /** + * Calculates tile slab info for the case where the **array** tile order is + * column-major + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ + template + static void *calculate_tile_slab_info_col(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **array** tile order is column-major. * * @param T The domain type. * @param id The tile slab id. @@ -400,10 +556,21 @@ class ArraySortedReadState { */ template void calculate_tile_slab_info_col(int id); + + /** + * Calculates tile slab info for the case where the **array** tile order is + * row-major + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ + template + static void *calculate_tile_slab_info_row(void* data); /** - * Calculates the info used in the copy_tile_slab() function for the case - * of row-major order. + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **array** tile order is row-major. * * @param T The domain type. * @param id The tile slab id. @@ -517,11 +684,10 @@ class ArraySortedReadState { * * @template T The domain type. * @param id The slab id. - * @param tile_num The number of tiles overlapped by the tile slab. * @return void. */ template - void init_tile_slab_info(int id, int64_t tile_num); + void init_tile_slab_info(int id); /** Initializes the tile slab state. */ void init_tile_slab_state(); diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index e20bda90..a42c9c58 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -80,6 +80,8 @@ ArraySortedReadState::ArraySortedReadState( read_tile_slabs_done_ = false; resume_copy_ = false; resume_aio_ = false; + tile_coords_ = NULL; + tile_domain_ = NULL; for(int i=0; i<2; ++i) { buffer_sizes_[i] = NULL; buffers_[i] = NULL; @@ -111,6 +113,9 @@ ArraySortedReadState::ArraySortedReadState( ArraySortedReadState::~ArraySortedReadState() { // Clean up + free(tile_coords_); + free(tile_domain_); + for(int i=0; i<2; ++i) { if(buffer_sizes_[i] != NULL) delete [] buffer_sizes_[i]; @@ -301,28 +306,88 @@ int ArraySortedReadState::init() { } // Initialize functors + const ArraySchema* array_schema = array_->array_schema(); int mode = array_->mode(); - int coords_type = array_->array_schema()->coords_type(); + int cell_order = array_schema->cell_order(); + int tile_order = array_schema->tile_order(); + int coords_type = array_schema->coords_type(); if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(coords_type == TILEDB_INT32) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else if(coords_type == TILEDB_INT64) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else if(coords_type == TILEDB_FLOAT32) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else if(coords_type == TILEDB_FLOAT64) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else { + assert(0); + } + } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + if(coords_type == TILEDB_INT32) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else if(coords_type == TILEDB_INT64) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else if(coords_type == TILEDB_FLOAT32) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else if(coords_type == TILEDB_FLOAT64) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else { + assert(0); + } + } + if(tile_order == TILEDB_ROW_MAJOR) { if(coords_type == TILEDB_INT32) - advance_cell_slab_ = advance_cell_slab_row; + calculate_tile_slab_info_ = calculate_tile_slab_info_row; else if(coords_type == TILEDB_INT64) - advance_cell_slab_ = advance_cell_slab_row; + calculate_tile_slab_info_ = calculate_tile_slab_info_row; else if(coords_type == TILEDB_FLOAT32) - advance_cell_slab_ = advance_cell_slab_row; + calculate_tile_slab_info_ = calculate_tile_slab_info_row; else if(coords_type == TILEDB_FLOAT64) - advance_cell_slab_ = advance_cell_slab_row; + calculate_tile_slab_info_ = calculate_tile_slab_info_row; else assert(0); - } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + } else { // tile_order == TILEDB_COL_MAJOR if(coords_type == TILEDB_INT32) - advance_cell_slab_ = advance_cell_slab_col; + calculate_tile_slab_info_ = calculate_tile_slab_info_col; else if(coords_type == TILEDB_INT64) - advance_cell_slab_ = advance_cell_slab_col; + calculate_tile_slab_info_ = calculate_tile_slab_info_col; else if(coords_type == TILEDB_FLOAT32) - advance_cell_slab_ = advance_cell_slab_col; + calculate_tile_slab_info_ = calculate_tile_slab_info_col; else if(coords_type == TILEDB_FLOAT64) - advance_cell_slab_ = advance_cell_slab_col; + calculate_tile_slab_info_ = calculate_tile_slab_info_col; else assert(0); } @@ -337,7 +402,7 @@ int ArraySortedReadState::init() { /* ****************************** */ template -void *ArraySortedReadState::advance_cell_slab_col(void* data) { +void *ArraySortedReadState::advance_cell_slab_col_s(void* data) { ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; int aid = ((ASRS_Data*) data)->id_; asrs->advance_cell_slab_col(aid); @@ -345,7 +410,7 @@ void *ArraySortedReadState::advance_cell_slab_col(void* data) { } template -void *ArraySortedReadState::advance_cell_slab_row(void* data) { +void *ArraySortedReadState::advance_cell_slab_row_s(void* data) { ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; int aid = ((ASRS_Data*) data)->id_; asrs->advance_cell_slab_row(aid); @@ -479,23 +544,329 @@ void ArraySortedReadState::calculate_buffer_sizes() { } template -void ArraySortedReadState::calculate_tile_slab_info_col(int id) { +void *ArraySortedReadState::calculate_cell_slab_info_col_col_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_col_col(id, tid); + return NULL; +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_col_row_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_col_row(id, tid); + return NULL; +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_row_col_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_row_col(id, tid); + return NULL; +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_row_row_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_row_row(id, tid); + return NULL; +} + +template +void ArraySortedReadState::calculate_cell_slab_info_col_col( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + const T* tile_domain = (const T*) tile_domain_; + int64_t tile_num, cell_num; + + // Calculate number of cells in cell slab + cell_num = range_overlap[1] - range_overlap[0] + 1; + for(int i=0; i +void ArraySortedReadState::calculate_cell_slab_info_row_row( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + const T* tile_domain = (const T*) tile_domain_; + int64_t tile_num, cell_num; + + // Calculate number of cells in cell slab + cell_num = range_overlap[2*(dim_num_-1)+1] - range_overlap[2*(dim_num_-1)] +1; + for(int i=dim_num_-1; i>0; --i) { + tile_num = tile_domain[2*i+1] - tile_domain[2*i] + 1; + if(tile_num == 1) + cell_num *= range_overlap[2*(i-1)+1] - range_overlap[2*(i-1)] + 1; + else + break; + } + tile_slab_info_[id].cell_slab_num_[tid] = cell_num; + + // Calculate size of a cell slab per attribute + for(int aid=0; aid=0; --i) { + cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); + tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; + } +} + +template +void ArraySortedReadState::calculate_cell_slab_info_col_row( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + + // Calculate number of cells in cell slab + tile_slab_info_[id].cell_slab_num_[tid] = 1; + + // Calculate size of a cell slab per attribute + for(int aid=0; aid=0; --i) { + cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); + tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; + } +} + +template +void ArraySortedReadState::calculate_cell_slab_info_row_col( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + + // Calculate number of cells in cell slab + tile_slab_info_[id].cell_slab_num_[tid] = 1; + + // Calculate size of a cell slab per attribute + for(int aid=0; aid +void ArraySortedReadState::calculate_tile_domain(int id) { + // Initializations + tile_coords_ = malloc(coords_size_); + tile_domain_ = malloc(2*coords_size_); + + // For easy reference + const T* tile_slab = (const T*) tile_slab_norm_[id]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + T* tile_coords = (T*) tile_coords_; + T* tile_domain = (T*) tile_domain_; + + // Calculate tile domain and initial tile coordinates + for(int i=0; i +void ArraySortedReadState::calculate_tile_slab_info(int id) { // Calculate number of tiles, if they are not already calculated - int64_t tile_num = array_->array_schema()->tile_num(tile_slab_[id]); if(tile_slab_info_[id].tile_num_ == -1) - init_tile_slab_info(id, tile_num); + init_tile_slab_info(id); - // TODO + // Calculate tile domain, if not calculated yet + if(tile_domain_ == NULL) + calculate_tile_domain(id); + + ASRS_Data asrs_data = { id, 0, this }; + (*calculate_tile_slab_info_)(&asrs_data); +} + +template +void *ArraySortedReadState::calculate_tile_slab_info_col(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + asrs->calculate_tile_slab_info_col(id); + return NULL; +} + +template +void ArraySortedReadState::calculate_tile_slab_info_col(int id) { + // For easy reference + const T* tile_domain = (const T*) tile_domain_; + T* tile_coords = (T*) tile_coords_; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + T** range_overlap = (T**) tile_slab_info_[id].range_overlap_; + const T* tile_slab = (const T*) tile_slab_norm_[id]; + int64_t tile_offset, tile_cell_num, total_cell_num = 0; + int anum = (int) attribute_ids_.size(); + int d; + + // Iterate over all tiles in the tile domain + int64_t tid=0; // Tile id + while(tile_coords[dim_num_-1] <= tile_domain[2*(dim_num_-1)+1]) { + // Calculate range overlap, number of cells in the tile + tile_cell_num = 1; + for(int i=0; i tile_domain[2*d+1]) { + tile_coords[d] = tile_domain[2*d]; + ++tile_coords[++d]; + } + + // Advance tile id + ++tid; + } +} + +template +void *ArraySortedReadState::calculate_tile_slab_info_row(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + asrs->calculate_tile_slab_info_row(id); + return NULL; } template void ArraySortedReadState::calculate_tile_slab_info_row(int id) { - // Calculate number of tiles, if they are not already calculated - int64_t tile_num = array_->array_schema()->tile_num(tile_slab_[id]); - if(tile_slab_info_[id].tile_num_ == -1) - init_tile_slab_info(id, tile_num); + // For easy reference + const T* tile_domain = (const T*) tile_domain_; + T* tile_coords = (T*) tile_coords_; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + T** range_overlap = (T**) tile_slab_info_[id].range_overlap_; + const T* tile_slab = (const T*) tile_slab_norm_[id]; + int64_t tile_offset, tile_cell_num, total_cell_num = 0; + int anum = (int) attribute_ids_.size(); + int d; + + // Iterate over all tiles in the tile domain + int64_t tid=0; // Tile id + while(tile_coords[0] <= tile_domain[1]) { + // Calculate range overlap, number of cells in the tile + tile_cell_num = 1; + for(int i=0; i=0; --i) { + tile_offset *= (tile_domain[2*(i+1)+1] - tile_domain[2*(i+1)] + 1); + tile_slab_info_[id].tile_offset_per_dim_[i] = tile_offset; + } - // TODO + // Calculate cell slab info + ASRS_Data asrs_data = { id, tid, this }; + (*calculate_cell_slab_info_)(&asrs_data); + + // Calculate start offsets + for(int aid=0; aid 0 && tile_coords[d] > tile_domain[2*d+1]) { + tile_coords[d] = tile_domain[2*d]; + ++tile_coords[--d]; + } + + // Advance tile id + ++tid; + } } int ArraySortedReadState::cancel_copy_thread() { @@ -590,7 +961,7 @@ void ArraySortedReadState::copy_tile_slab(int aid, int bid) { buffer_offset += cell_slab_size; // Prepare for new slab - ASRS_Data asrs_data = { aid, this }; + ASRS_Data asrs_data = { aid, 0, this }; (*advance_cell_slab_)(&asrs_data); // Terminating condition @@ -669,7 +1040,7 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { buffer_offset_var += cell_slab_size_var; // Prepare for new slab - ASRS_Data asrs_data = { aid, this }; + ASRS_Data asrs_data = { aid, 0, this }; (*advance_cell_slab_)(&asrs_data); // Terminating condition @@ -747,9 +1118,6 @@ void ArraySortedReadState::free_tile_slab_info() { } delete [] tile_slab_info_[i].start_offsets_; - if(tile_slab_info_[i].tile_mapping_ != NULL) - delete [] tile_slab_info_[i].tile_mapping_; - delete [] tile_slab_info_[i].tile_offset_per_dim_; } } @@ -853,7 +1221,6 @@ void ArraySortedReadState::init_tile_slab_info() { tile_slab_info_[i].cell_slab_num_ = NULL; tile_slab_info_[i].range_overlap_ = NULL; tile_slab_info_[i].start_offsets_ = new size_t*[anum]; - tile_slab_info_[i].tile_mapping_ = NULL; tile_slab_info_[i].tile_offset_per_dim_ = new int64_t[dim_num_]; for(int j=0; j -void ArraySortedReadState::init_tile_slab_info(int id, int64_t tile_num) { +void ArraySortedReadState::init_tile_slab_info(int id) { // For easy reference int anum = (int) attribute_ids_.size(); + // Calculate tile number + int64_t tile_num = array_->array_schema()->tile_num(tile_slab_[id]); + + // Initializations tile_slab_info_[id].cell_offset_per_dim_ = new int64_t*[tile_num]; tile_slab_info_[id].cell_slab_num_ = new int64_t[tile_num]; tile_slab_info_[id].range_overlap_ = new void*[tile_num]; @@ -877,7 +1248,6 @@ void ArraySortedReadState::init_tile_slab_info(int id, int64_t tile_num) { tile_slab_info_[id].range_overlap_[i] = malloc(coords_size_); tile_slab_info_[id].cell_offset_per_dim_[i] = new int64_t[dim_num_]; } - tile_slab_info_[id].tile_mapping_ = new int64_t[tile_num]; for(int i=0; i(aio_id_); + calculate_tile_slab_info(aio_id_); // Success return true; @@ -1105,7 +1475,7 @@ bool ArraySortedReadState::next_tile_slab_row() { } // Calculate tile slab info and reset tile slab state - calculate_tile_slab_info_row(aio_id_); + calculate_tile_slab_info(aio_id_); // Success return true; @@ -1235,7 +1605,7 @@ int ArraySortedReadState::read_tile_slab() { // TODO: attribute overflows // Prepare AIO request - ASRS_Data asrs_data = { aio_id_, this }; + ASRS_Data asrs_data = { aio_id_, 0, this }; AIO_Request aio_request = {}; aio_request.buffers_ = buffers_[aio_id_]; aio_request.buffer_sizes_ = buffer_sizes_[aio_id_]; @@ -1403,7 +1773,7 @@ void ArraySortedReadState::update_current_tile_and_offset(int aid) { int64_t cid; // Calculate the new tile id - tid = tile_slab_info_[copy_id_].tile_mapping_[get_tile_id(aid)]; + tid = get_tile_id(aid); // Calculate the cell id cid = get_cell_id(aid); From 8fc98458ca7a2fdf32fc0c5465baf69d1b1777aa Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 30 Sep 2016 16:49:12 -0400 Subject: [PATCH 07/57] Finished dense sorted reads. Not tested yet. --- core/include/array/array_sorted_read_state.h | 32 +++++ core/src/array/array.cc | 8 ++ core/src/array/array_sorted_read_state.cc | 129 ++++++++++++++++--- 3 files changed, 150 insertions(+), 19 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 06696131..e4bb2a22 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -166,6 +166,12 @@ class ArraySortedReadState { /** Returns true if copying into the user buffers resulted in overflow. */ bool overflow() const; + /** + * Returns true if copying into the user buffers resulted in overflow, for + * the input attribute id. + */ + bool overflow(int attribute_id) const; + /** * Same as Array::read(), but it sorts the cells in the buffers based on the * order the user specified in Array::init(). Note that this function will @@ -216,6 +222,9 @@ class ArraySortedReadState { /** Function for advancing a cell slab during a copy operation. */ void *(*advance_cell_slab_) (void*); + /** AIO counter. */ + int aio_cnt_; + /** The AIO mutex conditions (one for each buffer). */ pthread_cond_t aio_cond_[2]; @@ -225,6 +234,9 @@ class ArraySortedReadState { /** The AIO mutex. */ pthread_mutex_t aio_mtx_; + /** Indicates overflow per tile slab per attribute upon an AIO operation. */ + bool* aio_overflow_[2]; + /** The array this sorted read state belongs to. */ Array* array_; @@ -243,6 +255,9 @@ class ArraySortedReadState { /** Allocated sizes for buffers_ (similar to those used in Array::read). */ size_t* buffer_sizes_[2]; + /** Temporary buffer sizes used in AIO requests. */ + size_t* buffer_sizes_tmp_[2]; + /** Local buffers (similar to those used in Array::read). */ void** buffers_[2]; @@ -377,6 +392,9 @@ class ArraySortedReadState { */ static void *aio_done(void* data); + /** True if some attribute overflowed for the input tile slab upon an AIO. */ + bool aio_overflow(int aio_id); + /** Sets the flag of wait_aio_[id] to true. */ void block_aio(int id); @@ -817,6 +835,12 @@ class ArraySortedReadState { */ int release_overflow(); + /** Resets the AIO overflow flags for the input tile slab id. */ + void reset_aio_overflow(int aio_id); + + /** Resets the temporary buffer sizes for the input tile slab id. */ + void reset_buffer_sizes_tmp(int id); + /** Resets the copy state using the input buffer info. */ void reset_copy_state(void** buffers, size_t* buffer_sizes); @@ -832,6 +856,14 @@ class ArraySortedReadState { template void reset_tile_slab_state(); + /** + * Sends an AIO request. + * + * @param aio_id The id of the tile slab the AIO request focuses on. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int send_aio_request(int aio_id); + /** * Unlocks the AIO mutex. * diff --git a/core/src/array/array.cc b/core/src/array/array.cc index e42b4017..de78ffd0 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -68,6 +68,7 @@ std::string tiledb_ar_errmsg = ""; Array::Array() { array_read_state_ = NULL; + array_sorted_read_state_ = NULL; array_schema_ = NULL; subarray_ = NULL; aio_thread_created_ = false; @@ -230,10 +231,17 @@ bool Array::overflow() const { if(!read_mode()) return false; + // Check the array sorted read state first + if(array_sorted_read_state_ != NULL && + array_sorted_read_state_->overflow()) + return true; + + // Check the (non-sorted) array read state next for(int i=0; i @@ -72,10 +73,11 @@ ArraySortedReadState::ArraySortedReadState( int anum = (int) attribute_ids_.size(); // Initializations + aio_id_ = 0; + aio_cnt_ = 0; coords_size_ = array_schema->coords_size(); copy_id_ = 0; dim_num_ = array_schema->dim_num(); - aio_id_ = 0; copy_thread_running_ = false; read_tile_slabs_done_ = false; resume_copy_ = false; @@ -83,7 +85,9 @@ ArraySortedReadState::ArraySortedReadState( tile_coords_ = NULL; tile_domain_ = NULL; for(int i=0; i<2; ++i) { + aio_overflow_[i] = new bool[anum]; buffer_sizes_[i] = NULL; + buffer_sizes_tmp_[i] = NULL; buffers_[i] = NULL; tile_slab_[i] = NULL; tile_slab_norm_[i] = NULL; @@ -117,8 +121,12 @@ ArraySortedReadState::~ArraySortedReadState() { free(tile_domain_); for(int i=0; i<2; ++i) { + delete [] aio_overflow_[i]; + if(buffer_sizes_[i] != NULL) delete [] buffer_sizes_[i]; + if(buffer_sizes_tmp_[i] != NULL) + delete [] buffer_sizes_tmp_[i]; if(buffers_[i] != NULL) { for(int b=0; basrs_; int id = ((ASRS_Data*) data)->id_; - asrs->block_copy(id); - asrs->release_aio(id); + + // For easy reference + int anum = (int) asrs->attribute_ids_.size(); + const ArraySchema* array_schema = asrs->array_->array_schema(); + + // Check for overflow and update buffer sizes + bool overflow = false; + for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + } else { // VAR + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + if(asrs->aio_overflow_[id][i]) { + // Expand buffers + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + overflow = true; + } else { + asrs->buffer_sizes_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + } + ++b; + } + } + + if(overflow) { // OVERFLOW + // Send the request again + asrs->send_aio_request(id); + } else { // NO OVERFLOW + // Manage the mutexes and conditions + asrs->block_copy(id); + asrs->release_aio(id); + } return NULL; } +bool ArraySortedReadState::aio_overflow(int aio_id) { + // For easy reference + int anum = (int) attribute_ids_.size(); + + for(int i=0; ivar_size(attribute_ids_[i])) { @@ -1064,7 +1128,7 @@ int ArraySortedReadState::create_buffers() { } for(int b=0; b < buffer_num_; ++b) { - buffers_[j][b] = aligned_alloc(ALIGNMENT, buffer_sizes_[j][b]); + buffers_[j][b] = malloc(buffer_sizes_[j][b]); if(buffers_[j][b] == NULL) { std::string errmsg = "Cannot allocate local buffer"; PRINT_ERROR(errmsg); @@ -1600,24 +1664,16 @@ int ArraySortedReadState::read_tile_slab() { resume_aio_ = true; return TILEDB_ASRS_OK; } - - // TODO: This has to go in a loop to capture the case a variable-length - // TODO: attribute overflows - // Prepare AIO request - ASRS_Data asrs_data = { aio_id_, 0, this }; - AIO_Request aio_request = {}; - aio_request.buffers_ = buffers_[aio_id_]; - aio_request.buffer_sizes_ = buffer_sizes_[aio_id_]; - aio_request.subarray_ = tile_slab_[aio_id_]; - aio_request.completion_handle_ = aio_done; - aio_request.completion_data_ = &asrs_data; + // Reset AIO overflow flags + reset_aio_overflow(aio_id_); - // Send the AIO request - if(array_->aio_read(&aio_request) != TILEDB_AR_OK) { - // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; + // Reset temporary buffer sizes + reset_buffer_sizes_tmp(aio_id_); + + // Send AIO request + if(send_aio_request(aio_id_) != TILEDB_ASRS_OK) return TILEDB_ASRS_ERR; - } // Change aio_id_ aio_id_ = (aio_id_ + 1) % 2; @@ -1698,6 +1754,20 @@ int ArraySortedReadState::release_overflow() { return TILEDB_ASRS_OK; } +void ArraySortedReadState::reset_aio_overflow(int aio_id) { + // For easy reference + int anum = (int) attribute_ids_.size(); + + // Reset aio_overflow_ + for(int i=0; iaio_read(&aio_request) != TILEDB_AR_OK) { + // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + int ArraySortedReadState::unlock_aio_mtx() { if(pthread_mutex_unlock(&aio_mtx_)) { std::string errmsg = "Cannot unlock AIO mutex"; From 695b353d4b980f626110bdc1007a63f14dcdfdcc Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 3 Oct 2016 18:21:47 -0400 Subject: [PATCH 08/57] Finished preliminary testing and debugging of dense sorted reads --- core/include/array/aio_request.h | 9 + core/include/array/array.h | 10 + core/include/array/array_sorted_read_state.h | 28 +- core/src/array/array.cc | 94 +++++- core/src/array/array_sorted_read_state.cc | 297 ++++++++++++------ core/src/c_api/c_api.cc | 2 + .../src/tiledb_array_read_sorted_dense.cc | 9 +- 7 files changed, 346 insertions(+), 103 deletions(-) diff --git a/core/include/array/aio_request.h b/core/include/array/aio_request.h index bfb54d47..9f1a2b0c 100644 --- a/core/include/array/aio_request.h +++ b/core/include/array/aio_request.h @@ -61,6 +61,15 @@ struct AIO_Request { void* completion_data_; /** A unique request id. */ size_t id_; + /** + * It can be one of the following: + * - TILEDB_ARRAY_READ + * - TILEDB_ARRAY_READ_SORTED_COL + * - TILEDB_ARRAY_READ_SORTED_ROW + * - TILEDB_ARRAY_WRITE + * - TILEDB_ARRAY_WRITE_UNSORTED + */ + int mode_; /** * Applicable only to read requests. * Indicates whether a buffer has overflowed during a read request. diff --git a/core/include/array/array.h b/core/include/array/array.h index c9a42ba6..06b4be4e 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -324,6 +324,16 @@ class Array { */ int reset_subarray(const void* subarray); + /** + * Same as reset_subarray(), with the difference that the + * ArraySortedReadState object of the array is not re-initialized. + * + * @param subarray The new subarray. Note that the type of the values in + * *subarray* should match the coordinates type in the array schema. + * @return TILEDB_AR_OK on success, and TILEDB_AR_ERR on error. + */ + int reset_subarray_soft(const void* subarray); + /** * Performs a write operation in the array. The cell values are provided * in a set of buffers (one per attribute specified upon initialization). diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index e4bb2a22..b46793fa 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -228,6 +228,9 @@ class ArraySortedReadState { /** The AIO mutex conditions (one for each buffer). */ pthread_cond_t aio_cond_[2]; + /** Data for the AIO requests. */ + ASRS_Data aio_data_[2]; + /** The current id of the buffers the next AIO will occur into. */ int aio_id_; @@ -237,6 +240,12 @@ class ArraySortedReadState { /** Indicates overflow per tile slab per attribute upon an AIO operation. */ bool* aio_overflow_[2]; + /** AIO requests. */ + AIO_Request aio_request_[2]; + + /** The status of the AIO requests.*/ + int aio_status_[2]; + /** The array this sorted read state belongs to. */ Array* array_; @@ -298,7 +307,7 @@ class ArraySortedReadState { pthread_mutex_t overflow_mtx_; /** Overflow flag for each attribute. */ - std::vector overflow_; + bool* overflow_; /** True if no more tile slabs to read. */ bool read_tile_slabs_done_; @@ -310,7 +319,7 @@ class ArraySortedReadState { bool resume_aio_; /** The query subarray. */ - const void* subarray_; + void* subarray_; /** Auxiliary variable used in calculate_tile_slab_info(). */ void* tile_coords_; @@ -321,6 +330,9 @@ class ArraySortedReadState { /** The tile slab to be read for the first and second buffers. */ void* tile_slab_[2]; + /** Indicates if the tile slab has been initialized. */ + bool tile_slab_init_[2]; + /** Normalized tile slab. */ void* tile_slab_norm_[2]; @@ -690,6 +702,9 @@ class ArraySortedReadState { template void handle_copy_requests(); + /** Initializes the AIO requests. */ + void init_aio_requests(); + /** Initializes the copy state. */ void init_copy_state(); @@ -846,6 +861,15 @@ class ArraySortedReadState { /** Resets the oveflow flags to **false**. */ void reset_overflow(); + + /** + * Resets the tile_coords_ auxiliary variable. + * + * @template T The domain type. + * @return void. + */ + template + void reset_tile_coords(); /** * Resets the tile slab state. diff --git a/core/src/array/array.cc b/core/src/array/array.cc index de78ffd0..e166ba84 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -152,9 +152,6 @@ void Array::aio_handle_requests() { // Set last handled AIO request aio_last_handled_request_ = aio_next_request->id_; - - // Clean request - free(aio_next_request); } } @@ -638,7 +635,7 @@ int Array::init( } aio_thread_canceled_ = false; aio_thread_created_ = false; - aio_last_handled_request_ = 0; + aio_last_handled_request_ = -1; // Return return TILEDB_AR_OK; @@ -766,6 +763,61 @@ int Array::reset_subarray(const void* subarray) { return TILEDB_AR_OK; } +int Array::reset_subarray_soft(const void* subarray) { + // Sanity check + assert(read_mode() || write_mode()); + + // For easy referencd + int fragment_num = fragments_.size(); + + // Finalize fragments if in write mode + if(write_mode()) { + // Finalize and delete fragments + for(int i=0; ifinalize(); + delete fragments_[i]; + } + fragments_.clear(); + } + + // Set subarray + size_t subarray_size = 2*array_schema_->coords_size(); + if(subarray_ == NULL) + subarray_ = malloc(subarray_size); + if(subarray == NULL) + memcpy(subarray_, array_schema_->domain(), subarray_size); + else + memcpy(subarray_, subarray, subarray_size); + + // Re-set of re-initialize fragments + if(write_mode()) { // WRITE MODE + // Get new fragment name + std::string new_fragment_name = this->new_fragment_name(); + if(new_fragment_name == "") + return TILEDB_AS_ERR; + + // Create new fragment + Fragment* fragment = new Fragment(this); + fragments_.push_back(fragment); + if(fragment->init(new_fragment_name, mode_, subarray) != TILEDB_FG_OK) + return TILEDB_AR_ERR; + } else { // READ MODE + // Re-initialize the read state of the fragments + for(int i=0; ireset_read_state(); + + // Re-initialize array read state + if(array_read_state_ != NULL) { + delete array_read_state_; + array_read_state_ = NULL; + } + array_read_state_ = new ArrayReadState(this); + } + + // Success + return TILEDB_AR_OK; +} + int Array::write(const void** buffers, const size_t* buffer_sizes) { // Sanity checks if(!write_mode()) { @@ -828,20 +880,41 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { if(read_mode()) { // READ MODE // Reset the subarray only if this request does not continue from the last if(aio_last_handled_request_ != aio_request->id_) - rc = reset_subarray(aio_request->subarray_); + rc = reset_subarray_soft(aio_request->subarray_); // Invoke the read - if(rc == TILEDB_AR_OK) - rc = read(aio_request->buffers_, aio_request->buffer_sizes_); + if(rc == TILEDB_AR_OK) { + if(aio_request->mode_ == TILEDB_ARRAY_READ) { + + +const int64_t* s = (const int64_t*) subarray_; +std::cout << "SUBARRAY: " << s[0] << " " << s[1] << " " << s[2] << " " << s[3] << "\n"; + + rc = read_default(aio_request->buffers_, aio_request->buffer_sizes_); + +std::cout << "=== buffer sizes: " << aio_request->buffer_sizes_[0] << " ===\n"; + + } else { + rc = read(aio_request->buffers_, aio_request->buffer_sizes_); + } + } } else { // WRITE MODE + // TODO: Fix according to read above rc = write( (const void**) aio_request->buffers_, (const size_t*) aio_request->buffer_sizes_); } if(rc == TILEDB_AR_OK) { // Success + +std::cout << "=== AIO done === \n"; + // Check for overflow if(overflow()) { + + +std::cout << "=== OVERFLOW === \n"; + *aio_request->status_= TILEDB_AIO_OVERFLOW; if(aio_request->overflow_ != NULL) { for(int i=0; istatus_= TILEDB_AIO_COMPLETED; - // Invoke the callback - if(aio_request->completion_handle_ != NULL) + +std::cout << "=== CALLBACK === \n"; + + if(aio_request->completion_handle_ != NULL) { (*(aio_request->completion_handle_))(aio_request->completion_data_); + } } } else { // Error *aio_request->status_= TILEDB_AIO_ERR; diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 3d8d2e99..9b7f62aa 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -66,8 +66,7 @@ std::string tiledb_asrs_errmsg = ""; ArraySortedReadState::ArraySortedReadState( Array* array) : array_(array), - attribute_ids_(array->attribute_ids()), - subarray_(array->subarray()) { + attribute_ids_(array->attribute_ids()) { // For easy reference const ArraySchema* array_schema = array_->array_schema(); int anum = (int) attribute_ids_.size(); @@ -89,12 +88,13 @@ ArraySortedReadState::ArraySortedReadState( buffer_sizes_[i] = NULL; buffer_sizes_tmp_[i] = NULL; buffers_[i] = NULL; - tile_slab_[i] = NULL; - tile_slab_norm_[i] = NULL; + tile_slab_[i] = malloc(2*coords_size_); + tile_slab_norm_[i] = malloc(2*coords_size_); + tile_slab_init_[i] = false; wait_copy_[i] = false; wait_aio_[i] = true; } - overflow_.resize(anum); + overflow_ = new bool[anum]; for(int i=0; ivar_size(attribute_ids_[i])) @@ -103,6 +103,9 @@ ArraySortedReadState::ArraySortedReadState( attribute_sizes_.push_back(array_schema->cell_size(attribute_ids_[i])); } + subarray_ = malloc(2*coords_size_); + memcpy(subarray_, array_->subarray(), 2*coords_size_); + // Calculate number of buffers calculate_buffer_num(); @@ -117,8 +120,10 @@ ArraySortedReadState::ArraySortedReadState( ArraySortedReadState::~ArraySortedReadState() { // Clean up + free(subarray_); free(tile_coords_); free(tile_domain_); + delete [] overflow_; for(int i=0; i<2; ++i) { delete [] aio_overflow_[i]; @@ -132,10 +137,9 @@ ArraySortedReadState::~ArraySortedReadState() { free(buffers_[i][b]); free(buffers_[i]); } - if(tile_slab_[i] != NULL) - free(tile_slab_[i]); - if(tile_slab_norm_[i] != NULL) - free(tile_slab_norm_[i]); + + free(tile_slab_[i]); + free(tile_slab_norm_[i]); } // Destroy thread, conditions and mutexes @@ -189,7 +193,7 @@ ArraySortedReadState::~ArraySortedReadState() { /* ****************************** */ bool ArraySortedReadState::copy_tile_slab_done() const { - for(int i=0; (int) attribute_ids_.size(); ++i) { + for(int i=0; i < (int) attribute_ids_.size(); ++i) { if(!tile_slab_state_.copy_tile_slab_done_[i]) return false; } @@ -205,8 +209,8 @@ bool ArraySortedReadState::done() const { } bool ArraySortedReadState::overflow() const { - for(int i=0; (int) attribute_ids_.size(); ++i) { - if(overflow_[i]) + for(int i=0; i < (int) attribute_ids_.size(); ++i) { + if(overflow_[i]) return true; } @@ -214,7 +218,7 @@ bool ArraySortedReadState::overflow() const { } bool ArraySortedReadState::overflow(int attribute_id) const { - for(int i=0; (int) attribute_ids_.size(); ++i) { + for(int i=0; i < (int) attribute_ids_.size(); ++i) { if(attribute_ids_[i] == attribute_id) return overflow_[i]; } @@ -266,6 +270,9 @@ int ArraySortedReadState::init() { if(create_buffers() != TILEDB_ASRS_OK) return TILEDB_ASRS_ERR; + // Create AIO requests + init_aio_requests(); + // Create the thread that will be handling all the copying if(pthread_create( ©_thread_, @@ -522,8 +529,10 @@ void *ArraySortedReadState::aio_done(void* data) { asrs->send_aio_request(id); } else { // NO OVERFLOW // Manage the mutexes and conditions - asrs->block_copy(id); + +std::cout << "AIO done!\n"; asrs->release_aio(id); +std::cout << "Released AIO: " << id << " \n"; } return NULL; @@ -542,17 +551,17 @@ bool ArraySortedReadState::aio_overflow(int aio_id) { } void ArraySortedReadState::block_aio(int id) { - lock_copy_mtx(); - wait_copy_[id] = true; - unlock_copy_mtx(); -} - -void ArraySortedReadState::block_copy(int id) { lock_aio_mtx(); wait_aio_[id] = true; unlock_aio_mtx(); } +void ArraySortedReadState::block_copy(int id) { + lock_copy_mtx(); + wait_copy_[id] = true; + unlock_copy_mtx(); +} + void ArraySortedReadState::block_overflow() { lock_overflow_mtx(); resume_copy_ = true; @@ -687,7 +696,7 @@ void ArraySortedReadState::calculate_cell_slab_info_row_row( const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; const T* tile_domain = (const T*) tile_domain_; int64_t tile_num, cell_num; - + // Calculate number of cells in cell slab cell_num = range_overlap[2*(dim_num_-1)+1] - range_overlap[2*(dim_num_-1)] +1; for(int i=dim_num_-1; i>0; --i) { @@ -781,6 +790,11 @@ void ArraySortedReadState::calculate_tile_domain(int id) { tile_domain[2*i] = tile_slab[2*i] / tile_extents[i]; tile_domain[2*i+1] = tile_slab[2*i+1] / tile_extents[i]; } + +std::cout << "Tile domain: " + << tile_domain[0] << " " << tile_domain[1] << " " + << tile_domain[2] << " " << tile_domain[3] << "\n"; + } template @@ -793,6 +807,10 @@ void ArraySortedReadState::calculate_tile_slab_info(int id) { if(tile_domain_ == NULL) calculate_tile_domain(id); + // Reset tile coordinates + reset_tile_coords(); + + // Calculate tile slab info ASRS_Data asrs_data = { id, 0, this }; (*calculate_tile_slab_info_)(&asrs_data); } @@ -827,7 +845,7 @@ void ArraySortedReadState::calculate_tile_slab_info_col(int id) { range_overlap[tid][2*i] = std::max(tile_coords[i] * tile_extents[i], tile_slab[2*i]); range_overlap[tid][2*i+1] = - std::min(tile_coords[i] * (tile_extents[i]+1) - 1, tile_slab[2*i+1]); + std::min((tile_coords[i]+1) * tile_extents[i] - 1, tile_slab[2*i+1]); // Number of cells in this tile tile_cell_num *= range_overlap[tid][2*i+1] - range_overlap[tid][2*i] + 1; @@ -847,7 +865,7 @@ void ArraySortedReadState::calculate_tile_slab_info_col(int id) { // Calculate start offsets for(int aid=0; aid buffer_size) { + +std::cout << "OVERFLOW !!!\n"; +std::cout << "buffer offset: " << buffer_offset << "\n"; +std::cout << "buffer size: " << buffer_size << "\n"; +std::cout << "cell slab size: " << cell_slab_size << "\n"; + overflow_[aid] = true; break; } // Copy cell slab + +std::cout << "buffer offset: " << buffer_offset << "\n"; +std::cout << "local buffer offset: " << local_buffer_offset << "\n"; + memcpy( buffer + buffer_offset, local_buffer + local_buffer_offset, @@ -1035,6 +1094,8 @@ void ArraySortedReadState::copy_tile_slab(int aid, int bid) { // Set user buffer size buffer_size = buffer_offset; + +std::cout << "--- Finished copying " << copy_id_ << " ---\n"; } void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { @@ -1240,9 +1301,14 @@ template void ArraySortedReadState::handle_copy_requests() { // Handle copy requests indefinitely for(;;) { + +std::cout << "--- Waiting on AIO... ---\n"; + // Wait for AIO wait_aio(copy_id_); +std::cout << "--- Finished waiting on AIO... ---\n"; + // Reset the tile slab state if(copy_tile_slab_done()) reset_tile_slab_state(); @@ -1259,6 +1325,8 @@ void ArraySortedReadState::handle_copy_requests() { continue; } +std::cout << "--- Copy is done ---\n"; + // Copy is done block_aio(copy_id_); release_copy(copy_id_); @@ -1266,6 +1334,21 @@ void ArraySortedReadState::handle_copy_requests() { } } +void ArraySortedReadState::init_aio_requests() { + for(int i=0; i<2; ++i) { + aio_data_[i] = { i, 0, this }; + aio_request_[i] = {}; + aio_request_[i].buffer_sizes_ = buffer_sizes_tmp_[i]; + aio_request_[i].buffers_ = buffers_[i]; + aio_request_[i].mode_ = TILEDB_ARRAY_READ; + aio_request_[i].subarray_ = tile_slab_[i]; + aio_request_[i].completion_handle_ = aio_done; + aio_request_[i].completion_data_ = &(aio_data_[i]); + aio_request_[i].overflow_ = aio_overflow_[i]; + aio_request_[i].status_ = &(aio_status_[i]); + } +} + void ArraySortedReadState::init_copy_state() { copy_state_.buffer_sizes_ = NULL; copy_state_.buffers_ = NULL; @@ -1387,12 +1470,6 @@ bool ArraySortedReadState::next_tile_slab_col() { return true; } - // Allocate space for the tile slab if necessary - if(tile_slab_[aio_id_] == NULL) - tile_slab_[aio_id_] = malloc(2*coords_size_); - if(tile_slab_norm_[aio_id_] == NULL) - tile_slab_norm_[aio_id_] = malloc(2*coords_size_); - // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -1402,17 +1479,18 @@ bool ArraySortedReadState::next_tile_slab_col() { T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); for(int i=0; i<2; ++i) tile_slab[i] = static_cast(tile_slab_[i]); - int prev_id = (aio_id_-1)%2; + int prev_id = (aio_id_+1)%2; + T tile_start; // Check again if done, this time based on the tile slab and subarray - if(tile_slab[prev_id] != NULL && + if(tile_slab_init_[prev_id] && tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { read_tile_slabs_done_ = true; return false; } // If this is the first time this function is called, initialize - if(tile_slab[prev_id] == NULL) { + if(!tile_slab_init_[prev_id]) { // Crop the subarray extent along the first axis to fit in the first tile tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; T upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; @@ -1421,17 +1499,11 @@ bool ArraySortedReadState::next_tile_slab_col() { tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; tile_slab[aio_id_][2*(dim_num_-1)+1] = std::min(cropped_upper - 1, subarray[2*(dim_num_-1)+1]); - tile_slab_norm[2*(dim_num_-1)] = - tile_slab[aio_id_][2*(dim_num_-1)] - domain[2*(dim_num_-1)]; - tile_slab_norm[2*(dim_num_-1)+1] = - tile_slab[aio_id_][2*(dim_num_-1)+1] - domain[2*(dim_num_-1)]; // Leave the rest of the subarray extents intact for(int i=0; i(aio_id_); + // Mark this tile slab as initialized + tile_slab_init_[aio_id_] = true; + // Success return true; } @@ -1476,11 +1559,7 @@ bool ArraySortedReadState::next_tile_slab_row() { return true; } - // Allocate space for the tile slab if necessary - if(tile_slab_[aio_id_] == NULL) - tile_slab_[aio_id_] = malloc(2*coords_size_); - if(tile_slab_norm_[aio_id_] == NULL) - tile_slab_norm_[aio_id_] = malloc(2*coords_size_); +std::cout << "--- Next tile slab ---\n"; // For easy reference const ArraySchema* array_schema = array_->array_schema(); @@ -1491,32 +1570,32 @@ bool ArraySortedReadState::next_tile_slab_row() { T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); for(int i=0; i<2; ++i) tile_slab[i] = static_cast(tile_slab_[i]); - int prev_id = (aio_id_-1)%2; + int prev_id = (aio_id_+1)%2; + T tile_start; // Check again if done, this time based on the tile slab and subarray - if(tile_slab[prev_id] != NULL && + if(tile_slab_init_[prev_id] && tile_slab[prev_id][1] == subarray[1]) { read_tile_slabs_done_ = true; + +std::cout << "--- DONE --- \n"; + return false; } // If this is the first time this function is called, initialize - if(tile_slab[prev_id] == NULL) { + if(!tile_slab_init_[prev_id]) { // Crop the subarray extent along the first axis to fit in the first tile tile_slab[aio_id_][0] = subarray[0]; T upper = subarray[0] + tile_extents[0]; T cropped_upper = (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); - tile_slab_norm[0] = tile_slab[aio_id_][0] - domain[0]; - tile_slab_norm[1] = tile_slab[aio_id_][1] - domain[0]; // Leave the rest of the subarray extents intact for(int i=1; i(aio_id_); + // Mark this tile slab as initialized + tile_slab_init_[aio_id_] = true; + // Success return true; } @@ -1591,12 +1683,18 @@ int ArraySortedReadState::read_dense_sorted_col() { } // Wait for copy to finish - for(int i=0; i<2; ++i) - wait_copy(i); + int prev = (aio_id_ + 1) % 2; +std::cout << "--- Waiting for copy to finish ---\n"; + wait_copy(prev); +std::cout << "--- Finished waiting for copy ---\n"; + + // Assign the true buffer sizes + for(int i=0; i()) { // Read the next tile slab with the default cell order @@ -1626,13 +1726,19 @@ int ArraySortedReadState::read_dense_sorted_row() { break; } - // Wait for copy to finish - for(int i=0; i<2; ++i) - wait_copy(i); + // Wait for copy and AIO to finish + int prev = (aio_id_ + 1) % 2; +std::cout << "--- Waiting for copy to finish ---\n"; + wait_copy(prev); +std::cout << "--- Finished waiting for copy ---\n"; + + // Assign the true buffer sizes + for(int i=0; i +void ArraySortedReadState::reset_tile_coords() { + T* tile_coords = (T*) tile_coords_; + for(int i=0; i void ArraySortedReadState::reset_tile_slab_state() { // For easy reference @@ -1800,22 +1926,17 @@ void ArraySortedReadState::reset_tile_slab_state() { } int ArraySortedReadState::send_aio_request(int aio_id) { - ASRS_Data asrs_data = { aio_id, 0, this }; - AIO_Request aio_request = {}; - aio_request.buffer_sizes_ = buffer_sizes_tmp_[aio_id]; - aio_request.buffers_ = buffers_[aio_id]; - aio_request.id_ = aio_cnt_++; - aio_request.subarray_ = tile_slab_[aio_id]; - aio_request.completion_handle_ = aio_done; - aio_request.completion_data_ = &asrs_data; - aio_request.overflow_ = aio_overflow_[aio_id]; + // Important!! + aio_request_[aio_id].id_ = aio_cnt_++; // Send the AIO request - if(array_->aio_read(&aio_request) != TILEDB_AR_OK) { + if(array_->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; return TILEDB_ASRS_ERR; } +std::cout << "AIO request sent\n"; + // Success return TILEDB_ASRS_OK; } diff --git a/core/src/c_api/c_api.cc b/core/src/c_api/c_api.cc index 48d8affb..3c43a2ea 100644 --- a/core/src/c_api/c_api.cc +++ b/core/src/c_api/c_api.cc @@ -1533,6 +1533,7 @@ int tiledb_array_aio_read( aio_request->id_ = (size_t) tiledb_aio_request; aio_request->buffers_ = tiledb_aio_request->buffers_; aio_request->buffer_sizes_ = tiledb_aio_request->buffer_sizes_; + aio_request->mode_ = tiledb_array->array_->mode(); aio_request->status_ = &(tiledb_aio_request->status_); aio_request->subarray_ = tiledb_aio_request->subarray_; aio_request->completion_handle_ = tiledb_aio_request->completion_handle_; @@ -1560,6 +1561,7 @@ int tiledb_array_aio_write( aio_request->id_ = (size_t) tiledb_aio_request; aio_request->buffers_ = tiledb_aio_request->buffers_; aio_request->buffer_sizes_ = tiledb_aio_request->buffer_sizes_; + aio_request->mode_ = tiledb_array->array_->mode(); aio_request->status_ = &(tiledb_aio_request->status_); aio_request->subarray_ = tiledb_aio_request->subarray_; aio_request->completion_handle_ = tiledb_aio_request->completion_handle_; diff --git a/examples/src/tiledb_array_read_sorted_dense.cc b/examples/src/tiledb_array_read_sorted_dense.cc index 2a4d95b6..852f031c 100644 --- a/examples/src/tiledb_array_read_sorted_dense.cc +++ b/examples/src/tiledb_array_read_sorted_dense.cc @@ -41,7 +41,7 @@ int main() { tiledb_ctx_init(&tiledb_ctx, NULL); // Subarray and attributes - int64_t subarray[] = { 1, 4, 1, 2 }; + int64_t subarray[] = { 1, 2, 1, 4 }; const char* attributes[] = { "a1" }; // Initialize array @@ -56,24 +56,25 @@ int main() { 1); // Number of attributes // Prepare cell buffers - int buffer_a1[3]; + int buffer_a1[9]; void* buffers[] = { buffer_a1 }; size_t buffer_sizes[] = { sizeof(buffer_a1) }; // Loop until no overflow printf(" a1\n----\n"); - do { +// do { printf("Reading cells...\n"); // Read from array tiledb_array_read(tiledb_array, buffers, buffer_sizes); // Print cell values + printf("Printing cells...\n"); int64_t result_num = buffer_sizes[0] / sizeof(int); for(int i=0; i Date: Tue, 4 Oct 2016 15:24:21 -0400 Subject: [PATCH 09/57] Finished some more debugging. --- core/include/array/array_sorted_read_state.h | 7 -- core/src/array/array.cc | 9 +++ core/src/array/array_sorted_read_state.cc | 70 +++++++++---------- core/src/storage_manager/storage_manager.cc | 3 +- .../src/tiledb_array_read_sorted_dense.cc | 14 ++-- 5 files changed, 55 insertions(+), 48 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index b46793fa..c8914b95 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -609,13 +609,6 @@ class ArraySortedReadState { template void calculate_tile_slab_info_row(int id); - /** - * Kills the copy thread (if it is still running). - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ - int cancel_copy_thread(); - /** * Function called by the copy thread. * diff --git a/core/src/array/array.cc b/core/src/array/array.cc index e166ba84..2c47b012 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -88,6 +88,9 @@ Array::~Array() { if(array_read_state_ != NULL) delete array_read_state_; + + if(array_sorted_read_state_ != NULL) + delete array_sorted_read_state_; } @@ -468,6 +471,12 @@ int Array::finalize() { array_read_state_ = NULL; } + // Clean the array sorted read state + if(array_sorted_read_state_ != NULL) { + delete array_sorted_read_state_; + array_sorted_read_state_ = NULL; + } + // Clean the AIO-related members int rc_aio_thread = aio_thread_destroy(); int rc_aio_cond = TILEDB_AR_OK, rc_aio_mtx = TILEDB_AR_OK; diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 9b7f62aa..26c6a5c8 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -140,9 +140,14 @@ ArraySortedReadState::~ArraySortedReadState() { free(tile_slab_[i]); free(tile_slab_norm_[i]); - } + } + + // Free tile slab info and state, and copy state + free_copy_state(); + free_tile_slab_state(); + free_tile_slab_info(); - // Destroy thread, conditions and mutexes + // Destroy conditions and mutexes for(int i=0; i<2; ++i) { if(pthread_cond_destroy(&(aio_cond_[i]))) { std::string errmsg = "Cannot destroy AIO mutex condition"; @@ -175,14 +180,7 @@ ArraySortedReadState::~ArraySortedReadState() { PRINT_ERROR(errmsg); tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; } - - // Kill copy thread - cancel_copy_thread(); - // Free tile slab info and state, and copy state - free_copy_state(); - free_tile_slab_state(); - free_tile_slab_info(); } @@ -977,24 +975,6 @@ std::cout << "Tile start offset: " } } -int ArraySortedReadState::cancel_copy_thread() { - // If the thread is not running, exit with success - if(!copy_thread_running_) - return TILEDB_ASRS_OK; - - // Kill copy thread - if(pthread_cancel(copy_thread_)) { - std::string errmsg = "Cannot destroy AIO thread"; - PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; - } - copy_thread_running_ = false; - - // Success - return TILEDB_ASRS_OK; -} - void *ArraySortedReadState::copy_handler(void* context) { // For easy reference ArraySortedReadState* asrs = (ArraySortedReadState*) context; @@ -1307,6 +1287,10 @@ std::cout << "--- Waiting on AIO... ---\n"; // Wait for AIO wait_aio(copy_id_); + // Kill thread + if(!copy_thread_running_) + return; + std::cout << "--- Finished waiting on AIO... ---\n"; // Reset the tile slab state @@ -1392,7 +1376,7 @@ void ArraySortedReadState::init_tile_slab_info(int id) { tile_slab_info_[id].cell_slab_num_ = new int64_t[tile_num]; tile_slab_info_[id].range_overlap_ = new void*[tile_num]; for(int64_t i=0; i()) { // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) + if(read_tile_slab() != TILEDB_ASRS_OK) { + +std::cout << "ERROOOOOOOOOOR\n"; + return TILEDB_ASRS_ERR; + } // Handle overflow if(resume_aio_) break; } +std::cout << "Resume AIO: " << resume_aio_ << "\n"; + // Wait for copy to finish int prev = (aio_id_ + 1) % 2; std::cout << "--- Waiting for copy to finish ---\n"; @@ -1692,9 +1686,13 @@ std::cout << "--- Finished waiting for copy ---\n"; for(int i=0; isecond->cnt_ == 0) { // Clean up book-keeping std::vector::iterator bit = it->second->book_keeping_.begin(); - for(; bit != it->second->book_keeping_.end(); ++bit) { + for(; bit != it->second->book_keeping_.end(); ++bit) delete *bit; - } // Unlock and destroy mutexes it->second->mutex_unlock(); diff --git a/examples/src/tiledb_array_read_sorted_dense.cc b/examples/src/tiledb_array_read_sorted_dense.cc index 852f031c..47b0496c 100644 --- a/examples/src/tiledb_array_read_sorted_dense.cc +++ b/examples/src/tiledb_array_read_sorted_dense.cc @@ -41,7 +41,7 @@ int main() { tiledb_ctx_init(&tiledb_ctx, NULL); // Subarray and attributes - int64_t subarray[] = { 1, 2, 1, 4 }; + int64_t subarray[] = { 1, 3, 1, 4 }; const char* attributes[] = { "a1" }; // Initialize array @@ -50,13 +50,13 @@ int main() { tiledb_ctx, // Context &tiledb_array, // Array object "my_workspace/dense_arrays/my_array_A", // Array name - TILEDB_ARRAY_READ_SORTED_ROW, // Mode + TILEDB_ARRAY_READ_SORTED_COL, // Mode subarray, // Constrain in subarray attributes, // Subset on attributes 1); // Number of attributes // Prepare cell buffers - int buffer_a1[9]; + int buffer_a1[16]; void* buffers[] = { buffer_a1 }; size_t buffer_sizes[] = { sizeof(buffer_a1) }; @@ -67,11 +67,17 @@ int main() { printf("Reading cells...\n"); // Read from array - tiledb_array_read(tiledb_array, buffers, buffer_sizes); + int rc = tiledb_array_read(tiledb_array, buffers, buffer_sizes); + +if(rc != TILEDB_OK) + printf("ERROR!!!\n"); // Print cell values printf("Printing cells...\n"); int64_t result_num = buffer_sizes[0] / sizeof(int); + +printf("Result num: %lld\n", result_num); + for(int i=0; i Date: Wed, 5 Oct 2016 13:55:57 -0400 Subject: [PATCH 10/57] Tested and debugged sorted dense reads for variable-sized attributes --- core/src/array/array_sorted_read_state.cc | 80 ++++++++++++++--------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 26c6a5c8..6a9d536e 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -500,29 +500,38 @@ void *ArraySortedReadState::aio_done(void* data) { int anum = (int) asrs->attribute_ids_.size(); const ArraySchema* array_schema = asrs->array_->array_schema(); - // Check for overflow and update buffer sizes + // Check for overflow bool overflow = false; - for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED - asrs->buffer_sizes_tmp_[id][b] = 0; - ++b; - } else { // VAR - asrs->buffer_sizes_tmp_[id][b] = 0; - ++b; - if(asrs->aio_overflow_[id][i]) { - // Expand buffers - expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); - asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; - overflow = true; - } else { - asrs->buffer_sizes_[id][b] = asrs->buffer_sizes_tmp_[id][b]; - asrs->buffer_sizes_tmp_[id][b] = 0; - } - ++b; + for(int i=0; iaio_overflow_[id][i]) { + overflow = true; + break; } } + if(overflow) { // OVERFLOW + // Update buffer sizes + for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + } else { // VAR + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + if(asrs->aio_overflow_[id][i]) { + // Expand buffers + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + overflow = true; + } else { + asrs->buffer_sizes_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + } + ++b; + } + } + // Send the request again asrs->send_aio_request(id); } else { // NO OVERFLOW @@ -1038,6 +1047,8 @@ std::cout << "--- Starting copying... " << copy_id_ << " ---\n"; size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; +std::cout << "CELL SLAB SIZE NON-VAR: " << cell_slab_size << "\n"; + // Handle overflow if(buffer_offset + cell_slab_size > buffer_size) { @@ -1095,12 +1106,12 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { size_t buffer_size_var = copy_state_.buffer_sizes_[bid+1]; char* buffer = (char*) copy_state_.buffers_[bid]; char* buffer_var = (char*) copy_state_.buffers_[bid+1]; - char* local_buffer = (char*) buffers_[copy_id_][bid]; char* local_buffer_var = (char*) buffers_[copy_id_][bid+1]; - size_t local_buffer_size = buffer_sizes_[copy_id_][bid]; - size_t local_buffer_var_size = buffer_sizes_[copy_id_][bid+1]; + size_t local_buffer_size = buffer_sizes_tmp_[copy_id_][bid]; + size_t local_buffer_var_size = buffer_sizes_tmp_[copy_id_][bid+1]; size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; int64_t cell_num_in_buffer = local_buffer_size / sizeof(size_t); + size_t var_offset = buffer_offset_var; // For all overlapping tiles, in a round-robin fashion for(;;) { @@ -1124,24 +1135,33 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { local_buffer_var_size - local_buffer_s[cell_start] : local_buffer_s[cell_end] - local_buffer_s[cell_start]; +std::cout << "CELL NUM IN BUFFER: " << cell_num_in_buffer << "\n"; +std::cout << "CELL START/END: " << cell_start << " " << cell_end << "\n"; +std::cout << "CELL SLAB SIZE VAR: " << cell_slab_size_var << "\n"; + // Handle overflow for the the variable-length buffer if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { overflow_[aid] = true; break; } - // Copy cell slabs - memcpy( - buffer + buffer_offset, - local_buffer + local_buffer_offset, - cell_slab_size); + // Copy fixed-sized offsets + for(int64_t i=cell_start; i()) { // Read the next tile slab with the default cell order From 3836625ee09bcb162646bc615448a8ebe79880c7 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 5 Oct 2016 17:40:18 -0400 Subject: [PATCH 11/57] Tested and debugged the 3D case for dense sorted reads. --- core/src/array/array_sorted_read_state.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 6a9d536e..2fdb3358 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -450,9 +450,11 @@ void ArraySortedReadState::advance_cell_slab_col(int aid) { // Advance cell slab coordinates int d = 0; current_coords[d] += cell_slab_num; - while(d < dim_num_-1 && current_coords[d] > tile_slab[2*d+1]) { - current_coords[d] = tile_slab[2*d]; - ++current_coords[++d]; + int64_t dim_overflow; + for(int i=0; i 0 && current_coords[d] > tile_slab[2*d+1]) { - current_coords[d] = tile_slab[2*d]; - ++current_coords[--d]; + int64_t dim_overflow; + for(int i=d; i>0; --i) { + dim_overflow = current_coords[i] / (tile_slab[2*i+1]-tile_slab[2*i]+1); + current_coords[i-1] += dim_overflow; + current_coords[i] -= dim_overflow * (tile_slab[2*i+1]-tile_slab[2*i]+1); } // Check if done From c79d4af696ec90514f89ee305a72f0cad633f61f Mon Sep 17 00:00:00 2001 From: spapadop Date: Thu, 6 Oct 2016 17:19:18 -0400 Subject: [PATCH 12/57] Finished testing and debugging cases of overflow for dense sorted reads. --- core/include/array/array_read_state.h | 3 + core/include/array/array_sorted_read_state.h | 12 ++ core/src/array/array.cc | 104 +++++------- core/src/array/array_read_state.cc | 9 + core/src/array/array_sorted_read_state.cc | 167 +++++-------------- 5 files changed, 112 insertions(+), 183 deletions(-) diff --git a/core/include/array/array_read_state.h b/core/include/array/array_read_state.h index 0ac7e681..56dc8a44 100644 --- a/core/include/array/array_read_state.h +++ b/core/include/array/array_read_state.h @@ -142,6 +142,9 @@ class ArrayReadState { /* ACCESSORS */ /* ********************************* */ + /** Indicates whether the read on at least one attribute overflowed. */ + bool overflow() const; + /** Indicates whether the read on a particular attribute overflowed. */ bool overflow(int attribute_id) const; diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index c8914b95..edc4bb17 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -267,6 +267,12 @@ class ArraySortedReadState { /** Temporary buffer sizes used in AIO requests. */ size_t* buffer_sizes_tmp_[2]; + /** + * Backup of temporary buffer sizes used in AIO requests (used when there is + * overflow). + */ + size_t* buffer_sizes_tmp_bak_[2]; + /** Local buffers (similar to those used in Array::read). */ void** buffers_[2]; @@ -309,6 +315,12 @@ class ArraySortedReadState { /** Overflow flag for each attribute. */ bool* overflow_; + /** + * Overflow flag for each attribute. It starts with *true* for all + * attributes, and becomes false once an attribute does not overflow any more. + */ + bool* overflow_still_; + /** True if no more tile slabs to read. */ bool read_tile_slabs_done_; diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 2c47b012..a15b5a16 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -112,10 +112,25 @@ void Array::aio_handle_requests() { PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; return; + } + + // If the thread is canceled, unblock and exit + if(aio_thread_canceled_) { + if(pthread_mutex_unlock(&aio_mtx_)) + PRINT_ERROR("Cannot unlock AIO mutex while canceling AIO thread"); + else + aio_thread_created_ = false; + return; } // Wait for AIO requests while(aio_queue_.size() == 0) { + // Wait to be signaled + if(pthread_cond_wait(&aio_cond_, &aio_mtx_)) { + PRINT_ERROR("Cannot wait on AIO mutex condition"); + return; + } + // If the thread is canceled, unblock and exit if(aio_thread_canceled_) { if(pthread_mutex_unlock(&aio_mtx_)) { @@ -128,16 +143,8 @@ void Array::aio_handle_requests() { } return; } - - // Wait to be signaled - if(pthread_cond_wait(&aio_cond_, &aio_mtx_)) { - std::string errmsg = "Cannot wait on AIO mutex condition"; - PRINT_ERROR(errmsg); - tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; - return; - } } - + // Pop the next AIO request aio_next_request = aio_queue_.front(); aio_queue_.pop(); @@ -231,18 +238,11 @@ bool Array::overflow() const { if(!read_mode()) return false; - // Check the array sorted read state first - if(array_sorted_read_state_ != NULL && - array_sorted_read_state_->overflow()) - return true; - - // Check the (non-sorted) array read state next - for(int i=0; ioverflow(); + else + return array_read_state_->overflow(); } bool Array::overflow(int attribute_id) const { @@ -251,9 +251,12 @@ bool Array::overflow(int attribute_id) const { // Trivial case if(fragments_.size() == 0) return false; - - // Check the array read state - return array_read_state_->overflow(attribute_id); + + // Check overflow + if(array_sorted_read_state_ != NULL) + return array_sorted_read_state_->overflow(attribute_id); + else + return array_read_state_->overflow(attribute_id); } int Array::read(void** buffers, size_t* buffer_sizes) { @@ -893,19 +896,10 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { // Invoke the read if(rc == TILEDB_AR_OK) { - if(aio_request->mode_ == TILEDB_ARRAY_READ) { - - -const int64_t* s = (const int64_t*) subarray_; -std::cout << "SUBARRAY: " << s[0] << " " << s[1] << " " << s[2] << " " << s[3] << "\n"; - + if(aio_request->mode_ == TILEDB_ARRAY_READ) rc = read_default(aio_request->buffers_, aio_request->buffer_sizes_); - -std::cout << "=== buffer sizes: " << aio_request->buffer_sizes_[0] << " ===\n"; - - } else { + else rc = read(aio_request->buffers_, aio_request->buffer_sizes_); - } } } else { // WRITE MODE // TODO: Fix according to read above @@ -915,30 +909,32 @@ std::cout << "=== buffer sizes: " << aio_request->buffer_sizes_[0] << " ===\n"; } if(rc == TILEDB_AR_OK) { // Success - -std::cout << "=== AIO done === \n"; - // Check for overflow - if(overflow()) { - + if(aio_request->mode_ == TILEDB_ARRAY_READ && + array_read_state_->overflow()) { -std::cout << "=== OVERFLOW === \n"; *aio_request->status_= TILEDB_AIO_OVERFLOW; if(aio_request->overflow_ != NULL) { for(int i=0; ioverflow_[i] = overflow(attribute_ids_[i]); + aio_request->overflow_[i] = + array_read_state_->overflow(attribute_ids_[i]); + } + } else if(aio_request->mode_ != TILEDB_ARRAY_READ && + array_sorted_read_state_->overflow()) { + *aio_request->status_= TILEDB_AIO_OVERFLOW; + if(aio_request->overflow_ != NULL) { + for(int i=0; ioverflow_[i] = + array_sorted_read_state_->overflow(attribute_ids_[i]); } } else { // Completion *aio_request->status_= TILEDB_AIO_COMPLETED; - // Invoke the callback - -std::cout << "=== CALLBACK === \n"; - - if(aio_request->completion_handle_ != NULL) { - (*(aio_request->completion_handle_))(aio_request->completion_data_); - } } + + // Invoke the callback + if(aio_request->completion_handle_ != NULL) + (*(aio_request->completion_handle_))(aio_request->completion_data_); } else { // Error *aio_request->status_= TILEDB_AIO_ERR; } @@ -1040,16 +1036,6 @@ int Array::aio_thread_destroy() { // Wait for cancelation to take place while(aio_thread_created_); - // Cancel thread - if(pthread_cancel(aio_thread_)) { - std::string errmsg = "Cannot destroy AIO thread"; - PRINT_ERROR(errmsg); - tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; - return TILEDB_AR_ERR; - } - - aio_thread_created_ = false; - // Success return TILEDB_AR_OK; } diff --git a/core/src/array/array_read_state.cc b/core/src/array/array_read_state.cc index e169200d..d7e8b77c 100644 --- a/core/src/array/array_read_state.cc +++ b/core/src/array/array_read_state.cc @@ -123,6 +123,15 @@ ArrayReadState::~ArrayReadState() { /* ACCESSORS */ /* ****************************** */ +bool ArrayReadState::overflow() const { + int attribute_num = (int) array_->attribute_ids().size(); + for(int i=0; ivar_size(attribute_ids_[i])) attribute_sizes_.push_back(sizeof(size_t)); else @@ -132,6 +135,8 @@ ArraySortedReadState::~ArraySortedReadState() { delete [] buffer_sizes_[i]; if(buffer_sizes_tmp_[i] != NULL) delete [] buffer_sizes_tmp_[i]; + if(buffer_sizes_tmp_bak_[i] != NULL) + delete [] buffer_sizes_tmp_bak_[i]; if(buffers_[i] != NULL) { for(int b=0; barray_schema()->coords_type(); @@ -507,43 +515,58 @@ void *ArraySortedReadState::aio_done(void* data) { // Check for overflow bool overflow = false; for(int i=0; iaio_overflow_[id][i]) { + if(asrs->overflow_still_[i] && asrs->aio_overflow_[id][i]) { overflow = true; break; } } - if(overflow) { // OVERFLOW // Update buffer sizes for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED + // Backup sizes and zero them + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; asrs->buffer_sizes_tmp_[id][b] = 0; ++b; + // Does not overflow any more + asrs->overflow_still_[i] = false; } else { // VAR - asrs->buffer_sizes_tmp_[id][b] = 0; - ++b; if(asrs->aio_overflow_[id][i]) { + // Re-assign the buffer size for the fixed-sized offsets + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + ++b; // Expand buffers expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + // Assign the new buffer size for the variable-sized values asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; - overflow = true; + ++b; } else { - asrs->buffer_sizes_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + // Backup sizes and zero them (fixed-sized offsets) + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + // Backup sizes and zero them (variable-sized values) + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + // Does not overflow any more + asrs->overflow_still_[i] = false; } - ++b; } } // Send the request again asrs->send_aio_request(id); } else { // NO OVERFLOW - // Manage the mutexes and conditions + // Restore backup temporary buffer sizes + for(int b=0; bbuffer_num_; ++b) { + if(asrs->buffer_sizes_tmp_bak_[id][b] != 0) + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_tmp_bak_[id][b]; + } -std::cout << "AIO done!\n"; + // Manage the mutexes and conditions asrs->release_aio(id); -std::cout << "Released AIO: " << id << " \n"; } return NULL; @@ -611,16 +634,20 @@ void ArraySortedReadState::calculate_buffer_sizes() { for(int j=0; j<2; ++j) { buffer_sizes_[j] = new size_t[buffer_num_]; buffer_sizes_tmp_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_bak_[j] = new size_t[buffer_num_]; for(int i=0, b=0; ivar_size(attribute_ids_[i])) { buffer_sizes_[j][b] = tile_slab_cell_num * array_schema->cell_size(attribute_ids_[i]); + buffer_sizes_tmp_bak_[j][b] = 0; ++b; } else { // Variable-sized attribute buffer_sizes_[j][b] = tile_slab_cell_num * sizeof(size_t); + buffer_sizes_tmp_bak_[j][b] = 0; ++b; buffer_sizes_[j][b] = 2 * tile_slab_cell_num * sizeof(size_t); + buffer_sizes_tmp_bak_[j][b] = 0; ++b; } } @@ -801,11 +828,6 @@ void ArraySortedReadState::calculate_tile_domain(int id) { tile_domain[2*i] = tile_slab[2*i] / tile_extents[i]; tile_domain[2*i+1] = tile_slab[2*i+1] / tile_extents[i]; } - -std::cout << "Tile domain: " - << tile_domain[0] << " " << tile_domain[1] << " " - << tile_domain[2] << " " << tile_domain[3] << "\n"; - } template @@ -914,8 +936,6 @@ void ArraySortedReadState::calculate_tile_slab_info_row(int id) { int anum = (int) attribute_ids_.size(); int d; -std::cout << "tile coords: " << tile_coords[0] << "\n"; - // Iterate over all tiles in the tile domain int64_t tid=0; // Tile id while(tile_coords[0] <= tile_domain[1]) { @@ -932,15 +952,6 @@ std::cout << "tile coords: " << tile_coords[0] << "\n"; tile_cell_num *= range_overlap[tid][2*i+1] - range_overlap[tid][2*i] + 1; } -std::cout << "Tile id: " << tid << "\n"; -std::cout << "Tile coords: " - << tile_coords[0] << " " << tile_coords[1] << "\n"; -std::cout << "Range overlap: " - << range_overlap[tid][0] << " " - << range_overlap[tid][1] << " " - << range_overlap[tid][2] << " " - << range_overlap[tid][3] << "\n"; - // Calculate tile offsets per dimension tile_offset = 1; tile_slab_info_[id].tile_offset_per_dim_[dim_num_-1] = tile_offset; @@ -949,22 +960,10 @@ std::cout << "Range overlap: " tile_slab_info_[id].tile_offset_per_dim_[i] = tile_offset; } -std::cout << "Tile offsets per dimension: " - << tile_slab_info_[id].tile_offset_per_dim_[0] << " " - << tile_slab_info_[id].tile_offset_per_dim_[1] << "\n"; - // Calculate cell slab info ASRS_Data asrs_data = { id, tid, this }; (*calculate_cell_slab_info_)(&asrs_data); -std::cout << "Cell slab num: " - << tile_slab_info_[id].cell_slab_num_[tid] << "\n"; -std::cout << "Cell slab size: " - << tile_slab_info_[id].cell_slab_size_[0][tid] << "\n"; -std::cout << "Cell offset per dim: " - << tile_slab_info_[id].cell_offset_per_dim_[tid][0] << " " - << tile_slab_info_[id].cell_offset_per_dim_[tid][1] << "\n"; - // Calculate start offsets for(int aid=0; aid buffer_size) { - -std::cout << "OVERFLOW !!!\n"; -std::cout << "buffer offset: " << buffer_offset << "\n"; -std::cout << "buffer size: " << buffer_size << "\n"; -std::cout << "cell slab size: " << cell_slab_size << "\n"; - overflow_[aid] = true; break; } // Copy cell slab - -std::cout << "buffer offset: " << buffer_offset << "\n"; -std::cout << "local buffer offset: " << local_buffer_offset << "\n"; - memcpy( buffer + buffer_offset, local_buffer + local_buffer_offset, @@ -1089,8 +1068,6 @@ std::cout << "local buffer offset: " << local_buffer_offset << "\n"; // Set user buffer size buffer_size = buffer_offset; - -std::cout << "--- Finished copying " << copy_id_ << " ---\n"; } void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { @@ -1139,10 +1116,6 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { local_buffer_var_size - local_buffer_s[cell_start] : local_buffer_s[cell_end] - local_buffer_s[cell_start]; -std::cout << "CELL NUM IN BUFFER: " << cell_num_in_buffer << "\n"; -std::cout << "CELL START/END: " << cell_start << " " << cell_end << "\n"; -std::cout << "CELL SLAB SIZE VAR: " << cell_slab_size_var << "\n"; - // Handle overflow for the the variable-length buffer if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { overflow_[aid] = true; @@ -1305,9 +1278,6 @@ template void ArraySortedReadState::handle_copy_requests() { // Handle copy requests indefinitely for(;;) { - -std::cout << "--- Waiting on AIO... ---\n"; - // Wait for AIO wait_aio(copy_id_); @@ -1315,8 +1285,6 @@ std::cout << "--- Waiting on AIO... ---\n"; if(!copy_thread_running_) return; -std::cout << "--- Finished waiting on AIO... ---\n"; - // Reset the tile slab state if(copy_tile_slab_done()) reset_tile_slab_state(); @@ -1333,8 +1301,6 @@ std::cout << "--- Finished waiting on AIO... ---\n"; continue; } -std::cout << "--- Copy is done ---\n"; - // Copy is done block_aio(copy_id_); release_copy(copy_id_); @@ -1494,8 +1460,6 @@ bool ArraySortedReadState::next_tile_slab_col() { if(tile_slab_init_[prev_id] && tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { read_tile_slabs_done_ = true; - -std::cout << "--- DONE --- \n"; return false; } @@ -1540,13 +1504,6 @@ std::cout << "--- DONE --- \n"; tile_slab_norm[2*i+1] = tile_slab[aio_id_][2*i+1] - tile_start; } -std::cout << "Tile slab: " - << tile_slab[aio_id_][0] << " " << tile_slab[aio_id_][1] << " " - << tile_slab[aio_id_][2] << " " << tile_slab[aio_id_][3] << "\n"; -std::cout << "Tile slab norm: " - << tile_slab_norm[0] << " " << tile_slab_norm[1] << " " - << tile_slab_norm[2] << " " << tile_slab_norm[3] << "\n"; - // Calculate tile slab info and reset tile slab state calculate_tile_slab_info(aio_id_); @@ -1569,8 +1526,6 @@ bool ArraySortedReadState::next_tile_slab_row() { return true; } -std::cout << "--- Next tile slab ---\n"; - // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -1587,9 +1542,6 @@ std::cout << "--- Next tile slab ---\n"; if(tile_slab_init_[prev_id] && tile_slab[prev_id][1] == subarray[1]) { read_tile_slabs_done_ = true; - -std::cout << "--- DONE --- \n"; - return false; } @@ -1630,13 +1582,6 @@ std::cout << "--- DONE --- \n"; tile_slab_norm[2*i+1] = tile_slab[aio_id_][2*i+1] - tile_start; } -std::cout << "Tile slab: " - << tile_slab[aio_id_][0] << " " << tile_slab[aio_id_][1] << " " - << tile_slab[aio_id_][2] << " " << tile_slab[aio_id_][3] << "\n"; -std::cout << "Tile slab norm: " - << tile_slab_norm[0] << " " << tile_slab_norm[1] << " " - << tile_slab_norm[2] << " " << tile_slab_norm[3] << "\n"; - // Calculate tile slab info and reset tile slab state calculate_tile_slab_info(aio_id_); @@ -1681,30 +1626,20 @@ int ArraySortedReadState::read_dense_sorted_col() { copy_state_.buffers_, copy_state_.buffer_sizes_); -std::cout << "HEEEEEEEEEEEEEERE\n"; - // Iterate over each tile slab while(next_tile_slab_col()) { // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) { - -std::cout << "ERROOOOOOOOOOR\n"; - + if(read_tile_slab() != TILEDB_ASRS_OK) return TILEDB_ASRS_ERR; - } // Handle overflow if(resume_aio_) break; } -std::cout << "Resume AIO: " << resume_aio_ << "\n"; - // Wait for copy to finish - int prev = (aio_id_ + 1) % 2; -std::cout << "--- Waiting for copy to finish ---\n"; - wait_copy(prev); -std::cout << "--- Finished waiting for copy ---\n"; + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); // Assign the true buffer sizes for(int i=0; i Date: Fri, 7 Oct 2016 16:07:57 -0400 Subject: [PATCH 13/57] Fixed bug in asynchornous AIO + sorted dense reads --- core/include/array/array.h | 20 ++++--- core/include/array/array_sorted_read_state.h | 3 ++ core/src/array/array.cc | 54 ++++++++++++------- core/src/array/array_sorted_read_state.cc | 28 +++++++--- core/src/storage_manager/storage_manager.cc | 50 ++++++++++++----- .../src/tiledb_array_read_sorted_dense.cc | 22 +++----- 6 files changed, 118 insertions(+), 59 deletions(-) diff --git a/core/include/array/array.h b/core/include/array/array.h index 06b4be4e..516333af 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -129,6 +129,9 @@ class Array { /** Returns the array schema. */ const ArraySchema* array_schema() const; + /** Returns the array clone. */ + Array* array_clone() const; + /** Returns the ids of the attributes the array focuses on. */ const std::vector& attribute_ids() const; @@ -278,16 +281,18 @@ class Array { * - TILEDB_ARRAY_READ * - TILEDB_ARRAY_READ_SORTED_COL * - TILEDB_ARRAY_READ_SORTED_ROW - * @param subarray The subarray in which the array read/write will be - * constrained on. If it is NULL, then the subarray is set to the entire - * array domain. For the case of writes, this is meaningful only for - * dense arrays, and specifically dense writes. * @param attributes A subset of the array attributes the read/write will be * constrained on. A NULL value indicates **all** attributes (including * the coordinates in the case of sparse arrays). * @param attribute_num The number of the input attributes. If *attributes* is * NULL, then this should be set to 0. + * @param subarray The subarray in which the array read/write will be + * constrained on. If it is NULL, then the subarray is set to the entire + * array domain. For the case of writes, this is meaningful only for + * dense arrays, and specifically dense writes. * @param config Configuration parameters. + * @param array_clone An clone of this array object. Used specifically in + * asynchronous IO (AIO) read/write operations. * @return TILEDB_AR_OK on success, and TILEDB_AR_ERR on error. */ int init( @@ -297,8 +302,9 @@ class Array { int mode, const char** attributes, int attribute_num, - const void* range, - const Config* config); + const void* subarray, + const Config* config, + Array* array_clone = NULL); /** * Resets the attributes used upon initialization of the array. @@ -394,6 +400,8 @@ class Array { bool aio_thread_canceled_; /** Indicates whether the AIO thread was created or not. */ bool aio_thread_created_; + /** An array clone, used in AIO requests. */ + Array* array_clone_; /** The array schema. */ const ArraySchema* array_schema_; /** The read state of the array. */ diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index edc4bb17..fe42f460 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -300,6 +300,9 @@ class ArraySortedReadState { /** The thread tha handles all the copying in the background. */ pthread_t copy_thread_; + /** True if the copy thread is canceled. */ + bool copy_thread_canceled_; + /** True if the copy thread is running. */ bool copy_thread_running_; diff --git a/core/src/array/array.cc b/core/src/array/array.cc index a15b5a16..e9478455 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -72,25 +72,30 @@ Array::Array() { array_schema_ = NULL; subarray_ = NULL; aio_thread_created_ = false; + array_clone_ = NULL; } Array::~Array() { + // Applicable to both arrays and array clones std::vector::iterator it = fragments_.begin(); for(; it != fragments_.end(); ++it) if(*it != NULL) delete *it; - - if(array_schema_ != NULL) - delete array_schema_; - - if(subarray_ != NULL) - free(subarray_); - if(array_read_state_ != NULL) delete array_read_state_; - if(array_sorted_read_state_ != NULL) delete array_sorted_read_state_; + + // Applicable only to clones + if(array_clone_ != NULL) { + array_clone_->finalize(); + delete array_clone_; + } else { // Applicable only to (non-clone) arrays + if(array_schema_ != NULL) + delete array_schema_; + if(subarray_ != NULL) + free(subarray_); + } } @@ -209,6 +214,10 @@ int Array::aio_write(AIO_Request* aio_request) { return TILEDB_AR_OK; } +Array* Array::array_clone() const { + return array_clone_; +} + const ArraySchema* Array::array_schema() const { return array_schema_; } @@ -524,10 +533,14 @@ int Array::init( const char** attributes, int attribute_num, const void* subarray, - const Config* config) { + const Config* config, + Array* array_clone) { // Set mode mode_ = mode; + // Set array clone + array_clone_ = array_clone; + // Sanity check on mode if(!read_mode() && !write_mode()) { std::string errmsg = "Cannot initialize array; Invalid array mode"; @@ -890,16 +903,19 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { void Array::aio_handle_next_request(AIO_Request* aio_request) { int rc = TILEDB_AR_OK; if(read_mode()) { // READ MODE - // Reset the subarray only if this request does not continue from the last - if(aio_last_handled_request_ != aio_request->id_) - rc = reset_subarray_soft(aio_request->subarray_); - // Invoke the read - if(rc == TILEDB_AR_OK) { - if(aio_request->mode_ == TILEDB_ARRAY_READ) - rc = read_default(aio_request->buffers_, aio_request->buffer_sizes_); - else - rc = read(aio_request->buffers_, aio_request->buffer_sizes_); + if(aio_request->mode_ == TILEDB_ARRAY_READ) { + // Reset the subarray only if this request does not continue from the last + if(aio_last_handled_request_ != aio_request->id_) + reset_subarray_soft(aio_request->subarray_); + rc = read_default(aio_request->buffers_, aio_request->buffer_sizes_); + } else { + // This may initiate a series of new AIO requests + // Reset the subarray hard this time (updating also the subarray + // of the ArraySortedReadState object. + if(aio_last_handled_request_ != aio_request->id_) + reset_subarray(aio_request->subarray_); + rc = read(aio_request->buffers_, aio_request->buffer_sizes_); } } else { // WRITE MODE // TODO: Fix according to read above @@ -912,8 +928,6 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { // Check for overflow if(aio_request->mode_ == TILEDB_ARRAY_READ && array_read_state_->overflow()) { - - *aio_request->status_= TILEDB_AIO_OVERFLOW; if(aio_request->overflow_ != NULL) { for(int i=0; idim_num(); copy_thread_running_ = false; + copy_thread_canceled_ = false; read_tile_slabs_done_ = false; resume_copy_ = false; resume_aio_ = false; @@ -152,6 +153,13 @@ ArraySortedReadState::~ArraySortedReadState() { free_tile_slab_state(); free_tile_slab_info(); + // Cancel copy thread + copy_thread_canceled_ = true; + for(int i=0; i<2; ++i) + release_aio(i); + // Wait for thread to be destroyed + while(copy_thread_running_); + // Destroy conditions and mutexes for(int i=0; i<2; ++i) { if(pthread_cond_destroy(&(aio_cond_[i]))) { @@ -1281,9 +1289,11 @@ void ArraySortedReadState::handle_copy_requests() { // Wait for AIO wait_aio(copy_id_); - // Kill thread - if(!copy_thread_running_) + // Kill thread, after releasing any blocked resources + if(copy_thread_canceled_) { + copy_thread_running_ = false; return; + } // Reset the tile slab state if(copy_tile_slab_done()) @@ -1647,7 +1657,7 @@ int ArraySortedReadState::read_dense_sorted_col() { // The following will make the copy thread terminate if(done()) { - copy_thread_running_ = false; + copy_thread_canceled_ = true; release_aio(aio_id_); } @@ -1689,7 +1699,7 @@ int ArraySortedReadState::read_dense_sorted_row() { // The following will make the copy thread terminate if(done()) { - copy_thread_running_ = false; + copy_thread_canceled_ = true; release_aio(aio_id_); } @@ -1872,8 +1882,14 @@ int ArraySortedReadState::send_aio_request(int aio_id) { // Important!! aio_request_[aio_id].id_ = aio_cnt_++; - // Send the AIO request - if(array_->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { + // For easy reference + Array* array_clone = array_->array_clone(); + + // Sanity check + assert(array_clone != NULL); + + // Send the AIO request to the clone array + if(array_clone->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; return TILEDB_ASRS_ERR; } diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 282b361c..386c9c09 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -569,26 +569,52 @@ int StorageManager::array_init( return TILEDB_SM_ERR; } - // Create Array object + // Create the clone Array object + Array* array_clone = new Array(); + int rc_clone = array_clone->init( + array_schema, + open_array->fragment_names_, + open_array->book_keeping_, + mode, + attributes, + attribute_num, + subarray, + config_); + + // Handle error + if(rc_clone != TILEDB_AR_OK) { + delete array_schema; + delete array_clone; + array = NULL; + array_close(array_dir); + return TILEDB_SM_ERR; + } + + // Create actual array array = new Array(); - if(array->init( - array_schema, - open_array->fragment_names_, - open_array->book_keeping_, - mode, - attributes, - attribute_num, - subarray, - config_) != TILEDB_AR_OK) { + int rc = array->init( + array_schema, + open_array->fragment_names_, + open_array->book_keeping_, + mode, + attributes, + attribute_num, + subarray, + config_, + array_clone); + + // Handle error + if(rc != TILEDB_AR_OK) { delete array_schema; delete array; array = NULL; array_close(array_dir); tiledb_sm_errmsg = tiledb_as_errmsg; return TILEDB_SM_ERR; - } else { - return TILEDB_SM_OK; } + + // Success + return TILEDB_SM_OK; } int StorageManager::array_finalize(Array* array) { diff --git a/examples/src/tiledb_array_read_sorted_dense.cc b/examples/src/tiledb_array_read_sorted_dense.cc index 47b0496c..5b4a9b8d 100644 --- a/examples/src/tiledb_array_read_sorted_dense.cc +++ b/examples/src/tiledb_array_read_sorted_dense.cc @@ -41,7 +41,7 @@ int main() { tiledb_ctx_init(&tiledb_ctx, NULL); // Subarray and attributes - int64_t subarray[] = { 1, 3, 1, 4 }; + int64_t subarray[] = { 3, 4, 2, 4 }; const char* attributes[] = { "a1" }; // Initialize array @@ -50,37 +50,29 @@ int main() { tiledb_ctx, // Context &tiledb_array, // Array object "my_workspace/dense_arrays/my_array_A", // Array name - TILEDB_ARRAY_READ_SORTED_COL, // Mode + TILEDB_ARRAY_READ_SORTED_ROW, // Mode subarray, // Constrain in subarray attributes, // Subset on attributes 1); // Number of attributes // Prepare cell buffers - int buffer_a1[16]; + int buffer_a1[3]; void* buffers[] = { buffer_a1 }; size_t buffer_sizes[] = { sizeof(buffer_a1) }; // Loop until no overflow printf(" a1\n----\n"); -// do { - printf("Reading cells...\n"); - + do { // Read from array - int rc = tiledb_array_read(tiledb_array, buffers, buffer_sizes); - -if(rc != TILEDB_OK) - printf("ERROR!!!\n"); + printf("Reading cells...\n"); + tiledb_array_read(tiledb_array, buffers, buffer_sizes); // Print cell values - printf("Printing cells...\n"); int64_t result_num = buffer_sizes[0] / sizeof(int); - -printf("Result num: %lld\n", result_num); - for(int i=0; i Date: Fri, 14 Oct 2016 19:14:58 -0400 Subject: [PATCH 14/57] Finished sparse sorted reads. Not tested and debugged yet. --- core/include/array/array_sorted_read_state.h | 155 ++- core/include/fragment/write_state.h | 207 ---- core/include/misc/comparators.h | 233 ++++ core/src/array/array_sorted_read_state.cc | 1023 ++++++++++++++++-- core/src/fragment/write_state.cc | 1 + 5 files changed, 1296 insertions(+), 323 deletions(-) create mode 100644 core/include/misc/comparators.h diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index fe42f460..1cb7b1bf 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -52,6 +52,9 @@ /** Default error message. */ #define TILEDB_ASRS_ERRMSG std::string("[TileDB::ArraySortedReadState] Error: ") +/** Initial internal buffer size for the case of sparse arrays. */ +#define TILEDB_ASRS_INIT_BUFFER_SIZE 10000000 // ~ 10MB + @@ -95,7 +98,7 @@ class ArraySortedReadState { void** buffers_; }; - /** Info about a tile slab. It is used by the copy_tile_slab() function. */ + /** Info about a tile slab. */ struct TileSlabInfo { /** Used in calculations of cell ids, one vector per tile. */ int64_t** cell_offset_per_dim_; @@ -122,6 +125,11 @@ class ArraySortedReadState { struct TileSlabState { /** Keeps track of whether a tile slab copy for an attribute id done. */ bool* copy_tile_slab_done_; + /** + * Applicable only to the sparse case. It holds the current cell position + * to be considered, per attribute. + */ + int64_t* current_cell_pos_; /** Current coordinates in tile slab per attribute. */ void** current_coords_; /** @@ -250,7 +258,7 @@ class ArraySortedReadState { Array* array_; /** The ids of the attributes the array was initialized with. */ - const std::vector& attribute_ids_; + std::vector attribute_ids_; /** * The sizes of the attributes. For variable-length attributes, sizeof(size_t) @@ -282,6 +290,24 @@ class ArraySortedReadState { /** Function for calculating tile slab info during a copy operation. */ void *(*calculate_tile_slab_info_) (void*); + /** + * Used only in the sparse case. Holds the sorted positions of the cells + * for the current tile slab to be copied. + */ + std::vector cell_pos_; + + /** + * Used only in the sparse case. It is the element index in attribute_ids_ + * that represents the coordinates attribute. + */ + int coords_attr_i_; + + /** + * Used only in the sparse case. It is the element index in buffers_ + * that represents the coordinates attribute. + */ + int coords_buf_i_; + /** The coordinates size of the array. */ size_t coords_size_; @@ -309,6 +335,14 @@ class ArraySortedReadState { /** The number of dimensions in the array. */ int dim_num_; + /** + * Used only in the sparse case. It is true if the coordinates are not asked + * by the user and, thus, TileDB had to append them as an extra attribute + * to facilitate sorting the cell positions. + * + */ + bool extra_coords_; + /** The overflow mutex condition. */ pthread_cond_t overflow_cond_; @@ -431,6 +465,12 @@ class ArraySortedReadState { /** Sets the flag of resume_copy_ to true. */ void block_overflow(); + /** + * Calculate the attribute ids specified by the user upon array + * initialization. + */ + void calculate_attribute_ids(); + /** * Calculates the number of buffers to be allocated, based on the number * of attributes initialized for the array. @@ -440,13 +480,28 @@ class ArraySortedReadState { void calculate_buffer_num(); /** - * Calculates the buffer sizes based on the subarray and the number of cells - * in a (full) tile slab. + * Calculates the buffer sizes based on the array type. * * @return void */ void calculate_buffer_sizes(); + /** + * Calculates the buffer sizes based on the subarray and the number of cells + * in a (full) tile slab. Applicable to dense arrays. + * + * @return void + */ + void calculate_buffer_sizes_dense(); + + /** + * Calculates the buffer sizes based on configurable parameters. Applicable to + * sparse arrays. + * + * @return void + */ + void calculate_buffer_sizes_sparse(); + /** * Calculates the info used in the copy_tile_slab() function, for the case * where the **user** cell order is column-major and the **array** cell @@ -636,32 +691,68 @@ class ArraySortedReadState { /** * Copies a tile slab from the local buffers into the user buffers, * properly re-organizing the cell order to fit the targeted order. + * Applicable to dense arrays. * * @return void. */ - void copy_tile_slab(); + void copy_tile_slab_dense(); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order. + * Applicable to sparse arrays. + * + * @return void. + */ + void copy_tile_slab_sparse(); /** * Copies a tile slab from the local buffers into the user buffers, * properly re-organizing the cell order to fit the targeted order, * focusing on a particular fixed-length attribute. + * Applicable to dense arrays. * * @param aid The index on attribute_ids_ to focus on. * @param bid The index on the copy state buffers to focus on. * @return void. */ - void copy_tile_slab(int aid, int bid); + void copy_tile_slab_dense(int aid, int bid); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular fixed-length attribute. + * Applicable to sparse arrays. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ + void copy_tile_slab_sparse(int aid, int bid); /** * Copies a tile slab from the local buffers into the user buffers, * properly re-organizing the cell order to fit the targeted order, * focusing on a particular variable-length attribute. + * Applicable to dense arrays. * * @param aid The index on attribute_ids_ to focus on. * @param bid The index on the copy state buffers to focus on. * @return void. */ - void copy_tile_slab_var(int aid, int bid); + void copy_tile_slab_dense_var(int aid, int bid); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular variable-length attribute. + * Applicable to sparse arrays. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ + void copy_tile_slab_sparse_var(int aid, int bid); /** * Creates the buffers based on the calculated buffer sizes. @@ -702,13 +793,22 @@ class ArraySortedReadState { int64_t get_tile_id(int aid); /** - * Handles the copy requests. + * Handles the copy requests. Applicable to dense arrays. * * @template T The domain type. * @return void. */ template - void handle_copy_requests(); + void handle_copy_requests_dense(); + + /** + * Handles the copy requests. Applicable to sparse arrays. + * + * @template T The domain type. + * @return void. + */ + template + void handle_copy_requests_sparse(); /** Initializes the AIO requests. */ void init_aio_requests(); @@ -755,22 +855,44 @@ class ArraySortedReadState { int lock_overflow_mtx(); /** - * Retrieves the next column tile slab to be processed. + * Retrieves the next column tile slab to be processed. Applicable to dense + * arrays. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ + template + bool next_tile_slab_dense_col(); + + /** + * Retrieves the next row tile slab to be processed. Applicable to dense + * arrays. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ + template + bool next_tile_slab_dense_row(); + + /** + * Retrieves the next column tile slab to be processed. Applicable to sparse + * arrays. * * @template T The domain type. * @return True if the next tile slab was retrieved, and false otherwise. */ template - bool next_tile_slab_col(); + bool next_tile_slab_sparse_col(); /** - * Retrieves the next row tile slab to be processed. + * Retrieves the next row tile slab to be processed. Applicable to sparse + * arrays. * * @template T The domain type. * @return True if the next tile slab was retrieved, and false otherwise. */ template - bool next_tile_slab_row(); + bool next_tile_slab_sparse_row(); /** * Same as Array::read(), but it sorts the cells in the buffers based on the @@ -896,6 +1018,13 @@ class ArraySortedReadState { */ int send_aio_request(int aio_id); + /** + * It sorts the positions of the cells based on the coordinates + * of the current tile slab to be copied. + */ + template + void sort_cell_pos(); + /** * Unlocks the AIO mutex. * diff --git a/core/include/fragment/write_state.h b/core/include/fragment/write_state.h index c88b0f01..e735a6ed 100644 --- a/core/include/fragment/write_state.h +++ b/core/include/fragment/write_state.h @@ -75,20 +75,6 @@ class Fragment; /** Stores the state necessary when writing cells to a fragment. */ class WriteState { public: - /* ********************************* */ - /* TYPE DEFINITIONS */ - /* ********************************* */ - - /**@{*/ - /** Custom comparator in cell sorting. */ - template class SmallerIdCol; - template class SmallerIdRow; - template class SmallerCol; - template class SmallerRow; - /**@}*/ - - - /* ********************************* */ /* CONSTRUCTORS & DESTRUCTORS */ @@ -655,197 +641,4 @@ class WriteState { const std::vector& cell_pos); }; -/** - * Wrapper of comparison function for sorting cells; first by the smallest id, - * and then by column-major order of coordinates. - */ -template -class WriteState::SmallerIdCol { - public: - /** - * Constructor. - * - * @param buffer The buffer containing the cells to be sorted. - * @param dim_num The number of dimensions of the cells. - * @param ids The ids of the cells in the buffer. - */ - SmallerIdCol(const T* buffer, int dim_num, const std::vector& ids) - : buffer_(buffer), - dim_num_(dim_num), - ids_(ids) { } - - /** - * Comparison operator. - * - * @param a The first cell position in the cell buffer. - * @param b The second cell position in the cell buffer. - */ - bool operator () (int64_t a, int64_t b) { - if(ids_[a] < ids_[b]) - return true; - - if(ids_[a] > ids_[b]) - return false; - - // a.id_ == b.id_ --> check coordinates - const T* coords_a = &buffer_[a * dim_num_]; - const T* coords_b = &buffer_[b * dim_num_]; - - for(int i=dim_num_-1; i>=0; --i) - if(coords_a[i] < coords_b[i]) - return true; - else if(coords_a[i] > coords_b[i]) - return false; - // else coords_a[i] == coords_b[i] --> continue - - return false; - } - - private: - /** Cell buffer. */ - const T* buffer_; - /** Number of dimensions. */ - int dim_num_; - /** The cell ids. */ - const std::vector& ids_; -}; - -/** - * Wrapper of comparison function for sorting cells; first by the smallest id, - * and then by row-major order of coordinates. - */ -template -class WriteState::SmallerIdRow { - public: - /** - * Constructor. - * - * @param buffer The buffer containing the cells to be sorted. - * @param dim_num The number of dimensions of the cells. - * @param ids The ids of the cells in the buffer. - */ - SmallerIdRow(const T* buffer, int dim_num, const std::vector& ids) - : buffer_(buffer), - dim_num_(dim_num), - ids_(ids) { } - - /** - * Comparison operator. - * - * @param a The first cell position in the cell buffer. - * @param b The second cell position in the cell buffer. - */ - bool operator () (int64_t a, int64_t b) { - if(ids_[a] < ids_[b]) - return true; - - if(ids_[a] > ids_[b]) - return false; - - // a.id_ == b.id_ --> check coordinates - const T* coords_a = &buffer_[a * dim_num_]; - const T* coords_b = &buffer_[b * dim_num_]; - - for(int i=0; i coords_b[i]) - return false; - // else coords_a[i] == coords_b[i] --> continue - } - - return false; - } - - private: - /** Cell buffer. */ - const T* buffer_; - /** Number of dimensions. */ - int dim_num_; - /** The cell ids. */ - const std::vector& ids_; -}; - -/** Wrapper of comparison function for sorting cells on column-major order. */ -template -class WriteState::SmallerCol { - public: - /** - * Constructor. - * - * @param buffer The buffer containing the cells to be sorted. - * @param dim_num The number of dimensions of the cells. - */ - SmallerCol(const T* buffer, int dim_num) - : buffer_(buffer), - dim_num_(dim_num) { } - - /** - * Comparison operator. - * - * @param a The first cell position in the cell buffer. - * @param b The second cell position in the cell buffer. - */ - bool operator () (int64_t a, int64_t b) { - const T* coords_a = &buffer_[a * dim_num_]; - const T* coords_b = &buffer_[b * dim_num_]; - - for(int i=dim_num_-1; i>=0; --i) - if(coords_a[i] < coords_b[i]) - return true; - else if(coords_a[i] > coords_b[i]) - return false; - // else coords_a[i] == coords_b[i] --> continue - - return false; - } - - private: - /** Cell buffer. */ - const T* buffer_; - /** Number of dimensions. */ - int dim_num_; -}; - -/** Wrapper of comparison function for sorting cells on row-major order. */ -template -class WriteState::SmallerRow { - public: - /** - * Constructor. - * - * @param buffer The buffer containing the cells to be sorted. - * @param dim_num The number of dimensions of the cells. - */ - SmallerRow(const T* buffer, int dim_num) - : buffer_(buffer), - dim_num_(dim_num) { } - - /** - * Comparison operator. - * - * @param a The first cell position in the cell buffer. - * @param b The second cell position in the cell buffer. - */ - bool operator () (int64_t a, int64_t b) { - const T* coords_a = &buffer_[a * dim_num_]; - const T* coords_b = &buffer_[b * dim_num_]; - - for(int i=0; i coords_b[i]) - return false; - // else coords_a[i] == coords_b[i] --> continue - - return false; - } - - private: - /** Cell buffer. */ - const T* buffer_; - /** Number of dimensions. */ - int dim_num_; -}; - #endif diff --git a/core/include/misc/comparators.h b/core/include/misc/comparators.h new file mode 100644 index 00000000..00090633 --- /dev/null +++ b/core/include/misc/comparators.h @@ -0,0 +1,233 @@ +/** + * @file comparators.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Defines custom comparators to be used in cell position sorting in the case + * of sparse arrays. + */ + +#ifndef __COMPARATORS_H__ +#define __COMPARATORS_H__ + +#include +#include + +/** + * Wrapper of comparison function for sorting cells; first by the smallest id, + * and then by column-major order of coordinates. + */ +template +class SmallerIdCol { + public: + /** + * Constructor. + * + * @param buffer The buffer containing the cells to be sorted. + * @param dim_num The number of dimensions of the cells. + * @param ids The ids of the cells in the buffer. + */ + SmallerIdCol(const T* buffer, int dim_num, const std::vector& ids) + : buffer_(buffer), + dim_num_(dim_num), + ids_(ids) { } + + /** + * Comparison operator. + * + * @param a The first cell position in the cell buffer. + * @param b The second cell position in the cell buffer. + */ + bool operator () (int64_t a, int64_t b) { + if(ids_[a] < ids_[b]) + return true; + + if(ids_[a] > ids_[b]) + return false; + + // a.id_ == b.id_ --> check coordinates + const T* coords_a = &buffer_[a * dim_num_]; + const T* coords_b = &buffer_[b * dim_num_]; + + for(int i=dim_num_-1; i>=0; --i) + if(coords_a[i] < coords_b[i]) + return true; + else if(coords_a[i] > coords_b[i]) + return false; + // else coords_a[i] == coords_b[i] --> continue + + return false; + } + + private: + /** Cell buffer. */ + const T* buffer_; + /** Number of dimensions. */ + int dim_num_; + /** The cell ids. */ + const std::vector& ids_; +}; + +/** + * Wrapper of comparison function for sorting cells; first by the smallest id, + * and then by row-major order of coordinates. + */ +template +class SmallerIdRow { + public: + /** + * Constructor. + * + * @param buffer The buffer containing the cells to be sorted. + * @param dim_num The number of dimensions of the cells. + * @param ids The ids of the cells in the buffer. + */ + SmallerIdRow(const T* buffer, int dim_num, const std::vector& ids) + : buffer_(buffer), + dim_num_(dim_num), + ids_(ids) { } + + /** + * Comparison operator. + * + * @param a The first cell position in the cell buffer. + * @param b The second cell position in the cell buffer. + */ + bool operator () (int64_t a, int64_t b) { + if(ids_[a] < ids_[b]) + return true; + + if(ids_[a] > ids_[b]) + return false; + + // a.id_ == b.id_ --> check coordinates + const T* coords_a = &buffer_[a * dim_num_]; + const T* coords_b = &buffer_[b * dim_num_]; + + for(int i=0; i coords_b[i]) + return false; + // else coords_a[i] == coords_b[i] --> continue + } + + return false; + } + + private: + /** Cell buffer. */ + const T* buffer_; + /** Number of dimensions. */ + int dim_num_; + /** The cell ids. */ + const std::vector& ids_; +}; + +/** Wrapper of comparison function for sorting cells on column-major order. */ +template +class SmallerCol { + public: + /** + * Constructor. + * + * @param buffer The buffer containing the cells to be sorted. + * @param dim_num The number of dimensions of the cells. + */ + SmallerCol(const T* buffer, int dim_num) + : buffer_(buffer), + dim_num_(dim_num) { } + + /** + * Comparison operator. + * + * @param a The first cell position in the cell buffer. + * @param b The second cell position in the cell buffer. + */ + bool operator () (int64_t a, int64_t b) { + const T* coords_a = &buffer_[a * dim_num_]; + const T* coords_b = &buffer_[b * dim_num_]; + + for(int i=dim_num_-1; i>=0; --i) + if(coords_a[i] < coords_b[i]) + return true; + else if(coords_a[i] > coords_b[i]) + return false; + // else coords_a[i] == coords_b[i] --> continue + + return false; + } + + private: + /** Cell buffer. */ + const T* buffer_; + /** Number of dimensions. */ + int dim_num_; +}; + +/** Wrapper of comparison function for sorting cells on row-major order. */ +template +class SmallerRow { + public: + /** + * Constructor. + * + * @param buffer The buffer containing the cells to be sorted. + * @param dim_num The number of dimensions of the cells. + */ + SmallerRow(const T* buffer, int dim_num) + : buffer_(buffer), + dim_num_(dim_num) { } + + /** + * Comparison operator. + * + * @param a The first cell position in the cell buffer. + * @param b The second cell position in the cell buffer. + */ + bool operator () (int64_t a, int64_t b) { + const T* coords_a = &buffer_[a * dim_num_]; + const T* coords_b = &buffer_[b * dim_num_]; + + for(int i=0; i coords_b[i]) + return false; + // else coords_a[i] == coords_b[i] --> continue + + return false; + } + + private: + /** Cell buffer. */ + const T* buffer_; + /** Number of dimensions. */ + int dim_num_; +}; + +#endif diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index bea783cd..efdf2648 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -31,6 +31,8 @@ */ #include "array_sorted_read_state.h" +#include "comparators.h" +#include "math.h" #include "utils.h" #include @@ -47,6 +49,13 @@ # define PRINT_ERROR(x) do { } while(0) #endif +#ifdef OPENMP + #include + #define SORT(first, last, comp) __gnu_parallel::sort((first), (last), (comp)) +#else + #include + #define SORT(first, last, comp) std::sort((first), (last), (comp)) +#endif @@ -65,8 +74,10 @@ std::string tiledb_asrs_errmsg = ""; ArraySortedReadState::ArraySortedReadState( Array* array) - : array_(array), - attribute_ids_(array->attribute_ids()) { + : array_(array) { + // Calculate the attribute ids + calculate_attribute_ids(); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); int anum = (int) attribute_ids_.size(); @@ -529,22 +540,34 @@ void *ArraySortedReadState::aio_done(void* data) { } } + // Handle overflow + bool sparse = array_schema->dense(); if(overflow) { // OVERFLOW // Update buffer sizes for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED - // Backup sizes and zero them - asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; - asrs->buffer_sizes_tmp_[id][b] = 0; + if(asrs->aio_overflow_[id][i]) { + // Expand buffer + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + // Re-assign the buffer size for the fixed-sized offsets + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + } else { + // Backup sizes and zero them + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + // Does not overflow any more + asrs->overflow_still_[i] = false; + } ++b; - // Does not overflow any more - asrs->overflow_still_[i] = false; } else { // VAR if(asrs->aio_overflow_[id][i]) { + // Expand offset buffer only in the case of sparse arrays + if(sparse) + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); // Re-assign the buffer size for the fixed-sized offsets asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; ++b; - // Expand buffers + // Expand variable-length cell buffers for both dense and sparse expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); // Assign the new buffer size for the variable-sized values asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; @@ -610,23 +633,66 @@ void ArraySortedReadState::block_overflow() { unlock_overflow_mtx(); } +void ArraySortedReadState::calculate_attribute_ids() { + // Initialization + attribute_ids_ = array_->attribute_ids(); + + // For ease reference + const ArraySchema* array_schema = array_->array_schema(); + int attribute_num = array_schema->attribute_num(); + + // No need to do anything else in case the array is dense + if(array_schema->dense()) + return; + + // Find the coordinates index + coords_attr_i_ = -1; + for(int i=0; i<(int)attribute_ids_.size(); ++i) { + if(attribute_ids_[i] == attribute_num) { + coords_attr_i_ = i; + break; + } + } + + // If the coordinates index is not found, append coordinates attribute + // to attribute ids. + if(coords_attr_i_ == -1) { + attribute_ids_.push_back(attribute_num); + coords_attr_i_ = attribute_ids_.size() - 1; + extra_coords_ = true; + } else { // No extra coordinates appended + extra_coords_ = false; + } +} + void ArraySortedReadState::calculate_buffer_num() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); + int attribute_num = array_schema->attribute_num(); // Calculate number of buffers buffer_num_ = 0; int attribute_id_num = (int) attribute_ids_.size(); for(int i=0; ivar_size(attribute_ids_[i])) + if(!array_schema->var_size(attribute_ids_[i])) { + if(attribute_ids_[i] == attribute_num) + coords_buf_i_ = i; // Buffer that holds the coordinates ++buffer_num_; - else // Variable-sized attribute + } else { // Variable-sized attribute buffer_num_ += 2; + } } } void ArraySortedReadState::calculate_buffer_sizes() { + if(array_->array_schema()->dense()) + calculate_buffer_sizes_dense(); + else + calculate_buffer_sizes_sparse(); +} + +void ArraySortedReadState::calculate_buffer_sizes_dense() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); @@ -662,6 +728,30 @@ void ArraySortedReadState::calculate_buffer_sizes() { } } +void ArraySortedReadState::calculate_buffer_sizes_sparse() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Calculate buffer sizes + int attribute_id_num = (int) attribute_ids_.size(); + for(int j=0; j<2; ++j) { + buffer_sizes_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_bak_[j] = new size_t[buffer_num_]; + for(int i=0, b=0; ivar_size(attribute_ids_[i])) { // Variable-sized buffer + buffer_sizes_[j][b] = 2*TILEDB_ASRS_INIT_BUFFER_SIZE; + buffer_sizes_tmp_bak_[j][b] = 0; + ++b; + } + } + } +} + template void *ArraySortedReadState::calculate_cell_slab_info_col_col_s(void* data) { ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; @@ -999,38 +1089,51 @@ void *ArraySortedReadState::copy_handler(void* context) { // This will enter an indefinite loop that will handle all incoming copy // requests int coords_type = asrs->array_->array_schema()->coords_type(); - if(coords_type == TILEDB_INT32) - asrs->handle_copy_requests(); - else if(coords_type == TILEDB_INT64) - asrs->handle_copy_requests(); - else if(coords_type == TILEDB_FLOAT32) - asrs->handle_copy_requests(); - else if(coords_type == TILEDB_FLOAT64) - asrs->handle_copy_requests(); - else - assert(0); + if(asrs->array_->array_schema()->dense()) { // DENSE + if(coords_type == TILEDB_INT32) + asrs->handle_copy_requests_dense(); + else if(coords_type == TILEDB_INT64) + asrs->handle_copy_requests_dense(); + else if(coords_type == TILEDB_FLOAT32) + asrs->handle_copy_requests_dense(); + else if(coords_type == TILEDB_FLOAT64) + asrs->handle_copy_requests_dense(); + else + assert(0); + } else { // SPARSE + if(coords_type == TILEDB_INT32) + asrs->handle_copy_requests_sparse(); + else if(coords_type == TILEDB_INT64) + asrs->handle_copy_requests_sparse(); + else if(coords_type == TILEDB_FLOAT32) + asrs->handle_copy_requests_sparse(); + else if(coords_type == TILEDB_FLOAT64) + asrs->handle_copy_requests_sparse(); + else + assert(0); + } // Return return NULL; } -void ArraySortedReadState::copy_tile_slab() { +void ArraySortedReadState::copy_tile_slab_dense() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); // Copy tile slab for each attribute separately for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { if(!array_schema->var_size(attribute_ids_[i])) { - copy_tile_slab(i, b); + copy_tile_slab_dense(i, b); ++b; } else { - copy_tile_slab_var(i, b); + copy_tile_slab_dense_var(i, b); b += 2; } } } -void ArraySortedReadState::copy_tile_slab(int aid, int bid) { +void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { // Exit if copy is done for this attribute if(tile_slab_state_.copy_tile_slab_done_[aid]) { copy_state_.buffer_sizes_[bid] = 0; // Nothing written @@ -1078,7 +1181,7 @@ void ArraySortedReadState::copy_tile_slab(int aid, int bid) { buffer_size = buffer_offset; } -void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { +void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { // Exit if copy is done for this attribute if(tile_slab_state_.copy_tile_slab_done_[aid]) { copy_state_.buffer_sizes_[bid] = 0; // Nothing written @@ -1163,6 +1266,140 @@ void ArraySortedReadState::copy_tile_slab_var(int aid, int bid) { buffer_size_var = buffer_offset_var; } +void ArraySortedReadState::copy_tile_slab_sparse() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Copy tile slab for each attribute separately + for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { + if(!array_schema->var_size(attribute_ids_[i])) { // FIXED + // Make sure not to copy coordinates if the user has not requested them + if(i != coords_attr_i_ || !extra_coords_) + copy_tile_slab_sparse(i, b); + ++b; + } else { // VAR + copy_tile_slab_sparse_var(i, b); + b += 2; + } + } +} + +void ArraySortedReadState::copy_tile_slab_sparse(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + return; + } + + // For easy reference + size_t cell_size = array_->array_schema()->cell_size(attribute_ids_[aid]); + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* local_buffer = (char*) buffers_[copy_id_][bid]; + size_t local_buffer_offset; + int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; + int64_t& current_cell_pos = tile_slab_state_.current_cell_pos_[aid]; + + // Iterate over the remaining tile slab cells in a sorted order + for(; current_cell_pos buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate new local buffer offset + local_buffer_offset = cell_pos_[current_cell_pos] * cell_size; + + // Copy cell slab + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_size); + + // Update buffer offset + buffer_offset += cell_size; + } + + // Mark tile slab as done + if(current_cell_pos == cell_num) + tile_slab_state_.copy_tile_slab_done_[aid] = true; + + // Set user buffer size + buffer_size = buffer_offset; +} + + +void ArraySortedReadState::copy_tile_slab_sparse_var(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + copy_state_.buffer_sizes_[bid+1] = 0; // Nothing written + return; + } + + // For easy reference + size_t cell_size = sizeof(size_t); + size_t cell_size_var; + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t& buffer_offset_var = copy_state_.buffer_offsets_[bid+1]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + size_t buffer_size_var = copy_state_.buffer_sizes_[bid+1]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* buffer_var = (char*) copy_state_.buffers_[bid+1]; + char* local_buffer_var = (char*) buffers_[copy_id_][bid+1]; + size_t local_buffer_var_size = buffer_sizes_tmp_[copy_id_][bid+1]; + size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; + int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; + int64_t& current_cell_pos = tile_slab_state_.current_cell_pos_[aid]; + + // Iterate over the remaining tile slab cells in a sorted order + for(; current_cell_pos buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate variable cell size + int64_t cell_start = cell_pos_[current_cell_pos]; + int64_t cell_end = cell_start + 1; + cell_size_var = + (cell_end == cell_num) ? + local_buffer_var_size - local_buffer_s[cell_start] : + local_buffer_s[cell_end] - local_buffer_s[cell_start]; + + // Handle overflow for the the variable-length buffer + if(buffer_offset_var + cell_size_var > buffer_size_var) { + overflow_[aid] = true; + break; + } + + // Copy fixed-sized offset + memcpy( + buffer + buffer_offset, + &buffer_offset_var, + sizeof(size_t)); + buffer_offset += sizeof(size_t); + + // Copy variable-sized values + memcpy( + buffer_var + buffer_offset_var, + local_buffer_var + local_buffer_s[cell_start], + cell_size_var); + buffer_offset_var += cell_size_var; + } + + // Mark tile slab as done + if(current_cell_pos == cell_num) + tile_slab_state_.copy_tile_slab_done_[aid] = true; + + // Set user buffer sizes + buffer_size = buffer_offset; + buffer_size_var = buffer_offset_var; +} + int ArraySortedReadState::create_buffers() { for(int j=0; j<2; ++j) { buffers_[j] = (void**) malloc(buffer_num_ * sizeof(void*)); @@ -1237,13 +1474,23 @@ void ArraySortedReadState::free_tile_slab_state() { int anum = (int) attribute_ids_.size(); // Clean up - for(int i=0; i @@ -1283,7 +1530,7 @@ int64_t ArraySortedReadState::get_tile_id(int aid) { } template -void ArraySortedReadState::handle_copy_requests() { +void ArraySortedReadState::handle_copy_requests_dense() { // Handle copy requests indefinitely for(;;) { // Wait for AIO @@ -1300,7 +1547,45 @@ void ArraySortedReadState::handle_copy_requests() { reset_tile_slab_state(); // Start the copy - copy_tile_slab(); + copy_tile_slab_dense(); + + // Wait in case of overflow + if(overflow()) { + block_overflow(); + block_aio(copy_id_); + release_copy(copy_id_); + wait_overflow(); + continue; + } + + // Copy is done + block_aio(copy_id_); + release_copy(copy_id_); + copy_id_ = (copy_id_ + 1) % 2; + } +} + +template +void ArraySortedReadState::handle_copy_requests_sparse() { + // Handle copy requests indefinitely + for(;;) { + // Wait for AIO + wait_aio(copy_id_); + + // Kill thread, after releasing any blocked resources + if(copy_thread_canceled_) { + copy_thread_running_ = false; + return; + } + + // Sort the cell positions + if(copy_tile_slab_done()) { + reset_tile_slab_state(); + sort_cell_pos(); + } + + // Start the copy + copy_tile_slab_sparse(); // Wait in case of overflow if(overflow()) { @@ -1342,6 +1627,10 @@ void ArraySortedReadState::init_copy_state() { } void ArraySortedReadState::init_tile_slab_info() { + // Do nothing in the case of sparse arrays + if(!array_->array_schema()->dense()) + return; + // For easy reference int anum = (int) attribute_ids_.size(); @@ -1365,6 +1654,9 @@ void ArraySortedReadState::init_tile_slab_info() { template void ArraySortedReadState::init_tile_slab_info(int id) { + // Sanity check + assert(array_->array_schema()->dense()); + // For easy reference int anum = (int) attribute_ids_.size(); @@ -1391,18 +1683,34 @@ void ArraySortedReadState::init_tile_slab_info(int id) { void ArraySortedReadState::init_tile_slab_state() { // For easy reference int anum = (int) attribute_ids_.size(); + bool dense = array_->array_schema()->dense(); - // Allocations and initializations + // Both for dense and sparse tile_slab_state_.copy_tile_slab_done_ = new bool[anum]; - tile_slab_state_.current_offsets_ = new size_t[anum]; - tile_slab_state_.current_coords_ = new void*[anum]; - tile_slab_state_.current_tile_ = new int64_t[anum]; - - for(int i=0; i -bool ArraySortedReadState::next_tile_slab_col() { +bool ArraySortedReadState::next_tile_slab_dense_col() { // Quick check if done if(read_tile_slabs_done_) return false; @@ -1525,7 +1833,7 @@ bool ArraySortedReadState::next_tile_slab_col() { } template -bool ArraySortedReadState::next_tile_slab_row() { +bool ArraySortedReadState::next_tile_slab_dense_row() { // Quick check if done if(read_tile_slabs_done_) return false; @@ -1603,62 +1911,464 @@ bool ArraySortedReadState::next_tile_slab_row() { } template -int ArraySortedReadState::read() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - int mode = array_->mode(); +bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; - if(mode == TILEDB_ARRAY_READ_SORTED_COL) { - if(array_schema->dense()) - return read_dense_sorted_col(); - else - return read_sparse_sorted_col(); - } else if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { - if(array_schema->dense()) - return read_dense_sorted_row(); - else - return read_sparse_sorted_row(); - } else { - assert(0); // The code should never reach here + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; } -} -template -int ArraySortedReadState::read_dense_sorted_col() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_+1)%2; - // Check if this can be satisfied with a default read - if(array_schema->cell_order() == TILEDB_COL_MAJOR && - array_schema->is_contained_in_tile_slab_row(subarray)) - return array_->read_default( - copy_state_.buffers_, - copy_state_.buffer_sizes_); - - // Iterate over each tile slab - while(next_tile_slab_col()) { - // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; - - // Handle overflow - if(resume_aio_) - break; + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; } - // Wait for copy to finish - int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; - wait_copy(copy_id); - - // Assign the true buffer sizes - for(int i=0; i +bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const float* subarray = (const float*) subarray_; + const float* domain = (const float*) array_schema->domain(); + const float* tile_extents = (const float*) array_schema->tile_extents(); + float* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (float*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + float upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; + float cropped_upper = + floor((upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1]) * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - FLT_MIN, subarray[2*(dim_num_-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; i +bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const double* subarray = (const double*) subarray_; + const double* domain = (const double*) array_schema->domain(); + const double* tile_extents = (const double*) array_schema->tile_extents(); + double* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (double*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + double upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; + double cropped_upper = + floor((upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1]) * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - DBL_MIN, subarray[2*(dim_num_-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; i +bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + T upper = subarray[0] + tile_extents[0]; + T cropped_upper = + (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i +bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const float* subarray = (const float*) subarray_; + const float* domain = (const float*) array_schema->domain(); + const float* tile_extents = (const float*) array_schema->tile_extents(); + float* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (float*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + float upper = subarray[0] + tile_extents[0]; + float cropped_upper = + floor((upper - domain[0]) / tile_extents[0]) * tile_extents[0] + + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - FLT_MIN, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i +bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const double* subarray = (const double*) subarray_; + const double* domain = (const double*) array_schema->domain(); + const double* tile_extents = (const double*) array_schema->tile_extents(); + double* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (double*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + double upper = subarray[0] + tile_extents[0]; + double cropped_upper = + floor((upper - domain[0]) / tile_extents[0]) * tile_extents[0] + + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - DBL_MIN, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i +int ArraySortedReadState::read() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int mode = array_->mode(); + + if(mode == TILEDB_ARRAY_READ_SORTED_COL) { + if(array_schema->dense()) + return read_dense_sorted_col(); + else + return read_sparse_sorted_col(); + } else if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(array_schema->dense()) + return read_dense_sorted_row(); + else + return read_sparse_sorted_row(); + } else { + assert(0); // The code should never reach here + } +} + +template +int ArraySortedReadState::read_dense_sorted_col() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_COL_MAJOR && + array_schema->is_contained_in_tile_slab_row(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_dense_col()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i()) { + while(next_tile_slab_dense_row()) { // Read the next tile slab with the default cell order if(read_tile_slab() != TILEDB_ASRS_OK) return TILEDB_ASRS_ERR; @@ -1709,7 +2419,41 @@ int ArraySortedReadState::read_dense_sorted_row() { template int ArraySortedReadState::read_sparse_sorted_col() { - // TODO + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_COL_MAJOR && + array_schema->is_contained_in_tile_slab_row(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_sparse_col()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i int ArraySortedReadState::read_sparse_sorted_row() { - // TODO + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_ROW_MAJOR && + array_schema->is_contained_in_tile_slab_col(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_sparse_row()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + // Wait for copy and AIO to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i void ArraySortedReadState::reset_tile_slab_state() { // For easy reference int anum = (int) attribute_ids_.size(); - T** current_coords = (T**) tile_slab_state_.current_coords_; - const T* tile_slab = (const T*) tile_slab_norm_[copy_id_]; + bool dense = array_->array_schema()->dense(); - // Reset values - for(int i=0; i +void ArraySortedReadState::sort_cell_pos() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int dim_num = array_schema->dim_num(); + int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; + int mode = array_->mode(); + const T* buffer = static_cast(buffers_[copy_id_][coords_buf_i_]); + + // Populate cell_pos + cell_pos_.resize(cell_num); + for(int i=0; i(buffer, dim_num)); + } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + // Sort cell positions + SORT( + cell_pos_.begin(), + cell_pos_.end(), + SmallerCol(buffer, dim_num)); + } +} + int ArraySortedReadState::unlock_aio_mtx() { if(pthread_mutex_unlock(&aio_mtx_)) { std::string errmsg = "Cannot unlock AIO mutex"; diff --git a/core/src/fragment/write_state.cc b/core/src/fragment/write_state.cc index 2e2744bc..cdae69b9 100644 --- a/core/src/fragment/write_state.cc +++ b/core/src/fragment/write_state.cc @@ -30,6 +30,7 @@ * This file implements the WriteState class. */ +#include "comparators.h" #include "constants.h" #include "utils.h" #include "write_state.h" From 01a82abc5e95aa6576ec82124a6cbef80b71f5a6 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 17 Oct 2016 13:08:29 -0400 Subject: [PATCH 15/57] Debugged sorted sparse reads --- core/src/array/array.cc | 9 ++ core/src/array/array_sorted_read_state.cc | 8 +- .../src/tiledb_array_read_sorted_sparse.cc | 87 +++++++++++++++++++ 3 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 examples/src/tiledb_array_read_sorted_sparse.cc diff --git a/core/src/array/array.cc b/core/src/array/array.cc index e9478455..96d01ff9 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -571,6 +571,8 @@ int Array::init( attributes_vec.pop_back(); } else { // Custom attributes // Get attributes + bool coords_found = false; + bool sparse = !array_schema->dense(); for(int i=0; i TILEDB_NAME_MAX_LEN) { @@ -580,6 +582,8 @@ int Array::init( return TILEDB_AR_ERR; } attributes_vec.push_back(attributes[i]); + if(!strcmp(attributes[i], TILEDB_COORDS)) + coords_found = true; } // Sanity check on duplicates @@ -589,6 +593,11 @@ int Array::init( tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; return TILEDB_AR_ERR; } + + // For the case of the clone sparse array, append coordinates if they do + // not exist already + if(sparse && array_clone == NULL && !coords_found) + attributes_vec.push_back(TILEDB_COORDS); } // Set attribute ids diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index efdf2648..162cc222 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -204,7 +204,6 @@ ArraySortedReadState::~ArraySortedReadState() { PRINT_ERROR(errmsg); tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; } - } @@ -1431,6 +1430,10 @@ void ArraySortedReadState::free_copy_state() { } void ArraySortedReadState::free_tile_slab_info() { + // Do nothing in the case of sparse arrays + if(!array_->array_schema()->dense()) + return; + // For easy reference int anum = (int) attribute_ids_.size(); @@ -1703,14 +1706,13 @@ void ArraySortedReadState::init_tile_slab_state() { tile_slab_state_.current_tile_[i] = 0; } } else { // SPARSE - tile_slab_state_.copy_tile_slab_done_ = NULL; tile_slab_state_.current_offsets_ = NULL; tile_slab_state_.current_coords_ = NULL; tile_slab_state_.current_tile_ = NULL; tile_slab_state_.current_cell_pos_ = new int64_t[anum]; for(int i=0; i + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Subarray and attributes + int64_t subarray[] = { 3, 4, 2, 4 }; + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + "my_workspace/sparse_arrays/my_array_B", // Array name + TILEDB_ARRAY_READ_SORTED_ROW, // Mode + subarray, // Constrain in subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Prepare cell buffers + int buffer_a1[2]; + void* buffers[] = { buffer_a1 }; + size_t buffer_sizes[] = { sizeof(buffer_a1) }; + + + // Loop until no overflow + printf(" a1\n----\n"); + do { + printf("Reading cells...\n"); + + // Read from array + tiledb_array_read(tiledb_array, buffers, buffer_sizes); + + // Print cell values + int64_t result_num = buffer_sizes[0] / sizeof(int); + for(int i=0; i Date: Mon, 17 Oct 2016 16:44:44 -0400 Subject: [PATCH 16/57] Fixed bug in sorted sparse reads and started sorted dense writes --- core/include/array/array.h | 53 +- core/include/array/array_sorted_read_state.h | 2 +- core/include/array/array_sorted_write_state.h | 1069 ++++++ core/include/c_api/c_api.h | 19 +- core/include/c_api/constants.h | 6 +- core/src/array/array.cc | 128 +- core/src/array/array_sorted_read_state.cc | 10 +- core/src/array/array_sorted_write_state.cc | 2877 +++++++++++++++++ core/src/misc/utils.cc | 2 + .../src/tiledb_array_write_sorted_dense.cc | 80 + 10 files changed, 4215 insertions(+), 31 deletions(-) create mode 100644 core/include/array/array_sorted_write_state.h create mode 100644 core/src/array/array_sorted_write_state.cc create mode 100644 examples/src/tiledb_array_write_sorted_dense.cc diff --git a/core/include/array/array.h b/core/include/array/array.h index 516333af..3393bdfd 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -36,6 +36,7 @@ #include "aio_request.h" #include "array_read_state.h" #include "array_sorted_read_state.h" +#include "array_sorted_write_state.h" #include "array_schema.h" #include "book_keeping.h" #include "config.h" @@ -73,6 +74,7 @@ extern std::string tiledb_ar_errmsg; class ArrayReadState; class ArraySortedReadState; +class ArraySortedWriteState; class Fragment; @@ -277,6 +279,8 @@ class Array { * of the array. * @param mode The mode of the array. It must be one of the following: * - TILEDB_ARRAY_WRITE + * - TILEDB_ARRAY_WRITE_SORTED_COL + * - TILEDB_ARRAY_WRITE_SORTED_ROW * - TILEDB_ARRAY_WRITE_UNSORTED * - TILEDB_ARRAY_READ * - TILEDB_ARRAY_READ_SORTED_COL @@ -357,6 +361,17 @@ class Array { * of times, and all the writes will occur in the same fragment. * Moreover, the buffers need not be synchronized, i.e., some buffers * may have more cells than others when the function is invoked. + * - TILEDB_ARRAY_WRITE_SORTED_COL: \n + * In this mode, the cell values are provided in the buffer in + * column-major + * order with respect to the subarray used upon array initialization. + * TileDB will properly re-organize the cells so that they follow the + * array cell order for storage on the disk. + * - TILEDB_ARRAY_WRITE_SORTED_ROW: \n + * In this mode, the cell values are provided in the buffer in row-major + * order with respect to the subarray used upon array initialization. + * TileDB will properly re-organize the cells so that they follow the + * array cell order for storage on the disk. * - TILEDB_ARRAY_WRITE_UNSORTED: \n * This mode is applicable to sparse arrays, or when writing sparse * updates to a dense array. One of the buffers holds the coordinates. @@ -379,7 +394,31 @@ class Array { * a one-to-one correspondence). * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. */ - int write(const void** buffers, const size_t* buffer_sizes); + int write(const void** buffers, const size_t* buffer_sizes); + + /** + * Performs a write operation in the array. The cell values are provided + * in a set of buffers (one per attribute specified upon initialization). + * Note that there must be a one-to-one correspondance between the cell + * values across the attribute buffers. + * + * The array must be initialized in moder TILEDB_ARRAY_WRITE or + * TILEDB_ARRAY_WRITE_UNSORTED. These modes are essentially the default modes. + * Modes TILEDB_ARRAY_WRITE_SORTED_COL and TILEDB_ARRAY_WRITE_SORTED_ROW are + * more complicated and, thus, handled by the ArraySortedWriteState class. + * + * @param buffers An array of buffers, one for each attribute. These must be + * provided in the same order as the attributes specified in + * init() or reset_attributes(). The case of variable-sized attributes is + * special. Instead of providing a single buffer for such an attribute, + * **two** must be provided: the second holds the variable-sized cell + * values, whereas the first holds the start offsets of each cell in the + * second buffer. + * @param buffer_sizes The sizes (in bytes) of the input buffers (there is + * a one-to-one correspondence). + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ + int write_default(const void** buffers, const size_t* buffer_sizes); private: /* ********************************* */ @@ -408,6 +447,8 @@ class Array { ArrayReadState* array_read_state_; /** The sorted read state of the array. */ ArraySortedReadState* array_sorted_read_state_; + /** The sorted write state of the array. */ + ArraySortedWriteState* array_sorted_write_state_; /** * The ids of the attributes the array is initialized with. Note that the * array may be initialized with a subset of attributes when writing or @@ -420,9 +461,13 @@ class Array { std::vector fragments_; /** * The array mode. It must be one of the following: - * - TILEDB_WRITE - * - TILEDB_WRITE_UNSORTED - * - TILEDB_READ + * - TILEDB_ARRAY_WRITE + * - TILEDB_ARRAY_WRITE_SORTED_COL + * - TILEDB_ARRAY_WRITE_SORTED_ROW + * - TILEDB_ARRAY_WRITE_UNSORTED + * - TILEDB_ARRAY_READ + * - TILEDB_ARRAY_READ_SORTED_COL + * - TILEDB_ARRAY_READ_SORTED_ROW */ int mode_; /** diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 1cb7b1bf..0aec22c5 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -215,7 +215,7 @@ class ArraySortedReadState { /** - * Initialized the array sorted read state. + * Initializes the array sorted read state. * * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. */ diff --git a/core/include/array/array_sorted_write_state.h b/core/include/array/array_sorted_write_state.h new file mode 100644 index 00000000..69deda30 --- /dev/null +++ b/core/include/array/array_sorted_write_state.h @@ -0,0 +1,1069 @@ +/** + * @file array_sorted_write_state.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file defines class ArraySortedWriteState. + */ + +#ifndef __ARRAY_SORTED_WRITE_STATE_H__ +#define __ARRAY_SORTED_WRITE_STATE_H__ + +#include "array.h" +#include +#include +#include + + +/* ********************************* */ +/* CONSTANTS */ +/* ********************************* */ + +/**@{*/ +/** Return code. */ +#define TILEDB_ASWS_OK 0 +#define TILEDB_ASWS_ERR -1 +/**@}*/ + +/** Default error message. */ +#define TILEDB_ASWS_ERRMSG std::string("[TileDB::ArraySortedWriteState] Error: ") + + + + +/* ********************************* */ +/* GLOBAL VARIABLES */ +/* ********************************* */ + +extern std::string tiledb_asws_errmsg; + + +class Array; + +/** + * It is responsibled for re-arranging the cells sorted in column- or row-major + * order within the user subarray, such that they are sorted along the array + * global cell order, and writes them into a new fragment. + */ +class ArraySortedWriteState { + public: + + /* ********************************* */ + /* TYPE DEFINITIONS */ + /* ********************************* */ + + /** Used in functors. */ +// struct ASRS_Data { + /** An id (typically an attribute id or a tile slab id. */ +// int id_; + /** Another id (typically a tile id). */ +// int64_t id_2_; + /** The calling object. */ +// ArraySortedReadState* asrs_; +// }; + + /** Stores state about the current read/copy request. */ +// struct CopyState { + /** Current offsets in user buffers. */ +// size_t* buffer_offsets_; + /** User buffer sizes. */ +// size_t* buffer_sizes_; + /** User buffers. */ +// void** buffers_; +// }; + + /** Info about a tile slab. */ +// struct TileSlabInfo { + /** Used in calculations of cell ids, one vector per tile. */ +// int64_t** cell_offset_per_dim_; + /** Cell slab size per attribute per tile. */ +// size_t** cell_slab_size_; + /** Number of cells in a cell slab per tile. */ +// int64_t* cell_slab_num_; + /** + * The range overlap of the **normalized** tile slab with each + * **normalized** tile range. + */ +// void** range_overlap_; + /** + * Start offsets of each tile in the local buffer, per attribute per tile. + */ +// size_t** start_offsets_; + /** Number of tiles in the tile slab. */ +// int64_t tile_num_; + /** Used in calculations of tile ids. */ +// int64_t* tile_offset_per_dim_; +// }; + + /** The state for a tile slab copy. */ +// struct TileSlabState { + /** Keeps track of whether a tile slab copy for an attribute id done. */ +// bool* copy_tile_slab_done_; + /** + * Applicable only to the sparse case. It holds the current cell position + * to be considered, per attribute. + */ +// int64_t* current_cell_pos_; + /** Current coordinates in tile slab per attribute. */ +// void** current_coords_; + /** + * The offset in the local buffers of the next cell slab to be copied per + * attribute. Note that this applies only to fixed-sized attributes + * because the offsets of the variable-sized attributes can be derived from + * the buffers that hold the fixed-sized offsets. + */ +// size_t* current_offsets_; + /** The current tile per attribute. */ +// int64_t* current_tile_; +// }; + + + /* ********************************* */ + /* CONSTRUCTORS & DESTRUCTORS */ + /* ********************************* */ + + /** + * Constructor. + * + * @param array The array this array sorted read state belongs to. + */ + ArraySortedWriteState(Array* array); + + /** Destructor. */ + ~ArraySortedWriteState(); + + + + + /* ********************************* */ + /* ACCESSORS */ + /* ********************************* */ + + /** Returns true if the current slab is finished being copied. */ +// bool copy_tile_slab_done() const; + + /** True if read is done for all attributes. */ +// bool done() const; + + /** Returns true if copying into the user buffers resulted in overflow. */ +// bool overflow() const; + + /** + * Returns true if copying into the user buffers resulted in overflow, for + * the input attribute id. + */ +// bool overflow(int attribute_id) const; + + + + /* ********************************* */ + /* MUTATORS */ + /* ********************************* */ + + + /** + * Initializes the array sorted write state. + * + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. + */ + int init(); + + /** + * Same as Array::write(), but it sorts the cells in the buffers based on the + * array global cell order, prior to writing them to the disk. Note that this + * function will fail if there is not enough system memory to hold the cells + * of a 'tile slab' overlapping with the selected subarray. + * + * @param buffers The buffers that hold the input cells to be written. + * @param buffer_sizes The corresponding buffer sizes. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. + */ + int write(const void** buffers, const size_t* buffer_sizes); + + + + + private: + /* ********************************* */ + /* PRIVATE ATTRIBUTES */ + /* ********************************* */ + + /** Function for advancing a cell slab during a copy operation. */ +// void *(*advance_cell_slab_) (void*); + + /** AIO counter. */ +// int aio_cnt_; + + /** The AIO mutex conditions (one for each buffer). */ +// pthread_cond_t aio_cond_[2]; + + /** Data for the AIO requests. */ +// ASRS_Data aio_data_[2]; + + /** The current id of the buffers the next AIO will occur into. */ +// int aio_id_; + + /** The AIO mutex. */ +// pthread_mutex_t aio_mtx_; + + /** Indicates overflow per tile slab per attribute upon an AIO operation. */ +// bool* aio_overflow_[2]; + + /** AIO requests. */ +// AIO_Request aio_request_[2]; + + /** The status of the AIO requests.*/ +// int aio_status_[2]; + + /** The array this sorted read state belongs to. */ + Array* array_; + + /** The ids of the attributes the array was initialized with. */ +// std::vector attribute_ids_; + + /** + * The sizes of the attributes. For variable-length attributes, sizeof(size_t) + * is stored. + */ +// std::vector attribute_sizes_; + + /** Number of allocated buffers. */ +// int buffer_num_; + + /** Allocated sizes for buffers_ (similar to those used in Array::read). */ +// size_t* buffer_sizes_[2]; + + /** Temporary buffer sizes used in AIO requests. */ +// size_t* buffer_sizes_tmp_[2]; + + /** + * Backup of temporary buffer sizes used in AIO requests (used when there is + * overflow). + */ +// size_t* buffer_sizes_tmp_bak_[2]; + + /** Local buffers (similar to those used in Array::read). */ +// void** buffers_[2]; + + /** Function for calculating cell slab info during a copy operation. */ +// void *(*calculate_cell_slab_info_) (void*); + + /** Function for calculating tile slab info during a copy operation. */ +// void *(*calculate_tile_slab_info_) (void*); + + /** + * Used only in the sparse case. Holds the sorted positions of the cells + * for the current tile slab to be copied. + */ +// std::vector cell_pos_; + + /** + * Used only in the sparse case. It is the element index in attribute_ids_ + * that represents the coordinates attribute. + */ +// int coords_attr_i_; + + /** + * Used only in the sparse case. It is the element index in buffers_ + * that represents the coordinates attribute. + */ +// int coords_buf_i_; + + /** The coordinates size of the array. */ +// size_t coords_size_; + + /** The copy mutex conditions (one for each buffer). */ +// pthread_cond_t copy_cond_[2]; + + /** The current id of the buffers the next copy will occur from. */ +// int copy_id_; + + /** The copy state. */ +// CopyState copy_state_; + + /** The copy mutex. */ +// pthread_mutex_t copy_mtx_; + + /** The thread tha handles all the copying in the background. */ +// pthread_t copy_thread_; + + /** True if the copy thread is canceled. */ +// bool copy_thread_canceled_; + + /** True if the copy thread is running. */ +// bool copy_thread_running_; + + /** The number of dimensions in the array. */ +// int dim_num_; + + /** + * Used only in the sparse case. It is true if the coordinates are not asked + * by the user and, thus, TileDB had to append them as an extra attribute + * to facilitate sorting the cell positions. + * + */ +// bool extra_coords_; + + /** The overflow mutex condition. */ + // pthread_cond_t overflow_cond_; + + /** The overflow mutex. */ +// pthread_mutex_t overflow_mtx_; + + /** Overflow flag for each attribute. */ +// bool* overflow_; + + /** + * Overflow flag for each attribute. It starts with *true* for all + * attributes, and becomes false once an attribute does not overflow any more. + */ +// bool* overflow_still_; + + /** True if no more tile slabs to read. */ +// bool read_tile_slabs_done_; + + /** True if a copy must be resumed. */ +// bool resume_copy_; + + /** True if an AIO must be resumed. */ +// bool resume_aio_; + + /** The query subarray. */ +// void* subarray_; + + /** Auxiliary variable used in calculate_tile_slab_info(). */ +// void* tile_coords_; + + /** Auxiliary variable used in calculate_tile_slab_info(). */ +// void* tile_domain_; + + /** The tile slab to be read for the first and second buffers. */ +// void* tile_slab_[2]; + + /** Indicates if the tile slab has been initialized. */ +// bool tile_slab_init_[2]; + + /** Normalized tile slab. */ +// void* tile_slab_norm_[2]; + + /** The info for each of the two tile slabs under investigation. */ +// TileSlabInfo tile_slab_info_[2]; + + /** The state for the current tile slab being copied. */ +// TileSlabState tile_slab_state_; + + /** Wait for copy flags, one for each local buffer. */ +// bool wait_copy_[2]; + + /** Wait for AIO flags, one for each local buffer. */ +// bool wait_aio_[2]; + + /* ********************************* */ + /* PRIVATE METHODS */ + /* ********************************* */ + + /** + * Advances a cell slab focusing on column-major order, and updates + * the CopyState and TileSlabState. + * Used in copy_tile_slab(). + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template +// static void *advance_cell_slab_col_s(void* data); + + /** + * Advances a cell slab focusing on row-major order, and updates + * the CopyState and TileSlabState. + * Used in copy_tile_slab(). + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template + // static void *advance_cell_slab_row_s(void* data); + + /** + * Advances a cell slab when the requested order is column-major. + * + * @template T The domain type. + * @param aid The id of the attribute in attribute_ids_ to focus on. + * @return void + */ +// template +// void advance_cell_slab_col(int aid); + + /** + * Advances a cell slab when the requested order is row-major. + * + * @template T The domain type. + * @param aid The id of the attribute in attribute_ids_ to focus on. + * @return void + */ +// template +// void advance_cell_slab_row(int aid); + + /** + * Called when an AIO completes. + * + * @param data A ASRS_Request object. + * @return void + */ +// static void *aio_done(void* data); + + /** True if some attribute overflowed for the input tile slab upon an AIO. */ +// bool aio_overflow(int aio_id); + + /** Sets the flag of wait_aio_[id] to true. */ +// void block_aio(int id); + + /** Sets the flag of wait_copy_[id] to true. */ +// void block_copy(int id); + + /** Sets the flag of resume_copy_ to true. */ +// void block_overflow(); + + /** + * Calculate the attribute ids specified by the user upon array + * initialization. + */ +// void calculate_attribute_ids(); + + /** + * Calculates the number of buffers to be allocated, based on the number + * of attributes initialized for the array. + * + * @return void + */ +// void calculate_buffer_num(); + + /** + * Calculates the buffer sizes based on the array type. + * + * @return void + */ +// void calculate_buffer_sizes(); + + /** + * Calculates the buffer sizes based on the subarray and the number of cells + * in a (full) tile slab. Applicable to dense arrays. + * + * @return void + */ +// void calculate_buffer_sizes_dense(); + + /** + * Calculates the buffer sizes based on configurable parameters. Applicable to + * sparse arrays. + * + * @return void + */ +// void calculate_buffer_sizes_sparse(); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is column-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template +// static void *calculate_cell_slab_info_col_col_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is row-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template + // static void *calculate_cell_slab_info_col_row_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order in row-major and the **array** cell + * order is column-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template +// static void *calculate_cell_slab_info_row_col_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is row-major and the **array** cell + * order is row-major. + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template +// static void *calculate_cell_slab_info_row_row_s(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ +// template +// void calculate_cell_slab_info_col_col(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is column-major and the **array** cell + * order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ +// template +// void calculate_cell_slab_info_col_row(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is row-major and the **array** cell + * order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ +// template +// void calculate_cell_slab_info_row_row(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **user** cell order is row-major and the **array** cell + * order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ +// template +// void calculate_cell_slab_info_row_col(int id, int64_t tid); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **array** cell order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @param tid The tile id. + * @return void. + */ +// template +// void calculate_cell_slab_info_row(int id, int64_t tid); + + /** + * Calculates the **normalized** tile domain overlapped by the input tile + * slab. Note that this domain is the same for all tile slabs + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ +// template +// void calculate_tile_domain(int id); + + /** + * Calculates the info used in the copy_tile_slab() function. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ +// template +// void calculate_tile_slab_info(int id); + + /** + * Calculates tile slab info for the case where the **array** tile order is + * column-major + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template +// static void *calculate_tile_slab_info_col(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **array** tile order is column-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ +// template +// void calculate_tile_slab_info_col(int id); + + /** + * Calculates tile slab info for the case where the **array** tile order is + * row-major + * + * @template T The domain type. + * @param data Essentially a pointer to a ASRS_Data object. + * @return void + */ +// template +// static void *calculate_tile_slab_info_row(void* data); + + /** + * Calculates the info used in the copy_tile_slab() function, for the case + * where the **array** tile order is row-major. + * + * @param T The domain type. + * @param id The tile slab id. + * @return void. + */ +// template +// void calculate_tile_slab_info_row(int id); + + /** + * Function called by the copy thread. + * + * @param context This is practically the ArraySortedReadState object for + * which the function is called (typically *this* is passed to this + * argument by the caller). + */ +// static void *copy_handler(void* context); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order. + * Applicable to dense arrays. + * + * @return void. + */ +// void copy_tile_slab_dense(); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order. + * Applicable to sparse arrays. + * + * @return void. + */ +// void copy_tile_slab_sparse(); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular fixed-length attribute. + * Applicable to dense arrays. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ +// void copy_tile_slab_dense(int aid, int bid); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular fixed-length attribute. + * Applicable to sparse arrays. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ +// void copy_tile_slab_sparse(int aid, int bid); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular variable-length attribute. + * Applicable to dense arrays. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ +// void copy_tile_slab_dense_var(int aid, int bid); + + /** + * Copies a tile slab from the local buffers into the user buffers, + * properly re-organizing the cell order to fit the targeted order, + * focusing on a particular variable-length attribute. + * Applicable to sparse arrays. + * + * @param aid The index on attribute_ids_ to focus on. + * @param bid The index on the copy state buffers to focus on. + * @return void. + */ +// void copy_tile_slab_sparse_var(int aid, int bid); + + /** + * Creates the buffers based on the calculated buffer sizes. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int create_buffers(); + + /** Frees the copy state. */ + // void free_copy_state(); + + /** Frees the tile slab info. */ +// void free_tile_slab_info(); + + /** Frees the tile slab state. */ +// void free_tile_slab_state(); + + /** + * Returns the cell id along the **array** order for the current coordinates + * in the tile slab state for a particular attribute. + * + * @template T The domain type. + * @param aid The targeted attribute. + * @return The cell id. + */ +// template +// int64_t get_cell_id(int aid); + + /** + * Returns the tile id along the **array** order for the current coordinates + * in the tile slab state for a particular attribute. + * + * @template T The domain type. + * @param aid The targeted attribute. + * @return The tile id. + */ +// template +// int64_t get_tile_id(int aid); + + /** + * Handles the copy requests. Applicable to dense arrays. + * + * @template T The domain type. + * @return void. + */ +// template +// void handle_copy_requests_dense(); + + /** + * Handles the copy requests. Applicable to sparse arrays. + * + * @template T The domain type. + * @return void. + */ +// template +// void handle_copy_requests_sparse(); + + /** Initializes the AIO requests. */ +// void init_aio_requests(); + + /** Initializes the copy state. */ +// void init_copy_state(); + + /** Initializes the tile slab info. */ +// void init_tile_slab_info(); + + /** + * Initializes the tile slab info for a particular tile slab, using the + * input tile number. + * + * @template T The domain type. + * @param id The slab id. + * @return void. + */ +// template +// void init_tile_slab_info(int id); + + /** Initializes the tile slab state. */ +// void init_tile_slab_state(); + + /** + * Locks the AIO mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int lock_aio_mtx(); + + /** + * Locks the copy mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int lock_copy_mtx(); + + /** + * Locks the overflow mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int lock_overflow_mtx(); + + /** + * Retrieves the next column tile slab to be processed. Applicable to dense + * arrays. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ +// template +// bool next_tile_slab_dense_col(); + + /** + * Retrieves the next row tile slab to be processed. Applicable to dense + * arrays. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ +// template +// bool next_tile_slab_dense_row(); + + /** + * Retrieves the next column tile slab to be processed. Applicable to sparse + * arrays. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ +// template +// bool next_tile_slab_sparse_col(); + + /** + * Retrieves the next row tile slab to be processed. Applicable to sparse + * arrays. + * + * @template T The domain type. + * @return True if the next tile slab was retrieved, and false otherwise. + */ +// template +// bool next_tile_slab_sparse_row(); + + /** + * Same as Array::read(), but it sorts the cells in the buffers based on the + * order the user specified in Array::init(). Note that this function will + * fail if there is not enough system memory to hold the cells of a + * 'tile slab' overlapping with the selected subarray. + * + * @template T The domain type. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// template +// int read(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * column-major order with respect to the selected subarray. + * Applicable only to dense arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ +// template +// int read_dense_sorted_col(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * row-major order with respect to the selected subarray. + * Applicable only to dense arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ +// template +// int read_dense_sorted_row(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * column-major order with respect to the selected subarray. + * Applicable only to sparse arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ +// template +// int read_sparse_sorted_col(); + + /** + * Same as read(), but the cells are placed in 'buffers' sorted in + * row-major order with respect to the selected subarray. + * Applicable only to sparse arrays. + * + * @template T The domain type. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + */ +// template +// int read_sparse_sorted_row(); + + /** + * Reads the current tile slab into the input buffers. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int read_tile_slab(); + + /** + * Signals an AIO condition. + * + * @param id The id of the AIO condition to be signaled. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int release_aio(int id); + + /** + * Signals a copy condition. + * + * @param id The id of the copy condition to be signaled. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int release_copy(int id); + + /** + * Signals the overflow condition. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int release_overflow(); + + /** Resets the AIO overflow flags for the input tile slab id. */ +// void reset_aio_overflow(int aio_id); + + /** Resets the temporary buffer sizes for the input tile slab id. */ +// void reset_buffer_sizes_tmp(int id); + + /** Resets the copy state using the input buffer info. */ +// void reset_copy_state(void** buffers, size_t* buffer_sizes); + + /** Resets the oveflow flags to **false**. */ +// void reset_overflow(); + + /** + * Resets the tile_coords_ auxiliary variable. + * + * @template T The domain type. + * @return void. + */ +// template +// void reset_tile_coords(); + + /** + * Resets the tile slab state. + * + * @template T The domain type. + * @return void. + */ +// template +// void reset_tile_slab_state(); + + /** + * Sends an AIO request. + * + * @param aio_id The id of the tile slab the AIO request focuses on. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int send_aio_request(int aio_id); + + /** + * It sorts the positions of the cells based on the coordinates + * of the current tile slab to be copied. + */ +// template +// void sort_cell_pos(); + + /** + * Unlocks the AIO mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int unlock_aio_mtx(); + + /** + * Unlocks the copy mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int unlock_copy_mtx(); + + /** + * Unlocks the overflow mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int unlock_overflow_mtx(); + + /** + * Calculates the new tile and local buffer offset for the new (already + * computed) current cell coordinates in the tile slab. + * + * @template T The domain type + * @param aid The attribute id to focus on. + * @return void. + */ +// template +// void update_current_tile_and_offset(int aid); + + /** + * Waits on a copy operation for the buffer with input id to finish. + * + * @param id The id of the buffer the copy operation must be completed. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int wait_copy(int id); + + /** + * Waits on a AIO operation for the buffer with input id to finish. + * + * @param id The id of the buffer the AIO operation must be completed. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int wait_aio(int id); + + /** + * Waits until there is no buffer overflow. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ +// int wait_overflow(); +}; + +#endif diff --git a/core/include/c_api/c_api.h b/core/include/c_api/c_api.h index 744371f9..b97deb6f 100755 --- a/core/include/c_api/c_api.h +++ b/core/include/c_api/c_api.h @@ -342,8 +342,12 @@ TILEDB_EXPORT int tiledb_array_create( * @param array The directory of the array to be initialized. * @param mode The mode of the array. It must be one of the following: * - TILEDB_ARRAY_WRITE + * - TILEDB_ARRAY_WRITE_SORTED_COL + * - TILEDB_ARRAY_WRITE_SORTED_ROW * - TILEDB_ARRAY_WRITE_UNSORTED * - TILEDB_ARRAY_READ + * - TILEDB_ARRAY_READ_SORTED_COL + * - TILEDB_ARRAY_READ_SORTED_ROW * @param subarray The subarray in which the array read/write will be * constrained on. It should be a sequence of [low, high] pairs (one * pair per dimension), whose type should be the same as that of the @@ -447,6 +451,16 @@ TILEDB_EXPORT int tiledb_array_free_schema( * of times, and all the writes will occur in the same fragment. * Moreover, the buffers need not be synchronized, i.e., some buffers * may have more cells than others when the function is invoked. + * - TILEDB_ARRAY_WRITE_SORTED_COL: \n + * In this mode, the cell values are provided in the buffer in column-major + * order with respect to the subarray used upon array initialization. + * TileDB will properly re-organize the cells so that they follow the + * array cell order for storage on the disk. + * - TILEDB_ARRAY_WRITE_SORTED_ROW: \n + * In this mode, the cell values are provided in the buffer in row-major + * order with respect to the subarray used upon array initialization. + * TileDB will properly re-organize the cells so that they follow the + * array cell order for storage on the disk. * - TILEDB_ARRAY_WRITE_UNSORTED: \n * This mode is applicable to sparse arrays, or when writing sparse updates * to a dense array. One of the buffers holds the coordinates. The cells @@ -477,8 +491,9 @@ TILEDB_EXPORT int tiledb_array_write( /** * Performs a read operation on an array, which must be initialized with mode - * TILEDB_ARRAY_READ. The function retrieves the result cells that lie inside - * the subarray specified in tiledb_array_init() or + * TILEDB_ARRAY_READ, TILEDB_ARRAY_READ_SORTED_COL or + * TILEDB_ARRAY_READ_SORTED_ROW. The function retrieves the result cells that + * lie inside the subarray specified in tiledb_array_init() or * tiledb_array_reset_subarray(). The results are written in input buffers * provided by the user, which are also allocated by the user. Note that the * results are written in the buffers in the same order they appear on the diff --git a/core/include/c_api/constants.h b/core/include/c_api/constants.h index 3d80056f..7df1a061 100644 --- a/core/include/c_api/constants.h +++ b/core/include/c_api/constants.h @@ -37,7 +37,7 @@ #include /** Version. */ -#define TILEDB_VERSION "0.3.4" +#define TILEDB_VERSION "0.3.5" /**@{*/ /** Return code. */ @@ -51,7 +51,9 @@ #define TILEDB_ARRAY_READ_SORTED_COL 1 #define TILEDB_ARRAY_READ_SORTED_ROW 2 #define TILEDB_ARRAY_WRITE 3 -#define TILEDB_ARRAY_WRITE_UNSORTED 4 +#define TILEDB_ARRAY_WRITE_SORTED_COL 4 +#define TILEDB_ARRAY_WRITE_SORTED_ROW 5 +#define TILEDB_ARRAY_WRITE_UNSORTED 6 /**@}*/ /**@{*/ diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 96d01ff9..bb57f698 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -69,6 +69,7 @@ std::string tiledb_ar_errmsg = ""; Array::Array() { array_read_state_ = NULL; array_sorted_read_state_ = NULL; + array_sorted_write_state_ = NULL; array_schema_ = NULL; subarray_ = NULL; aio_thread_created_ = false; @@ -85,6 +86,8 @@ Array::~Array() { delete array_read_state_; if(array_sorted_read_state_ != NULL) delete array_sorted_read_state_; + if(array_sorted_write_state_ != NULL) + delete array_sorted_write_state_; // Applicable only to clones if(array_clone_ != NULL) { @@ -489,6 +492,12 @@ int Array::finalize() { array_sorted_read_state_ = NULL; } + // Clean the array sorted write state + if(array_sorted_write_state_ != NULL) { + delete array_sorted_write_state_; + array_sorted_write_state_ = NULL; + } + // Clean the AIO-related members int rc_aio_thread = aio_thread_destroy(); int rc_aio_cond = TILEDB_AR_OK, rc_aio_mtx = TILEDB_AR_OK; @@ -564,7 +573,6 @@ int Array::init( std::vector attributes_vec; if(attributes == NULL) { // Default: all attributes attributes_vec = array_schema->attributes(); - // TODO: revisit this for sorted writes if(array_schema->dense() && mode != TILEDB_ARRAY_WRITE_UNSORTED) // Remove coordinates attribute for dense arrays, // unless in TILEDB_WRITE_UNSORTED mode @@ -629,6 +637,20 @@ int Array::init( tiledb_ar_errmsg = tiledb_fg_errmsg; return TILEDB_AR_ERR; } + + // Create ArraySortedWriteState + if(mode_ == TILEDB_ARRAY_WRITE_SORTED_COL || + mode_ == TILEDB_ARRAY_WRITE_SORTED_ROW) { + array_sorted_write_state_ = new ArraySortedWriteState(this); + if(array_sorted_write_state_->init() != TILEDB_ASWS_OK) { + // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asrs_errmsg + delete array_sorted_write_state_; + array_sorted_write_state_ = NULL; + return TILEDB_AR_ERR; + } + } else { + array_sorted_write_state_ = NULL; + } } else { // READ MODE // Open fragments if(open_fragments(fragment_names, book_keeping) != TILEDB_AR_OK) { @@ -747,8 +769,34 @@ int Array::reset_subarray(const void* subarray) { else memcpy(subarray_, subarray, subarray_size); - // Re-set of re-initialize fragments + // Re-set or re-initialize fragments if(write_mode()) { // WRITE MODE + // Finalize last fragment + if(fragments_.size() != 0) { + assert(fragments_.size() == 1); + if(fragments_[0]->finalize() != TILEDB_FG_OK) + // TODO: propagate error message here + return TILEDB_AR_ERR; + delete fragments_[0]; + fragments_.clear(); + } + + // Re-initialize ArraySortedWriteState + if(array_sorted_write_state_ != NULL) + delete array_sorted_write_state_; + if(mode_ == TILEDB_ARRAY_WRITE_SORTED_COL || + mode_ == TILEDB_ARRAY_WRITE_SORTED_ROW) { + array_sorted_write_state_ = new ArraySortedWriteState(this); + if(array_sorted_write_state_->init() != TILEDB_ASWS_OK) { + // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asws_errmsg + delete array_sorted_write_state_; + array_sorted_write_state_ = NULL; + return TILEDB_AR_ERR; + } + } else { + array_sorted_write_state_ = NULL; + } + // Get new fragment name std::string new_fragment_name = this->new_fragment_name(); if(new_fragment_name == "") { @@ -823,19 +871,10 @@ int Array::reset_subarray_soft(const void* subarray) { else memcpy(subarray_, subarray, subarray_size); - // Re-set of re-initialize fragments + // Re-set or re-initialize fragments if(write_mode()) { // WRITE MODE - // Get new fragment name - std::string new_fragment_name = this->new_fragment_name(); - if(new_fragment_name == "") - return TILEDB_AS_ERR; - - // Create new fragment - Fragment* fragment = new Fragment(this); - fragments_.push_back(fragment); - if(fragment->init(new_fragment_name, mode_, subarray) != TILEDB_FG_OK) - return TILEDB_AR_ERR; - } else { // READ MODE + // Do nothing + } else { // READ MODE // Re-initialize the read state of the fragments for(int i=0; ireset_read_state(); @@ -861,6 +900,30 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { return TILEDB_AR_ERR; } + // Handle sorted modes + if(mode_ == TILEDB_ARRAY_WRITE_SORTED_COL || + mode_ == TILEDB_ARRAY_WRITE_SORTED_ROW) { + int rc = array_sorted_write_state_->write(buffers, buffer_sizes); + if(rc == TILEDB_ASWS_OK) { + return TILEDB_AR_OK; + } else { + tiledb_ar_errmsg = tiledb_asws_errmsg; + return TILEDB_AR_ERR; + } + } else { // mode_ == TILDB_ARRAY_WRITE or TILEDB_ARRAY_WRITE_UNSORTED + return write_default(buffers, buffer_sizes); + } +} + +int Array::write_default(const void** buffers, const size_t* buffer_sizes) { + // Sanity checks + if(!write_mode()) { + std::string errmsg = "Cannot write to array; Invalid mode"; + PRINT_ERROR(errmsg); + tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; + return TILEDB_AR_ERR; + } + // Create and initialize a new fragment if(fragments_.size() == 0) { // Get new fragment name @@ -887,9 +950,8 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { return TILEDB_AR_ERR; } - // In WRITE_UNSORTED mode, the fragment must be finalized - // TODO: revisit this for sorted writes - if(mode_ == TILEDB_ARRAY_WRITE_UNSORTED) { + // In all modes except TILEDB_ARRAY_WRITE, the fragment must be finalized + if(mode_ != TILEDB_ARRAY_WRITE) { if(fragments_[0]->finalize() != TILEDB_FG_OK) { tiledb_ar_errmsg = tiledb_fg_errmsg; return TILEDB_AR_ERR; @@ -917,6 +979,8 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { // Reset the subarray only if this request does not continue from the last if(aio_last_handled_request_ != aio_request->id_) reset_subarray_soft(aio_request->subarray_); + + // Read rc = read_default(aio_request->buffers_, aio_request->buffer_sizes_); } else { // This may initiate a series of new AIO requests @@ -924,17 +988,38 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { // of the ArraySortedReadState object. if(aio_last_handled_request_ != aio_request->id_) reset_subarray(aio_request->subarray_); + + // Read rc = read(aio_request->buffers_, aio_request->buffer_sizes_); } } else { // WRITE MODE - // TODO: Fix according to read above - rc = write( + // Invoke the write + if(aio_request->mode_ == TILEDB_ARRAY_WRITE || + aio_request->mode_ == TILEDB_ARRAY_WRITE_UNSORTED) { + // Reset the subarray only if this request does not continue from the last + if(aio_last_handled_request_ != aio_request->id_) + reset_subarray_soft(aio_request->subarray_); + + // Write + rc = write_default( (const void**) aio_request->buffers_, (const size_t*) aio_request->buffer_sizes_); + } else { + // This may initiate a series of new AIO requests + // Reset the subarray hard this time (updating also the subarray + // of the ArraySortedReadState object. + if(aio_last_handled_request_ != aio_request->id_) + reset_subarray(aio_request->subarray_); + + // Write + rc = write_default( + (const void**) aio_request->buffers_, + (const size_t*) aio_request->buffer_sizes_); + } } if(rc == TILEDB_AR_OK) { // Success - // Check for overflow + // Check for overflow (applicable only to reads) if(aio_request->mode_ == TILEDB_ARRAY_READ && array_read_state_->overflow()) { *aio_request->status_= TILEDB_AIO_OVERFLOW; @@ -943,7 +1028,8 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { aio_request->overflow_[i] = array_read_state_->overflow(attribute_ids_[i]); } - } else if(aio_request->mode_ != TILEDB_ARRAY_READ && + } else if((aio_request->mode_ == TILEDB_ARRAY_READ_SORTED_COL || + aio_request->mode_ == TILEDB_ARRAY_READ_SORTED_ROW ) && array_sorted_read_state_->overflow()) { *aio_request->status_= TILEDB_AIO_OVERFLOW; if(aio_request->overflow_ != NULL) { diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 162cc222..3f5e5c7e 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -215,6 +215,11 @@ ArraySortedReadState::~ArraySortedReadState() { bool ArraySortedReadState::copy_tile_slab_done() const { for(int i=0; i < (int) attribute_ids_.size(); ++i) { + // Special case for sparse arrays with extra coordinates attribute + if(i == coords_attr_i_ && extra_coords_) + continue; + + // Check if(!tile_slab_state_.copy_tile_slab_done_[i]) return false; } @@ -635,6 +640,7 @@ void ArraySortedReadState::block_overflow() { void ArraySortedReadState::calculate_attribute_ids() { // Initialization attribute_ids_ = array_->attribute_ids(); + coords_attr_i_ = -1; // For ease reference const ArraySchema* array_schema = array_->array_schema(); @@ -645,7 +651,6 @@ void ArraySortedReadState::calculate_attribute_ids() { return; // Find the coordinates index - coords_attr_i_ = -1; for(int i=0; i<(int)attribute_ids_.size(); ++i) { if(attribute_ids_[i] == attribute_num) { coords_attr_i_ = i; @@ -1583,6 +1588,9 @@ void ArraySortedReadState::handle_copy_requests_sparse() { // Sort the cell positions if(copy_tile_slab_done()) { + +std::cout << "resetting...\n"; + reset_tile_slab_state(); sort_cell_pos(); } diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc new file mode 100644 index 00000000..3dfbd7a9 --- /dev/null +++ b/core/src/array/array_sorted_write_state.cc @@ -0,0 +1,2877 @@ +/** + * @file array_sorted_write_state.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file implements the ArraySortedWriteState class. + */ + +#include "array_sorted_write_state.h" +#include "math.h" +#include "utils.h" +#include + + + + +/* ****************************** */ +/* MACROS */ +/* ****************************** */ + +#ifdef VERBOSE +# define PRINT_ERROR(x) std::cerr << TILEDB_ASWS_ERRMSG << x << ".\n" +#else +# define PRINT_ERROR(x) do { } while(0) +#endif + + + + +/* ****************************** */ +/* GLOBAL VARIABLES */ +/* ****************************** */ + +std::string tiledb_asws_errmsg = ""; + + + + +/* ****************************** */ +/* CONSTRUCTORS & DESTRUCTORS */ +/* ****************************** */ + +ArraySortedWriteState::ArraySortedWriteState( + Array* array) + : array_(array) { + +// TODO + +/* + + // Calculate the attribute ids + calculate_attribute_ids(); + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int anum = (int) attribute_ids_.size(); + + // Initializations + aio_id_ = 0; + aio_cnt_ = 0; + coords_size_ = array_schema->coords_size(); + copy_id_ = 0; + dim_num_ = array_schema->dim_num(); + copy_thread_running_ = false; + copy_thread_canceled_ = false; + read_tile_slabs_done_ = false; + resume_copy_ = false; + resume_aio_ = false; + tile_coords_ = NULL; + tile_domain_ = NULL; + for(int i=0; i<2; ++i) { + aio_overflow_[i] = new bool[anum]; + buffer_sizes_[i] = NULL; + buffer_sizes_tmp_[i] = NULL; + buffer_sizes_tmp_bak_[i] = NULL; + buffers_[i] = NULL; + tile_slab_[i] = malloc(2*coords_size_); + tile_slab_norm_[i] = malloc(2*coords_size_); + tile_slab_init_[i] = false; + wait_copy_[i] = false; + wait_aio_[i] = true; + } + overflow_ = new bool[anum]; + overflow_still_ = new bool[anum]; + for(int i=0; ivar_size(attribute_ids_[i])) + attribute_sizes_.push_back(sizeof(size_t)); + else + attribute_sizes_.push_back(array_schema->cell_size(attribute_ids_[i])); + } + + subarray_ = malloc(2*coords_size_); + memcpy(subarray_, array_->subarray(), 2*coords_size_); + + // Calculate number of buffers + calculate_buffer_num(); + + // Calculate buffer sizes + calculate_buffer_sizes(); + + // Initialize tile slab info and state, and copy state + init_tile_slab_info(); + init_tile_slab_state(); + init_copy_state(); + +*/ +} + +ArraySortedWriteState::~ArraySortedWriteState() { +// TODO + +/* + + // Clean up + free(subarray_); + free(tile_coords_); + free(tile_domain_); + delete [] overflow_; + + for(int i=0; i<2; ++i) { + delete [] aio_overflow_[i]; + + if(buffer_sizes_[i] != NULL) + delete [] buffer_sizes_[i]; + if(buffer_sizes_tmp_[i] != NULL) + delete [] buffer_sizes_tmp_[i]; + if(buffer_sizes_tmp_bak_[i] != NULL) + delete [] buffer_sizes_tmp_bak_[i]; + if(buffers_[i] != NULL) { + for(int b=0; barray_schema(); + int mode = array_->mode(); + int cell_order = array_schema->cell_order(); + int tile_order = array_schema->tile_order(); + int coords_type = array_schema->coords_type(); + if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(coords_type == TILEDB_INT32) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else if(coords_type == TILEDB_INT64) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else if(coords_type == TILEDB_FLOAT32) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else if(coords_type == TILEDB_FLOAT64) { + advance_cell_slab_ = advance_cell_slab_row_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_row_row_s : + calculate_cell_slab_info_row_col_s; + } else { + assert(0); + } + } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + if(coords_type == TILEDB_INT32) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else if(coords_type == TILEDB_INT64) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else if(coords_type == TILEDB_FLOAT32) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else if(coords_type == TILEDB_FLOAT64) { + advance_cell_slab_ = advance_cell_slab_col_s; + calculate_cell_slab_info_ = + (cell_order == TILEDB_ROW_MAJOR) ? + calculate_cell_slab_info_col_row_s : + calculate_cell_slab_info_col_col_s; + } else { + assert(0); + } + } + if(tile_order == TILEDB_ROW_MAJOR) { + if(coords_type == TILEDB_INT32) + calculate_tile_slab_info_ = calculate_tile_slab_info_row; + else if(coords_type == TILEDB_INT64) + calculate_tile_slab_info_ = calculate_tile_slab_info_row; + else if(coords_type == TILEDB_FLOAT32) + calculate_tile_slab_info_ = calculate_tile_slab_info_row; + else if(coords_type == TILEDB_FLOAT64) + calculate_tile_slab_info_ = calculate_tile_slab_info_row; + else + assert(0); + } else { // tile_order == TILEDB_COL_MAJOR + if(coords_type == TILEDB_INT32) + calculate_tile_slab_info_ = calculate_tile_slab_info_col; + else if(coords_type == TILEDB_INT64) + calculate_tile_slab_info_ = calculate_tile_slab_info_col; + else if(coords_type == TILEDB_FLOAT32) + calculate_tile_slab_info_ = calculate_tile_slab_info_col; + else if(coords_type == TILEDB_FLOAT64) + calculate_tile_slab_info_ = calculate_tile_slab_info_col; + else + assert(0); + } +*/ + + // Success + return TILEDB_ASWS_OK; +} + +int ArraySortedWriteState::write( + const void** buffers, + const size_t* buffer_sizes) { + +// TODO +/* + + // Trivial case + if(done()) { + for(int i=0; iarray_schema()->coords_type(); + if(type == TILEDB_INT32) + return read(); + else if(type == TILEDB_INT64) + return read(); + else if(type == TILEDB_FLOAT32) + return read(); + else if(type == TILEDB_FLOAT64) + return read(); + else + assert(0); +*/ + + // Success + return TILEDB_ASWS_OK; +} + + +/* ****************************** */ +/* PRIVATE METHODS */ +/* ****************************** */ + +/* + +template +void *ArraySortedReadState::advance_cell_slab_col_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int aid = ((ASRS_Data*) data)->id_; + asrs->advance_cell_slab_col(aid); + return NULL; +} + +template +void *ArraySortedReadState::advance_cell_slab_row_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int aid = ((ASRS_Data*) data)->id_; + asrs->advance_cell_slab_row(aid); + return NULL; +} + +template +void ArraySortedReadState::advance_cell_slab_col(int aid) { + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile id + int64_t cell_slab_num = tile_slab_info_[copy_id_].cell_slab_num_[tid]; + T* current_coords = (T*) tile_slab_state_.current_coords_[aid]; + const T* tile_slab = (const T*) tile_slab_norm_[copy_id_]; + + // Advance cell slab coordinates + int d = 0; + current_coords[d] += cell_slab_num; + int64_t dim_overflow; + for(int i=0; i tile_slab[2*(dim_num_-1)+1]) { + tile_slab_state_.copy_tile_slab_done_[aid] = true; + return; + } + + // Calculate new tile and offset for the current coords + update_current_tile_and_offset(aid); +} + +template +void ArraySortedReadState::advance_cell_slab_row(int aid) { + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile id + int64_t cell_slab_num = tile_slab_info_[copy_id_].cell_slab_num_[tid]; + T* current_coords = (T*) tile_slab_state_.current_coords_[aid]; + const T* tile_slab = (const T*) tile_slab_norm_[copy_id_]; + + // Advance cell slab coordinates + int d = dim_num_-1; + current_coords[d] += cell_slab_num; + int64_t dim_overflow; + for(int i=d; i>0; --i) { + dim_overflow = current_coords[i] / (tile_slab[2*i+1]-tile_slab[2*i]+1); + current_coords[i-1] += dim_overflow; + current_coords[i] -= dim_overflow * (tile_slab[2*i+1]-tile_slab[2*i]+1); + } + + // Check if done + if(current_coords[0] > tile_slab[1]) { + tile_slab_state_.copy_tile_slab_done_[aid] = true; + return; + } + + // Calculate new tile and offset for the current coords + update_current_tile_and_offset(aid); +} + +void *ArraySortedReadState::aio_done(void* data) { + // Retrieve data + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + + // For easy reference + int anum = (int) asrs->attribute_ids_.size(); + const ArraySchema* array_schema = asrs->array_->array_schema(); + + // Check for overflow + bool overflow = false; + for(int i=0; ioverflow_still_[i] && asrs->aio_overflow_[id][i]) { + overflow = true; + break; + } + } + + // Handle overflow + bool sparse = array_schema->dense(); + if(overflow) { // OVERFLOW + // Update buffer sizes + for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED + if(asrs->aio_overflow_[id][i]) { + // Expand buffer + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + // Re-assign the buffer size for the fixed-sized offsets + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + } else { + // Backup sizes and zero them + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + // Does not overflow any more + asrs->overflow_still_[i] = false; + } + ++b; + } else { // VAR + if(asrs->aio_overflow_[id][i]) { + // Expand offset buffer only in the case of sparse arrays + if(sparse) + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + // Re-assign the buffer size for the fixed-sized offsets + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + ++b; + // Expand variable-length cell buffers for both dense and sparse + expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); + // Assign the new buffer size for the variable-sized values + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; + ++b; + } else { + // Backup sizes and zero them (fixed-sized offsets) + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + // Backup sizes and zero them (variable-sized values) + asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; + asrs->buffer_sizes_tmp_[id][b] = 0; + ++b; + // Does not overflow any more + asrs->overflow_still_[i] = false; + } + } + } + + // Send the request again + asrs->send_aio_request(id); + } else { // NO OVERFLOW + // Restore backup temporary buffer sizes + for(int b=0; bbuffer_num_; ++b) { + if(asrs->buffer_sizes_tmp_bak_[id][b] != 0) + asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_tmp_bak_[id][b]; + } + + // Manage the mutexes and conditions + asrs->release_aio(id); + } + + return NULL; +} + +bool ArraySortedReadState::aio_overflow(int aio_id) { + // For easy reference + int anum = (int) attribute_ids_.size(); + + for(int i=0; iattribute_ids(); + + // For ease reference + const ArraySchema* array_schema = array_->array_schema(); + int attribute_num = array_schema->attribute_num(); + + // No need to do anything else in case the array is dense + if(array_schema->dense()) + return; + + // Find the coordinates index + coords_attr_i_ = -1; + for(int i=0; i<(int)attribute_ids_.size(); ++i) { + if(attribute_ids_[i] == attribute_num) { + coords_attr_i_ = i; + break; + } + } + + // If the coordinates index is not found, append coordinates attribute + // to attribute ids. + if(coords_attr_i_ == -1) { + attribute_ids_.push_back(attribute_num); + coords_attr_i_ = attribute_ids_.size() - 1; + extra_coords_ = true; + } else { // No extra coordinates appended + extra_coords_ = false; + } +} + +void ArraySortedReadState::calculate_buffer_num() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int attribute_num = array_schema->attribute_num(); + + // Calculate number of buffers + buffer_num_ = 0; + int attribute_id_num = (int) attribute_ids_.size(); + for(int i=0; ivar_size(attribute_ids_[i])) { + if(attribute_ids_[i] == attribute_num) + coords_buf_i_ = i; // Buffer that holds the coordinates + ++buffer_num_; + } else { // Variable-sized attribute + buffer_num_ += 2; + } + } +} + +void ArraySortedReadState::calculate_buffer_sizes() { + if(array_->array_schema()->dense()) + calculate_buffer_sizes_dense(); + else + calculate_buffer_sizes_sparse(); +} + +void ArraySortedReadState::calculate_buffer_sizes_dense() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Get cell number in a (full) tile slab + int64_t tile_slab_cell_num; + if(array_->mode() == TILEDB_ARRAY_READ_SORTED_ROW) + tile_slab_cell_num = array_schema->tile_slab_row_cell_num(subarray_); + else // TILEDB_ARRAY_READ_SORTED_COL + tile_slab_cell_num = array_schema->tile_slab_col_cell_num(subarray_); + + // Calculate buffer sizes + int attribute_id_num = (int) attribute_ids_.size(); + for(int j=0; j<2; ++j) { + buffer_sizes_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_bak_[j] = new size_t[buffer_num_]; + for(int i=0, b=0; ivar_size(attribute_ids_[i])) { + buffer_sizes_[j][b] = + tile_slab_cell_num * array_schema->cell_size(attribute_ids_[i]); + buffer_sizes_tmp_bak_[j][b] = 0; + ++b; + } else { // Variable-sized attribute + buffer_sizes_[j][b] = tile_slab_cell_num * sizeof(size_t); + buffer_sizes_tmp_bak_[j][b] = 0; + ++b; + buffer_sizes_[j][b] = 2 * tile_slab_cell_num * sizeof(size_t); + buffer_sizes_tmp_bak_[j][b] = 0; + ++b; + } + } + } +} + +void ArraySortedReadState::calculate_buffer_sizes_sparse() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Calculate buffer sizes + int attribute_id_num = (int) attribute_ids_.size(); + for(int j=0; j<2; ++j) { + buffer_sizes_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_[j] = new size_t[buffer_num_]; + buffer_sizes_tmp_bak_[j] = new size_t[buffer_num_]; + for(int i=0, b=0; ivar_size(attribute_ids_[i])) { // Variable-sized buffer + buffer_sizes_[j][b] = 2*TILEDB_ASRS_INIT_BUFFER_SIZE; + buffer_sizes_tmp_bak_[j][b] = 0; + ++b; + } + } + } +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_col_col_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_col_col(id, tid); + return NULL; +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_col_row_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_col_row(id, tid); + return NULL; +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_row_col_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_row_col(id, tid); + return NULL; +} + +template +void *ArraySortedReadState::calculate_cell_slab_info_row_row_s(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + int tid = ((ASRS_Data*) data)->id_2_; + asrs->calculate_cell_slab_info_row_row(id, tid); + return NULL; +} + +template +void ArraySortedReadState::calculate_cell_slab_info_col_col( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + const T* tile_domain = (const T*) tile_domain_; + int64_t tile_num, cell_num; + + // Calculate number of cells in cell slab + cell_num = range_overlap[1] - range_overlap[0] + 1; + for(int i=0; i +void ArraySortedReadState::calculate_cell_slab_info_row_row( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + const T* tile_domain = (const T*) tile_domain_; + int64_t tile_num, cell_num; + + // Calculate number of cells in cell slab + cell_num = range_overlap[2*(dim_num_-1)+1] - range_overlap[2*(dim_num_-1)] +1; + for(int i=dim_num_-1; i>0; --i) { + tile_num = tile_domain[2*i+1] - tile_domain[2*i] + 1; + if(tile_num == 1) + cell_num *= range_overlap[2*(i-1)+1] - range_overlap[2*(i-1)] + 1; + else + break; + } + tile_slab_info_[id].cell_slab_num_[tid] = cell_num; + + // Calculate size of a cell slab per attribute + for(int aid=0; aid=0; --i) { + cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); + tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; + } +} + +template +void ArraySortedReadState::calculate_cell_slab_info_col_row( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + + // Calculate number of cells in cell slab + tile_slab_info_[id].cell_slab_num_[tid] = 1; + + // Calculate size of a cell slab per attribute + for(int aid=0; aid=0; --i) { + cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); + tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; + } +} + +template +void ArraySortedReadState::calculate_cell_slab_info_row_col( + int id, + int64_t tid) { + // For easy reference + int anum = (int) attribute_ids_.size(); + const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + + // Calculate number of cells in cell slab + tile_slab_info_[id].cell_slab_num_[tid] = 1; + + // Calculate size of a cell slab per attribute + for(int aid=0; aid +void ArraySortedReadState::calculate_tile_domain(int id) { + // Initializations + tile_coords_ = malloc(coords_size_); + tile_domain_ = malloc(2*coords_size_); + + // For easy reference + const T* tile_slab = (const T*) tile_slab_norm_[id]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + T* tile_coords = (T*) tile_coords_; + T* tile_domain = (T*) tile_domain_; + + // Calculate tile domain and initial tile coordinates + for(int i=0; i +void ArraySortedReadState::calculate_tile_slab_info(int id) { + // Calculate number of tiles, if they are not already calculated + if(tile_slab_info_[id].tile_num_ == -1) + init_tile_slab_info(id); + + // Calculate tile domain, if not calculated yet + if(tile_domain_ == NULL) + calculate_tile_domain(id); + + // Reset tile coordinates + reset_tile_coords(); + + // Calculate tile slab info + ASRS_Data asrs_data = { id, 0, this }; + (*calculate_tile_slab_info_)(&asrs_data); +} + +template +void *ArraySortedReadState::calculate_tile_slab_info_col(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + asrs->calculate_tile_slab_info_col(id); + return NULL; +} + +template +void ArraySortedReadState::calculate_tile_slab_info_col(int id) { + // For easy reference + const T* tile_domain = (const T*) tile_domain_; + T* tile_coords = (T*) tile_coords_; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + T** range_overlap = (T**) tile_slab_info_[id].range_overlap_; + const T* tile_slab = (const T*) tile_slab_norm_[id]; + int64_t tile_offset, tile_cell_num, total_cell_num = 0; + int anum = (int) attribute_ids_.size(); + int d; + + // Iterate over all tiles in the tile domain + int64_t tid=0; // Tile id + while(tile_coords[dim_num_-1] <= tile_domain[2*(dim_num_-1)+1]) { + // Calculate range overlap, number of cells in the tile + tile_cell_num = 1; + for(int i=0; i tile_domain[2*d+1]) { + tile_coords[d] = tile_domain[2*d]; + ++tile_coords[++d]; + } + + // Advance tile id + ++tid; + } +} + +template +void *ArraySortedReadState::calculate_tile_slab_info_row(void* data) { + ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; + int id = ((ASRS_Data*) data)->id_; + asrs->calculate_tile_slab_info_row(id); + return NULL; +} + +template +void ArraySortedReadState::calculate_tile_slab_info_row(int id) { + // For easy reference + const T* tile_domain = (const T*) tile_domain_; + T* tile_coords = (T*) tile_coords_; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + T** range_overlap = (T**) tile_slab_info_[id].range_overlap_; + const T* tile_slab = (const T*) tile_slab_norm_[id]; + int64_t tile_offset, tile_cell_num, total_cell_num = 0; + int anum = (int) attribute_ids_.size(); + int d; + + // Iterate over all tiles in the tile domain + int64_t tid=0; // Tile id + while(tile_coords[0] <= tile_domain[1]) { + // Calculate range overlap, number of cells in the tile + tile_cell_num = 1; + for(int i=0; i=0; --i) { + tile_offset *= (tile_domain[2*(i+1)+1] - tile_domain[2*(i+1)] + 1); + tile_slab_info_[id].tile_offset_per_dim_[i] = tile_offset; + } + + // Calculate cell slab info + ASRS_Data asrs_data = { id, tid, this }; + (*calculate_cell_slab_info_)(&asrs_data); + + // Calculate start offsets + for(int aid=0; aid 0 && tile_coords[d] > tile_domain[2*d+1]) { + tile_coords[d] = tile_domain[2*d]; + ++tile_coords[--d]; + } + + // Advance tile id + ++tid; + } +} + +void *ArraySortedReadState::copy_handler(void* context) { + // For easy reference + ArraySortedReadState* asrs = (ArraySortedReadState*) context; + + // This will enter an indefinite loop that will handle all incoming copy + // requests + int coords_type = asrs->array_->array_schema()->coords_type(); + if(asrs->array_->array_schema()->dense()) { // DENSE + if(coords_type == TILEDB_INT32) + asrs->handle_copy_requests_dense(); + else if(coords_type == TILEDB_INT64) + asrs->handle_copy_requests_dense(); + else if(coords_type == TILEDB_FLOAT32) + asrs->handle_copy_requests_dense(); + else if(coords_type == TILEDB_FLOAT64) + asrs->handle_copy_requests_dense(); + else + assert(0); + } else { // SPARSE + if(coords_type == TILEDB_INT32) + asrs->handle_copy_requests_sparse(); + else if(coords_type == TILEDB_INT64) + asrs->handle_copy_requests_sparse(); + else if(coords_type == TILEDB_FLOAT32) + asrs->handle_copy_requests_sparse(); + else if(coords_type == TILEDB_FLOAT64) + asrs->handle_copy_requests_sparse(); + else + assert(0); + } + + // Return + return NULL; +} + +void ArraySortedReadState::copy_tile_slab_dense() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + + // Copy tile slab for each attribute separately + for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { + if(!array_schema->var_size(attribute_ids_[i])) { + copy_tile_slab_dense(i, b); + ++b; + } else { + copy_tile_slab_dense_var(i, b); + b += 2; + } + } +} + +void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + return; + } + + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* local_buffer = (char*) buffers_[copy_id_][bid]; + + // Iterate over the tile slab cells + for(;;) { + // For easy reference + size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; + size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; + + // Handle overflow + if(buffer_offset + cell_slab_size > buffer_size) { + overflow_[aid] = true; + break; + } + + // Copy cell slab + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_slab_size); + + // Update buffer offset + buffer_offset += cell_slab_size; + + // Prepare for new slab + ASRS_Data asrs_data = { aid, 0, this }; + (*advance_cell_slab_)(&asrs_data); + + // Terminating condition + if(tile_slab_state_.copy_tile_slab_done_[aid]) + break; + } + + // Set user buffer size + buffer_size = buffer_offset; +} + +void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + copy_state_.buffer_sizes_[bid+1] = 0; // Nothing written + return; + } + + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; + size_t cell_slab_size_var; + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t& buffer_offset_var = copy_state_.buffer_offsets_[bid+1]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + size_t buffer_size_var = copy_state_.buffer_sizes_[bid+1]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* buffer_var = (char*) copy_state_.buffers_[bid+1]; + char* local_buffer_var = (char*) buffers_[copy_id_][bid+1]; + size_t local_buffer_size = buffer_sizes_tmp_[copy_id_][bid]; + size_t local_buffer_var_size = buffer_sizes_tmp_[copy_id_][bid+1]; + size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; + int64_t cell_num_in_buffer = local_buffer_size / sizeof(size_t); + size_t var_offset = buffer_offset_var; + + // For all overlapping tiles, in a round-robin fashion + for(;;) { + // For easy reference + size_t cell_slab_size = + tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; + int64_t cell_num_in_slab = cell_slab_size / sizeof(size_t); + size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; + + // Handle overflow + if(buffer_offset + cell_slab_size > buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate variable cell slab size + int64_t cell_start = local_buffer_offset / sizeof(size_t); + int64_t cell_end = cell_start + cell_num_in_slab; + cell_slab_size_var = + (cell_end == cell_num_in_buffer) ? + local_buffer_var_size - local_buffer_s[cell_start] : + local_buffer_s[cell_end] - local_buffer_s[cell_start]; + + // Handle overflow for the the variable-length buffer + if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { + overflow_[aid] = true; + break; + } + + // Copy fixed-sized offsets + for(int64_t i=cell_start; iarray_schema(); + + // Copy tile slab for each attribute separately + for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { + if(!array_schema->var_size(attribute_ids_[i])) { // FIXED + // Make sure not to copy coordinates if the user has not requested them + if(i != coords_attr_i_ || !extra_coords_) + copy_tile_slab_sparse(i, b); + ++b; + } else { // VAR + copy_tile_slab_sparse_var(i, b); + b += 2; + } + } +} + +void ArraySortedReadState::copy_tile_slab_sparse(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + return; + } + + // For easy reference + size_t cell_size = array_->array_schema()->cell_size(attribute_ids_[aid]); + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* local_buffer = (char*) buffers_[copy_id_][bid]; + size_t local_buffer_offset; + int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; + int64_t& current_cell_pos = tile_slab_state_.current_cell_pos_[aid]; + + // Iterate over the remaining tile slab cells in a sorted order + for(; current_cell_pos buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate new local buffer offset + local_buffer_offset = cell_pos_[current_cell_pos] * cell_size; + + // Copy cell slab + memcpy( + buffer + buffer_offset, + local_buffer + local_buffer_offset, + cell_size); + + // Update buffer offset + buffer_offset += cell_size; + } + + // Mark tile slab as done + if(current_cell_pos == cell_num) + tile_slab_state_.copy_tile_slab_done_[aid] = true; + + // Set user buffer size + buffer_size = buffer_offset; +} + + +void ArraySortedReadState::copy_tile_slab_sparse_var(int aid, int bid) { + // Exit if copy is done for this attribute + if(tile_slab_state_.copy_tile_slab_done_[aid]) { + copy_state_.buffer_sizes_[bid] = 0; // Nothing written + copy_state_.buffer_sizes_[bid+1] = 0; // Nothing written + return; + } + + // For easy reference + size_t cell_size = sizeof(size_t); + size_t cell_size_var; + size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; + size_t& buffer_offset_var = copy_state_.buffer_offsets_[bid+1]; + size_t buffer_size = copy_state_.buffer_sizes_[bid]; + size_t buffer_size_var = copy_state_.buffer_sizes_[bid+1]; + char* buffer = (char*) copy_state_.buffers_[bid]; + char* buffer_var = (char*) copy_state_.buffers_[bid+1]; + char* local_buffer_var = (char*) buffers_[copy_id_][bid+1]; + size_t local_buffer_var_size = buffer_sizes_tmp_[copy_id_][bid+1]; + size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; + int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; + int64_t& current_cell_pos = tile_slab_state_.current_cell_pos_[aid]; + + // Iterate over the remaining tile slab cells in a sorted order + for(; current_cell_pos buffer_size) { + overflow_[aid] = true; + break; + } + + // Calculate variable cell size + int64_t cell_start = cell_pos_[current_cell_pos]; + int64_t cell_end = cell_start + 1; + cell_size_var = + (cell_end == cell_num) ? + local_buffer_var_size - local_buffer_s[cell_start] : + local_buffer_s[cell_end] - local_buffer_s[cell_start]; + + // Handle overflow for the the variable-length buffer + if(buffer_offset_var + cell_size_var > buffer_size_var) { + overflow_[aid] = true; + break; + } + + // Copy fixed-sized offset + memcpy( + buffer + buffer_offset, + &buffer_offset_var, + sizeof(size_t)); + buffer_offset += sizeof(size_t); + + // Copy variable-sized values + memcpy( + buffer_var + buffer_offset_var, + local_buffer_var + local_buffer_s[cell_start], + cell_size_var); + buffer_offset_var += cell_size_var; + } + + // Mark tile slab as done + if(current_cell_pos == cell_num) + tile_slab_state_.copy_tile_slab_done_[aid] = true; + + // Set user buffer sizes + buffer_size = buffer_offset; + buffer_size_var = buffer_offset_var; +} + +int ArraySortedReadState::create_buffers() { + for(int j=0; j<2; ++j) { + buffers_[j] = (void**) malloc(buffer_num_ * sizeof(void*)); + if(buffers_[j] == NULL) { + std::string errmsg = "Cannot create local buffers"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + for(int b=0; b < buffer_num_; ++b) { + buffers_[j][b] = malloc(buffer_sizes_[j][b]); + if(buffers_[j][b] == NULL) { + std::string errmsg = "Cannot allocate local buffer"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + } + + // Success + return TILEDB_ASRS_OK; +} + +void ArraySortedReadState::free_copy_state() { + if(copy_state_.buffer_offsets_ != NULL) + delete [] copy_state_.buffer_offsets_; +} + +void ArraySortedReadState::free_tile_slab_info() { + // Do nothing in the case of sparse arrays + if(!array_->array_schema()->dense()) + return; + + // For easy reference + int anum = (int) attribute_ids_.size(); + + // Free + for(int i=0; i<2; ++i) { + int64_t tile_num = tile_slab_info_[i].tile_num_; + + if(tile_slab_info_[i].cell_offset_per_dim_ != NULL) { + for(int j=0; j +int64_t ArraySortedReadState::get_cell_id(int aid) { + // For easy reference + const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; + int64_t tid = tile_slab_state_.current_tile_[aid]; + const T* range_overlap = + (const T*) tile_slab_info_[copy_id_].range_overlap_[tid]; + int64_t* cell_offset_per_dim = + tile_slab_info_[copy_id_].cell_offset_per_dim_[tid]; + + // Calculate cell id + int64_t cid = 0; + for(int i=0; i +int64_t ArraySortedReadState::get_tile_id(int aid) { + // For easy reference + const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); + int64_t* tile_offset_per_dim = tile_slab_info_[copy_id_].tile_offset_per_dim_; + + // Calculate tile id + int64_t tid = 0; + for(int i=0; i +void ArraySortedReadState::handle_copy_requests_dense() { + // Handle copy requests indefinitely + for(;;) { + // Wait for AIO + wait_aio(copy_id_); + + // Kill thread, after releasing any blocked resources + if(copy_thread_canceled_) { + copy_thread_running_ = false; + return; + } + + // Reset the tile slab state + if(copy_tile_slab_done()) + reset_tile_slab_state(); + + // Start the copy + copy_tile_slab_dense(); + + // Wait in case of overflow + if(overflow()) { + block_overflow(); + block_aio(copy_id_); + release_copy(copy_id_); + wait_overflow(); + continue; + } + + // Copy is done + block_aio(copy_id_); + release_copy(copy_id_); + copy_id_ = (copy_id_ + 1) % 2; + } +} + +template +void ArraySortedReadState::handle_copy_requests_sparse() { + // Handle copy requests indefinitely + for(;;) { + // Wait for AIO + wait_aio(copy_id_); + + // Kill thread, after releasing any blocked resources + if(copy_thread_canceled_) { + copy_thread_running_ = false; + return; + } + + // Sort the cell positions + if(copy_tile_slab_done()) { + reset_tile_slab_state(); + sort_cell_pos(); + } + + // Start the copy + copy_tile_slab_sparse(); + + // Wait in case of overflow + if(overflow()) { + block_overflow(); + block_aio(copy_id_); + release_copy(copy_id_); + wait_overflow(); + continue; + } + + // Copy is done + block_aio(copy_id_); + release_copy(copy_id_); + copy_id_ = (copy_id_ + 1) % 2; + } +} + +void ArraySortedReadState::init_aio_requests() { + for(int i=0; i<2; ++i) { + aio_data_[i] = { i, 0, this }; + aio_request_[i] = {}; + aio_request_[i].buffer_sizes_ = buffer_sizes_tmp_[i]; + aio_request_[i].buffers_ = buffers_[i]; + aio_request_[i].mode_ = TILEDB_ARRAY_READ; + aio_request_[i].subarray_ = tile_slab_[i]; + aio_request_[i].completion_handle_ = aio_done; + aio_request_[i].completion_data_ = &(aio_data_[i]); + aio_request_[i].overflow_ = aio_overflow_[i]; + aio_request_[i].status_ = &(aio_status_[i]); + } +} + +void ArraySortedReadState::init_copy_state() { + copy_state_.buffer_sizes_ = NULL; + copy_state_.buffers_ = NULL; + copy_state_.buffer_offsets_ = new size_t[buffer_num_]; + for(int i=0; iarray_schema()->dense()) + return; + + // For easy reference + int anum = (int) attribute_ids_.size(); + + // Initialize + for(int i=0; i<2; ++i) { + tile_slab_info_[i].cell_offset_per_dim_ = NULL; + tile_slab_info_[i].cell_slab_size_ = new size_t*[anum]; + tile_slab_info_[i].cell_slab_num_ = NULL; + tile_slab_info_[i].range_overlap_ = NULL; + tile_slab_info_[i].start_offsets_ = new size_t*[anum]; + tile_slab_info_[i].tile_offset_per_dim_ = new int64_t[dim_num_]; + + for(int j=0; j +void ArraySortedReadState::init_tile_slab_info(int id) { + // Sanity check + assert(array_->array_schema()->dense()); + + // For easy reference + int anum = (int) attribute_ids_.size(); + + // Calculate tile number + int64_t tile_num = array_->array_schema()->tile_num(tile_slab_[id]); + + // Initializations + tile_slab_info_[id].cell_offset_per_dim_ = new int64_t*[tile_num]; + tile_slab_info_[id].cell_slab_num_ = new int64_t[tile_num]; + tile_slab_info_[id].range_overlap_ = new void*[tile_num]; + for(int64_t i=0; iarray_schema()->dense(); + + // Both for dense and sparse + tile_slab_state_.copy_tile_slab_done_ = new bool[anum]; + for(int i=0; i +bool ArraySortedReadState::next_tile_slab_dense_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_+1)%2; + T tile_start; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + T upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; + T cropped_upper = + (upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1] * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - 1, subarray[2*(dim_num_-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; i(aio_id_); + + // Mark this tile slab as initialized + tile_slab_init_[aio_id_] = true; + + // Success + return true; +} + +template +bool ArraySortedReadState::next_tile_slab_dense_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_+1)%2; + T tile_start; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + T upper = subarray[0] + tile_extents[0]; + T cropped_upper = + (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i(aio_id_); + + // Mark this tile slab as initialized + tile_slab_init_[aio_id_] = true; + + // Success + return true; +} + +template +bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + T upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; + T cropped_upper = + (upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1] * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - 1, subarray[2*(dim_num_-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; i +bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const float* subarray = (const float*) subarray_; + const float* domain = (const float*) array_schema->domain(); + const float* tile_extents = (const float*) array_schema->tile_extents(); + float* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (float*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + float upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; + float cropped_upper = + floor((upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1]) * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - FLT_MIN, subarray[2*(dim_num_-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; i +bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const double* subarray = (const double*) subarray_; + const double* domain = (const double*) array_schema->domain(); + const double* tile_extents = (const double*) array_schema->tile_extents(); + double* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (double*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + double upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; + double cropped_upper = + floor((upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1]) * + tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; + tile_slab[aio_id_][2*(dim_num_-1)+1] = + std::min(cropped_upper - DBL_MIN, subarray[2*(dim_num_-1)+1]); + + // Leave the rest of the subarray extents intact + for(int i=0; i +bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + const T* domain = static_cast(array_schema->domain()); + const T* tile_extents = static_cast(array_schema->tile_extents()); + T* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = static_cast(tile_slab_[i]); + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + T upper = subarray[0] + tile_extents[0]; + T cropped_upper = + (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i +bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const float* subarray = (const float*) subarray_; + const float* domain = (const float*) array_schema->domain(); + const float* tile_extents = (const float*) array_schema->tile_extents(); + float* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (float*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + float upper = subarray[0] + tile_extents[0]; + float cropped_upper = + floor((upper - domain[0]) / tile_extents[0]) * tile_extents[0] + + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - FLT_MIN, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i +bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Quick check if done + if(read_tile_slabs_done_) + return false; + + // If the AIO needs to be resumed, exit (no need for a new tile slab) + if(resume_aio_) { + resume_aio_ = false; + return true; + } + + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const double* subarray = (const double*) subarray_; + const double* domain = (const double*) array_schema->domain(); + const double* tile_extents = (const double*) array_schema->tile_extents(); + double* tile_slab[2]; + for(int i=0; i<2; ++i) + tile_slab[i] = (double*) tile_slab_[i]; + int prev_id = (aio_id_+1)%2; + + // Check again if done, this time based on the tile slab and subarray + if(tile_slab_init_[prev_id] && + tile_slab[prev_id][1] == subarray[1]) { + read_tile_slabs_done_ = true; + return false; + } + + // If this is the first time this function is called, initialize + if(!tile_slab_init_[prev_id]) { + // Crop the subarray extent along the first axis to fit in the first tile + tile_slab[aio_id_][0] = subarray[0]; + double upper = subarray[0] + tile_extents[0]; + double cropped_upper = + floor((upper - domain[0]) / tile_extents[0]) * tile_extents[0] + + domain[0]; + tile_slab[aio_id_][1] = std::min(cropped_upper - DBL_MIN, subarray[1]); + + // Leave the rest of the subarray extents intact + for(int i=1; i +int ArraySortedReadState::read() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int mode = array_->mode(); + + if(mode == TILEDB_ARRAY_READ_SORTED_COL) { + if(array_schema->dense()) + return read_dense_sorted_col(); + else + return read_sparse_sorted_col(); + } else if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(array_schema->dense()) + return read_dense_sorted_row(); + else + return read_sparse_sorted_row(); + } else { + assert(0); // The code should never reach here + } +} + +template +int ArraySortedReadState::read_dense_sorted_col() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_COL_MAJOR && + array_schema->is_contained_in_tile_slab_row(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_dense_col()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i +int ArraySortedReadState::read_dense_sorted_row() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_ROW_MAJOR && + array_schema->is_contained_in_tile_slab_col(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_dense_row()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy and AIO to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i +int ArraySortedReadState::read_sparse_sorted_col() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_COL_MAJOR && + array_schema->is_contained_in_tile_slab_row(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_sparse_col()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i +int ArraySortedReadState::read_sparse_sorted_row() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + const T* subarray = static_cast(subarray_); + + // Check if this can be satisfied with a default read + if(array_schema->cell_order() == TILEDB_ROW_MAJOR && + array_schema->is_contained_in_tile_slab_col(subarray)) + return array_->read_default( + copy_state_.buffers_, + copy_state_.buffer_sizes_); + + // Iterate over each tile slab + while(next_tile_slab_sparse_row()) { + // Read the next tile slab with the default cell order + if(read_tile_slab() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Handle overflow + if(resume_aio_) + break; + } + + // Wait for copy and AIO to finish + int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; + wait_copy(copy_id); + + // Assign the true buffer sizes + for(int i=0; i +void ArraySortedReadState::reset_tile_coords() { + T* tile_coords = (T*) tile_coords_; + for(int i=0; i +void ArraySortedReadState::reset_tile_slab_state() { + // For easy reference + int anum = (int) attribute_ids_.size(); + bool dense = array_->array_schema()->dense(); + + // Both dense and sparse + for(int i=0; iarray_clone(); + + // Sanity check + assert(array_clone != NULL); + + // Send the AIO request to the clone array + if(array_clone->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { + // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +template +void ArraySortedReadState::sort_cell_pos() { + // For easy reference + const ArraySchema* array_schema = array_->array_schema(); + int dim_num = array_schema->dim_num(); + int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; + int mode = array_->mode(); + const T* buffer = static_cast(buffers_[copy_id_][coords_buf_i_]); + + // Populate cell_pos + cell_pos_.resize(cell_num); + for(int i=0; i(buffer, dim_num)); + } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + // Sort cell positions + SORT( + cell_pos_.begin(), + cell_pos_.end(), + SmallerCol(buffer, dim_num)); + } +} + +int ArraySortedReadState::unlock_aio_mtx() { + if(pthread_mutex_unlock(&aio_mtx_)) { + std::string errmsg = "Cannot unlock AIO mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::unlock_copy_mtx() { + if(pthread_mutex_unlock(©_mtx_)) { + std::string errmsg = "Cannot unlock copy mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::unlock_overflow_mtx() { + if(pthread_mutex_unlock(&overflow_mtx_)) { + std::string errmsg = "Cannot unlock overflow mutex"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + + // Success + return TILEDB_ASRS_OK; +} + +template +void ArraySortedReadState::update_current_tile_and_offset(int aid) { + // For easy reference + int64_t& tid = tile_slab_state_.current_tile_[aid]; + size_t& current_offset = tile_slab_state_.current_offsets_[aid]; + int64_t cid; + + // Calculate the new tile id + tid = get_tile_id(aid); + + // Calculate the cell id + cid = get_cell_id(aid); + + // Calculate new offset + current_offset = + tile_slab_info_[copy_id_].start_offsets_[aid][tid] + + cid * attribute_sizes_[aid]; +} + +int ArraySortedReadState::wait_aio(int id) { + // Lock AIO mutex + if(lock_aio_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Wait to be signaled + while(wait_aio_[id]) { + if(pthread_cond_wait(&(aio_cond_[id]), &aio_mtx_)) { + std::string errmsg = "Cannot wait on IO mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + + // Unlock AIO mutex + if(unlock_aio_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::wait_copy(int id) { + // Lock copy mutex + if(lock_copy_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Wait to be signaled + while(wait_copy_[id]) { + if(pthread_cond_wait(&(copy_cond_[id]), ©_mtx_)) { + std::string errmsg = "Cannot wait on copy mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + + // Unlock copy mutex + if(unlock_copy_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + + // Success + return TILEDB_ASRS_OK; +} + +int ArraySortedReadState::wait_overflow() { + // Wait to be signaled + while(overflow()) { + if(pthread_cond_wait(&overflow_cond_, &overflow_mtx_)) { + std::string errmsg = "Cannot wait on IO mutex condition"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + } + + // Success + return TILEDB_ASRS_OK; +} + +// Explicit template instantiations + +template int ArraySortedReadState::read_dense_sorted_col(); +template int ArraySortedReadState::read_dense_sorted_col(); +template int ArraySortedReadState::read_dense_sorted_col(); +template int ArraySortedReadState::read_dense_sorted_col(); + +template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedReadState::read_dense_sorted_row(); + + +*/ diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 0473b2bc..180141d5 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -87,6 +87,8 @@ bool array_read_mode(int mode) { bool array_write_mode(int mode) { return mode == TILEDB_ARRAY_WRITE || + mode == TILEDB_ARRAY_WRITE_SORTED_COL || + mode == TILEDB_ARRAY_WRITE_SORTED_ROW || mode == TILEDB_ARRAY_WRITE_UNSORTED; } diff --git a/examples/src/tiledb_array_write_sorted_dense.cc b/examples/src/tiledb_array_write_sorted_dense.cc new file mode 100644 index 00000000..96162952 --- /dev/null +++ b/examples/src/tiledb_array_write_sorted_dense.cc @@ -0,0 +1,80 @@ +/** + * @file tiledb_array_write_sorted_dense.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * It shows how to write to a subarray of a dense array. The cells are provided + * in the user buffers in row-major order with respect to the specified subarray + * (i.e., not following the array global cell order). + */ + +#include "c_api.h" + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + int64_t subarray[] = { 3, 4, 2, 4 }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + "my_workspace/dense_arrays/my_array_A", // Array name + TILEDB_ARRAY_WRITE_SORTED_ROW, // Mode + subarray, // Subarray + NULL, // All attributes + 0); // Number of attributes + + // Prepare cell buffers + int buffer_a1[] = { 9, 12, 13, 11, 14, 15 }; + size_t buffer_a2[] = { 0, 2, 3, 5, 9, 12 }; + const char buffer_var_a2[] = "jjmnnllllooopppp"; + float buffer_a3[] = + { 9.1, 9.2, 12.1, 12.2, 13.1, 13.2, 11.1, 11.2, 14.1, 14.2 }; + const void* buffers[] = { buffer_a1, buffer_a2, buffer_var_a2, buffer_a3 }; + size_t buffer_sizes[] = + { + sizeof(buffer_a1), + sizeof(buffer_a2), + sizeof(buffer_var_a2)-1, // No need to store the last '\0' character + sizeof(buffer_a3) + }; + + // Write to array + tiledb_array_write(tiledb_array, buffers, buffer_sizes); + + // Finalize array + tiledb_array_finalize(tiledb_array); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} From 69a9bae937fc510948bd5297dd7dfe7ab0d0326a Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 19 Oct 2016 18:02:58 -0400 Subject: [PATCH 17/57] Progress on dense sorted writes --- core/include/array/array_sorted_read_state.h | 8 +- core/include/array/array_sorted_write_state.h | 646 ++---- core/src/array/array.cc | 4 +- core/src/array/array_sorted_write_state.cc | 2006 ++++------------- 4 files changed, 619 insertions(+), 2045 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 0aec22c5..cdb56485 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -912,7 +912,7 @@ class ArraySortedReadState { * Applicable only to dense arrays. * * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. */ template int read_dense_sorted_col(); @@ -923,7 +923,7 @@ class ArraySortedReadState { * Applicable only to dense arrays. * * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. */ template int read_dense_sorted_row(); @@ -934,7 +934,7 @@ class ArraySortedReadState { * Applicable only to sparse arrays. * * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. */ template int read_sparse_sorted_col(); @@ -945,7 +945,7 @@ class ArraySortedReadState { * Applicable only to sparse arrays. * * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. */ template int read_sparse_sorted_row(); diff --git a/core/include/array/array_sorted_write_state.h b/core/include/array/array_sorted_write_state.h index 69deda30..6e7d5b69 100644 --- a/core/include/array/array_sorted_write_state.h +++ b/core/include/array/array_sorted_write_state.h @@ -50,7 +50,8 @@ /**@}*/ /** Default error message. */ -#define TILEDB_ASWS_ERRMSG std::string("[TileDB::ArraySortedWriteState] Error: ") +#define TILEDB_ASWS_ERRMSG \ + std::string("[TileDB::ArraySortedWriteState] Error: ") @@ -77,69 +78,62 @@ class ArraySortedWriteState { /* ********************************* */ /** Used in functors. */ -// struct ASRS_Data { + struct ASWS_Data { /** An id (typically an attribute id or a tile slab id. */ -// int id_; + int id_; /** Another id (typically a tile id). */ -// int64_t id_2_; + int64_t id_2_; /** The calling object. */ -// ArraySortedReadState* asrs_; -// }; - - /** Stores state about the current read/copy request. */ -// struct CopyState { - /** Current offsets in user buffers. */ -// size_t* buffer_offsets_; - /** User buffer sizes. */ -// size_t* buffer_sizes_; - /** User buffers. */ -// void** buffers_; -// }; + ArraySortedWriteState* asws_; + }; + + /** Stores local state about the current write/copy request. */ + struct CopyState { + /** Local buffer sizes. */ + size_t* buffer_sizes_[2]; + /** Local buffers. */ + void** buffers_[2]; + }; /** Info about a tile slab. */ -// struct TileSlabInfo { + struct TileSlabInfo { /** Used in calculations of cell ids, one vector per tile. */ -// int64_t** cell_offset_per_dim_; + int64_t** cell_offset_per_dim_; /** Cell slab size per attribute per tile. */ -// size_t** cell_slab_size_; + size_t** cell_slab_size_; /** Number of cells in a cell slab per tile. */ -// int64_t* cell_slab_num_; + int64_t* cell_slab_num_; /** * The range overlap of the **normalized** tile slab with each * **normalized** tile range. */ -// void** range_overlap_; + void** range_overlap_; /** - * Start offsets of each tile in the local buffer, per attribute per tile. + * Start offsets of each tile in the user buffer, per attribute per tile. */ -// size_t** start_offsets_; + size_t** start_offsets_; /** Number of tiles in the tile slab. */ -// int64_t tile_num_; + int64_t tile_num_; /** Used in calculations of tile ids. */ -// int64_t* tile_offset_per_dim_; -// }; + int64_t* tile_offset_per_dim_; + }; /** The state for a tile slab copy. */ -// struct TileSlabState { + struct TileSlabState { /** Keeps track of whether a tile slab copy for an attribute id done. */ -// bool* copy_tile_slab_done_; - /** - * Applicable only to the sparse case. It holds the current cell position - * to be considered, per attribute. - */ -// int64_t* current_cell_pos_; + bool* copy_tile_slab_done_; /** Current coordinates in tile slab per attribute. */ -// void** current_coords_; + void** current_coords_; /** * The offset in the local buffers of the next cell slab to be copied per * attribute. Note that this applies only to fixed-sized attributes * because the offsets of the variable-sized attributes can be derived from * the buffers that hold the fixed-sized offsets. */ -// size_t* current_offsets_; + size_t* current_offsets_; /** The current tile per attribute. */ -// int64_t* current_tile_; -// }; + int64_t* current_tile_; + }; /* ********************************* */ @@ -164,19 +158,11 @@ class ArraySortedWriteState { /* ********************************* */ /** Returns true if the current slab is finished being copied. */ -// bool copy_tile_slab_done() const; + bool copy_tile_slab_done() const; - /** True if read is done for all attributes. */ -// bool done() const; + /** True if write is done for all attributes. */ + bool done() const; - /** Returns true if copying into the user buffers resulted in overflow. */ -// bool overflow() const; - - /** - * Returns true if copying into the user buffers resulted in overflow, for - * the input attribute id. - */ -// bool overflow(int attribute_id) const; @@ -213,174 +199,115 @@ class ArraySortedWriteState { /* ********************************* */ /** Function for advancing a cell slab during a copy operation. */ -// void *(*advance_cell_slab_) (void*); + void *(*advance_cell_slab_) (void*); /** AIO counter. */ -// int aio_cnt_; + int aio_cnt_; /** The AIO mutex conditions (one for each buffer). */ -// pthread_cond_t aio_cond_[2]; + pthread_cond_t aio_cond_[2]; /** Data for the AIO requests. */ -// ASRS_Data aio_data_[2]; + ASWS_Data aio_data_[2]; /** The current id of the buffers the next AIO will occur into. */ -// int aio_id_; + int aio_id_; /** The AIO mutex. */ -// pthread_mutex_t aio_mtx_; + pthread_mutex_t aio_mtx_; - /** Indicates overflow per tile slab per attribute upon an AIO operation. */ -// bool* aio_overflow_[2]; - /** AIO requests. */ -// AIO_Request aio_request_[2]; + AIO_Request aio_request_[2]; /** The status of the AIO requests.*/ -// int aio_status_[2]; + int aio_status_[2]; + + /** The thread tha handles all the AIO in the background. */ + pthread_t aio_thread_; + + /** True if the copy thread is canceled. */ + bool aio_thread_canceled_; + + /** True if the copy thread is running. */ + bool aio_thread_running_; /** The array this sorted read state belongs to. */ Array* array_; /** The ids of the attributes the array was initialized with. */ -// std::vector attribute_ids_; + const std::vector attribute_ids_; /** * The sizes of the attributes. For variable-length attributes, sizeof(size_t) * is stored. */ -// std::vector attribute_sizes_; + std::vector attribute_sizes_; /** Number of allocated buffers. */ -// int buffer_num_; - - /** Allocated sizes for buffers_ (similar to those used in Array::read). */ -// size_t* buffer_sizes_[2]; + int buffer_num_; - /** Temporary buffer sizes used in AIO requests. */ -// size_t* buffer_sizes_tmp_[2]; - - /** - * Backup of temporary buffer sizes used in AIO requests (used when there is - * overflow). - */ -// size_t* buffer_sizes_tmp_bak_[2]; + /** The user buffer sizes. */ + const size_t* buffer_sizes_; - /** Local buffers (similar to those used in Array::read). */ -// void** buffers_[2]; + /** The user buffers. */ + const void** buffers_; /** Function for calculating cell slab info during a copy operation. */ -// void *(*calculate_cell_slab_info_) (void*); + void *(*calculate_cell_slab_info_) (void*); /** Function for calculating tile slab info during a copy operation. */ -// void *(*calculate_tile_slab_info_) (void*); - - /** - * Used only in the sparse case. Holds the sorted positions of the cells - * for the current tile slab to be copied. - */ -// std::vector cell_pos_; - - /** - * Used only in the sparse case. It is the element index in attribute_ids_ - * that represents the coordinates attribute. - */ -// int coords_attr_i_; - - /** - * Used only in the sparse case. It is the element index in buffers_ - * that represents the coordinates attribute. - */ -// int coords_buf_i_; + void *(*calculate_tile_slab_info_) (void*); /** The coordinates size of the array. */ -// size_t coords_size_; + size_t coords_size_; /** The copy mutex conditions (one for each buffer). */ -// pthread_cond_t copy_cond_[2]; + pthread_cond_t copy_cond_[2]; /** The current id of the buffers the next copy will occur from. */ -// int copy_id_; + int copy_id_; - /** The copy state. */ -// CopyState copy_state_; + /** The copy state, one per tile slab. */ + CopyState copy_state_; /** The copy mutex. */ -// pthread_mutex_t copy_mtx_; - - /** The thread tha handles all the copying in the background. */ -// pthread_t copy_thread_; - - /** True if the copy thread is canceled. */ -// bool copy_thread_canceled_; - - /** True if the copy thread is running. */ -// bool copy_thread_running_; + pthread_mutex_t copy_mtx_; /** The number of dimensions in the array. */ -// int dim_num_; + int dim_num_; - /** - * Used only in the sparse case. It is true if the coordinates are not asked - * by the user and, thus, TileDB had to append them as an extra attribute - * to facilitate sorting the cell positions. - * - */ -// bool extra_coords_; - - /** The overflow mutex condition. */ - // pthread_cond_t overflow_cond_; - - /** The overflow mutex. */ -// pthread_mutex_t overflow_mtx_; - - /** Overflow flag for each attribute. */ -// bool* overflow_; - - /** - * Overflow flag for each attribute. It starts with *true* for all - * attributes, and becomes false once an attribute does not overflow any more. - */ -// bool* overflow_still_; - - /** True if no more tile slabs to read. */ -// bool read_tile_slabs_done_; - - /** True if a copy must be resumed. */ -// bool resume_copy_; - - /** True if an AIO must be resumed. */ -// bool resume_aio_; + /** The expanded subarray, such that it coincides with tile boundaries. */ + void* expanded_subarray_; /** The query subarray. */ -// void* subarray_; + void* subarray_; /** Auxiliary variable used in calculate_tile_slab_info(). */ -// void* tile_coords_; + void* tile_coords_; /** Auxiliary variable used in calculate_tile_slab_info(). */ -// void* tile_domain_; + void* tile_domain_; /** The tile slab to be read for the first and second buffers. */ -// void* tile_slab_[2]; + void* tile_slab_[2]; /** Indicates if the tile slab has been initialized. */ -// bool tile_slab_init_[2]; + bool tile_slab_init_[2]; /** Normalized tile slab. */ -// void* tile_slab_norm_[2]; + void* tile_slab_norm_[2]; /** The info for each of the two tile slabs under investigation. */ -// TileSlabInfo tile_slab_info_[2]; + TileSlabInfo tile_slab_info_[2]; /** The state for the current tile slab being copied. */ -// TileSlabState tile_slab_state_; + TileSlabState tile_slab_state_; /** Wait for copy flags, one for each local buffer. */ -// bool wait_copy_[2]; + bool wait_copy_[2]; /** Wait for AIO flags, one for each local buffer. */ -// bool wait_aio_[2]; + bool wait_aio_[2]; /* ********************************* */ /* PRIVATE METHODS */ @@ -392,11 +319,11 @@ class ArraySortedWriteState { * Used in copy_tile_slab(). * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a ASWS_Data object. * @return void */ -// template -// static void *advance_cell_slab_col_s(void* data); + template + static void *advance_cell_slab_col_s(void* data); /** * Advances a cell slab focusing on row-major order, and updates @@ -404,11 +331,11 @@ class ArraySortedWriteState { * Used in copy_tile_slab(). * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a ASWS_Data object. * @return void */ -// template - // static void *advance_cell_slab_row_s(void* data); + template + static void *advance_cell_slab_row_s(void* data); /** * Advances a cell slab when the requested order is column-major. @@ -417,8 +344,8 @@ class ArraySortedWriteState { * @param aid The id of the attribute in attribute_ids_ to focus on. * @return void */ -// template -// void advance_cell_slab_col(int aid); + template + void advance_cell_slab_col(int aid); /** * Advances a cell slab when the requested order is row-major. @@ -427,34 +354,22 @@ class ArraySortedWriteState { * @param aid The id of the attribute in attribute_ids_ to focus on. * @return void */ -// template -// void advance_cell_slab_row(int aid); + template + void advance_cell_slab_row(int aid); /** * Called when an AIO completes. * - * @param data A ASRS_Request object. + * @param data A ASWS_Request object. * @return void */ -// static void *aio_done(void* data); - - /** True if some attribute overflowed for the input tile slab upon an AIO. */ -// bool aio_overflow(int aio_id); + static void *aio_done(void* data); /** Sets the flag of wait_aio_[id] to true. */ -// void block_aio(int id); + void block_aio(int id); /** Sets the flag of wait_copy_[id] to true. */ -// void block_copy(int id); - - /** Sets the flag of resume_copy_ to true. */ -// void block_overflow(); - - /** - * Calculate the attribute ids specified by the user upon array - * initialization. - */ -// void calculate_attribute_ids(); + void block_copy(int id); /** * Calculates the number of buffers to be allocated, based on the number @@ -462,30 +377,14 @@ class ArraySortedWriteState { * * @return void */ -// void calculate_buffer_num(); + void calculate_buffer_num(); /** * Calculates the buffer sizes based on the array type. * * @return void */ -// void calculate_buffer_sizes(); - - /** - * Calculates the buffer sizes based on the subarray and the number of cells - * in a (full) tile slab. Applicable to dense arrays. - * - * @return void - */ -// void calculate_buffer_sizes_dense(); - - /** - * Calculates the buffer sizes based on configurable parameters. Applicable to - * sparse arrays. - * - * @return void - */ -// void calculate_buffer_sizes_sparse(); + void calculate_buffer_sizes(); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -493,11 +392,11 @@ class ArraySortedWriteState { * order is column-major. * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a ASWS_Data object. * @return void */ -// template -// static void *calculate_cell_slab_info_col_col_s(void* data); + template + static void *calculate_cell_slab_info_col_col_s(void* data); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -505,11 +404,11 @@ class ArraySortedWriteState { * order is row-major. * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a ASWS_Data object. * @return void */ -// template - // static void *calculate_cell_slab_info_col_row_s(void* data); + template + static void *calculate_cell_slab_info_col_row_s(void* data); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -517,11 +416,11 @@ class ArraySortedWriteState { * order is column-major. * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a AWRS_Data object. * @return void */ -// template -// static void *calculate_cell_slab_info_row_col_s(void* data); + template + static void *calculate_cell_slab_info_row_col_s(void* data); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -529,11 +428,11 @@ class ArraySortedWriteState { * order is row-major. * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a AWRS_Data object. * @return void */ -// template -// static void *calculate_cell_slab_info_row_row_s(void* data); + template + static void *calculate_cell_slab_info_row_row_s(void* data); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -545,8 +444,8 @@ class ArraySortedWriteState { * @param tid The tile id. * @return void. */ -// template -// void calculate_cell_slab_info_col_col(int id, int64_t tid); + template + void calculate_cell_slab_info_col_col(int id, int64_t tid); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -558,8 +457,8 @@ class ArraySortedWriteState { * @param tid The tile id. * @return void. */ -// template -// void calculate_cell_slab_info_col_row(int id, int64_t tid); + template + void calculate_cell_slab_info_col_row(int id, int64_t tid); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -571,8 +470,8 @@ class ArraySortedWriteState { * @param tid The tile id. * @return void. */ -// template -// void calculate_cell_slab_info_row_row(int id, int64_t tid); + template + void calculate_cell_slab_info_row_row(int id, int64_t tid); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -584,8 +483,8 @@ class ArraySortedWriteState { * @param tid The tile id. * @return void. */ -// template -// void calculate_cell_slab_info_row_col(int id, int64_t tid); + template + void calculate_cell_slab_info_row_col(int id, int64_t tid); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -596,8 +495,8 @@ class ArraySortedWriteState { * @param tid The tile id. * @return void. */ -// template -// void calculate_cell_slab_info_row(int id, int64_t tid); + template + void calculate_cell_slab_info_row(int id, int64_t tid); /** * Calculates the **normalized** tile domain overlapped by the input tile @@ -607,8 +506,8 @@ class ArraySortedWriteState { * @param id The tile slab id. * @return void. */ -// template -// void calculate_tile_domain(int id); + template + void calculate_tile_domain(int id); /** * Calculates the info used in the copy_tile_slab() function. @@ -617,19 +516,19 @@ class ArraySortedWriteState { * @param id The tile slab id. * @return void. */ -// template -// void calculate_tile_slab_info(int id); + template + void calculate_tile_slab_info(int id); /** * Calculates tile slab info for the case where the **array** tile order is * column-major * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a ASWS_Data object. * @return void */ -// template -// static void *calculate_tile_slab_info_col(void* data); + template + static void *calculate_tile_slab_info_col(void* data); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -639,19 +538,19 @@ class ArraySortedWriteState { * @param id The tile slab id. * @return void. */ -// template -// void calculate_tile_slab_info_col(int id); + template + void calculate_tile_slab_info_col(int id); /** * Calculates tile slab info for the case where the **array** tile order is * row-major * * @template T The domain type. - * @param data Essentially a pointer to a ASRS_Data object. + * @param data Essentially a pointer to a ASWS_Data object. * @return void */ -// template -// static void *calculate_tile_slab_info_row(void* data); + template + static void *calculate_tile_slab_info_row(void* data); /** * Calculates the info used in the copy_tile_slab() function, for the case @@ -661,99 +560,64 @@ class ArraySortedWriteState { * @param id The tile slab id. * @return void. */ -// template -// void calculate_tile_slab_info_row(int id); + template + void calculate_tile_slab_info_row(int id); /** * Function called by the copy thread. * - * @param context This is practically the ArraySortedReadState object for + * @param context This is practically the ArraySortedWriteState object for * which the function is called (typically *this* is passed to this * argument by the caller). */ -// static void *copy_handler(void* context); - - /** - * Copies a tile slab from the local buffers into the user buffers, - * properly re-organizing the cell order to fit the targeted order. - * Applicable to dense arrays. - * - * @return void. - */ -// void copy_tile_slab_dense(); + static void *copy_handler(void* context); /** - * Copies a tile slab from the local buffers into the user buffers, - * properly re-organizing the cell order to fit the targeted order. - * Applicable to sparse arrays. + * Copies a tile slab from the user buffers into the local buffers, + * properly re-organizing the cell order to follow the array global + * cell order. * * @return void. */ -// void copy_tile_slab_sparse(); + void copy_tile_slab(); /** * Copies a tile slab from the local buffers into the user buffers, * properly re-organizing the cell order to fit the targeted order, * focusing on a particular fixed-length attribute. - * Applicable to dense arrays. - * - * @param aid The index on attribute_ids_ to focus on. - * @param bid The index on the copy state buffers to focus on. - * @return void. - */ -// void copy_tile_slab_dense(int aid, int bid); - - /** - * Copies a tile slab from the local buffers into the user buffers, - * properly re-organizing the cell order to fit the targeted order, - * focusing on a particular fixed-length attribute. - * Applicable to sparse arrays. - * - * @param aid The index on attribute_ids_ to focus on. - * @param bid The index on the copy state buffers to focus on. - * @return void. - */ -// void copy_tile_slab_sparse(int aid, int bid); - - /** - * Copies a tile slab from the local buffers into the user buffers, - * properly re-organizing the cell order to fit the targeted order, - * focusing on a particular variable-length attribute. - * Applicable to dense arrays. * * @param aid The index on attribute_ids_ to focus on. * @param bid The index on the copy state buffers to focus on. * @return void. */ -// void copy_tile_slab_dense_var(int aid, int bid); + void copy_tile_slab(int aid, int bid); /** * Copies a tile slab from the local buffers into the user buffers, * properly re-organizing the cell order to fit the targeted order, * focusing on a particular variable-length attribute. - * Applicable to sparse arrays. * * @param aid The index on attribute_ids_ to focus on. * @param bid The index on the copy state buffers to focus on. * @return void. */ -// void copy_tile_slab_sparse_var(int aid, int bid); + void copy_tile_slab_var(int aid, int bid); /** - * Creates the buffers based on the calculated buffer sizes. + * Creates the copy state buffers. * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int create_buffers(); + int create_copy_state_buffers(); /** Frees the copy state. */ - // void free_copy_state(); + void free_copy_state(); /** Frees the tile slab info. */ -// void free_tile_slab_info(); + void free_tile_slab_info(); /** Frees the tile slab state. */ -// void free_tile_slab_state(); + void free_tile_slab_state(); /** * Returns the cell id along the **array** order for the current coordinates @@ -763,8 +627,8 @@ class ArraySortedWriteState { * @param aid The targeted attribute. * @return The cell id. */ -// template -// int64_t get_cell_id(int aid); + template + int64_t get_cell_id(int aid); /** * Returns the tile id along the **array** order for the current coordinates @@ -774,35 +638,26 @@ class ArraySortedWriteState { * @param aid The targeted attribute. * @return The tile id. */ -// template -// int64_t get_tile_id(int aid); - - /** - * Handles the copy requests. Applicable to dense arrays. - * - * @template T The domain type. - * @return void. - */ -// template -// void handle_copy_requests_dense(); + template + int64_t get_tile_id(int aid); /** - * Handles the copy requests. Applicable to sparse arrays. + * Handles the AIO requests. * * @template T The domain type. * @return void. */ -// template -// void handle_copy_requests_sparse(); + template + void handle_aio_requests(); /** Initializes the AIO requests. */ -// void init_aio_requests(); + void init_aio_requests(); /** Initializes the copy state. */ -// void init_copy_state(); + void init_copy_state(); /** Initializes the tile slab info. */ -// void init_tile_slab_info(); + void init_tile_slab_info(); /** * Initializes the tile slab info for a particular tile slab, using the @@ -812,179 +667,103 @@ class ArraySortedWriteState { * @param id The slab id. * @return void. */ -// template -// void init_tile_slab_info(int id); + template + void init_tile_slab_info(int id); /** Initializes the tile slab state. */ -// void init_tile_slab_state(); + void init_tile_slab_state(); /** * Locks the AIO mutex. * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int lock_aio_mtx(); + int lock_aio_mtx(); /** * Locks the copy mutex. * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// int lock_copy_mtx(); - - /** - * Locks the overflow mutex. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// int lock_overflow_mtx(); - - /** - * Retrieves the next column tile slab to be processed. Applicable to dense - * arrays. - * - * @template T The domain type. - * @return True if the next tile slab was retrieved, and false otherwise. - */ -// template -// bool next_tile_slab_dense_col(); - - /** - * Retrieves the next row tile slab to be processed. Applicable to dense - * arrays. - * - * @template T The domain type. - * @return True if the next tile slab was retrieved, and false otherwise. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// template -// bool next_tile_slab_dense_row(); + int lock_copy_mtx(); /** - * Retrieves the next column tile slab to be processed. Applicable to sparse - * arrays. + * Retrieves the next column tile slab to be processed. * * @template T The domain type. * @return True if the next tile slab was retrieved, and false otherwise. */ -// template -// bool next_tile_slab_sparse_col(); + template + bool next_tile_slab_col(); /** - * Retrieves the next row tile slab to be processed. Applicable to sparse - * arrays. + * Retrieves the next row tile slab to be processed. * * @template T The domain type. * @return True if the next tile slab was retrieved, and false otherwise. */ -// template -// bool next_tile_slab_sparse_row(); + template + bool next_tile_slab_row(); /** - * Same as Array::read(), but it sorts the cells in the buffers based on the - * order the user specified in Array::init(). Note that this function will - * fail if there is not enough system memory to hold the cells of a + * Same as Array::write(), but it sorts the cells in the buffers based on the + * global cell order prior to writing them on disk. Note that this function + * will fail if there is not enough system memory to hold the cells of a * 'tile slab' overlapping with the selected subarray. * * @template T The domain type. - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// template -// int read(); - - /** - * Same as read(), but the cells are placed in 'buffers' sorted in - * column-major order with respect to the selected subarray. - * Applicable only to dense arrays. - * - * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. - */ -// template -// int read_dense_sorted_col(); - - /** - * Same as read(), but the cells are placed in 'buffers' sorted in - * row-major order with respect to the selected subarray. - * Applicable only to dense arrays. - * - * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// template -// int read_dense_sorted_row(); + template + int write(); /** - * Same as read(), but the cells are placed in 'buffers' sorted in + * Same as write(), but the cells are provided by the user sorted in * column-major order with respect to the selected subarray. - * Applicable only to sparse arrays. * * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// template -// int read_sparse_sorted_col(); + template + int write_sorted_col(); /** - * Same as read(), but the cells are placed in 'buffers' sorted in + * Same as write(), but the cells are provided by the user sorted in * row-major order with respect to the selected subarray. - * Applicable only to sparse arrays. * * @template T The domain type. - * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. - */ -// template -// int read_sparse_sorted_row(); - - /** - * Reads the current tile slab into the input buffers. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int read_tile_slab(); + template + int write_sorted_row(); /** * Signals an AIO condition. * * @param id The id of the AIO condition to be signaled. - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int release_aio(int id); + int release_aio(int id); /** * Signals a copy condition. * * @param id The id of the copy condition to be signaled. - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// int release_copy(int id); - - /** - * Signals the overflow condition. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int release_overflow(); + int release_copy(int id); - /** Resets the AIO overflow flags for the input tile slab id. */ -// void reset_aio_overflow(int aio_id); - /** Resets the temporary buffer sizes for the input tile slab id. */ // void reset_buffer_sizes_tmp(int id); - /** Resets the copy state using the input buffer info. */ -// void reset_copy_state(void** buffers, size_t* buffer_sizes); - - /** Resets the oveflow flags to **false**. */ -// void reset_overflow(); - /** * Resets the tile_coords_ auxiliary variable. * * @template T The domain type. * @return void. */ -// template -// void reset_tile_coords(); + template + void reset_tile_coords(); /** * Resets the tile slab state. @@ -992,44 +771,30 @@ class ArraySortedWriteState { * @template T The domain type. * @return void. */ -// template -// void reset_tile_slab_state(); + template + void reset_tile_slab_state(); /** * Sends an AIO request. * * @param aio_id The id of the tile slab the AIO request focuses on. - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// int send_aio_request(int aio_id); - - /** - * It sorts the positions of the cells based on the coordinates - * of the current tile slab to be copied. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// template -// void sort_cell_pos(); + int send_aio_request(int aio_id); /** * Unlocks the AIO mutex. * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int unlock_aio_mtx(); + int unlock_aio_mtx(); /** * Unlocks the copy mutex. * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// int unlock_copy_mtx(); - - /** - * Unlocks the overflow mutex. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int unlock_overflow_mtx(); + int unlock_copy_mtx(); /** * Calculates the new tile and local buffer offset for the new (already @@ -1039,31 +804,24 @@ class ArraySortedWriteState { * @param aid The attribute id to focus on. * @return void. */ -// template -// void update_current_tile_and_offset(int aid); + template + void update_current_tile_and_offset(int aid); /** * Waits on a copy operation for the buffer with input id to finish. * * @param id The id of the buffer the copy operation must be completed. - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int wait_copy(int id); + int wait_copy(int id); /** * Waits on a AIO operation for the buffer with input id to finish. * * @param id The id of the buffer the AIO operation must be completed. - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ -// int wait_aio(int id); - - /** - * Waits until there is no buffer overflow. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + * @return TILEDB_ASWS_OK for success and TILEDB_ASWS_ERR for error. */ -// int wait_overflow(); + int wait_aio(int id); }; #endif diff --git a/core/src/array/array.cc b/core/src/array/array.cc index bb57f698..d80eb146 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -1007,12 +1007,12 @@ void Array::aio_handle_next_request(AIO_Request* aio_request) { } else { // This may initiate a series of new AIO requests // Reset the subarray hard this time (updating also the subarray - // of the ArraySortedReadState object. + // of the ArraySortedWriteState object. if(aio_last_handled_request_ != aio_request->id_) reset_subarray(aio_request->subarray_); // Write - rc = write_default( + rc = write( (const void**) aio_request->buffers_, (const size_t*) aio_request->buffer_sizes_); } diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 3dfbd7a9..a2e23707 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -66,15 +66,8 @@ std::string tiledb_asws_errmsg = ""; ArraySortedWriteState::ArraySortedWriteState( Array* array) - : array_(array) { - -// TODO - -/* - - // Calculate the attribute ids - calculate_attribute_ids(); - + : array_(array), + attribute_ids_(array->attribute_ids()) { // For easy reference const ArraySchema* array_schema = array_->array_schema(); int anum = (int) attribute_ids_.size(); @@ -82,33 +75,23 @@ ArraySortedWriteState::ArraySortedWriteState( // Initializations aio_id_ = 0; aio_cnt_ = 0; + aio_thread_running_ = false; + aio_thread_canceled_ = false; coords_size_ = array_schema->coords_size(); copy_id_ = 0; dim_num_ = array_schema->dim_num(); - copy_thread_running_ = false; - copy_thread_canceled_ = false; - read_tile_slabs_done_ = false; - resume_copy_ = false; - resume_aio_ = false; tile_coords_ = NULL; tile_domain_ = NULL; + buffer_sizes_ = NULL; + buffers_ = NULL; for(int i=0; i<2; ++i) { - aio_overflow_[i] = new bool[anum]; - buffer_sizes_[i] = NULL; - buffer_sizes_tmp_[i] = NULL; - buffer_sizes_tmp_bak_[i] = NULL; - buffers_[i] = NULL; tile_slab_[i] = malloc(2*coords_size_); tile_slab_norm_[i] = malloc(2*coords_size_); tile_slab_init_[i] = false; - wait_copy_[i] = false; - wait_aio_[i] = true; + wait_copy_[i] = true; + wait_aio_[i] = false; } - overflow_ = new bool[anum]; - overflow_still_ = new bool[anum]; for(int i=0; ivar_size(attribute_ids_[i])) attribute_sizes_.push_back(sizeof(size_t)); else @@ -118,46 +101,28 @@ ArraySortedWriteState::ArraySortedWriteState( subarray_ = malloc(2*coords_size_); memcpy(subarray_, array_->subarray(), 2*coords_size_); + // Calculate expanded subarray + expanded_subarray_ = malloc(2*coords_size_); + memcpy(expanded_subarray_, subarray_, 2*coords_size_); + array_schema->expand_domain(expanded_subarray_); + // Calculate number of buffers calculate_buffer_num(); - // Calculate buffer sizes - calculate_buffer_sizes(); - // Initialize tile slab info and state, and copy state init_tile_slab_info(); init_tile_slab_state(); init_copy_state(); - -*/ } ArraySortedWriteState::~ArraySortedWriteState() { -// TODO - -/* - // Clean up free(subarray_); + free(expanded_subarray_); free(tile_coords_); free(tile_domain_); - delete [] overflow_; for(int i=0; i<2; ++i) { - delete [] aio_overflow_[i]; - - if(buffer_sizes_[i] != NULL) - delete [] buffer_sizes_[i]; - if(buffer_sizes_tmp_[i] != NULL) - delete [] buffer_sizes_tmp_[i]; - if(buffer_sizes_tmp_bak_[i] != NULL) - delete [] buffer_sizes_tmp_bak_[i]; - if(buffers_[i] != NULL) { - for(int b=0; barray_schema(); @@ -339,7 +224,7 @@ exit(0); int cell_order = array_schema->cell_order(); int tile_order = array_schema->tile_order(); int coords_type = array_schema->coords_type(); - if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { + if(mode == TILEDB_ARRAY_WRITE_SORTED_ROW) { if(coords_type == TILEDB_INT32) { advance_cell_slab_ = advance_cell_slab_row_s; calculate_cell_slab_info_ = @@ -352,22 +237,10 @@ exit(0); (cell_order == TILEDB_ROW_MAJOR) ? calculate_cell_slab_info_row_row_s : calculate_cell_slab_info_row_col_s; - } else if(coords_type == TILEDB_FLOAT32) { - advance_cell_slab_ = advance_cell_slab_row_s; - calculate_cell_slab_info_ = - (cell_order == TILEDB_ROW_MAJOR) ? - calculate_cell_slab_info_row_row_s : - calculate_cell_slab_info_row_col_s; - } else if(coords_type == TILEDB_FLOAT64) { - advance_cell_slab_ = advance_cell_slab_row_s; - calculate_cell_slab_info_ = - (cell_order == TILEDB_ROW_MAJOR) ? - calculate_cell_slab_info_row_row_s : - calculate_cell_slab_info_row_col_s; } else { assert(0); } - } else { // mode == TILEDB_ARRAY_READ_SORTED_COL + } else { // mode == TILEDB_ARRAY_WRITE_SORTED_COL if(coords_type == TILEDB_INT32) { advance_cell_slab_ = advance_cell_slab_col_s; calculate_cell_slab_info_ = @@ -380,18 +253,6 @@ exit(0); (cell_order == TILEDB_ROW_MAJOR) ? calculate_cell_slab_info_col_row_s : calculate_cell_slab_info_col_col_s; - } else if(coords_type == TILEDB_FLOAT32) { - advance_cell_slab_ = advance_cell_slab_col_s; - calculate_cell_slab_info_ = - (cell_order == TILEDB_ROW_MAJOR) ? - calculate_cell_slab_info_col_row_s : - calculate_cell_slab_info_col_col_s; - } else if(coords_type == TILEDB_FLOAT64) { - advance_cell_slab_ = advance_cell_slab_col_s; - calculate_cell_slab_info_ = - (cell_order == TILEDB_ROW_MAJOR) ? - calculate_cell_slab_info_col_row_s : - calculate_cell_slab_info_col_col_s; } else { assert(0); } @@ -401,10 +262,6 @@ exit(0); calculate_tile_slab_info_ = calculate_tile_slab_info_row; else if(coords_type == TILEDB_INT64) calculate_tile_slab_info_ = calculate_tile_slab_info_row; - else if(coords_type == TILEDB_FLOAT32) - calculate_tile_slab_info_ = calculate_tile_slab_info_row; - else if(coords_type == TILEDB_FLOAT64) - calculate_tile_slab_info_ = calculate_tile_slab_info_row; else assert(0); } else { // tile_order == TILEDB_COL_MAJOR @@ -412,14 +269,9 @@ exit(0); calculate_tile_slab_info_ = calculate_tile_slab_info_col; else if(coords_type == TILEDB_INT64) calculate_tile_slab_info_ = calculate_tile_slab_info_col; - else if(coords_type == TILEDB_FLOAT32) - calculate_tile_slab_info_ = calculate_tile_slab_info_col; - else if(coords_type == TILEDB_FLOAT64) - calculate_tile_slab_info_ = calculate_tile_slab_info_col; else assert(0); } -*/ // Success return TILEDB_ASWS_OK; @@ -428,43 +280,22 @@ exit(0); int ArraySortedWriteState::write( const void** buffers, const size_t* buffer_sizes) { + // Locally store the buffers and sizes + buffers_ = buffers; + buffer_sizes_ = buffer_sizes_; -// TODO -/* - - // Trivial case - if(done()) { - for(int i=0; iarray_schema()->coords_type(); if(type == TILEDB_INT32) - return read(); + return write(); else if(type == TILEDB_INT64) - return read(); - else if(type == TILEDB_FLOAT32) - return read(); - else if(type == TILEDB_FLOAT64) - return read(); + return write(); else assert(0); -*/ // Success return TILEDB_ASWS_OK; @@ -475,26 +306,26 @@ int ArraySortedWriteState::write( /* PRIVATE METHODS */ /* ****************************** */ -/* template -void *ArraySortedReadState::advance_cell_slab_col_s(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int aid = ((ASRS_Data*) data)->id_; - asrs->advance_cell_slab_col(aid); +void *ArraySortedWriteState::advance_cell_slab_col_s(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int aid = ((ASWS_Data*) data)->id_; + asws->advance_cell_slab_col(aid); return NULL; } template -void *ArraySortedReadState::advance_cell_slab_row_s(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int aid = ((ASRS_Data*) data)->id_; - asrs->advance_cell_slab_row(aid); +void *ArraySortedWriteState::advance_cell_slab_row_s(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int aid = ((ASWS_Data*) data)->id_; + asws->advance_cell_slab_row(aid); return NULL; } + template -void ArraySortedReadState::advance_cell_slab_col(int aid) { +void ArraySortedWriteState::advance_cell_slab_col(int aid) { // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile id int64_t cell_slab_num = tile_slab_info_[copy_id_].cell_slab_num_[tid]; @@ -522,7 +353,7 @@ void ArraySortedReadState::advance_cell_slab_col(int aid) { } template -void ArraySortedReadState::advance_cell_slab_row(int aid) { +void ArraySortedWriteState::advance_cell_slab_row(int aid) { // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; // Tile id int64_t cell_slab_num = tile_slab_info_[copy_id_].cell_slab_num_[tid]; @@ -549,276 +380,88 @@ void ArraySortedReadState::advance_cell_slab_row(int aid) { update_current_tile_and_offset(aid); } -void *ArraySortedReadState::aio_done(void* data) { +void *ArraySortedWriteState::aio_done(void* data) { // Retrieve data - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - - // For easy reference - int anum = (int) asrs->attribute_ids_.size(); - const ArraySchema* array_schema = asrs->array_->array_schema(); - - // Check for overflow - bool overflow = false; - for(int i=0; ioverflow_still_[i] && asrs->aio_overflow_[id][i]) { - overflow = true; - break; - } - } - - // Handle overflow - bool sparse = array_schema->dense(); - if(overflow) { // OVERFLOW - // Update buffer sizes - for(int i=0, b=0; ivar_size(asrs->attribute_ids_[i])) { // FIXED - if(asrs->aio_overflow_[id][i]) { - // Expand buffer - expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); - // Re-assign the buffer size for the fixed-sized offsets - asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; - } else { - // Backup sizes and zero them - asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; - asrs->buffer_sizes_tmp_[id][b] = 0; - // Does not overflow any more - asrs->overflow_still_[i] = false; - } - ++b; - } else { // VAR - if(asrs->aio_overflow_[id][i]) { - // Expand offset buffer only in the case of sparse arrays - if(sparse) - expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); - // Re-assign the buffer size for the fixed-sized offsets - asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; - ++b; - // Expand variable-length cell buffers for both dense and sparse - expand_buffer(asrs->buffers_[id][b], asrs->buffer_sizes_[id][b]); - // Assign the new buffer size for the variable-sized values - asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_[id][b]; - ++b; - } else { - // Backup sizes and zero them (fixed-sized offsets) - asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; - asrs->buffer_sizes_tmp_[id][b] = 0; - ++b; - // Backup sizes and zero them (variable-sized values) - asrs->buffer_sizes_tmp_bak_[id][b] = asrs->buffer_sizes_tmp_[id][b]; - asrs->buffer_sizes_tmp_[id][b] = 0; - ++b; - // Does not overflow any more - asrs->overflow_still_[i] = false; - } - } - } - - // Send the request again - asrs->send_aio_request(id); - } else { // NO OVERFLOW - // Restore backup temporary buffer sizes - for(int b=0; bbuffer_num_; ++b) { - if(asrs->buffer_sizes_tmp_bak_[id][b] != 0) - asrs->buffer_sizes_tmp_[id][b] = asrs->buffer_sizes_tmp_bak_[id][b]; - } + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; - // Manage the mutexes and conditions - asrs->release_aio(id); - } + // Manage the mutexes and conditions + asws->release_aio(id); return NULL; } -bool ArraySortedReadState::aio_overflow(int aio_id) { - // For easy reference - int anum = (int) attribute_ids_.size(); - - for(int i=0; iattribute_ids(); - - // For ease reference - const ArraySchema* array_schema = array_->array_schema(); - int attribute_num = array_schema->attribute_num(); - - // No need to do anything else in case the array is dense - if(array_schema->dense()) - return; - - // Find the coordinates index - coords_attr_i_ = -1; - for(int i=0; i<(int)attribute_ids_.size(); ++i) { - if(attribute_ids_[i] == attribute_num) { - coords_attr_i_ = i; - break; - } - } - - // If the coordinates index is not found, append coordinates attribute - // to attribute ids. - if(coords_attr_i_ == -1) { - attribute_ids_.push_back(attribute_num); - coords_attr_i_ = attribute_ids_.size() - 1; - extra_coords_ = true; - } else { // No extra coordinates appended - extra_coords_ = false; - } -} - -void ArraySortedReadState::calculate_buffer_num() { +void ArraySortedWriteState::calculate_buffer_num() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); - int attribute_num = array_schema->attribute_num(); // Calculate number of buffers buffer_num_ = 0; int attribute_id_num = (int) attribute_ids_.size(); for(int i=0; ivar_size(attribute_ids_[i])) { - if(attribute_ids_[i] == attribute_num) - coords_buf_i_ = i; // Buffer that holds the coordinates + if(!array_schema->var_size(attribute_ids_[i])) ++buffer_num_; - } else { // Variable-sized attribute + else // Variable-sized attribute buffer_num_ += 2; - } - } -} - -void ArraySortedReadState::calculate_buffer_sizes() { - if(array_->array_schema()->dense()) - calculate_buffer_sizes_dense(); - else - calculate_buffer_sizes_sparse(); -} - -void ArraySortedReadState::calculate_buffer_sizes_dense() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - - // Get cell number in a (full) tile slab - int64_t tile_slab_cell_num; - if(array_->mode() == TILEDB_ARRAY_READ_SORTED_ROW) - tile_slab_cell_num = array_schema->tile_slab_row_cell_num(subarray_); - else // TILEDB_ARRAY_READ_SORTED_COL - tile_slab_cell_num = array_schema->tile_slab_col_cell_num(subarray_); - - // Calculate buffer sizes - int attribute_id_num = (int) attribute_ids_.size(); - for(int j=0; j<2; ++j) { - buffer_sizes_[j] = new size_t[buffer_num_]; - buffer_sizes_tmp_[j] = new size_t[buffer_num_]; - buffer_sizes_tmp_bak_[j] = new size_t[buffer_num_]; - for(int i=0, b=0; ivar_size(attribute_ids_[i])) { - buffer_sizes_[j][b] = - tile_slab_cell_num * array_schema->cell_size(attribute_ids_[i]); - buffer_sizes_tmp_bak_[j][b] = 0; - ++b; - } else { // Variable-sized attribute - buffer_sizes_[j][b] = tile_slab_cell_num * sizeof(size_t); - buffer_sizes_tmp_bak_[j][b] = 0; - ++b; - buffer_sizes_[j][b] = 2 * tile_slab_cell_num * sizeof(size_t); - buffer_sizes_tmp_bak_[j][b] = 0; - ++b; - } - } - } -} - -void ArraySortedReadState::calculate_buffer_sizes_sparse() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - - // Calculate buffer sizes - int attribute_id_num = (int) attribute_ids_.size(); - for(int j=0; j<2; ++j) { - buffer_sizes_[j] = new size_t[buffer_num_]; - buffer_sizes_tmp_[j] = new size_t[buffer_num_]; - buffer_sizes_tmp_bak_[j] = new size_t[buffer_num_]; - for(int i=0, b=0; ivar_size(attribute_ids_[i])) { // Variable-sized buffer - buffer_sizes_[j][b] = 2*TILEDB_ASRS_INIT_BUFFER_SIZE; - buffer_sizes_tmp_bak_[j][b] = 0; - ++b; - } - } } } template -void *ArraySortedReadState::calculate_cell_slab_info_col_col_s(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - int tid = ((ASRS_Data*) data)->id_2_; - asrs->calculate_cell_slab_info_col_col(id, tid); +void *ArraySortedWriteState::calculate_cell_slab_info_col_col_s(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; + int tid = ((ASWS_Data*) data)->id_2_; + asws->calculate_cell_slab_info_col_col(id, tid); return NULL; } template -void *ArraySortedReadState::calculate_cell_slab_info_col_row_s(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - int tid = ((ASRS_Data*) data)->id_2_; - asrs->calculate_cell_slab_info_col_row(id, tid); +void *ArraySortedWriteState::calculate_cell_slab_info_col_row_s(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; + int tid = ((ASWS_Data*) data)->id_2_; + asws->calculate_cell_slab_info_col_row(id, tid); return NULL; } template -void *ArraySortedReadState::calculate_cell_slab_info_row_col_s(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - int tid = ((ASRS_Data*) data)->id_2_; - asrs->calculate_cell_slab_info_row_col(id, tid); +void *ArraySortedWriteState::calculate_cell_slab_info_row_col_s(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; + int tid = ((ASWS_Data*) data)->id_2_; + asws->calculate_cell_slab_info_row_col(id, tid); return NULL; } template -void *ArraySortedReadState::calculate_cell_slab_info_row_row_s(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - int tid = ((ASRS_Data*) data)->id_2_; - asrs->calculate_cell_slab_info_row_row(id, tid); +void *ArraySortedWriteState::calculate_cell_slab_info_row_row_s(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; + int tid = ((ASWS_Data*) data)->id_2_; + asws->calculate_cell_slab_info_row_row(id, tid); return NULL; } template -void ArraySortedReadState::calculate_cell_slab_info_col_col( +void ArraySortedWriteState::calculate_cell_slab_info_col_col( int id, int64_t tid) { +// TODO + +/* // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; @@ -848,12 +491,19 @@ void ArraySortedReadState::calculate_cell_slab_info_col_col( cell_offset *= (range_overlap[2*(i-1)+1] - range_overlap[2*(i-1)] + 1); tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; } + +*/ } template -void ArraySortedReadState::calculate_cell_slab_info_row_row( +void ArraySortedWriteState::calculate_cell_slab_info_row_row( int id, int64_t tid) { + +// TODO + +/* + // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; @@ -883,12 +533,18 @@ void ArraySortedReadState::calculate_cell_slab_info_row_row( cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; } +*/ } template -void ArraySortedReadState::calculate_cell_slab_info_col_row( +void ArraySortedWriteState::calculate_cell_slab_info_col_row( int id, int64_t tid) { + +// TODO + +/* + // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; @@ -908,12 +564,18 @@ void ArraySortedReadState::calculate_cell_slab_info_col_row( cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; } +*/ } template -void ArraySortedReadState::calculate_cell_slab_info_row_col( +void ArraySortedWriteState::calculate_cell_slab_info_row_col( int id, int64_t tid) { + +// TODO + +/* + // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; @@ -933,10 +595,11 @@ void ArraySortedReadState::calculate_cell_slab_info_row_col( cell_offset *= (range_overlap[2*(i-1)+1] - range_overlap[2*(i-1)] + 1); tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; } +*/ } template -void ArraySortedReadState::calculate_tile_domain(int id) { +void ArraySortedWriteState::calculate_tile_domain(int id) { // Initializations tile_coords_ = malloc(coords_size_); tile_domain_ = malloc(2*coords_size_); @@ -956,7 +619,7 @@ void ArraySortedReadState::calculate_tile_domain(int id) { } template -void ArraySortedReadState::calculate_tile_slab_info(int id) { +void ArraySortedWriteState::calculate_tile_slab_info(int id) { // Calculate number of tiles, if they are not already calculated if(tile_slab_info_[id].tile_num_ == -1) init_tile_slab_info(id); @@ -969,20 +632,20 @@ void ArraySortedReadState::calculate_tile_slab_info(int id) { reset_tile_coords(); // Calculate tile slab info - ASRS_Data asrs_data = { id, 0, this }; - (*calculate_tile_slab_info_)(&asrs_data); + ASWS_Data asws_data = { id, 0, this }; + (*calculate_tile_slab_info_)(&asws_data); } template -void *ArraySortedReadState::calculate_tile_slab_info_col(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - asrs->calculate_tile_slab_info_col(id); +void *ArraySortedWriteState::calculate_tile_slab_info_col(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; + asws->calculate_tile_slab_info_col(id); return NULL; } template -void ArraySortedReadState::calculate_tile_slab_info_col(int id) { +void ArraySortedWriteState::calculate_tile_slab_info_col(int id) { // For easy reference const T* tile_domain = (const T*) tile_domain_; T* tile_coords = (T*) tile_coords_; @@ -1018,8 +681,8 @@ void ArraySortedReadState::calculate_tile_slab_info_col(int id) { } // Calculate cell slab info - ASRS_Data asrs_data = { id, tid, this }; - (*calculate_cell_slab_info_)(&asrs_data); + ASWS_Data asws_data = { id, tid, this }; + (*calculate_cell_slab_info_)(&asws_data); // Calculate start offsets for(int aid=0; aid -void *ArraySortedReadState::calculate_tile_slab_info_row(void* data) { - ArraySortedReadState* asrs = ((ASRS_Data*) data)->asrs_; - int id = ((ASRS_Data*) data)->id_; - asrs->calculate_tile_slab_info_row(id); +void *ArraySortedWriteState::calculate_tile_slab_info_row(void* data) { + ArraySortedWriteState* asws = ((ASWS_Data*) data)->asws_; + int id = ((ASWS_Data*) data)->id_; + asws->calculate_tile_slab_info_row(id); return NULL; } template -void ArraySortedReadState::calculate_tile_slab_info_row(int id) { +void ArraySortedWriteState::calculate_tile_slab_info_row(int id) { // For easy reference const T* tile_domain = (const T*) tile_domain_; T* tile_coords = (T*) tile_coords_; @@ -1086,8 +749,8 @@ void ArraySortedReadState::calculate_tile_slab_info_row(int id) { } // Calculate cell slab info - ASRS_Data asrs_data = { id, tid, this }; - (*calculate_cell_slab_info_)(&asrs_data); + ASWS_Data asws_data = { id, tid, this }; + (*calculate_cell_slab_info_)(&asws_data); // Calculate start offsets for(int aid=0; aidarray_->array_schema()->coords_type(); - if(asrs->array_->array_schema()->dense()) { // DENSE - if(coords_type == TILEDB_INT32) - asrs->handle_copy_requests_dense(); - else if(coords_type == TILEDB_INT64) - asrs->handle_copy_requests_dense(); - else if(coords_type == TILEDB_FLOAT32) - asrs->handle_copy_requests_dense(); - else if(coords_type == TILEDB_FLOAT64) - asrs->handle_copy_requests_dense(); - else - assert(0); - } else { // SPARSE - if(coords_type == TILEDB_INT32) - asrs->handle_copy_requests_sparse(); - else if(coords_type == TILEDB_INT64) - asrs->handle_copy_requests_sparse(); - else if(coords_type == TILEDB_FLOAT32) - asrs->handle_copy_requests_sparse(); - else if(coords_type == TILEDB_FLOAT64) - asrs->handle_copy_requests_sparse(); - else - assert(0); - } + int coords_type = asws->array_->array_schema()->coords_type(); + if(coords_type == TILEDB_INT32) + asws->handle_aio_requests(); + else if(coords_type == TILEDB_INT64) + asws->handle_aio_requests(); + else + assert(0); // Return return NULL; } -void ArraySortedReadState::copy_tile_slab_dense() { +void ArraySortedWriteState::copy_tile_slab() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); // Copy tile slab for each attribute separately for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { if(!array_schema->var_size(attribute_ids_[i])) { - copy_tile_slab_dense(i, b); + copy_tile_slab(i, b); ++b; } else { - copy_tile_slab_dense_var(i, b); + copy_tile_slab_var(i, b); b += 2; } } } -void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { +void ArraySortedWriteState::copy_tile_slab(int aid, int bid) { +// TODO +/* // Exit if copy is done for this attribute if(tile_slab_state_.copy_tile_slab_done_[aid]) { copy_state_.buffer_sizes_[bid] = 0; // Nothing written @@ -1196,8 +844,8 @@ void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { buffer_offset += cell_slab_size; // Prepare for new slab - ASRS_Data asrs_data = { aid, 0, this }; - (*advance_cell_slab_)(&asrs_data); + ASWS_Data asws_data = { aid, 0, this }; + (*advance_cell_slab_)(&asws_data); // Terminating condition if(tile_slab_state_.copy_tile_slab_done_[aid]) @@ -1206,9 +854,12 @@ void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { // Set user buffer size buffer_size = buffer_offset; +*/ } -void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { +void ArraySortedWriteState::copy_tile_slab_var(int aid, int bid) { +// TODO +/* // Exit if copy is done for this attribute if(tile_slab_state_.copy_tile_slab_done_[aid]) { copy_state_.buffer_sizes_[bid] = 0; // Nothing written @@ -1280,8 +931,8 @@ void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { buffer_offset_var += cell_slab_size_var; // Prepare for new slab - ASRS_Data asrs_data = { aid, 0, this }; - (*advance_cell_slab_)(&asrs_data); + ASWS_Data asws_data = { aid, 0, this }; + (*advance_cell_slab_)(&asws_data); // Terminating condition if(tile_slab_state_.copy_tile_slab_done_[aid]) @@ -1291,179 +942,80 @@ void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { // Set user buffer sizes buffer_size = buffer_offset; buffer_size_var = buffer_offset_var; +*/ } -void ArraySortedReadState::copy_tile_slab_sparse() { +int ArraySortedWriteState::create_copy_state_buffers() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); - - // Copy tile slab for each attribute separately - for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { - if(!array_schema->var_size(attribute_ids_[i])) { // FIXED - // Make sure not to copy coordinates if the user has not requested them - if(i != coords_attr_i_ || !extra_coords_) - copy_tile_slab_sparse(i, b); - ++b; - } else { // VAR - copy_tile_slab_sparse_var(i, b); - b += 2; - } - } -} -void ArraySortedReadState::copy_tile_slab_sparse(int aid, int bid) { - // Exit if copy is done for this attribute - if(tile_slab_state_.copy_tile_slab_done_[aid]) { - copy_state_.buffer_sizes_[bid] = 0; // Nothing written - return; - } + // Get cell number in a (full) tile slab + int64_t tile_slab_cell_num; + if(array_->mode() == TILEDB_ARRAY_WRITE_SORTED_ROW) + tile_slab_cell_num = + array_schema->tile_slab_row_cell_num(expanded_subarray_); + else // TILEDB_ARRAY_WRITE_SORTED_COL + tile_slab_cell_num = + array_schema->tile_slab_col_cell_num(expanded_subarray_); - // For easy reference - size_t cell_size = array_->array_schema()->cell_size(attribute_ids_[aid]); - size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; - size_t buffer_size = copy_state_.buffer_sizes_[bid]; - char* buffer = (char*) copy_state_.buffers_[bid]; - char* local_buffer = (char*) buffers_[copy_id_][bid]; - size_t local_buffer_offset; - int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; - int64_t& current_cell_pos = tile_slab_state_.current_cell_pos_[aid]; + // Calculate buffer sizes + int attribute_id_num = (int) attribute_ids_.size(); + for(int j=0; j<2; ++j) { + copy_state_.buffer_sizes_[j] = new size_t[buffer_num_]; + for(int i=0, b=0; ivar_size(attribute_ids_[i])) { + copy_state_.buffer_sizes_[j][b] = + tile_slab_cell_num * array_schema->cell_size(attribute_ids_[i]); + ++b; + } else { // Variable-sized attribute + copy_state_.buffer_sizes_[j][b++] = tile_slab_cell_num * sizeof(size_t); + copy_state_.buffer_sizes_[j][b++] = 2*tile_slab_cell_num*sizeof(size_t); + } + } + } - // Iterate over the remaining tile slab cells in a sorted order - for(; current_cell_pos buffer_size) { - overflow_[aid] = true; - break; + // Allocate buffers + for(int j=0; j<2; ++j) { + copy_state_.buffers_[j] = (void**) malloc(buffer_num_ * sizeof(void*)); + if(copy_state_.buffers_[j] == NULL) { + std::string errmsg = "Cannot create local buffers"; + PRINT_ERROR(errmsg); + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; } - // Calculate new local buffer offset - local_buffer_offset = cell_pos_[current_cell_pos] * cell_size; - - // Copy cell slab - memcpy( - buffer + buffer_offset, - local_buffer + local_buffer_offset, - cell_size); + for(int b=0; b < buffer_num_; ++b) { + copy_state_.buffers_[j][b] = malloc(copy_state_.buffer_sizes_[j][b]); + if(copy_state_.buffers_[j][b] == NULL) { + std::string errmsg = "Cannot allocate local buffer"; + PRINT_ERROR(errmsg); + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; + } + } + } - // Update buffer offset - buffer_offset += cell_size; - } + // Success + return TILEDB_ASWS_OK; +} - // Mark tile slab as done - if(current_cell_pos == cell_num) - tile_slab_state_.copy_tile_slab_done_[aid] = true; - // Set user buffer size - buffer_size = buffer_offset; +void ArraySortedWriteState::free_copy_state() { + for(int i=0; i<2; ++i) { + if(copy_state_.buffer_sizes_[i] != NULL) + delete [] copy_state_.buffer_sizes_[i]; + if(copy_state_.buffers_[i] != NULL) { + for(int b=0; b buffer_size) { - overflow_[aid] = true; - break; - } - - // Calculate variable cell size - int64_t cell_start = cell_pos_[current_cell_pos]; - int64_t cell_end = cell_start + 1; - cell_size_var = - (cell_end == cell_num) ? - local_buffer_var_size - local_buffer_s[cell_start] : - local_buffer_s[cell_end] - local_buffer_s[cell_start]; - - // Handle overflow for the the variable-length buffer - if(buffer_offset_var + cell_size_var > buffer_size_var) { - overflow_[aid] = true; - break; - } - - // Copy fixed-sized offset - memcpy( - buffer + buffer_offset, - &buffer_offset_var, - sizeof(size_t)); - buffer_offset += sizeof(size_t); - - // Copy variable-sized values - memcpy( - buffer_var + buffer_offset_var, - local_buffer_var + local_buffer_s[cell_start], - cell_size_var); - buffer_offset_var += cell_size_var; - } - - // Mark tile slab as done - if(current_cell_pos == cell_num) - tile_slab_state_.copy_tile_slab_done_[aid] = true; - - // Set user buffer sizes - buffer_size = buffer_offset; - buffer_size_var = buffer_offset_var; -} - -int ArraySortedReadState::create_buffers() { - for(int j=0; j<2; ++j) { - buffers_[j] = (void**) malloc(buffer_num_ * sizeof(void*)); - if(buffers_[j] == NULL) { - std::string errmsg = "Cannot create local buffers"; - PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; - } - - for(int b=0; b < buffer_num_; ++b) { - buffers_[j][b] = malloc(buffer_sizes_[j][b]); - if(buffers_[j][b] == NULL) { - std::string errmsg = "Cannot allocate local buffer"; - PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; - } - } - } - - // Success - return TILEDB_ASRS_OK; -} - -void ArraySortedReadState::free_copy_state() { - if(copy_state_.buffer_offsets_ != NULL) - delete [] copy_state_.buffer_offsets_; -} - -void ArraySortedReadState::free_tile_slab_info() { - // Do nothing in the case of sparse arrays - if(!array_->array_schema()->dense()) - return; - - // For easy reference - int anum = (int) attribute_ids_.size(); +void ArraySortedWriteState::free_tile_slab_info() { + // For easy reference + int anum = (int) attribute_ids_.size(); // Free for(int i=0; i<2; ++i) { @@ -1500,7 +1052,7 @@ void ArraySortedReadState::free_tile_slab_info() { } } -void ArraySortedReadState::free_tile_slab_state() { +void ArraySortedWriteState::free_tile_slab_state() { // For easy reference int anum = (int) attribute_ids_.size(); @@ -1519,13 +1071,10 @@ void ArraySortedReadState::free_tile_slab_state() { if(tile_slab_state_.current_tile_ != NULL) delete [] tile_slab_state_.current_tile_; - - if(tile_slab_state_.current_cell_pos_ != NULL) - delete [] tile_slab_state_.current_cell_pos_; } template -int64_t ArraySortedReadState::get_cell_id(int aid) { +int64_t ArraySortedWriteState::get_cell_id(int aid) { // For easy reference const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; int64_t tid = tile_slab_state_.current_tile_[aid]; @@ -1545,7 +1094,7 @@ int64_t ArraySortedReadState::get_cell_id(int aid) { } template -int64_t ArraySortedReadState::get_tile_id(int aid) { +int64_t ArraySortedWriteState::get_tile_id(int aid) { // For easy reference const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); @@ -1561,107 +1110,56 @@ int64_t ArraySortedReadState::get_tile_id(int aid) { } template -void ArraySortedReadState::handle_copy_requests_dense() { - // Handle copy requests indefinitely - for(;;) { - // Wait for AIO - wait_aio(copy_id_); - - // Kill thread, after releasing any blocked resources - if(copy_thread_canceled_) { - copy_thread_running_ = false; - return; - } - - // Reset the tile slab state - if(copy_tile_slab_done()) - reset_tile_slab_state(); - - // Start the copy - copy_tile_slab_dense(); - - // Wait in case of overflow - if(overflow()) { - block_overflow(); - block_aio(copy_id_); - release_copy(copy_id_); - wait_overflow(); - continue; - } - - // Copy is done - block_aio(copy_id_); - release_copy(copy_id_); - copy_id_ = (copy_id_ + 1) % 2; - } -} - -template -void ArraySortedReadState::handle_copy_requests_sparse() { - // Handle copy requests indefinitely +void ArraySortedWriteState::handle_aio_requests() { + // Handle AIO requests indefinitely for(;;) { // Wait for AIO - wait_aio(copy_id_); + wait_copy(aio_id_); - // Kill thread, after releasing any blocked resources - if(copy_thread_canceled_) { - copy_thread_running_ = false; + // Kill thread + if(aio_thread_canceled_) { + aio_thread_running_ = false; return; } - // Sort the cell positions - if(copy_tile_slab_done()) { - reset_tile_slab_state(); - sort_cell_pos(); - } + // Block copy + block_copy(aio_id_); - // Start the copy - copy_tile_slab_sparse(); - - // Wait in case of overflow - if(overflow()) { - block_overflow(); - block_aio(copy_id_); - release_copy(copy_id_); - wait_overflow(); - continue; - } + // Send AIO request + send_aio_request(aio_id_); - // Copy is done - block_aio(copy_id_); - release_copy(copy_id_); - copy_id_ = (copy_id_ + 1) % 2; + // Advance AIO id + aio_id_ = (aio_id_ + 1) % 2; } } -void ArraySortedReadState::init_aio_requests() { +void ArraySortedWriteState::init_aio_requests() { for(int i=0; i<2; ++i) { aio_data_[i] = { i, 0, this }; aio_request_[i] = {}; - aio_request_[i].buffer_sizes_ = buffer_sizes_tmp_[i]; - aio_request_[i].buffers_ = buffers_[i]; - aio_request_[i].mode_ = TILEDB_ARRAY_READ; - aio_request_[i].subarray_ = tile_slab_[i]; + aio_request_[i].buffer_sizes_ = copy_state_.buffer_sizes_[i]; + aio_request_[i].buffers_ = copy_state_.buffers_[i]; + aio_request_[i].mode_ = TILEDB_ARRAY_WRITE; + aio_request_[i].subarray_ = NULL; aio_request_[i].completion_handle_ = aio_done; aio_request_[i].completion_data_ = &(aio_data_[i]); - aio_request_[i].overflow_ = aio_overflow_[i]; + aio_request_[i].overflow_ = NULL; aio_request_[i].status_ = &(aio_status_[i]); } } -void ArraySortedReadState::init_copy_state() { - copy_state_.buffer_sizes_ = NULL; - copy_state_.buffers_ = NULL; - copy_state_.buffer_offsets_ = new size_t[buffer_num_]; - for(int i=0; iarray_schema()->dense()) - return; - +void ArraySortedWriteState::init_tile_slab_info() { // For easy reference int anum = (int) attribute_ids_.size(); @@ -1684,7 +1182,7 @@ void ArraySortedReadState::init_tile_slab_info() { } template -void ArraySortedReadState::init_tile_slab_info(int id) { +void ArraySortedWriteState::init_tile_slab_info(int id) { // Sanity check assert(array_->array_schema()->dense()); @@ -1711,87 +1209,53 @@ void ArraySortedReadState::init_tile_slab_info(int id) { tile_slab_info_[id].tile_num_ = tile_num; } -void ArraySortedReadState::init_tile_slab_state() { +void ArraySortedWriteState::init_tile_slab_state() { // For easy reference int anum = (int) attribute_ids_.size(); - bool dense = array_->array_schema()->dense(); - // Both for dense and sparse + // Allocations and initializations tile_slab_state_.copy_tile_slab_done_ = new bool[anum]; for(int i=0; i -bool ArraySortedReadState::next_tile_slab_dense_col() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } - +bool ArraySortedWriteState::next_tile_slab_col() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -1807,7 +1271,6 @@ bool ArraySortedReadState::next_tile_slab_dense_col() { // Check again if done, this time based on the tile slab and subarray if(tile_slab_init_[prev_id] && tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { - read_tile_slabs_done_ = true; return false; } @@ -1863,17 +1326,7 @@ bool ArraySortedReadState::next_tile_slab_dense_col() { } template -bool ArraySortedReadState::next_tile_slab_dense_row() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } - +bool ArraySortedWriteState::next_tile_slab_row() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -1889,7 +1342,6 @@ bool ArraySortedReadState::next_tile_slab_dense_row() { // Check again if done, this time based on the tile slab and subarray if(tile_slab_init_[prev_id] && tile_slab[prev_id][1] == subarray[1]) { - read_tile_slabs_done_ = true; return false; } @@ -1941,654 +1393,134 @@ bool ArraySortedReadState::next_tile_slab_dense_row() { } template -bool ArraySortedReadState::next_tile_slab_sparse_col() { - // Quick check if done - if(read_tile_slabs_done_) - return false; +int ArraySortedWriteState::write() { + // For easy reference + int mode = array_->mode(); - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } + if(mode == TILEDB_ARRAY_WRITE_SORTED_COL) + return write_sorted_col(); + else if(mode == TILEDB_ARRAY_WRITE_SORTED_ROW) + return write_sorted_row(); + else + assert(0); // The code should never reach here +} +template +int ArraySortedWriteState::write_sorted_col() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); - const T* domain = static_cast(array_schema->domain()); - const T* tile_extents = static_cast(array_schema->tile_extents()); - T* tile_slab[2]; - for(int i=0; i<2; ++i) - tile_slab[i] = static_cast(tile_slab_[i]); - int prev_id = (aio_id_+1)%2; - // Check again if done, this time based on the tile slab and subarray - if(tile_slab_init_[prev_id] && - tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { - read_tile_slabs_done_ = true; - return false; - } + // Check if this can be satisfied with a default write + if(array_schema->cell_order() == TILEDB_COL_MAJOR && + !memcmp(subarray_, expanded_subarray_, 2*coords_size_) && + array_schema->is_contained_in_tile_slab_row(subarray)) + return array_->write_default(buffers_, buffer_sizes_); - // If this is the first time this function is called, initialize - if(!tile_slab_init_[prev_id]) { - // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; - T upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; - T cropped_upper = - (upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1] * - tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; - tile_slab[aio_id_][2*(dim_num_-1)+1] = - std::min(cropped_upper - 1, subarray[2*(dim_num_-1)+1]); + // Iterate over each tile slab + while(next_tile_slab_col()) { + // Wait for AIO + wait_aio(copy_id_); - // Leave the rest of the subarray extents intact - for(int i=0; i(); + + // Copy tile slab + copy_tile_slab(); + + // Release copy + release_copy(copy_id_); + + // Advance copy id + copy_id_ = (copy_id_ + 1) % 2; } - // Mark this tile slab as initialized - tile_slab_init_[aio_id_] = true; + // Wait for last AIO to finish + wait_aio((copy_id_ + 1) % 2); + + // The following will make the AIO thread terminate + aio_thread_canceled_ = true; + release_copy(copy_id_); // Success - return true; + return TILEDB_ASWS_OK; } -template<> -bool ArraySortedReadState::next_tile_slab_sparse_col() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } - +template +int ArraySortedWriteState::write_sorted_row() { // For easy reference const ArraySchema* array_schema = array_->array_schema(); - const float* subarray = (const float*) subarray_; - const float* domain = (const float*) array_schema->domain(); - const float* tile_extents = (const float*) array_schema->tile_extents(); - float* tile_slab[2]; - for(int i=0; i<2; ++i) - tile_slab[i] = (float*) tile_slab_[i]; - int prev_id = (aio_id_+1)%2; + const T* subarray = static_cast(subarray_); - // Check again if done, this time based on the tile slab and subarray - if(tile_slab_init_[prev_id] && - tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { - read_tile_slabs_done_ = true; - return false; - } + // Check if this can be satisfied with a default write + if(array_schema->cell_order() == TILEDB_ROW_MAJOR && + !memcmp(subarray_, expanded_subarray_, 2*coords_size_) && + array_schema->is_contained_in_tile_slab_col(subarray)) + return array_->write_default(buffers_, buffer_sizes_); - // If this is the first time this function is called, initialize - if(!tile_slab_init_[prev_id]) { - // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; - float upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; - float cropped_upper = - floor((upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1]) * - tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; - tile_slab[aio_id_][2*(dim_num_-1)+1] = - std::min(cropped_upper - FLT_MIN, subarray[2*(dim_num_-1)+1]); + // Iterate over each tile slab + while(next_tile_slab_row()) { + // Wait for AIO + wait_aio(copy_id_); - // Leave the rest of the subarray extents intact - for(int i=0; i(); + + // Copy tile slab + copy_tile_slab(); + + // Release copy + release_copy(copy_id_); + + // Advance copy id + copy_id_ = (copy_id_ + 1) % 2; } - // Mark this tile slab as initialized - tile_slab_init_[aio_id_] = true; + // Wait for last AIO to finish + wait_aio((copy_id_ + 1) % 2); + + // The following will make the AIO thread terminate + aio_thread_canceled_ = true; + release_copy(copy_id_); // Success - return true; + return TILEDB_ASWS_OK; } -template<> -bool ArraySortedReadState::next_tile_slab_sparse_col() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } +int ArraySortedWriteState::release_aio(int id) { + // Lock the AIO mutex + if(lock_aio_mtx() != TILEDB_ASWS_OK) + return TILEDB_ASWS_ERR; - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const double* subarray = (const double*) subarray_; - const double* domain = (const double*) array_schema->domain(); - const double* tile_extents = (const double*) array_schema->tile_extents(); - double* tile_slab[2]; - for(int i=0; i<2; ++i) - tile_slab[i] = (double*) tile_slab_[i]; - int prev_id = (aio_id_+1)%2; + // Set AIO flag + wait_aio_[id] = false; - // Check again if done, this time based on the tile slab and subarray - if(tile_slab_init_[prev_id] && - tile_slab[prev_id][2*(dim_num_-1) + 1] == subarray[2*(dim_num_-1) + 1]) { - read_tile_slabs_done_ = true; - return false; + // Signal condition + if(pthread_cond_signal(&(aio_cond_[id]))) { + std::string errmsg = "Cannot signal AIO condition"; + PRINT_ERROR(errmsg); + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; } - // If this is the first time this function is called, initialize - if(!tile_slab_init_[prev_id]) { - // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; - double upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; - double cropped_upper = - floor((upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1]) * - tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; - tile_slab[aio_id_][2*(dim_num_-1)+1] = - std::min(cropped_upper - DBL_MIN, subarray[2*(dim_num_-1)+1]); - - // Leave the rest of the subarray extents intact - for(int i=0; i -bool ArraySortedReadState::next_tile_slab_sparse_row() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } - - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const T* subarray = static_cast(subarray_); - const T* domain = static_cast(array_schema->domain()); - const T* tile_extents = static_cast(array_schema->tile_extents()); - T* tile_slab[2]; - for(int i=0; i<2; ++i) - tile_slab[i] = static_cast(tile_slab_[i]); - int prev_id = (aio_id_+1)%2; - - // Check again if done, this time based on the tile slab and subarray - if(tile_slab_init_[prev_id] && - tile_slab[prev_id][1] == subarray[1]) { - read_tile_slabs_done_ = true; - return false; - } - - // If this is the first time this function is called, initialize - if(!tile_slab_init_[prev_id]) { - // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][0] = subarray[0]; - T upper = subarray[0] + tile_extents[0]; - T cropped_upper = - (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; - tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); - - // Leave the rest of the subarray extents intact - for(int i=1; i -bool ArraySortedReadState::next_tile_slab_sparse_row() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } - - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const float* subarray = (const float*) subarray_; - const float* domain = (const float*) array_schema->domain(); - const float* tile_extents = (const float*) array_schema->tile_extents(); - float* tile_slab[2]; - for(int i=0; i<2; ++i) - tile_slab[i] = (float*) tile_slab_[i]; - int prev_id = (aio_id_+1)%2; - - // Check again if done, this time based on the tile slab and subarray - if(tile_slab_init_[prev_id] && - tile_slab[prev_id][1] == subarray[1]) { - read_tile_slabs_done_ = true; - return false; - } - - // If this is the first time this function is called, initialize - if(!tile_slab_init_[prev_id]) { - // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][0] = subarray[0]; - float upper = subarray[0] + tile_extents[0]; - float cropped_upper = - floor((upper - domain[0]) / tile_extents[0]) * tile_extents[0] + - domain[0]; - tile_slab[aio_id_][1] = std::min(cropped_upper - FLT_MIN, subarray[1]); - - // Leave the rest of the subarray extents intact - for(int i=1; i -bool ArraySortedReadState::next_tile_slab_sparse_row() { - // Quick check if done - if(read_tile_slabs_done_) - return false; - - // If the AIO needs to be resumed, exit (no need for a new tile slab) - if(resume_aio_) { - resume_aio_ = false; - return true; - } - - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const double* subarray = (const double*) subarray_; - const double* domain = (const double*) array_schema->domain(); - const double* tile_extents = (const double*) array_schema->tile_extents(); - double* tile_slab[2]; - for(int i=0; i<2; ++i) - tile_slab[i] = (double*) tile_slab_[i]; - int prev_id = (aio_id_+1)%2; - - // Check again if done, this time based on the tile slab and subarray - if(tile_slab_init_[prev_id] && - tile_slab[prev_id][1] == subarray[1]) { - read_tile_slabs_done_ = true; - return false; - } - - // If this is the first time this function is called, initialize - if(!tile_slab_init_[prev_id]) { - // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][0] = subarray[0]; - double upper = subarray[0] + tile_extents[0]; - double cropped_upper = - floor((upper - domain[0]) / tile_extents[0]) * tile_extents[0] + - domain[0]; - tile_slab[aio_id_][1] = std::min(cropped_upper - DBL_MIN, subarray[1]); - - // Leave the rest of the subarray extents intact - for(int i=1; i -int ArraySortedReadState::read() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - int mode = array_->mode(); - - if(mode == TILEDB_ARRAY_READ_SORTED_COL) { - if(array_schema->dense()) - return read_dense_sorted_col(); - else - return read_sparse_sorted_col(); - } else if(mode == TILEDB_ARRAY_READ_SORTED_ROW) { - if(array_schema->dense()) - return read_dense_sorted_row(); - else - return read_sparse_sorted_row(); - } else { - assert(0); // The code should never reach here - } -} - -template -int ArraySortedReadState::read_dense_sorted_col() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const T* subarray = static_cast(subarray_); - - // Check if this can be satisfied with a default read - if(array_schema->cell_order() == TILEDB_COL_MAJOR && - array_schema->is_contained_in_tile_slab_row(subarray)) - return array_->read_default( - copy_state_.buffers_, - copy_state_.buffer_sizes_); - - // Iterate over each tile slab - while(next_tile_slab_dense_col()) { - // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; - - // Handle overflow - if(resume_aio_) - break; - } - - // Wait for copy to finish - int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; - wait_copy(copy_id); - - // Assign the true buffer sizes - for(int i=0; i -int ArraySortedReadState::read_dense_sorted_row() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const T* subarray = static_cast(subarray_); - - // Check if this can be satisfied with a default read - if(array_schema->cell_order() == TILEDB_ROW_MAJOR && - array_schema->is_contained_in_tile_slab_col(subarray)) - return array_->read_default( - copy_state_.buffers_, - copy_state_.buffer_sizes_); - - // Iterate over each tile slab - while(next_tile_slab_dense_row()) { - // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; - - // Handle overflow - if(resume_aio_) - break; - } - - // Wait for copy and AIO to finish - int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; - wait_copy(copy_id); - - // Assign the true buffer sizes - for(int i=0; i -int ArraySortedReadState::read_sparse_sorted_col() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const T* subarray = static_cast(subarray_); - - // Check if this can be satisfied with a default read - if(array_schema->cell_order() == TILEDB_COL_MAJOR && - array_schema->is_contained_in_tile_slab_row(subarray)) - return array_->read_default( - copy_state_.buffers_, - copy_state_.buffer_sizes_); - - // Iterate over each tile slab - while(next_tile_slab_sparse_col()) { - // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; - - // Handle overflow - if(resume_aio_) - break; - } - - // Wait for copy to finish - int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; - wait_copy(copy_id); - - // Assign the true buffer sizes - for(int i=0; i -int ArraySortedReadState::read_sparse_sorted_row() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - const T* subarray = static_cast(subarray_); - - // Check if this can be satisfied with a default read - if(array_schema->cell_order() == TILEDB_ROW_MAJOR && - array_schema->is_contained_in_tile_slab_col(subarray)) - return array_->read_default( - copy_state_.buffers_, - copy_state_.buffer_sizes_); - - // Iterate over each tile slab - while(next_tile_slab_sparse_row()) { - // Read the next tile slab with the default cell order - if(read_tile_slab() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; - - // Handle overflow - if(resume_aio_) - break; - } - - // Wait for copy and AIO to finish - int copy_id = (resume_aio_) ? aio_id_ : (aio_id_ + 1) % 2; - wait_copy(copy_id); - - // Assign the true buffer sizes - for(int i=0; i -void ArraySortedReadState::reset_tile_coords() { +void ArraySortedWriteState::reset_tile_coords() { T* tile_coords = (T*) tile_coords_; for(int i=0; i -void ArraySortedReadState::reset_tile_slab_state() { +void ArraySortedWriteState::reset_tile_slab_state() { // For easy reference int anum = (int) attribute_ids_.size(); - bool dense = array_->array_schema()->dense(); + T** current_coords = (T**) tile_slab_state_.current_coords_; + const T* tile_slab = (const T*) tile_slab_norm_[copy_id_]; - // Both dense and sparse - for(int i=0; iarray_clone(); @@ -2707,82 +1585,40 @@ int ArraySortedReadState::send_aio_request(int aio_id) { // Send the AIO request to the clone array if(array_clone->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { - // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; - return TILEDB_ASRS_ERR; + // TODO: get error message: tiledb_asws_errmsg = tiledb_ar_msg; + return TILEDB_ASWS_ERR; } // Success - return TILEDB_ASRS_OK; -} - -template -void ArraySortedReadState::sort_cell_pos() { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - int dim_num = array_schema->dim_num(); - int64_t cell_num = buffer_sizes_tmp_[copy_id_][coords_buf_i_] / coords_size_; - int mode = array_->mode(); - const T* buffer = static_cast(buffers_[copy_id_][coords_buf_i_]); - - // Populate cell_pos - cell_pos_.resize(cell_num); - for(int i=0; i(buffer, dim_num)); - } else { // mode == TILEDB_ARRAY_READ_SORTED_COL - // Sort cell positions - SORT( - cell_pos_.begin(), - cell_pos_.end(), - SmallerCol(buffer, dim_num)); - } + return TILEDB_ASWS_OK; } -int ArraySortedReadState::unlock_aio_mtx() { +int ArraySortedWriteState::unlock_aio_mtx() { if(pthread_mutex_unlock(&aio_mtx_)) { std::string errmsg = "Cannot unlock AIO mutex"; PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; } // Success - return TILEDB_ASRS_OK; + return TILEDB_ASWS_OK; } -int ArraySortedReadState::unlock_copy_mtx() { +int ArraySortedWriteState::unlock_copy_mtx() { if(pthread_mutex_unlock(©_mtx_)) { std::string errmsg = "Cannot unlock copy mutex"; PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; } // Success - return TILEDB_ASRS_OK; -} - -int ArraySortedReadState::unlock_overflow_mtx() { - if(pthread_mutex_unlock(&overflow_mtx_)) { - std::string errmsg = "Cannot unlock overflow mutex"; - PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; - } - - // Success - return TILEDB_ASRS_OK; + return TILEDB_ASWS_OK; } template -void ArraySortedReadState::update_current_tile_and_offset(int aid) { +void ArraySortedWriteState::update_current_tile_and_offset(int aid) { // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; size_t& current_offset = tile_slab_state_.current_offsets_[aid]; @@ -2800,78 +1636,58 @@ void ArraySortedReadState::update_current_tile_and_offset(int aid) { cid * attribute_sizes_[aid]; } -int ArraySortedReadState::wait_aio(int id) { + +int ArraySortedWriteState::wait_aio(int id) { // Lock AIO mutex - if(lock_aio_mtx() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; + if(lock_aio_mtx() != TILEDB_ASWS_OK) + return TILEDB_ASWS_ERR; // Wait to be signaled while(wait_aio_[id]) { if(pthread_cond_wait(&(aio_cond_[id]), &aio_mtx_)) { std::string errmsg = "Cannot wait on IO mutex condition"; PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; } } // Unlock AIO mutex - if(unlock_aio_mtx() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; + if(unlock_aio_mtx() != TILEDB_ASWS_OK) + return TILEDB_ASWS_ERR; // Success - return TILEDB_ASRS_OK; + return TILEDB_ASWS_OK; } -int ArraySortedReadState::wait_copy(int id) { +int ArraySortedWriteState::wait_copy(int id) { // Lock copy mutex - if(lock_copy_mtx() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; + if(lock_copy_mtx() != TILEDB_ASWS_OK) + return TILEDB_ASWS_ERR; // Wait to be signaled while(wait_copy_[id]) { if(pthread_cond_wait(&(copy_cond_[id]), ©_mtx_)) { std::string errmsg = "Cannot wait on copy mutex condition"; PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; } } // Unlock copy mutex - if(unlock_copy_mtx() != TILEDB_ASRS_OK) - return TILEDB_ASRS_ERR; + if(unlock_copy_mtx() != TILEDB_ASWS_OK) + return TILEDB_ASWS_ERR; // Success - return TILEDB_ASRS_OK; -} - -int ArraySortedReadState::wait_overflow() { - // Wait to be signaled - while(overflow()) { - if(pthread_cond_wait(&overflow_cond_, &overflow_mtx_)) { - std::string errmsg = "Cannot wait on IO mutex condition"; - PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; - } - } - - // Success - return TILEDB_ASRS_OK; + return TILEDB_ASWS_OK; } // Explicit template instantiations -template int ArraySortedReadState::read_dense_sorted_col(); -template int ArraySortedReadState::read_dense_sorted_col(); -template int ArraySortedReadState::read_dense_sorted_col(); -template int ArraySortedReadState::read_dense_sorted_col(); +template int ArraySortedWriteState::write_sorted_col(); +template int ArraySortedWriteState::write_sorted_col(); -template int ArraySortedReadState::read_dense_sorted_row(); -template int ArraySortedReadState::read_dense_sorted_row(); -template int ArraySortedReadState::read_dense_sorted_row(); -template int ArraySortedReadState::read_dense_sorted_row(); +template int ArraySortedWriteState::write_sorted_row(); +template int ArraySortedWriteState::write_sorted_row(); - -*/ From b972a4a93b22bc4d15e91d07ebba82630adef5c4 Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 21 Oct 2016 17:52:32 -0400 Subject: [PATCH 18/57] Finished dense sorted writes (not tested yet). --- core/include/array/array_schema.h | 3 + core/include/array/array_sorted_write_state.h | 66 +++- core/src/array/array_schema.cc | 4 + core/src/array/array_sorted_read_state.cc | 8 +- core/src/array/array_sorted_write_state.cc | 285 ++++++++++-------- 5 files changed, 241 insertions(+), 125 deletions(-) diff --git a/core/include/array/array_schema.h b/core/include/array/array_schema.h index ad4a67e2..3ccddc65 100644 --- a/core/include/array/array_schema.h +++ b/core/include/array/array_schema.h @@ -141,6 +141,9 @@ class ArraySchema { /** Returns the size of cell on the input attribute. */ size_t cell_size(int attribute_id) const; + /** Returns the number of values per cell of the input attribute. */ + int cell_val_num(int attribute_id) const; + /** Returns the compression type of the attribute with the input id. */ int compression(int attribute_id) const; diff --git a/core/include/array/array_sorted_write_state.h b/core/include/array/array_sorted_write_state.h index 6e7d5b69..b855250c 100644 --- a/core/include/array/array_sorted_write_state.h +++ b/core/include/array/array_sorted_write_state.h @@ -89,6 +89,8 @@ class ArraySortedWriteState { /** Stores local state about the current write/copy request. */ struct CopyState { + /** Local buffer offsets. */ + size_t* buffer_offsets_[2]; /** Local buffer sizes. */ size_t* buffer_sizes_[2]; /** Local buffers. */ @@ -246,6 +248,9 @@ class ArraySortedWriteState { /** Number of allocated buffers. */ int buffer_num_; + /** The user buffer offsets. */ + size_t* buffer_offsets_; + /** The user buffer sizes. */ const size_t* buffer_sizes_; @@ -610,6 +615,63 @@ class ArraySortedWriteState { */ int create_copy_state_buffers(); + /** + * Creates the user buffers. + * + * @param buffers The user buffers that hold the input cells to be written. + * @param buffer_sizes The corresponding buffer sizes. + * @return void + */ + void create_user_buffers(const void** buffers, const size_t* buffer_sizes); + + /** + * Fills the buffer of a fixed-sized attribute with special empty values, + * in a given byte range [offset_start, offset_end). The buffer to be + * filled is essentially copy_state_.buffers_[copy_id_][bid]. + * Note that, after the invocation of the function, offset_start will + * be set to offset_end (it is passed by reference). + * + * @param aid The attribute id. + * @param bid The buffer id corresponding to the attribute id. + * @param offset_start The start of the byte range to be filled. + * @param offset_end The end of the byte range to be filled. + * @return void + */ + void fill_with_empty( + int aid, + int bid, + size_t& offset_start, + size_t offset_end); + + /** + * Fills the buffer of a variable-sized attribute with special empty values, + * in a given byte range [offset_start, offset_end) for the offsets buffer, + * and [offset_var_start, offset_var_start+empty_var_size) for the variable + * values buffer. The buffers to be filled are essentially + * copy_state_.buffers_[copy_id_][bid] (offsets) and + * copy_state_.buffers_[copy_id_][bid+1] (values). + * Note that, after the invocation of the function, offset_start will + * be set to offset_end, and offset_var_start to + * offset_var_start+empty_var_size (they are passed by reference), where + * empty_var_size is the size in bytes of the empty values written in the + * variable-sized buffer. + * + * @param aid The attribute id. + * @param bid The buffer id corresponding to the attribute id. + * @param offset_start The start of the byte range to be filled for the + * offset buffer. + * @param offset_end The end of the byte range to be filled. + * @param offset_var_start The start of the byte range to be filled for the + * values buffer. + * @return void + */ + void fill_with_empty( + int aid, + int bid, + size_t& offset_start, + size_t offset_end, + size_t& offset_var_start); + /** Frees the copy state. */ void free_copy_state(); @@ -753,8 +815,8 @@ class ArraySortedWriteState { */ int release_copy(int id); - /** Resets the temporary buffer sizes for the input tile slab id. */ -// void reset_buffer_sizes_tmp(int id); + /** Resets the copy state for the current copy id. */ + void reset_copy_state(); /** * Resets the tile_coords_ auxiliary variable. diff --git a/core/src/array/array_schema.cc b/core/src/array/array_schema.cc index 5b2805b0..3de8ed09 100644 --- a/core/src/array/array_schema.cc +++ b/core/src/array/array_schema.cc @@ -273,6 +273,10 @@ size_t ArraySchema::cell_size(int attribute_id) const { return cell_sizes_[attribute_id]; } +int ArraySchema::cell_val_num(int attribute_id) const { + return cell_val_num_[attribute_id]; +} + int ArraySchema::compression(int attribute_id) const { assert(attribute_id >= 0 && attribute_id <= attribute_num_+1); diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 3f5e5c7e..96e0041d 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -1150,6 +1150,7 @@ void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { size_t buffer_size = copy_state_.buffer_sizes_[bid]; char* buffer = (char*) copy_state_.buffers_[bid]; char* local_buffer = (char*) buffers_[copy_id_][bid]; + ASRS_Data asrs_data = { aid, 0, this }; // Iterate over the tile slab cells for(;;) { @@ -1172,8 +1173,7 @@ void ArraySortedReadState::copy_tile_slab_dense(int aid, int bid) { // Update buffer offset buffer_offset += cell_slab_size; - // Prepare for new slab - ASRS_Data asrs_data = { aid, 0, this }; + // Prepare for new cell slab (*advance_cell_slab_)(&asrs_data); // Terminating condition @@ -1208,6 +1208,7 @@ void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; int64_t cell_num_in_buffer = local_buffer_size / sizeof(size_t); size_t var_offset = buffer_offset_var; + ASRS_Data asrs_data = { aid, 0, this }; // For all overlapping tiles, in a round-robin fashion for(;;) { @@ -1256,8 +1257,7 @@ void ArraySortedReadState::copy_tile_slab_dense_var(int aid, int bid) { cell_slab_size_var); buffer_offset_var += cell_slab_size_var; - // Prepare for new slab - ASRS_Data asrs_data = { aid, 0, this }; + // Prepare for new cell slab (*advance_cell_slab_)(&asrs_data); // Terminating condition diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index a2e23707..586e0f7b 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -280,9 +280,8 @@ int ArraySortedWriteState::init() { int ArraySortedWriteState::write( const void** buffers, const size_t* buffer_sizes) { - // Locally store the buffers and sizes - buffers_ = buffers; - buffer_sizes_ = buffer_sizes_; + // Locally store user buffer information + create_user_buffers(buffers, buffer_sizes); // Create buffers if(create_copy_state_buffers() != TILEDB_ASWS_OK) @@ -459,13 +458,11 @@ template void ArraySortedWriteState::calculate_cell_slab_info_col_col( int id, int64_t tid) { -// TODO - -/* // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; const T* tile_domain = (const T*) tile_domain_; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); int64_t tile_num, cell_num; // Calculate number of cells in cell slab @@ -488,26 +485,20 @@ void ArraySortedWriteState::calculate_cell_slab_info_col_col( int64_t cell_offset = 1; tile_slab_info_[id].cell_offset_per_dim_[tid][0] = cell_offset; for(int i=1; i void ArraySortedWriteState::calculate_cell_slab_info_row_row( int id, int64_t tid) { - -// TODO - -/* - // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; const T* tile_domain = (const T*) tile_domain_; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); int64_t tile_num, cell_num; // Calculate number of cells in cell slab @@ -530,24 +521,18 @@ void ArraySortedWriteState::calculate_cell_slab_info_row_row( int64_t cell_offset = 1; tile_slab_info_[id].cell_offset_per_dim_[tid][dim_num_-1] = cell_offset; for(int i=dim_num_-2; i>=0; --i) { - cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); + cell_offset *= tile_extents[i+1]; tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; } -*/ } template void ArraySortedWriteState::calculate_cell_slab_info_col_row( int id, int64_t tid) { - -// TODO - -/* - // For easy reference int anum = (int) attribute_ids_.size(); - const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); // Calculate number of cells in cell slab tile_slab_info_[id].cell_slab_num_[tid] = 1; @@ -561,24 +546,18 @@ void ArraySortedWriteState::calculate_cell_slab_info_col_row( int64_t cell_offset = 1; tile_slab_info_[id].cell_offset_per_dim_[tid][dim_num_-1] = cell_offset; for(int i=dim_num_-2; i>=0; --i) { - cell_offset *= (range_overlap[2*(i+1)+1] - range_overlap[2*(i+1)] + 1); + cell_offset *= tile_extents[i+1]; tile_slab_info_[id].cell_offset_per_dim_[tid][i] = cell_offset; } -*/ } template void ArraySortedWriteState::calculate_cell_slab_info_row_col( int id, int64_t tid) { - -// TODO - -/* - // For easy reference int anum = (int) attribute_ids_.size(); - const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); // Calculate number of cells in cell slab tile_slab_info_[id].cell_slab_num_[tid] = 1; @@ -592,10 +571,9 @@ void ArraySortedWriteState::calculate_cell_slab_info_row_col( int64_t cell_offset = 1; tile_slab_info_[id].cell_offset_per_dim_[tid][0] = cell_offset; for(int i=1; i @@ -669,7 +647,7 @@ void ArraySortedWriteState::calculate_tile_slab_info_col(int id) { std::min((tile_coords[i]+1) * tile_extents[i] - 1, tile_slab[2*i+1]); // Number of cells in this tile - tile_cell_num *= range_overlap[tid][2*i+1] - range_overlap[tid][2*i] + 1; + tile_cell_num *= tile_extents[i]; } // Calculate tile offsets per dimension @@ -737,7 +715,7 @@ void ArraySortedWriteState::calculate_tile_slab_info_row(int id) { std::min((tile_coords[i]+1) * tile_extents[i] - 1, tile_slab[2*i+1]); // Number of cells in this tile - tile_cell_num *= range_overlap[tid][2*i+1] - range_overlap[tid][2*i] + 1; + tile_cell_num *= tile_extents[i]; } // Calculate tile offsets per dimension @@ -807,44 +785,35 @@ void ArraySortedWriteState::copy_tile_slab() { } void ArraySortedWriteState::copy_tile_slab(int aid, int bid) { -// TODO -/* - // Exit if copy is done for this attribute - if(tile_slab_state_.copy_tile_slab_done_[aid]) { - copy_state_.buffer_sizes_[bid] = 0; // Nothing written - return; - } - // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; - size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; - size_t buffer_size = copy_state_.buffer_sizes_[bid]; - char* buffer = (char*) copy_state_.buffers_[bid]; - char* local_buffer = (char*) buffers_[copy_id_][bid]; + size_t& buffer_offset = buffer_offsets_[bid]; + size_t buffer_size = buffer_sizes_[bid]; + char* buffer = (char*) buffers_[bid]; + char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + size_t& local_buffer_offset = copy_state_.buffer_offsets_[copy_id_][bid]; + ASWS_Data asws_data = { aid, 0, this }; // Iterate over the tile slab cells for(;;) { // For easy reference size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; - size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; + size_t& local_buffer_offset_cur = tile_slab_state_.current_offsets_[aid]; - // Handle overflow - if(buffer_offset + cell_slab_size > buffer_size) { - overflow_[aid] = true; - break; - } - - // Copy cell slab + // Fill with empty values + fill_with_empty(aid, bid, local_buffer_offset, local_buffer_offset_cur); + + // Copy cell slab from user to local buffer memcpy( + local_buffer + local_buffer_offset_cur, buffer + buffer_offset, - local_buffer + local_buffer_offset, cell_slab_size); - // Update buffer offset + // Update buffer offsets buffer_offset += cell_slab_size; + local_buffer_offset += cell_slab_size; // Prepare for new slab - ASWS_Data asws_data = { aid, 0, this }; (*advance_cell_slab_)(&asws_data); // Terminating condition @@ -852,36 +821,28 @@ void ArraySortedWriteState::copy_tile_slab(int aid, int bid) { break; } - // Set user buffer size - buffer_size = buffer_offset; -*/ + // Fill with empty values + fill_with_empty(aid, bid, local_buffer_offset, buffer_size); } void ArraySortedWriteState::copy_tile_slab_var(int aid, int bid) { -// TODO -/* - // Exit if copy is done for this attribute - if(tile_slab_state_.copy_tile_slab_done_[aid]) { - copy_state_.buffer_sizes_[bid] = 0; // Nothing written - copy_state_.buffer_sizes_[bid+1] = 0; // Nothing written - return; - } - // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; size_t cell_slab_size_var; - size_t& buffer_offset = copy_state_.buffer_offsets_[bid]; - size_t& buffer_offset_var = copy_state_.buffer_offsets_[bid+1]; - size_t buffer_size = copy_state_.buffer_sizes_[bid]; - size_t buffer_size_var = copy_state_.buffer_sizes_[bid+1]; - char* buffer = (char*) copy_state_.buffers_[bid]; - char* buffer_var = (char*) copy_state_.buffers_[bid+1]; - char* local_buffer_var = (char*) buffers_[copy_id_][bid+1]; - size_t local_buffer_size = buffer_sizes_tmp_[copy_id_][bid]; - size_t local_buffer_var_size = buffer_sizes_tmp_[copy_id_][bid+1]; - size_t* local_buffer_s = (size_t*) buffers_[copy_id_][bid]; - int64_t cell_num_in_buffer = local_buffer_size / sizeof(size_t); - size_t var_offset = buffer_offset_var; + size_t& buffer_offset = buffer_offsets_[bid]; + size_t& buffer_offset_var = buffer_offsets_[bid+1]; + size_t buffer_size = buffer_sizes_[bid]; + size_t buffer_var_size = buffer_sizes_[bid+1]; + char* buffer_var = (char*) buffers_[bid+1]; + size_t* buffer_s = (size_t*) buffers_[bid]; + char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + size_t local_buffer_offset = copy_state_.buffer_offsets_[copy_id_][bid]; + size_t local_buffer_offset_var = copy_state_.buffer_offsets_[copy_id_][bid+1]; + size_t& local_buffer_var_size = copy_state_.buffer_sizes_[copy_id_][bid+1]; + int64_t cell_num_in_buffer = buffer_size / sizeof(size_t); + size_t var_offset; + ASWS_Data asws_data = { aid, 0, this }; // For all overlapping tiles, in a round-robin fashion for(;;) { @@ -889,49 +850,53 @@ void ArraySortedWriteState::copy_tile_slab_var(int aid, int bid) { size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; int64_t cell_num_in_slab = cell_slab_size / sizeof(size_t); - size_t& local_buffer_offset = tile_slab_state_.current_offsets_[aid]; - - // Handle overflow - if(buffer_offset + cell_slab_size > buffer_size) { - overflow_[aid] = true; - break; - } + size_t& local_buffer_offset_cur = tile_slab_state_.current_offsets_[aid]; // Calculate variable cell slab size - int64_t cell_start = local_buffer_offset / sizeof(size_t); + int64_t cell_start = buffer_offset / sizeof(size_t); int64_t cell_end = cell_start + cell_num_in_slab; cell_slab_size_var = (cell_end == cell_num_in_buffer) ? - local_buffer_var_size - local_buffer_s[cell_start] : - local_buffer_s[cell_end] - local_buffer_s[cell_start]; + buffer_var_size - buffer_s[cell_start] : + buffer_s[cell_end] - buffer_s[cell_start]; + + // Fill with empty values + fill_with_empty( + aid, + bid, + local_buffer_offset, + local_buffer_offset_cur, + local_buffer_offset_var); - // Handle overflow for the the variable-length buffer - if(buffer_offset_var + cell_slab_size_var > buffer_size_var) { - overflow_[aid] = true; - break; - } - // Copy fixed-sized offsets + var_offset = local_buffer_offset_var; for(int64_t i=cell_start; i local_buffer_var_size) + expand_buffer( + copy_state_.buffers_[copy_id_][bid], + copy_state_.buffer_sizes_[copy_id_][bid+1]); + // Copy variable-sized values memcpy( - buffer_var + buffer_offset_var, - local_buffer_var + local_buffer_s[cell_start], + local_buffer_var + local_buffer_offset_var, + buffer_var + buffer_s[cell_start], cell_slab_size_var); buffer_offset_var += cell_slab_size_var; + local_buffer_offset_var += cell_slab_size_var; // Prepare for new slab - ASWS_Data asws_data = { aid, 0, this }; (*advance_cell_slab_)(&asws_data); // Terminating condition @@ -939,10 +904,13 @@ void ArraySortedWriteState::copy_tile_slab_var(int aid, int bid) { break; } - // Set user buffer sizes - buffer_size = buffer_offset; - buffer_size_var = buffer_offset_var; -*/ + // Fill with empty values + fill_with_empty( + aid, + bid, + local_buffer_offset, + buffer_size, + local_buffer_offset_var); } int ArraySortedWriteState::create_copy_state_buffers() { @@ -965,9 +933,8 @@ int ArraySortedWriteState::create_copy_state_buffers() { for(int i=0, b=0; ivar_size(attribute_ids_[i])) { - copy_state_.buffer_sizes_[j][b] = + copy_state_.buffer_sizes_[j][b++] = tile_slab_cell_num * array_schema->cell_size(attribute_ids_[i]); - ++b; } else { // Variable-sized attribute copy_state_.buffer_sizes_[j][b++] = tile_slab_cell_num * sizeof(size_t); copy_state_.buffer_sizes_[j][b++] = 2*tile_slab_cell_num*sizeof(size_t); @@ -1000,6 +967,87 @@ int ArraySortedWriteState::create_copy_state_buffers() { return TILEDB_ASWS_OK; } +void ArraySortedWriteState::create_user_buffers( + const void** buffers, + const size_t* buffer_sizes) { + buffers_ = buffers; + buffer_sizes_ = buffer_sizes_; + buffer_offsets_ = new size_t[buffer_num_]; + for(int i=0; iarray_schema(); + int attribute_id = attribute_ids_[aid]; + int type = array_schema->type(attribute_id); + int cell_val_num = array_schema->cell_val_num(attribute_id); + char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + + // Fill with empty values + if(type == TILEDB_INT32) { + int empty = TILEDB_EMPTY_INT32; + for(; offset_start < offset_end; ) + for(int i=0; iarray_schema(); + int attribute_id = attribute_ids_[aid]; + int type = array_schema->type(attribute_id); + size_t cell_var_size = + (type == TILEDB_EMPTY_INT32) ? sizeof(int) : sizeof(int64_t); + char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + int64_t cell_num = (offset_end - offset_start) / sizeof(size_t); + + // Fill buffers with empty values + if(type == TILEDB_INT32) { + int empty = TILEDB_EMPTY_INT32; + for(int64_t i=0; i(); + reset_copy_state(); // Copy tile slab copy_tile_slab(); @@ -1471,6 +1520,7 @@ int ArraySortedWriteState::write_sorted_row() { // Reset the tile slab state reset_tile_slab_state(); + reset_copy_state(); // Copy tile slab copy_tile_slab(); @@ -1541,13 +1591,10 @@ int ArraySortedWriteState::release_copy(int id) { return TILEDB_ASWS_OK; } -/* - -void ArraySortedWriteState::reset_buffer_sizes_tmp(int id) { +void ArraySortedWriteState::reset_copy_state() { for(int i=0; i void ArraySortedWriteState::reset_tile_coords() { From 497c824b8927e76e8aa0ddebe0221dbd796483e3 Mon Sep 17 00:00:00 2001 From: spapadop Date: Sun, 23 Oct 2016 21:01:26 -0400 Subject: [PATCH 19/57] Tested and debugged dense sorted writes --- core/include/array/array_sorted_write_state.h | 73 ++- core/src/array/array.cc | 49 +- core/src/array/array_sorted_write_state.cc | 445 +++++++++++------- core/src/fragment/write_state.cc | 4 +- examples/src/tiledb_array_read_dense_1.cc | 14 +- .../src/tiledb_array_write_sorted_dense.cc | 21 +- 6 files changed, 361 insertions(+), 245 deletions(-) diff --git a/core/include/array/array_sorted_write_state.h b/core/include/array/array_sorted_write_state.h index b855250c..f8fd78d7 100644 --- a/core/include/array/array_sorted_write_state.h +++ b/core/include/array/array_sorted_write_state.h @@ -203,8 +203,8 @@ class ArraySortedWriteState { /** Function for advancing a cell slab during a copy operation. */ void *(*advance_cell_slab_) (void*); - /** AIO counter. */ - int aio_cnt_; + /** Counter for the AIO requests. */ + size_t aio_cnt_; /** The AIO mutex conditions (one for each buffer). */ pthread_cond_t aio_cond_[2]; @@ -591,10 +591,12 @@ class ArraySortedWriteState { * properly re-organizing the cell order to fit the targeted order, * focusing on a particular fixed-length attribute. * + * @template T The attribute type. * @param aid The index on attribute_ids_ to focus on. * @param bid The index on the copy state buffers to focus on. * @return void. */ + template void copy_tile_slab(int aid, int bid); /** @@ -602,10 +604,12 @@ class ArraySortedWriteState { * properly re-organizing the cell order to fit the targeted order, * focusing on a particular variable-length attribute. * + * @template T The attribute type. * @param aid The index on attribute_ids_ to focus on. * @param bid The index on the copy state buffers to focus on. * @return void. */ + template void copy_tile_slab_var(int aid, int bid); /** @@ -625,52 +629,28 @@ class ArraySortedWriteState { void create_user_buffers(const void** buffers, const size_t* buffer_sizes); /** - * Fills the buffer of a fixed-sized attribute with special empty values, - * in a given byte range [offset_start, offset_end). The buffer to be - * filled is essentially copy_state_.buffers_[copy_id_][bid]. - * Note that, after the invocation of the function, offset_start will - * be set to offset_end (it is passed by reference). - * - * @param aid The attribute id. - * @param bid The buffer id corresponding to the attribute id. - * @param offset_start The start of the byte range to be filled. - * @param offset_end The end of the byte range to be filled. + * Fills the **entire** buffer of the current copy tile slab with the input id + * with empty values, based on the template type. Applicable only to + * fixed-sized attributes. + * + * @template T The attribute type. + * @param bid The buffer id corresponding to the targeted attribute. * @return void */ - void fill_with_empty( - int aid, - int bid, - size_t& offset_start, - size_t offset_end); + template + void fill_with_empty(int bid); /** - * Fills the buffer of a variable-sized attribute with special empty values, - * in a given byte range [offset_start, offset_end) for the offsets buffer, - * and [offset_var_start, offset_var_start+empty_var_size) for the variable - * values buffer. The buffers to be filled are essentially - * copy_state_.buffers_[copy_id_][bid] (offsets) and - * copy_state_.buffers_[copy_id_][bid+1] (values). - * Note that, after the invocation of the function, offset_start will - * be set to offset_end, and offset_var_start to - * offset_var_start+empty_var_size (they are passed by reference), where - * empty_var_size is the size in bytes of the empty values written in the - * variable-sized buffer. - * - * @param aid The attribute id. - * @param bid The buffer id corresponding to the attribute id. - * @param offset_start The start of the byte range to be filled for the - * offset buffer. - * @param offset_end The end of the byte range to be filled. - * @param offset_var_start The start of the byte range to be filled for the - * values buffer. + * Fills the **a single** cell in a variable-sized buffer of the current copy + * tile slab with the input id with an empty value, based on the template t + * ype. Applicable only to variable-sized attributes. + * + * @template T The attribute type. + * @param bid The buffer id corresponding to the targeted attribute. * @return void */ - void fill_with_empty( - int aid, - int bid, - size_t& offset_start, - size_t offset_end, - size_t& offset_var_start); + template + void fill_with_empty_var(int bid); /** Frees the copy state. */ void free_copy_state(); @@ -858,6 +838,15 @@ class ArraySortedWriteState { */ int unlock_copy_mtx(); + /** + * Calculates the new tile and local buffer offset for the new (already + * computed) current cell coordinates in the tile slab. + * + * @param aid The attribute id to focus on. + * @return void. + */ + void update_current_tile_and_offset(int aid); + /** * Calculates the new tile and local buffer offset for the new (already * computed) current cell coordinates in the tile slab. diff --git a/core/src/array/array.cc b/core/src/array/array.cc index d80eb146..695fdc2f 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -900,19 +900,36 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { return TILEDB_AR_ERR; } - // Handle sorted modes + // Write based on mode + int rc; if(mode_ == TILEDB_ARRAY_WRITE_SORTED_COL || mode_ == TILEDB_ARRAY_WRITE_SORTED_ROW) { - int rc = array_sorted_write_state_->write(buffers, buffer_sizes); - if(rc == TILEDB_ASWS_OK) { - return TILEDB_AR_OK; - } else { - tiledb_ar_errmsg = tiledb_asws_errmsg; - return TILEDB_AR_ERR; - } - } else { // mode_ == TILDB_ARRAY_WRITE or TILEDB_ARRAY_WRITE_UNSORTED - return write_default(buffers, buffer_sizes); + rc = array_sorted_write_state_->write(buffers, buffer_sizes); + } else if(mode_ == TILEDB_ARRAY_WRITE || + mode_ == TILEDB_ARRAY_WRITE_UNSORTED) { + rc = write_default(buffers, buffer_sizes); + } else { + assert(0); + } + + // Handle error + if(rc != TILEDB_ASWS_OK) { + tiledb_ar_errmsg = tiledb_asws_errmsg; + return TILEDB_AR_ERR; + } + + // In all modes except TILEDB_ARRAY_WRITE, the fragment must be finalized + if(mode_ != TILEDB_ARRAY_WRITE) { + if(fragments_[0]->finalize() != TILEDB_FG_OK) { + tiledb_ar_errmsg = tiledb_fg_errmsg; + return TILEDB_AR_ERR; + } + delete fragments_[0]; + fragments_.clear(); } + + // Success + return TILEDB_AR_OK; } int Array::write_default(const void** buffers, const size_t* buffer_sizes) { @@ -947,17 +964,7 @@ int Array::write_default(const void** buffers, const size_t* buffer_sizes) { // Dispatch the write command to the new fragment if(fragments_[0]->write(buffers, buffer_sizes) != TILEDB_FG_OK) { tiledb_ar_errmsg = tiledb_fg_errmsg; - return TILEDB_AR_ERR; - } - - // In all modes except TILEDB_ARRAY_WRITE, the fragment must be finalized - if(mode_ != TILEDB_ARRAY_WRITE) { - if(fragments_[0]->finalize() != TILEDB_FG_OK) { - tiledb_ar_errmsg = tiledb_fg_errmsg; - return TILEDB_AR_ERR; - } - delete fragments_[0]; - fragments_.clear(); + return TILEDB_AR_ERR; } // Success diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 586e0f7b..57d1be2d 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -73,8 +73,8 @@ ArraySortedWriteState::ArraySortedWriteState( int anum = (int) attribute_ids_.size(); // Initializations - aio_id_ = 0; aio_cnt_ = 0; + aio_id_ = 0; aio_thread_running_ = false; aio_thread_canceled_ = false; coords_size_ = array_schema->coords_size(); @@ -172,9 +172,6 @@ ArraySortedWriteState::~ArraySortedWriteState() { /* ****************************** */ int ArraySortedWriteState::init() { - // Create AIO requests - init_aio_requests(); - // Create the thread that will be handling all the copying if(pthread_create( &aio_thread_, @@ -287,6 +284,9 @@ int ArraySortedWriteState::write( if(create_copy_state_buffers() != TILEDB_ASWS_OK) return TILEDB_ASWS_ERR; + // Create AIO requests + init_aio_requests(); + // Call the appropriate templated read int type = array_->array_schema()->coords_type(); if(type == TILEDB_INT32) @@ -630,7 +630,8 @@ void ArraySortedWriteState::calculate_tile_slab_info_col(int id) { const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); T** range_overlap = (T**) tile_slab_info_[id].range_overlap_; const T* tile_slab = (const T*) tile_slab_norm_[id]; - int64_t tile_offset, tile_cell_num, total_cell_num = 0; + int64_t tile_offset, tile_cell_num; + int64_t total_cell_num = 0; int anum = (int) attribute_ids_.size(); int d; @@ -698,7 +699,8 @@ void ArraySortedWriteState::calculate_tile_slab_info_row(int id) { const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); T** range_overlap = (T**) tile_slab_info_[id].range_overlap_; const T* tile_slab = (const T*) tile_slab_norm_[id]; - int64_t tile_offset, tile_cell_num, total_cell_num = 0; + int64_t tile_offset, tile_cell_num; + int64_t total_cell_num = 0; int anum = (int) attribute_ids_.size(); int d; @@ -774,25 +776,51 @@ void ArraySortedWriteState::copy_tile_slab() { // Copy tile slab for each attribute separately for(int i=0, b=0; i<(int)attribute_ids_.size(); ++i) { + int type = array_schema->type(attribute_ids_[i]); if(!array_schema->var_size(attribute_ids_[i])) { - copy_tile_slab(i, b); + if(type == TILEDB_INT32) + copy_tile_slab(i, b); + else if(type == TILEDB_INT64) + copy_tile_slab(i, b); + else if(type == TILEDB_FLOAT32) + copy_tile_slab(i, b); + else if(type == TILEDB_FLOAT64) + copy_tile_slab(i, b); + else if(type == TILEDB_CHAR) + copy_tile_slab(i, b); ++b; } else { - copy_tile_slab_var(i, b); + if(type == TILEDB_INT32) + copy_tile_slab_var(i, b); + else if(type == TILEDB_INT64) + copy_tile_slab_var(i, b); + else if(type == TILEDB_FLOAT32) + copy_tile_slab_var(i, b); + else if(type == TILEDB_FLOAT64) + copy_tile_slab_var(i, b); + else if(type == TILEDB_CHAR) + copy_tile_slab_var(i, b); b += 2; } } } +template void ArraySortedWriteState::copy_tile_slab(int aid, int bid) { // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; size_t& buffer_offset = buffer_offsets_[bid]; - size_t buffer_size = buffer_sizes_[bid]; char* buffer = (char*) buffers_[bid]; char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; - size_t& local_buffer_offset = copy_state_.buffer_offsets_[copy_id_][bid]; - ASWS_Data asws_data = { aid, 0, this }; + size_t& local_buffer_offset = copy_state_.buffer_offsets_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + ASWS_Data asws_data = { aid, bid, this }; + + // Fill with empty + fill_with_empty(bid); + + // Important for initializing the current tile and offsets! + update_current_tile_and_offset(aid); // Iterate over the tile slab cells for(;;) { @@ -800,18 +828,14 @@ void ArraySortedWriteState::copy_tile_slab(int aid, int bid) { size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; size_t& local_buffer_offset_cur = tile_slab_state_.current_offsets_[aid]; - // Fill with empty values - fill_with_empty(aid, bid, local_buffer_offset, local_buffer_offset_cur); - // Copy cell slab from user to local buffer memcpy( local_buffer + local_buffer_offset_cur, buffer + buffer_offset, cell_slab_size); - // Update buffer offsets + // Update user buffer offset buffer_offset += cell_slab_size; - local_buffer_offset += cell_slab_size; // Prepare for new slab (*advance_cell_slab_)(&asws_data); @@ -821,81 +845,60 @@ void ArraySortedWriteState::copy_tile_slab(int aid, int bid) { break; } - // Fill with empty values - fill_with_empty(aid, bid, local_buffer_offset, buffer_size); + // Set local buffer offset + local_buffer_offset = local_buffer_size; } +template void ArraySortedWriteState::copy_tile_slab_var(int aid, int bid) { // For easy reference int64_t& tid = tile_slab_state_.current_tile_[aid]; - size_t cell_slab_size_var; size_t& buffer_offset = buffer_offsets_[bid]; - size_t& buffer_offset_var = buffer_offsets_[bid+1]; size_t buffer_size = buffer_sizes_[bid]; size_t buffer_var_size = buffer_sizes_[bid+1]; char* buffer_var = (char*) buffers_[bid+1]; size_t* buffer_s = (size_t*) buffers_[bid]; char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + size_t* local_buffer_s = (size_t*) copy_state_.buffers_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + size_t& local_buffer_offset = copy_state_.buffer_offsets_[copy_id_][bid]; char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; - size_t local_buffer_offset = copy_state_.buffer_offsets_[copy_id_][bid]; - size_t local_buffer_offset_var = copy_state_.buffer_offsets_[copy_id_][bid+1]; + size_t& local_buffer_offset_var = + copy_state_.buffer_offsets_[copy_id_][bid+1]; size_t& local_buffer_var_size = copy_state_.buffer_sizes_[copy_id_][bid+1]; int64_t cell_num_in_buffer = buffer_size / sizeof(size_t); - size_t var_offset; + int64_t cell_num_in_tile_slab = local_buffer_size / sizeof(size_t); ASWS_Data asws_data = { aid, 0, this }; - // For all overlapping tiles, in a round-robin fashion + // Important for initializing the current tile and offsets! + update_current_tile_and_offset(aid); + + // Fill the local buffer offsets with zeros + bzero(local_buffer, local_buffer_size); + + // Handle offsets first for(;;) { // For easy reference size_t cell_slab_size = tile_slab_info_[copy_id_].cell_slab_size_[aid][tid]; int64_t cell_num_in_slab = cell_slab_size / sizeof(size_t); - size_t& local_buffer_offset_cur = tile_slab_state_.current_offsets_[aid]; + size_t local_buffer_offset_cur = tile_slab_state_.current_offsets_[aid]; // Calculate variable cell slab size int64_t cell_start = buffer_offset / sizeof(size_t); int64_t cell_end = cell_start + cell_num_in_slab; - cell_slab_size_var = - (cell_end == cell_num_in_buffer) ? - buffer_var_size - buffer_s[cell_start] : - buffer_s[cell_end] - buffer_s[cell_start]; - - // Fill with empty values - fill_with_empty( - aid, - bid, - local_buffer_offset, - local_buffer_offset_cur, - local_buffer_offset_var); - - // Copy fixed-sized offsets - var_offset = local_buffer_offset_var; - for(int64_t i=cell_start; i local_buffer_var_size) - expand_buffer( - copy_state_.buffers_[copy_id_][bid], - copy_state_.buffer_sizes_[copy_id_][bid+1]); - - // Copy variable-sized values - memcpy( - local_buffer_var + local_buffer_offset_var, - buffer_var + buffer_s[cell_start], - cell_slab_size_var); - buffer_offset_var += cell_slab_size_var; - local_buffer_offset_var += cell_slab_size_var; - // Prepare for new slab (*advance_cell_slab_)(&asws_data); @@ -904,13 +907,46 @@ void ArraySortedWriteState::copy_tile_slab_var(int aid, int bid) { break; } - // Fill with empty values - fill_with_empty( - aid, - bid, - local_buffer_offset, - buffer_size, - local_buffer_offset_var); + // Rectify offsets and copy variable-sized cells + int64_t cell; + size_t cell_size_var; + for(int i=0; i(bid); + local_buffer_offset_var += sizeof(T); + continue; + } + + // Find size of variable-sized cell + cell = local_buffer_s[i]-1; // So that cell ids start from 0 + cell_size_var = + (cell == cell_num_in_buffer-1) ? + buffer_var_size - buffer_s[cell] : + buffer_s[cell+1] - buffer_s[cell]; + + // Rectify offset + local_buffer_s[i] = local_buffer_offset_var; + + // Expand the variable-sized buffer if necessary + while(local_buffer_offset_var + cell_size_var > local_buffer_var_size) { + expand_buffer( + copy_state_.buffers_[copy_id_][bid+1], + copy_state_.buffer_sizes_[copy_id_][bid+1]); + local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + } + + // Copy variable-sized cell + memcpy( + local_buffer_var + local_buffer_offset_var, + buffer_var + buffer_s[cell], + cell_size_var); + local_buffer_offset_var += cell_size_var; + } + + // Set local buffer offset + local_buffer_offset = local_buffer_size; } int ArraySortedWriteState::create_copy_state_buffers() { @@ -971,82 +1007,130 @@ void ArraySortedWriteState::create_user_buffers( const void** buffers, const size_t* buffer_sizes) { buffers_ = buffers; - buffer_sizes_ = buffer_sizes_; + buffer_sizes_ = buffer_sizes; buffer_offsets_ = new size_t[buffer_num_]; for(int i=0; i +void ArraySortedWriteState::fill_with_empty(int bid) { // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - int attribute_id = attribute_ids_[aid]; - int type = array_schema->type(attribute_id); - int cell_val_num = array_schema->cell_val_num(attribute_id); - char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + int* local_buffer = (int*) copy_state_.buffers_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + int empty = TILEDB_EMPTY_INT32; // Fill with empty values - if(type == TILEDB_INT32) { - int empty = TILEDB_EMPTY_INT32; - for(; offset_start < offset_end; ) - for(int i=0; i +void ArraySortedWriteState::fill_with_empty(int bid) { + // For easy reference + int64_t* local_buffer = (int64_t*) copy_state_.buffers_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + int64_t empty = TILEDB_EMPTY_INT64; + + // Fill with empty values + size_t offset = 0; + for(int64_t i=0; offset < local_buffer_size; offset += sizeof(int64_t), ++i) + local_buffer[i] = empty; } -void ArraySortedWriteState::fill_with_empty( - int aid, - int bid, - size_t& offset_start, - size_t offset_end, - size_t& offset_var_start) { +template<> +void ArraySortedWriteState::fill_with_empty(int bid) { + // For easy reference + float* local_buffer = (float*) copy_state_.buffers_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + float empty = TILEDB_EMPTY_FLOAT32; + + // Fill with empty values + size_t offset = 0; + for(int64_t i=0; offset < local_buffer_size; offset += sizeof(float), ++i) + local_buffer[i] = empty; +} + +template<> +void ArraySortedWriteState::fill_with_empty(int bid) { + // For easy reference + double* local_buffer = (double*) copy_state_.buffers_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + double empty = TILEDB_EMPTY_FLOAT64; + + // Fill with empty values + size_t offset = 0; + for(int64_t i=0; offset < local_buffer_size; offset += sizeof(double), ++i) + local_buffer[i] = empty; +} + +template<> +void ArraySortedWriteState::fill_with_empty(int bid) { // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - int attribute_id = attribute_ids_[aid]; - int type = array_schema->type(attribute_id); - size_t cell_var_size = - (type == TILEDB_EMPTY_INT32) ? sizeof(int) : sizeof(int64_t); char* local_buffer = (char*) copy_state_.buffers_[copy_id_][bid]; + size_t local_buffer_size = copy_state_.buffer_sizes_[copy_id_][bid]; + char empty = TILEDB_EMPTY_CHAR; + + // Fill with empty values + size_t offset = 0; + for(int64_t i=0; offset < local_buffer_size; offset += sizeof(char), ++i) + local_buffer[i] = empty; +} + +template<> +void ArraySortedWriteState::fill_with_empty_var(int bid) { + // For easy reference char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; - int64_t cell_num = (offset_end - offset_start) / sizeof(size_t); - - // Fill buffers with empty values - if(type == TILEDB_INT32) { - int empty = TILEDB_EMPTY_INT32; - for(int64_t i=0; i +void ArraySortedWriteState::fill_with_empty_var(int bid) { + // For easy reference + char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + size_t local_buffer_offset_var = copy_state_.buffer_offsets_[copy_id_][bid+1]; + int64_t empty = TILEDB_EMPTY_INT64; + + // Fill an empty value + memcpy(local_buffer_var + local_buffer_offset_var, &empty, sizeof(int64_t)); +} + +template<> +void ArraySortedWriteState::fill_with_empty_var(int bid) { + // For easy reference + char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + size_t local_buffer_offset_var = copy_state_.buffer_offsets_[copy_id_][bid+1]; + float empty = TILEDB_EMPTY_FLOAT32; + + // Fill an empty value + memcpy(local_buffer_var + local_buffer_offset_var, &empty, sizeof(float)); +} + +template<> +void ArraySortedWriteState::fill_with_empty_var(int bid) { + // For easy reference + char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + size_t local_buffer_offset_var = copy_state_.buffer_offsets_[copy_id_][bid+1]; + double empty = TILEDB_EMPTY_FLOAT64; + + // Fill an empty value + memcpy(local_buffer_var + local_buffer_offset_var, &empty, sizeof(double)); +} + +template<> +void ArraySortedWriteState::fill_with_empty_var(int bid) { + // For easy reference + char* local_buffer_var = (char*) copy_state_.buffers_[copy_id_][bid+1]; + size_t local_buffer_offset_var = copy_state_.buffer_offsets_[copy_id_][bid+1]; + char empty = TILEDB_EMPTY_CHAR; + + // Fill an empty value + memcpy(local_buffer_var + local_buffer_offset_var, &empty, sizeof(char)); } void ArraySortedWriteState::free_copy_state() { @@ -1125,6 +1209,7 @@ template int64_t ArraySortedWriteState::get_cell_id(int aid) { // For easy reference const T* current_coords = (const T*) tile_slab_state_.current_coords_[aid]; + const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); int64_t tid = tile_slab_state_.current_tile_[aid]; int64_t* cell_offset_per_dim = tile_slab_info_[copy_id_].cell_offset_per_dim_[tid]; @@ -1132,7 +1217,9 @@ int64_t ArraySortedWriteState::get_cell_id(int aid) { // Calculate cell id int64_t cid = 0; for(int i=0; imode(); + int tile_order = array_->array_schema()->tile_order(); + bool separate_fragments = + (mode == TILEDB_ARRAY_WRITE_SORTED_COL && tile_order == TILEDB_ROW_MAJOR) || + (mode == TILEDB_ARRAY_WRITE_SORTED_ROW && tile_order == TILEDB_COL_MAJOR); + + // Initialize AIO requests for(int i=0; i<2; ++i) { aio_data_[i] = { i, 0, this }; aio_request_[i] = {}; + aio_request_[i].id_ = (separate_fragments) ? aio_cnt_++ : 0; aio_request_[i].buffer_sizes_ = copy_state_.buffer_offsets_[i]; aio_request_[i].buffers_ = copy_state_.buffers_[i]; aio_request_[i].mode_ = TILEDB_ARRAY_WRITE; - aio_request_[i].subarray_ = NULL; + aio_request_[i].subarray_ = (separate_fragments) ? tile_slab_[i] : NULL; aio_request_[i].completion_handle_ = aio_done; aio_request_[i].completion_data_ = &(aio_data_[i]); aio_request_[i].overflow_ = NULL; @@ -1252,6 +1348,8 @@ void ArraySortedWriteState::init_tile_slab_info(int id) { for(int i=0; i(array_schema->domain()); const T* tile_extents = static_cast(array_schema->tile_extents()); T* tile_slab[2]; - T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); + T* tile_slab_norm = static_cast(tile_slab_norm_[copy_id_]); for(int i=0; i<2; ++i) tile_slab[i] = static_cast(tile_slab_[i]); - int prev_id = (aio_id_+1)%2; + int prev_id = (copy_id_+1)%2; T tile_start; // Check again if done, this time based on the tile slab and subarray @@ -1325,49 +1423,49 @@ bool ArraySortedWriteState::next_tile_slab_col() { // If this is the first time this function is called, initialize if(!tile_slab_init_[prev_id]) { // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; + tile_slab[copy_id_][2*(dim_num_-1)] = subarray[2*(dim_num_-1)]; T upper = subarray[2*(dim_num_-1)] + tile_extents[dim_num_-1]; T cropped_upper = (upper - domain[2*(dim_num_-1)]) / tile_extents[dim_num_-1] * tile_extents[dim_num_-1] + domain[2*(dim_num_-1)]; - tile_slab[aio_id_][2*(dim_num_-1)+1] = + tile_slab[copy_id_][2*(dim_num_-1)+1] = std::min(cropped_upper - 1, subarray[2*(dim_num_-1)+1]); // Leave the rest of the subarray extents intact for(int i=0; i(aio_id_); + calculate_tile_slab_info(copy_id_); // Mark this tile slab as initialized - tile_slab_init_[aio_id_] = true; + tile_slab_init_[copy_id_] = true; // Success return true; @@ -1381,10 +1479,10 @@ bool ArraySortedWriteState::next_tile_slab_row() { const T* domain = static_cast(array_schema->domain()); const T* tile_extents = static_cast(array_schema->tile_extents()); T* tile_slab[2]; - T* tile_slab_norm = static_cast(tile_slab_norm_[aio_id_]); + T* tile_slab_norm = static_cast(tile_slab_norm_[copy_id_]); for(int i=0; i<2; ++i) tile_slab[i] = static_cast(tile_slab_[i]); - int prev_id = (aio_id_+1)%2; + int prev_id = (copy_id_+1)%2; T tile_start; // Check again if done, this time based on the tile slab and subarray @@ -1396,45 +1494,45 @@ bool ArraySortedWriteState::next_tile_slab_row() { // If this is the first time this function is called, initialize if(!tile_slab_init_[prev_id]) { // Crop the subarray extent along the first axis to fit in the first tile - tile_slab[aio_id_][0] = subarray[0]; + tile_slab[copy_id_][0] = subarray[0]; T upper = subarray[0] + tile_extents[0]; T cropped_upper = (upper - domain[0]) / tile_extents[0] * tile_extents[0] + domain[0]; - tile_slab[aio_id_][1] = std::min(cropped_upper - 1, subarray[1]); + tile_slab[copy_id_][1] = std::min(cropped_upper - 1, subarray[1]); // Leave the rest of the subarray extents intact for(int i=1; i(aio_id_); + calculate_tile_slab_info(copy_id_); // Mark this tile slab as initialized - tile_slab_init_[aio_id_] = true; + tile_slab_init_[copy_id_] = true; // Success return true; @@ -1613,7 +1711,6 @@ void ArraySortedWriteState::reset_tile_slab_state() { // Reset values for(int i=0; iarray_clone(); @@ -1631,7 +1725,7 @@ int ArraySortedWriteState::send_aio_request(int aio_id) { assert(array_clone != NULL); // Send the AIO request to the clone array - if(array_clone->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { + if(array_clone->aio_write(&(aio_request_[aio_id])) != TILEDB_AR_OK) { // TODO: get error message: tiledb_asws_errmsg = tiledb_ar_msg; return TILEDB_ASWS_ERR; } @@ -1664,6 +1758,23 @@ int ArraySortedWriteState::unlock_copy_mtx() { return TILEDB_ASWS_OK; } +void ArraySortedWriteState::update_current_tile_and_offset(int aid) { + // For easy reference + int coords_type = array_->array_schema()->coords_type(); + + // Invoke the proper templated function + if(coords_type == TILEDB_INT32) + update_current_tile_and_offset(aid); + else if(coords_type == TILEDB_INT64) + update_current_tile_and_offset(aid); + else if(coords_type == TILEDB_FLOAT32) + update_current_tile_and_offset(aid); + else if(coords_type == TILEDB_FLOAT64) + update_current_tile_and_offset(aid); + else + assert(0); +} + template void ArraySortedWriteState::update_current_tile_and_offset(int aid) { // For easy reference diff --git a/core/src/fragment/write_state.cc b/core/src/fragment/write_state.cc index cdae69b9..df38a796 100644 --- a/core/src/fragment/write_state.cc +++ b/core/src/fragment/write_state.cc @@ -218,7 +218,9 @@ int WriteState::write(const void** buffers, const size_t* buffer_sizes) { } // Dispatch the proper write command - if(fragment_->mode() == TILEDB_ARRAY_WRITE) { // SORTED + if(fragment_->mode() == TILEDB_ARRAY_WRITE || + fragment_->mode() == TILEDB_ARRAY_WRITE_SORTED_COL || + fragment_->mode() == TILEDB_ARRAY_WRITE_SORTED_ROW) { // SORTED if(fragment_->dense()) // DENSE FRAGMENT return write_dense(buffers, buffer_sizes); else // SPARSE FRAGMENT diff --git a/examples/src/tiledb_array_read_dense_1.cc b/examples/src/tiledb_array_read_dense_1.cc index 7685302f..7c3ce4b3 100644 --- a/examples/src/tiledb_array_read_dense_1.cc +++ b/examples/src/tiledb_array_read_dense_1.cc @@ -66,16 +66,18 @@ int main() { // Read from array tiledb_array_read(tiledb_array, buffers, buffer_sizes); - // Print cell values + // Print only non-empty cell values int64_t result_num = buffer_sizes[0] / sizeof(int); printf(" a1\t a2\t (a3.first, a3.second)\n"); printf("-----------------------------------------\n"); for(int i=0; i Date: Mon, 24 Oct 2016 17:53:57 -0400 Subject: [PATCH 20/57] Minor fixes on some error messages --- core/src/array/array.cc | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 695fdc2f..a8a0be3a 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -287,7 +287,7 @@ int Array::read(void** buffers, size_t* buffer_sizes) { if(rc == TILEDB_ASRS_OK) { return TILEDB_AR_OK; } else { - // TODO: propagate error message + tiledb_ar_errmsg = tiledb_asrs_errmsg; return TILEDB_AR_ERR; } } else { // mode_ == TILDB_ARRAY_READ @@ -298,6 +298,7 @@ int Array::read(void** buffers, size_t* buffer_sizes) { int Array::read_default(void** buffers, size_t* buffer_sizes) { int buffer_i = 0; int attribute_id_num = attribute_ids_.size(); + bool success = false; // Check if there are no fragments if(fragments_.size() == 0) { @@ -315,18 +316,13 @@ int Array::read_default(void** buffers, size_t* buffer_sizes) { success = true; } - // Success + // Return + if(success) { return TILEDB_AR_OK; - } - - // There are fragments - Read - if(array_read_state_->read(buffers, buffer_sizes) != TILEDB_ARS_OK) { - tiledb_ar_errmsg = tiledb_ars_errmsg; - return TILEDB_AR_ERR; + } else { + tiledb_ar_errmsg = tiledb_ars_errmsg; + return TILEDB_AR_ERR; } - - // Success - return TILEDB_AR_OK; } bool Array::read_mode() const { @@ -610,7 +606,7 @@ int Array::init( // Set attribute ids if(array_schema->get_attribute_ids(attributes_vec, attribute_ids_) - != TILEDB_AS_OK) + != TILEDB_AS_OK) { tiledb_ar_errmsg = tiledb_as_errmsg; return TILEDB_AR_ERR; } @@ -643,7 +639,7 @@ int Array::init( mode_ == TILEDB_ARRAY_WRITE_SORTED_ROW) { array_sorted_write_state_ = new ArraySortedWriteState(this); if(array_sorted_write_state_->init() != TILEDB_ASWS_OK) { - // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asrs_errmsg + tiledb_ar_errmsg = tiledb_asws_errmsg; delete array_sorted_write_state_; array_sorted_write_state_ = NULL; return TILEDB_AR_ERR; @@ -665,7 +661,7 @@ int Array::init( if(mode_ != TILEDB_ARRAY_READ) { array_sorted_read_state_ = new ArraySortedReadState(this); if(array_sorted_read_state_->init() != TILEDB_ASRS_OK) { - // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asrs_errmsg + tiledb_ar_errmsg = tiledb_asrs_errmsg; delete array_sorted_read_state_; array_sorted_read_state_ = NULL; return TILEDB_AR_ERR; @@ -735,9 +731,8 @@ int Array::reset_attributes( return TILEDB_AR_ERR; // Reset subarray so that the read/write states are flushed - if(reset_subarray(subarray_) != TILEDB_AR_OK) + if(reset_subarray(subarray_) != TILEDB_AR_OK) return TILEDB_AR_ERR; - } // Success return TILEDB_AR_OK; @@ -775,7 +770,7 @@ int Array::reset_subarray(const void* subarray) { if(fragments_.size() != 0) { assert(fragments_.size() == 1); if(fragments_[0]->finalize() != TILEDB_FG_OK) - // TODO: propagate error message here + tiledb_ar_errmsg = tiledb_fg_errmsg; return TILEDB_AR_ERR; delete fragments_[0]; fragments_.clear(); @@ -788,7 +783,7 @@ int Array::reset_subarray(const void* subarray) { mode_ == TILEDB_ARRAY_WRITE_SORTED_ROW) { array_sorted_write_state_ = new ArraySortedWriteState(this); if(array_sorted_write_state_->init() != TILEDB_ASWS_OK) { - // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asws_errmsg + tiledb_ar_errmsg = tiledb_asws_errmsg; delete array_sorted_write_state_; array_sorted_write_state_ = NULL; return TILEDB_AR_ERR; @@ -831,7 +826,7 @@ int Array::reset_subarray(const void* subarray) { if(mode_ != TILEDB_ARRAY_READ) { array_sorted_read_state_ = new ArraySortedReadState(this); if(array_sorted_read_state_->init() != TILEDB_ASRS_OK) { - // TODO: carry the error message, tiledb_ar_errmsg = tiledb_asrs_errmsg + tiledb_ar_errmsg = tiledb_asrs_errmsg; delete array_sorted_read_state_; array_sorted_read_state_ = NULL; return TILEDB_AR_ERR; From b6ec74bfa02bf2d6c38c3eea7ac01deebad25530 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 24 Oct 2016 18:24:55 -0400 Subject: [PATCH 21/57] Minor fix on error message --- core/src/array/array_sorted_read_state.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 96e0041d..a6a2523c 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -2687,7 +2687,7 @@ int ArraySortedReadState::send_aio_request(int aio_id) { // Send the AIO request to the clone array if(array_clone->aio_read(&(aio_request_[aio_id])) != TILEDB_AR_OK) { - // TODO: get error message: tiledb_asrs_errmsg = tiledb_ar_msg; + tiledb_asrs_errmsg = tiledb_ar_errmsg; return TILEDB_ASRS_ERR; } From 4a2e035367efc562422e07cec017915c13eb3523 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 24 Oct 2016 19:34:23 -0400 Subject: [PATCH 22/57] Fixed array iterator so that it can admit the various read modes (sorted in native order or in column- or row-major order within the specified subarray --- core/include/c_api/c_api.h | 8 ++++++++ core/include/storage_manager/storage_manager.h | 8 ++++++++ core/src/c_api/c_api.cc | 2 ++ core/src/storage_manager/storage_manager.cc | 4 ++-- examples/src/tiledb_array_iterator_dense.cc | 1 + examples/src/tiledb_array_iterator_sparse.cc | 1 + 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/core/include/c_api/c_api.h b/core/include/c_api/c_api.h index b97deb6f..fd237152 100755 --- a/core/include/c_api/c_api.h +++ b/core/include/c_api/c_api.h @@ -576,6 +576,13 @@ typedef struct TileDB_ArrayIterator TileDB_ArrayIterator; * @param tiledb_array_it The TileDB array iterator to be created. The function * will allocate the appropriate memory space for the iterator. * @param array The directory of the array the iterator is initialized for. + * @param mode The read mode, which can be one of the following: + * - TILEDB_ARRAY_READ\n + * Reads the cells in the native order they are stored on the disk. + * - TILEDB_ARRAY_READ_SORTED_COL\n + * Reads the cells in column-major order within the specified subarray. + * - TILEDB_ARRAY_READ_SORTED_ROW\n + * Reads the cells in column-major order within the specified subarray. * @param subarray The subarray in which the array iterator will be * constrained on. It should be a sequence of [low, high] pairs (one * pair per dimension), whose type should be the same as that of the @@ -604,6 +611,7 @@ TILEDB_EXPORT int tiledb_array_iterator_init( const TileDB_CTX* tiledb_ctx, TileDB_ArrayIterator** tiledb_array_it, const char* array, + int mode, const void* subarray, const char** attributes, int attribute_num, diff --git a/core/include/storage_manager/storage_manager.h b/core/include/storage_manager/storage_manager.h index b12bf9df..1a5e273c 100755 --- a/core/include/storage_manager/storage_manager.h +++ b/core/include/storage_manager/storage_manager.h @@ -287,6 +287,13 @@ class StorageManager { * @param tiledb_array_it The TileDB array iterator to be created. The * function will allocate the appropriate memory space for the iterator. * @param array The directory of the array the iterator is initialized for. + * @param mode The read mode, which can be one of the following: + * - TILEDB_ARRAY_READ\n + * Reads the cells in the native order they are stored on the disk. + * - TILEDB_ARRAY_READ_SORTED_COL\n + * Reads the cells in column-major order within the specified subarray. + * - TILEDB_ARRAY_READ_SORTED_ROW\n + * Reads the cells in column-major order within the specified subarray. * @param subarray The subarray in which the array iterator will be * constrained on. If it is NULL, then the subarray is set to the entire * array domain. @@ -311,6 +318,7 @@ class StorageManager { int array_iterator_init( ArrayIterator*& array_it, const char* array, + int mode, const void* subarray, const char** attributes, int attribute_num, diff --git a/core/src/c_api/c_api.cc b/core/src/c_api/c_api.cc index 3c43a2ea..85d9e318 100644 --- a/core/src/c_api/c_api.cc +++ b/core/src/c_api/c_api.cc @@ -733,6 +733,7 @@ int tiledb_array_iterator_init( const TileDB_CTX* tiledb_ctx, TileDB_ArrayIterator** tiledb_array_it, const char* array, + int mode, const void* subarray, const char** attributes, int attribute_num, @@ -753,6 +754,7 @@ int tiledb_array_iterator_init( int rc = tiledb_ctx->storage_manager_->array_iterator_init( (*tiledb_array_it)->array_it_, array, + mode, subarray, attributes, attribute_num, diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 386c9c09..4d75c88f 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -646,6 +646,7 @@ int StorageManager::array_finalize(Array* array) { int StorageManager::array_iterator_init( ArrayIterator*& array_it, const char* array_dir, + int mode, const void* subarray, const char** attributes, int attribute_num, @@ -656,8 +657,7 @@ int StorageManager::array_iterator_init( if(array_init( array, array_dir, - // TODO: revisit this and pass the mode as input - change also the website - TILEDB_ARRAY_READ, + mode, subarray, attributes, attribute_num) != TILEDB_SM_OK) { diff --git a/examples/src/tiledb_array_iterator_dense.cc b/examples/src/tiledb_array_iterator_dense.cc index 716f8612..d2b198f7 100644 --- a/examples/src/tiledb_array_iterator_dense.cc +++ b/examples/src/tiledb_array_iterator_dense.cc @@ -53,6 +53,7 @@ int main() { tiledb_ctx, // Context &tiledb_array_it, // Array iterator "my_workspace/dense_arrays/my_array_A", // Array name + TILEDB_ARRAY_READ, // Mode subarray, // Constrain in subarray attributes, // Subset on attributes 1, // Number of attributes diff --git a/examples/src/tiledb_array_iterator_sparse.cc b/examples/src/tiledb_array_iterator_sparse.cc index 4999e031..94dceea4 100644 --- a/examples/src/tiledb_array_iterator_sparse.cc +++ b/examples/src/tiledb_array_iterator_sparse.cc @@ -53,6 +53,7 @@ int main() { tiledb_ctx, // Context &tiledb_array_it, // Array iterator "my_workspace/sparse_arrays/my_array_B", // Array name + TILEDB_ARRAY_READ, // Mode subarray, // Constrain in subarray attributes, // Subset on attributes 1, // Number of attributes From 036b1a1227919d2a3aeaf1ec6ac55f0740703642 Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 25 Oct 2016 10:06:24 -0400 Subject: [PATCH 23/57] Updating the version --- core/include/c_api/constants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/include/c_api/constants.h b/core/include/c_api/constants.h index 7df1a061..c7d1105c 100644 --- a/core/include/c_api/constants.h +++ b/core/include/c_api/constants.h @@ -37,7 +37,7 @@ #include /** Version. */ -#define TILEDB_VERSION "0.3.5" +#define TILEDB_VERSION "0.4.0" /**@{*/ /** Return code. */ From 1fd6c66ccc3de9d73355fb4a3a242f69ee4c0070 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 26 Oct 2016 12:45:16 -0400 Subject: [PATCH 24/57] Moved file sync to fragment finalization. Also added C API functions for manual syncing an array or a specific attribute file. --- core/include/array/array.h | 15 ++ core/include/c_api/c_api.h | 22 +++ core/include/fragment/fragment.h | 17 ++- core/include/fragment/write_state.h | 16 +++ core/include/misc/utils.h | 19 +++ .../include/storage_manager/storage_manager.h | 20 +++ core/src/array/array.cc | 42 ++++++ core/src/c_api/c_api.cc | 43 ++++++ core/src/fragment/fragment.cc | 31 +++- core/src/fragment/write_state.cc | 135 ++++++++++++++++++ core/src/misc/utils.cc | 83 +++++++++-- core/src/storage_manager/storage_manager.cc | 32 +++++ 12 files changed, 459 insertions(+), 16 deletions(-) diff --git a/core/include/array/array.h b/core/include/array/array.h index 3393bdfd..dd578d44 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -344,6 +344,21 @@ class Array { */ int reset_subarray_soft(const void* subarray); + /** + * Syncs all currently written files in the input array. + * + * @return TILEDB_AR_OK on success, and TILEDB_AR_ERR on error. + */ + int sync(); + + /** + * Syncs the currently written files associated with the input attribute + * in the input array. + * + * @return TILEDB_AR_OK on success, and TILEDB_AR_ERR on error. + */ + int sync_attribute(const std::string& attribute); + /** * Performs a write operation in the array. The cell values are provided * in a set of buffers (one per attribute specified upon initialization). diff --git a/core/include/c_api/c_api.h b/core/include/c_api/c_api.h index fd237152..c8d91570 100755 --- a/core/include/c_api/c_api.h +++ b/core/include/c_api/c_api.h @@ -564,6 +564,28 @@ TILEDB_EXPORT int tiledb_array_consolidate( TILEDB_EXPORT int tiledb_array_finalize( TileDB_Array* tiledb_array); +/** + * Syncs all currently written files in the input array. + * + * @param tiledb_array The array to be synced. + * @return TILEDB_OK on success, and TILEDB_ERR on error. + */ +TILEDB_EXPORT int tiledb_array_sync( + TileDB_Array* tiledb_array); + +/** + * Syncs the currently written files associated with the input attribute + * in the input array. + * + * @param tiledb_array The array to be synced. + * @param attribute The name of the attribute to be synced. + * @return TILEDB_OK on success, and TILEDB_ERR on error. + */ +TILEDB_EXPORT int tiledb_array_sync_attribute( + TileDB_Array* tiledb_array, + const char* attribute); + + /** A TileDB array iterator. */ typedef struct TileDB_ArrayIterator TileDB_ArrayIterator; diff --git a/core/include/fragment/fragment.h b/core/include/fragment/fragment.h index 1b186dad..5acc1a86 100644 --- a/core/include/fragment/fragment.h +++ b/core/include/fragment/fragment.h @@ -170,7 +170,22 @@ class Fragment { /** Resets the read state (typically to start a new read). */ void reset_read_state(); - /** + /** + * Syncs all attribute files in the fragment. + * + * @return TILEDB_WS_OK on success and TILEDB_WS_ERR on error. + */ + int sync(); + + /** + * Syncs the currently written files associated with the input attribute + * in the input array. + * + * @return TILEDB_AR_OK on success, and TILEDB_AR_ERR on error. + */ + int sync_attribute(const std::string& attribute); + + /** * Performs a write operation in the fragment. The cell values are provided * in a set of buffers (one per attribute specified upon initialization). * Note that there must be a one-to-one correspondance between the cell diff --git a/core/include/fragment/write_state.h b/core/include/fragment/write_state.h index e735a6ed..8282db47 100644 --- a/core/include/fragment/write_state.h +++ b/core/include/fragment/write_state.h @@ -104,6 +104,22 @@ class WriteState { * @return TILEDB_WS_OK for success and TILEDB_WS_ERR for error. */ int finalize(); + + /** + * Syncs all attribute files in the fragment. + * + * @return TILEDB_WS_OK on success and TILEDB_WS_ERR on error. + */ + int sync(); + + /** + * Syncs the input attribute in the fragment. + * + * @param attribute The attribute name. + * @return TILEDB_WS_OK on success and TILEDB_WS_ERR on error. + */ + int sync_attribute(const std::string& attribute); + /** * Performs a write operation in the fragment. The cell values are provided diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index 704f203d..edef1187 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -423,6 +423,17 @@ int mpi_io_read_from_file( void* buffer, size_t length); +/** + * Syncs a file or directory using MPI-IO. + * + * @param mpi_comm The MPI communicator. + * @param filename The name of the file. + * @return TILEDB_UT_OK on success and TILEDB_UT_ERR on error. + */ +int mpi_io_sync( + const MPI_Comm* mpi_comm, + const char* filaname); + /** * Writes the input buffer to a file using MPI-IO. * @@ -572,6 +583,14 @@ std::string real_dir(const std::string& dir); */ bool starts_with(const std::string& value, const std::string& prefix); +/** + * Syncs a file or directory. + * + * @param filename The name of the file. + * @return TILEDB_UT_OK on success, and TILEDB_UT_ERR on error. + */ +int sync(const char* filename); + /** * Writes the input buffer to a file. * diff --git a/core/include/storage_manager/storage_manager.h b/core/include/storage_manager/storage_manager.h index 1a5e273c..6cb9abf0 100755 --- a/core/include/storage_manager/storage_manager.h +++ b/core/include/storage_manager/storage_manager.h @@ -279,6 +279,26 @@ class StorageManager { */ int array_finalize(Array* array); + /** + * Syncs all currently written files in the input array. + * + * @param array The array to be synced. + * @return TILEDB_SM_OK on success, and TILEDB_SM_ERR on error. + */ + int array_sync(Array* array); + + /** + * Syncs the currently written files associated with the input attribute + * in the input array. + * + * @param array The array to be synced. + * @param attribute The name of the attribute to be synced. + * @return TILEDB_SM_OK on success, and TILEDB_SM_ERR on error. + */ + int array_sync_attribute( + Array* array, + const std::string& attribute); + /** * Initializes an array iterator for reading cells, potentially constraining * it on a subset of attributes, as well as a subarray. The cells will be read diff --git a/core/src/array/array.cc b/core/src/array/array.cc index a8a0be3a..5fe315f3 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -886,6 +886,48 @@ int Array::reset_subarray_soft(const void* subarray) { return TILEDB_AR_OK; } +int Array::sync() { + // Sanity check + if(!write_mode()) { + std::string errmsg = "Cannot sync array; Invalid mode"; + PRINT_ERROR(errmsg); + tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; + return TILEDB_AR_ERR; + } + + // Sanity check + assert(fragments_.size() == 1); + + // Sync fragment + if(fragments_[0]->sync() != TILEDB_FG_OK) { + tiledb_ar_errmsg = tiledb_fg_errmsg; + return TILEDB_AR_ERR; + } else { + return TILEDB_AR_OK; + } +} + +int Array::sync_attribute(const std::string& attribute) { + // Sanity checks + if(!write_mode()) { + std::string errmsg = "Cannot sync attribute; Invalid mode"; + PRINT_ERROR(errmsg); + tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; + return TILEDB_AR_ERR; + } + + // Sanity check + assert(fragments_.size() == 1); + + // Sync fragment + if(fragments_[0]->sync_attribute(attribute) != TILEDB_FG_OK) { + tiledb_ar_errmsg = tiledb_fg_errmsg; + return TILEDB_AR_ERR; + } else { + return TILEDB_AR_OK; + } +} + int Array::write(const void** buffers, const size_t* buffer_sizes) { // Sanity checks if(!write_mode()) { diff --git a/core/src/c_api/c_api.cc b/core/src/c_api/c_api.cc index 85d9e318..7c5c96a4 100644 --- a/core/src/c_api/c_api.cc +++ b/core/src/c_api/c_api.cc @@ -724,6 +724,49 @@ int tiledb_array_finalize(TileDB_Array* tiledb_array) { return TILEDB_OK; } +int tiledb_array_sync(TileDB_Array* tiledb_array) { + // Sanity check + if(!sanity_check(tiledb_array) || + !sanity_check(tiledb_array->tiledb_ctx_)) + return TILEDB_ERR; + + // Sync + int rc = tiledb_array->tiledb_ctx_->storage_manager_->array_sync( + tiledb_array->array_); + + // Error + if(rc != TILEDB_SM_OK) { + strcpy(tiledb_errmsg, tiledb_sm_errmsg.c_str()); + return TILEDB_ERR; + } + + // Success + return TILEDB_OK; +} + +int tiledb_array_sync_attribute( + TileDB_Array* tiledb_array, + const char* attribute) { + // Sanity check + if(!sanity_check(tiledb_array) || + !sanity_check(tiledb_array->tiledb_ctx_)) + return TILEDB_ERR; + + // Sync attribute + int rc = tiledb_array->tiledb_ctx_->storage_manager_->array_sync_attribute( + tiledb_array->array_, + attribute); + + // Error + if(rc != TILEDB_SM_OK) { + strcpy(tiledb_errmsg, tiledb_sm_errmsg.c_str()); + return TILEDB_ERR; + } + + // Success + return TILEDB_OK; +} + typedef struct TileDB_ArrayIterator { ArrayIterator* array_it_; const TileDB_CTX* tiledb_ctx_; diff --git a/core/src/fragment/fragment.cc b/core/src/fragment/fragment.cc index 0ad8d7fd..07758ea4 100644 --- a/core/src/fragment/fragment.cc +++ b/core/src/fragment/fragment.cc @@ -150,8 +150,7 @@ bool Fragment::write_mode() const { /* ****************************** */ int Fragment::finalize() { - // The fragment was opened for writing - if(write_state_ != NULL) { + if(write_state_ != NULL) { // WRITE assert(book_keeping_ != NULL); int rc_ws = write_state_->finalize(); int rc_bk = book_keeping_->finalize(); @@ -179,7 +178,7 @@ int Fragment::finalize() { // Success return TILEDB_FG_OK; - } else { // The fragment was opened for reading + } else { // READ // Nothing to be done return TILEDB_FG_OK; } @@ -253,6 +252,32 @@ void Fragment::reset_read_state() { read_state_->reset(); } +int Fragment::sync() { + // Sanity check + assert(write_state_ != NULL); + + // Sync + if(write_state_->sync() != TILEDB_WS_OK) { + tiledb_fg_errmsg = tiledb_ws_errmsg; + return TILEDB_FG_ERR; + } else { + return TILEDB_FG_OK; + } +} + +int Fragment::sync_attribute(const std::string& attribute) { + // Sanity check + assert(write_state_ != NULL); + + // Sync attribute + if(write_state_->sync_attribute(attribute) != TILEDB_WS_OK) { + tiledb_fg_errmsg = tiledb_ws_errmsg; + return TILEDB_FG_ERR; + } else { + return TILEDB_FG_OK; + } +} + int Fragment::write(const void** buffers, const size_t* buffer_sizes) { // Forward the write command to the write state int rc = write_state_->write(buffers, buffer_sizes); diff --git a/core/src/fragment/write_state.cc b/core/src/fragment/write_state.cc index df38a796..2a8e4e14 100644 --- a/core/src/fragment/write_state.cc +++ b/core/src/fragment/write_state.cc @@ -34,6 +34,7 @@ #include "constants.h" #include "utils.h" #include "write_state.h" +#include "utils.h" #include #include #include @@ -179,10 +180,144 @@ int WriteState::finalize() { tile_cell_num_[attribute_num] = 0; } + // Sync all attributes + sync(); + + // Success + return TILEDB_WS_OK; +} + +int WriteState::sync() { + // For easy reference + const ArraySchema* array_schema = fragment_->array()->array_schema(); + const std::vector& attribute_ids = fragment_->array()->attribute_ids(); + int write_method = fragment_->array()->config()->write_method(); + MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); + std::string filename; + int rc; + + // Sync all attributes + for(int i=0; i<(int)attribute_ids.size(); ++i) { + // For all attributes + filename = + fragment_->fragment_name() + "/" + + array_schema->attribute(attribute_ids[i]) + TILEDB_FILE_SUFFIX; + if(write_method == TILEDB_IO_WRITE) + rc = ::sync(filename.c_str()); + else if(write_method == TILEDB_IO_MPI) + rc = mpi_io_sync(mpi_comm, filename.c_str()); + else + assert(0); + + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } + + // Only for variable-size attributes (they have an extra file) + if(array_schema->var_size(attribute_ids[i])) { + filename = + fragment_->fragment_name() + "/" + + array_schema->attribute(attribute_ids[i]) + "_var" + + TILEDB_FILE_SUFFIX; + if(write_method == TILEDB_IO_WRITE) + rc = ::sync(filename.c_str()); + else if(write_method == TILEDB_IO_MPI) + rc = mpi_io_sync(mpi_comm, filename.c_str()); + else + assert(0); + } + + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } + } + + // Sync fragment directory + filename = fragment_->fragment_name(); + if(write_method == TILEDB_IO_WRITE) + rc = ::sync(filename.c_str()); + else if(write_method == TILEDB_IO_MPI) + rc = mpi_io_sync(mpi_comm, filename.c_str()); + else + assert(0); + + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } + + // Success + return TILEDB_WS_OK; +} + +int WriteState::sync_attribute(const std::string& attribute) { + // For easy reference + const ArraySchema* array_schema = fragment_->array()->array_schema(); + int write_method = fragment_->array()->config()->write_method(); + MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); + int attribute_id = array_schema->attribute_id(attribute); + std::string filename; + int rc; + + // Sync attribute + filename = fragment_->fragment_name() + "/" + attribute + TILEDB_FILE_SUFFIX; + if(write_method == TILEDB_IO_WRITE) + rc = ::sync(filename.c_str()); + else if(write_method == TILEDB_IO_MPI) + rc = mpi_io_sync(mpi_comm, filename.c_str()); + else + assert(0); + + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } + + // Only for variable-size attributes (they have an extra file) + if(array_schema->var_size(attribute_id)) { + filename = + fragment_->fragment_name() + "/" + + attribute + "_var" + TILEDB_FILE_SUFFIX; + if(write_method == TILEDB_IO_WRITE) + rc = ::sync(filename.c_str()); + else if(write_method == TILEDB_IO_MPI) + rc = mpi_io_sync(mpi_comm, filename.c_str()); + else + assert(0); + } + + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } + + // Sync fragment directory + filename = fragment_->fragment_name(); + if(write_method == TILEDB_IO_WRITE) + rc = ::sync(filename.c_str()); + else if(write_method == TILEDB_IO_MPI) + rc = mpi_io_sync(mpi_comm, filename.c_str()); + else + assert(0); + + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } + // Success return TILEDB_WS_OK; } + int WriteState::write(const void** buffers, const size_t* buffer_sizes) { // Create fragment directory if it does not exist std::string fragment_name = fragment_->fragment_name(); diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 180141d5..6059b7fc 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -735,10 +735,43 @@ int mpi_io_write_to_file( return TILEDB_UT_ERR; } + // Close file + if(MPI_File_close(&fh)) { + std::string errmsg = + std::string("Cannot write to file '") + filename + + "'; File closing error"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return TILEDB_UT_ERR; + } + + // Success + return TILEDB_UT_OK; +} + +int mpi_io_sync( + const MPI_Comm* mpi_comm, + const char* filename) { + // Open file + MPI_File fh; + if(MPI_File_open( + *mpi_comm, + filename, + MPI_MODE_RDONLY, + MPI_INFO_NULL, + &fh)) { + std::string errmsg = + std::string("Cannot sync file '") + filename + + "'; File opening error"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return TILEDB_UT_ERR; + } + // Sync if(MPI_File_sync(fh)) { std::string errmsg = - std::string("Cannot write to file '") + filename + + std::string("Cannot sync file '") + filename + "'; File syncing error"; PRINT_ERROR(errmsg); tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; @@ -748,7 +781,7 @@ int mpi_io_write_to_file( // Close file if(MPI_File_close(&fh)) { std::string errmsg = - std::string("Cannot write to file '") + filename + + std::string("Cannot sync file '") + filename + "'; File closing error"; PRINT_ERROR(errmsg); tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; @@ -1036,6 +1069,42 @@ bool starts_with(const std::string& value, const std::string& prefix) { return std::equal(prefix.begin(), prefix.end(), value.begin()); } +int sync(const char* filename) { + // Open file + int fd = open(filename, O_RDONLY, S_IRWXU); + if(fd == -1) { + std::string errmsg = + std::string("Cannot sync file '") + filename + + "'; File opening error"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return TILEDB_UT_ERR; + } + + // Sync + if(fsync(fd)) { + std::string errmsg = + std::string("Cannot sync file '") + filename + + "'; File syncing error"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return TILEDB_UT_ERR; + } + + // Close file + if(close(fd)) { + std::string errmsg = + std::string("Cannot sync file '") + filename + + "'; File closing error"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return TILEDB_UT_ERR; + } + + // Success + return TILEDB_UT_OK; +} + int write_to_file( const char* filename, const void* buffer, @@ -1079,16 +1148,6 @@ int write_to_file( return TILEDB_UT_ERR; } - // Sync - if(fsync(fd)) { - std::string errmsg = - std::string("Cannot write to file '") + filename + - "'; File syncing error"; - PRINT_ERROR(errmsg); - tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; - return TILEDB_UT_ERR; - } - // Close file if(close(fd)) { std::string errmsg = diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 4d75c88f..36e0c5a2 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -643,6 +643,38 @@ int StorageManager::array_finalize(Array* array) { return TILEDB_SM_OK; } +int StorageManager::array_sync(Array* array) { + // If the array is NULL, do nothing + if(array == NULL) + return TILEDB_SM_OK; + + // Sync array + if(array->sync() != TILEDB_AR_OK) { + tiledb_sm_errmsg = tiledb_ar_errmsg; + return TILEDB_SM_ERR; + } + + // Success + return TILEDB_SM_OK; +} + +int StorageManager::array_sync_attribute( + Array* array, + const std::string& attribute) { + // If the array is NULL, do nothing + if(array == NULL) + return TILEDB_SM_OK; + + // Sync array + if(array->sync_attribute(attribute) != TILEDB_AR_OK) { + tiledb_sm_errmsg = tiledb_ar_errmsg; + return TILEDB_SM_ERR; + } + + // Success + return TILEDB_SM_OK; +} + int StorageManager::array_iterator_init( ArrayIterator*& array_it, const char* array_dir, From 2d28e0a87bbeb2576cf032b055a72eed54f36094 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 26 Oct 2016 14:11:38 -0400 Subject: [PATCH 25/57] Minor fix in sync --- core/src/misc/utils.cc | 47 +++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 6059b7fc..995ccbb2 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -754,19 +754,32 @@ int mpi_io_sync( const char* filename) { // Open file MPI_File fh; - if(MPI_File_open( - *mpi_comm, - filename, - MPI_MODE_RDONLY, - MPI_INFO_NULL, - &fh)) { - std::string errmsg = - std::string("Cannot sync file '") + filename + - "'; File opening error"; - PRINT_ERROR(errmsg); - tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; - return TILEDB_UT_ERR; - } + int rc; + if(is_dir(filename)) // DIRECTORY + rc = MPI_File_open( + *mpi_comm, + filename, + MPI_MODE_RDONLY, + MPI_INFO_NULL, + &fh); + else // FILE + rc = MPI_File_open( + *mpi_comm, + filename, + MPI_MODE_WRONLY | MPI_MODE_APPEND | + MPI_MODE_CREATE | MPI_MODE_SEQUENTIAL, + MPI_INFO_NULL, + &fh); + + // Handle error + if(rc) { + std::string errmsg = + std::string("Cannot sync file '") + filename + + "'; File opening error"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return TILEDB_UT_ERR; + } // Sync if(MPI_File_sync(fh)) { @@ -1071,7 +1084,13 @@ bool starts_with(const std::string& value, const std::string& prefix) { int sync(const char* filename) { // Open file - int fd = open(filename, O_RDONLY, S_IRWXU); + int fd; + if(is_dir(filename)) // DIRECTORY + fd = open(filename, O_RDONLY, S_IRWXU); + else // FILE + fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU); + + // Handle error if(fd == -1) { std::string errmsg = std::string("Cannot sync file '") + filename + From 840f768117446d3afc722a31175c534be6812f88 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 26 Oct 2016 15:04:30 -0400 Subject: [PATCH 26/57] Changed preprocessor flag OPENMP to HAVE_OPENMP, and fixed a minor bug on properly including -pthread in case OpenMP is disabled. Added also a new preprocessor flag USE_PARALLEL_SORT to explicitly state whether parallel sort will be used or not when OpenMP is enabled (up until now, parallel sort was always used when OpenMP was enabled). --- Makefile | 22 ++++++++++++++----- core/include/misc/utils.h | 4 ++-- .../include/storage_manager/storage_manager.h | 6 ++--- core/src/array/array_sorted_read_state.cc | 2 +- core/src/fragment/write_state.cc | 2 +- core/src/misc/utils.cc | 2 +- core/src/storage_manager/storage_manager.cc | 18 +++++++-------- .../src/tiledb_array_parallel_read_dense_2.cc | 2 +- .../tiledb_array_parallel_read_sparse_2.cc | 2 +- .../tiledb_array_parallel_write_dense_2.cc | 2 +- .../tiledb_array_parallel_write_sparse_2.cc | 2 +- 11 files changed, 37 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 82a7d73c..6e560aab 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,13 @@ ifdef TRAVIS endif # --- Support for OpenMP --- # +OPENMP = OPENMP_FLAG = -ifeq ($(COMPILER), gcc) - CPPFLAGS += -DOPENMP - OPENMP_FLAG = -fopenmp +ifeq ($(COMPILER), gcc) + ifeq ($(OPENMP), 1) + CPPFLAGS += -DHAVE_OPENMP + OPENMP_FLAG = -fopenmp + endif endif # --- Debug/Release mode handler --- # @@ -45,6 +48,12 @@ ifeq ($(VERBOSE),1) CPPFLAGS += -DNVERBOSE endif +# --- Use parallel sort --- # +USE_PARALLEL_SORT = +ifeq ($(USE_PARALLEL_SORT),1) + CPPFLAGS += -DUSE_PARALLEL_SORT +endif + # --- Compilers --- # CXX = g++ @@ -110,6 +119,7 @@ ZLIB = -lz OPENSSLLIB = -lcrypto GTESTLIB = -lgtest -lgtest_main MPILIB = +PTHREADLIB = -pthread # --- For the TileDB dynamic library --- # ifeq ($(OS), Darwin) @@ -204,7 +214,7 @@ $(CORE_LIB_DIR)/libtiledb.$(SHLIB_EXT): $(CORE_OBJ) @mkdir -p $(CORE_LIB_DIR) @echo "Creating dynamic library libtiledb.$(SHLIB_EXT)" @$(CXX) $(SHLIB_FLAGS) $(SONAME) -o $@ $^ $(LIBRARY_PATHS) $(MPILIB) \ - $(ZLIB) $(OPENSSLLIB) $(OPENMP_FLAG) + $(PTHREADLIB) $(ZLIB) $(OPENSSLLIB) $(OPENMP_FLAG) $(CORE_LIB_DIR)/libtiledb.a: $(CORE_OBJ) @mkdir -p $(CORE_LIB_DIR) @@ -243,7 +253,7 @@ $(EXAMPLES_BIN_DIR)/%: $(EXAMPLES_OBJ_DIR)/%.o $(CORE_LIB_DIR)/libtiledb.a @mkdir -p $(EXAMPLES_BIN_DIR) @echo "Creating $@" @$(CXX) -std=gnu++11 -o $@ $^ $(LIBRARY_PATHS) $(MPILIB) $(ZLIB) \ - $(OPENSSLLIB) $(OPENMP_FLAG) + $(PTHREADLIB) $(OPENSSLLIB) $(OPENMP_FLAG) # --- Cleaning --- # @@ -277,7 +287,7 @@ $(TEST_BIN_DIR)/tiledb_test: $(TEST_OBJ) $(CORE_LIB_DIR)/libtiledb.a @mkdir -p $(TEST_BIN_DIR) @echo "Creating test_cmd" @$(CXX) -std=gnu++11 -o $@ $^ $(LIBRARY_PATHS) $(MPILIB) $(ZLIB) \ - $(OPENSSLLIB) $(GTESTLIB) $(OPENMP_FLAG) + $(PTHREADLIB) $(OPENSSLLIB) $(GTESTLIB) $(OPENMP_FLAG) # --- Cleaning --- # diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index edef1187..67b647f6 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -39,7 +39,7 @@ #include -#ifdef OPENMP +#ifdef HAVE_OPENMP #include #endif @@ -449,7 +449,7 @@ int mpi_io_write_to_file( const void* buffer, size_t buffer_size); -#ifdef OPENMP +#ifdef HAVE_OPENMP /** * Destroys an OpenMP mutex. * diff --git a/core/include/storage_manager/storage_manager.h b/core/include/storage_manager/storage_manager.h index 6cb9abf0..c154eacf 100755 --- a/core/include/storage_manager/storage_manager.h +++ b/core/include/storage_manager/storage_manager.h @@ -42,7 +42,7 @@ #include "metadata_iterator.h" #include "metadata_schema_c.h" #include -#ifdef OPENMP +#ifdef HAVE_OPENMP #include #endif #include @@ -549,7 +549,7 @@ class StorageManager { /** The directory of the master catalog. */ std::string master_catalog_dir_; /** OpneMP mutex for creating/deleting an OpenArray object. */ -#ifdef OPENMP +#ifdef HAVE_OPENMP omp_lock_t open_array_omp_mtx_; #endif /** Pthread mutex for creating/deleting an OpenArray object. */ @@ -925,7 +925,7 @@ class StorageManager::OpenArray { * An OpenMP mutex used to lock the array when loading the array schema and * the book-keeping structures from the disk. */ -#ifdef OPENMP +#ifdef HAVE_OPENMP omp_lock_t omp_mtx_; #endif /** diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index a6a2523c..079f4178 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -49,7 +49,7 @@ # define PRINT_ERROR(x) do { } while(0) #endif -#ifdef OPENMP +#if defined HAVE_OPENMP && defined USE_PARALLEL_SORT #include #define SORT(first, last, comp) __gnu_parallel::sort((first), (last), (comp)) #else diff --git a/core/src/fragment/write_state.cc b/core/src/fragment/write_state.cc index 2a8e4e14..cab2032d 100644 --- a/core/src/fragment/write_state.cc +++ b/core/src/fragment/write_state.cc @@ -55,7 +55,7 @@ # define PRINT_ERROR(x) do { } while(0) #endif -#ifdef OPENMP +#if defined HAVE_OPENMP && defined USE_PARALLEL_SORT #include #define SORT(first, last, comp) __gnu_parallel::sort((first), (last), (comp)) #else diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 995ccbb2..081dc2d3 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -805,7 +805,7 @@ int mpi_io_sync( return TILEDB_UT_OK; } -#ifdef OPENMP +#ifdef HAVE_OPENMP int mutex_destroy(omp_lock_t* mtx) { omp_destroy_lock(mtx); diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 36e0c5a2..4f96c2d7 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -51,7 +51,7 @@ # define PRINT_ERROR(x) do { } while(0) #endif -#ifdef OPENMP +#if defined HAVE_OPENMP && defined USE_PARALLEL_SORT #include #define SORT_LIB __gnu_parallel #else @@ -2272,7 +2272,7 @@ int StorageManager::metadata_move( } int StorageManager::open_array_mtx_destroy() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_destroy(&open_array_omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2290,7 +2290,7 @@ int StorageManager::open_array_mtx_destroy() { } int StorageManager::open_array_mtx_init() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_init(&open_array_omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2308,7 +2308,7 @@ int StorageManager::open_array_mtx_init() { } int StorageManager::open_array_mtx_lock() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_lock(&open_array_omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2326,7 +2326,7 @@ int StorageManager::open_array_mtx_lock() { } int StorageManager::open_array_mtx_unlock() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_unlock(&open_array_omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2575,7 +2575,7 @@ int StorageManager::workspace_move( } int StorageManager::OpenArray::mutex_destroy() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_destroy(&omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2593,7 +2593,7 @@ int StorageManager::OpenArray::mutex_destroy() { } int StorageManager::OpenArray::mutex_init() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_init(&omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2611,7 +2611,7 @@ int StorageManager::OpenArray::mutex_init() { } int StorageManager::OpenArray::mutex_lock() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_lock(&omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; @@ -2629,7 +2629,7 @@ int StorageManager::OpenArray::mutex_lock() { } int StorageManager::OpenArray::mutex_unlock() { -#ifdef OPENMP +#ifdef HAVE_OPENMP int rc_omp_mtx = ::mutex_unlock(&omp_mtx_); #else int rc_omp_mtx = TILEDB_UT_OK; diff --git a/examples/src/tiledb_array_parallel_read_dense_2.cc b/examples/src/tiledb_array_parallel_read_dense_2.cc index 5d2def45..1d05070e 100644 --- a/examples/src/tiledb_array_parallel_read_dense_2.cc +++ b/examples/src/tiledb_array_parallel_read_dense_2.cc @@ -33,7 +33,7 @@ #include "c_api.h" #include -#ifdef OPENMP +#ifdef HAVE_OPENMP #include // The function to be computed in parallel diff --git a/examples/src/tiledb_array_parallel_read_sparse_2.cc b/examples/src/tiledb_array_parallel_read_sparse_2.cc index 3cd1019e..b93c651a 100644 --- a/examples/src/tiledb_array_parallel_read_sparse_2.cc +++ b/examples/src/tiledb_array_parallel_read_sparse_2.cc @@ -33,7 +33,7 @@ #include "c_api.h" #include -#ifdef OPENMP +#ifdef HAVE_OPENMP #include diff --git a/examples/src/tiledb_array_parallel_write_dense_2.cc b/examples/src/tiledb_array_parallel_write_dense_2.cc index e9265648..2fc4a6b0 100644 --- a/examples/src/tiledb_array_parallel_write_dense_2.cc +++ b/examples/src/tiledb_array_parallel_write_dense_2.cc @@ -32,7 +32,7 @@ #include "c_api.h" -#ifdef OPENMP +#ifdef HAVE_OPENMP #include diff --git a/examples/src/tiledb_array_parallel_write_sparse_2.cc b/examples/src/tiledb_array_parallel_write_sparse_2.cc index 8ef5fdb0..f0e5bf95 100644 --- a/examples/src/tiledb_array_parallel_write_sparse_2.cc +++ b/examples/src/tiledb_array_parallel_write_sparse_2.cc @@ -32,7 +32,7 @@ #include "c_api.h" -#ifdef OPENMP +#ifdef HAVE_OPENMP #include From ab4c99b5eebb497a2405e0cb8e10f82785e4ded7 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 26 Oct 2016 16:50:09 -0400 Subject: [PATCH 27/57] Made MPI optional. Now it is enabled only by setting MPI=1 as argument in make. --- Makefile | 6 + core/include/c_api/c_api.h | 6 +- core/include/fragment/read_state.h | 2 + core/include/misc/utils.h | 6 +- core/include/storage_manager/config.h | 56 ++++- core/src/c_api/c_api.cc | 2 + core/src/fragment/read_state.cc | 145 ++++++++++-- core/src/fragment/write_state.cc | 211 +++++++++++++++--- core/src/misc/utils.cc | 2 + core/src/storage_manager/config.cc | 8 + ...tiledb_array_parallel_read_mpi_io_dense.cc | 12 +- 11 files changed, 388 insertions(+), 68 deletions(-) diff --git a/Makefile b/Makefile index 6e560aab..0dab7862 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,12 @@ ifeq ($(USE_PARALLEL_SORT),1) CPPFLAGS += -DUSE_PARALLEL_SORT endif +# --- Support for MPI --- # +MPI = +ifeq ($(MPI),1) + CPPFLAGS += -DHAVE_MPI +endif + # --- Compilers --- # CXX = g++ diff --git a/core/include/c_api/c_api.h b/core/include/c_api/c_api.h index c8d91570..49a25047 100755 --- a/core/include/c_api/c_api.h +++ b/core/include/c_api/c_api.h @@ -34,7 +34,9 @@ #define __C_API_H__ #include "constants.h" -#include +#ifdef HAVE_MPI + #include +#endif #include #include #include @@ -91,8 +93,10 @@ typedef struct TileDB_Config { * default home directory will be used, which is ~/.tiledb/. */ const char* home_; +#ifdef HAVE_MPI /** The MPI communicator. Use NULL if no MPI is used. */ MPI_Comm* mpi_comm_; +#endif /** * The method for reading data from a file. * It can be one of the following: diff --git a/core/include/fragment/read_state.h b/core/include/fragment/read_state.h index 0dd1dd57..81ed32be 100644 --- a/core/include/fragment/read_state.h +++ b/core/include/fragment/read_state.h @@ -686,6 +686,7 @@ class ReadState { off_t offset, size_t tile_size); +#ifdef HAVE_MPI /** * Reads a tile from the disk for an attribute into a local buffer, using * MPI-IO. This function focuses on the case of GZIP compression. @@ -714,6 +715,7 @@ class ReadState { int attribute_id, off_t offset, size_t tile_size); +#endif /** * Prepares a tile from the disk for reading for an attribute. diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index 67b647f6..1bb4d685 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -33,7 +33,9 @@ #ifndef __UTILS_H__ #define __UTILS_H__ -#include +#ifdef HAVE_MPI + #include +#endif #include #include #include @@ -406,6 +408,7 @@ bool is_unary_subarray(const T* subarray, int dim_num); */ bool is_workspace(const std::string& dir); +#ifdef HAVE_MPI /** * Reads data from a file into a buffer using MPI-IO. * @@ -448,6 +451,7 @@ int mpi_io_write_to_file( const char* filename, const void* buffer, size_t buffer_size); +#endif #ifdef HAVE_OPENMP /** diff --git a/core/include/storage_manager/config.h b/core/include/storage_manager/config.h index 2461f1a6..c8a0b92f 100644 --- a/core/include/storage_manager/config.h +++ b/core/include/storage_manager/config.h @@ -33,7 +33,9 @@ #ifndef __CONFIG_H__ #define __CONFIG_H__ -#include +#ifdef HAVE_MPI + #include +#endif #include @@ -59,6 +61,7 @@ class Config { /* MUTATORS */ /* ********************************* */ +#ifdef HAVE_MPI /** * Initializes the configuration parameters. * @@ -66,17 +69,17 @@ class Config { * @param mpi_comm The MPI communicator. * @param read_method The method for reading data from a file. * It can be one of the following: - * - TILEDB_USE_READ + * - TILEDB_IO_READ * TileDB will use POSIX read. - * - TILEDB_USE_MMAP + * - TILEDB_IO_MMAP * TileDB will use mmap. - * - TILEDB_USE_MPIIO + * - TILEDB_IO_MPI * TileDB will use MPI-IO read. * @param write_method The method for writing data to a file. * It can be one of the following: - * - TILEDB_USE_WRITE + * - TILEDB_IO_WRITE * TileDB will use POSIX write. - * - TILEDB_USE_MPI_IO + * - TILEDB_IO_MPI * TileDB will use MPI-IO write. * @return void. */ @@ -85,7 +88,32 @@ class Config { MPI_Comm* mpi_comm, int read_method, int write_methods); - +#else + /** + * Initializes the configuration parameters. + * + * @param home The TileDB home directory. + * @param read_method The method for reading data from a file. + * It can be one of the following: + * - TILEDB_IO_READ + * TileDB will use POSIX read. + * - TILEDB_IO_MMAP + * TileDB will use mmap. + * - TILEDB_IO_MPI + * TileDB will use MPI-IO read. + * @param write_method The method for writing data to a file. + * It can be one of the following: + * - TILEDB_IO_WRITE + * TileDB will use POSIX write. + * - TILEDB_IO_MPI + * TileDB will use MPI-IO write. + * @return void. + */ + void init( + const char* home, + int read_method, + int write_methods); +#endif /* ********************************* */ /* ACCESSORS */ @@ -94,8 +122,10 @@ class Config { /** Returns the TileDB home directory. */ const std::string& home() const; +#ifdef HAVE_MPI /** Returns the MPI communicator. */ MPI_Comm* mpi_comm() const; +#endif /** Returns the read method. */ int read_method() const; @@ -110,25 +140,27 @@ class Config { /** TileDB home directory. */ std::string home_; +#ifdef HAVE_MPI /** The MPI communicator. */ MPI_Comm* mpi_comm_; +#endif /** * The method for reading data from a file. * It can be one of the following: - * - TILEDB_USE_READ + * - TILEDB_IO_READ * TileDB will use POSIX read. - * - TILEDB_USE_MMAP + * - TILEDB_IO_MMAP * TileDB will use mmap. - * - TILEDB_USE_MPI_IO + * - TILEDB_IO_MPI * TileDB will use MPI-IO read. */ int read_method_; /** * The method for writing data to a file. * It can be one of the following: - * - TILEDB_USE_WRITE + * - TILEDB_IO_WRITE * TileDB will use POSIX write. - * - TILEDB_USE_MPI_IO + * - TILEDB_IO_MPI * TileDB will use MPI-IO write. */ int write_method_; diff --git a/core/src/c_api/c_api.cc b/core/src/c_api/c_api.cc index 7c5c96a4..142d0dd0 100644 --- a/core/src/c_api/c_api.cc +++ b/core/src/c_api/c_api.cc @@ -91,7 +91,9 @@ int tiledb_ctx_init( if(tiledb_config != NULL) config->init( tiledb_config->home_, +#ifdef HAVE_MPI tiledb_config->mpi_comm_, +#endif tiledb_config->read_method_, tiledb_config->write_method_); diff --git a/core/src/fragment/read_state.cc b/core/src/fragment/read_state.cc index b50471ab..d6c6fa5c 100644 --- a/core/src/fragment/read_state.cc +++ b/core/src/fragment/read_state.cc @@ -1052,20 +1052,33 @@ int ReadState::CMP_COORDS_TO_SEARCH_TILE( fragment_->fragment_name() + "/" + TILEDB_COORDS + TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int read_method = array_->config()->read_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = array_->config()->mpi_comm(); - if(read_method == TILEDB_IO_READ) +#endif + + if(read_method == TILEDB_IO_READ) { rc = read_from_file( filename, tiles_file_offsets_[attribute_num_+1] + tile_offset, tmp_coords_, coords_size_); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_from_file( mpi_comm, filename, tiles_file_offsets_[attribute_num_+1] + tile_offset, tmp_coords_, coords_size_); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot compare coordinates to search tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -1514,20 +1527,33 @@ int ReadState::GET_COORDS_PTR_FROM_SEARCH_TILE( fragment_->fragment_name() + "/" + TILEDB_COORDS + TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int read_method = array_->config()->read_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = array_->config()->mpi_comm(); - if(read_method == TILEDB_IO_READ) +#endif + + if(read_method == TILEDB_IO_READ) { rc = read_from_file( filename, tiles_file_offsets_[attribute_num_+1] + i*coords_size_, tmp_coords_, coords_size_); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_from_file( mpi_comm, filename, tiles_file_offsets_[attribute_num_+1] + i*coords_size_, tmp_coords_, coords_size_); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot get coordinates from search tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Get coordinates pointer coords = tmp_coords_; @@ -1562,20 +1588,33 @@ int ReadState::GET_CELL_PTR_FROM_OFFSET_TILE( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int read_method = array_->config()->read_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = array_->config()->mpi_comm(); - if(read_method == TILEDB_IO_READ) +#endif + + if(read_method == TILEDB_IO_READ) { rc = read_from_file( filename, tiles_file_offsets_[attribute_id] + i*sizeof(size_t), &tmp_offset_, sizeof(size_t)); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_from_file( mpi_comm, filename, tiles_file_offsets_[attribute_id] + i*sizeof(size_t), &tmp_offset_, sizeof(size_t)); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot get cell pointer from offset tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Get coordinates pointer offset = &tmp_offset_; @@ -1938,6 +1977,7 @@ int ReadState::map_tile_from_file_var_cmp_none( return TILEDB_RS_OK; } +#ifdef HAVE_MPI int ReadState::mpi_io_read_tile_from_file_cmp_gzip( int attribute_id, off_t offset, @@ -2019,6 +2059,7 @@ int ReadState::mpi_io_read_tile_from_file_var_cmp_gzip( // Success return TILEDB_RS_OK; } +#endif int ReadState::prepare_tile_for_reading( int attribute_id, @@ -2088,21 +2129,31 @@ int ReadState::prepare_tile_for_reading_cmp_gzip( // Read tile from file int rc = TILEDB_RS_OK; int read_method = array_->config()->read_method(); - if(read_method == TILEDB_IO_READ) + if(read_method == TILEDB_IO_READ) { rc = read_tile_from_file_cmp_gzip( attribute_id, file_offset, tile_compressed_size); - else if(read_method == TILEDB_IO_MMAP) + } else if(read_method == TILEDB_IO_MMAP) { rc = map_tile_from_file_cmp_gzip( attribute_id, file_offset, tile_compressed_size); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_tile_from_file_cmp_gzip( attribute_id, file_offset, tile_compressed_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot prepare tile for reading (gzip); MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Error if(rc != TILEDB_RS_OK) @@ -2233,21 +2284,31 @@ int ReadState::prepare_tile_for_reading_var_cmp_gzip( // Read tile from file int rc = TILEDB_RS_OK; int read_method = array_->config()->read_method(); - if(read_method == TILEDB_IO_READ) + if(read_method == TILEDB_IO_READ) { rc = read_tile_from_file_cmp_gzip( attribute_id, file_offset, tile_compressed_size); - else if(read_method == TILEDB_IO_MMAP) + } else if(read_method == TILEDB_IO_MMAP) { rc = map_tile_from_file_cmp_gzip( attribute_id, file_offset, tile_compressed_size); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_tile_from_file_cmp_gzip( attribute_id, file_offset, tile_compressed_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot prepare variable tile for reading (gzip); MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Error if(rc != TILEDB_RS_OK) @@ -2310,21 +2371,31 @@ int ReadState::prepare_tile_for_reading_var_cmp_gzip( // Read tile from file int rc = TILEDB_RS_OK; int read_method = array_->config()->read_method(); - if(read_method == TILEDB_IO_READ) + if(read_method == TILEDB_IO_READ) { rc = read_tile_from_file_var_cmp_gzip( attribute_id, file_offset, tile_compressed_size); - else if(read_method == TILEDB_IO_MMAP) + } else if(read_method == TILEDB_IO_MMAP) { rc = map_tile_from_file_var_cmp_gzip( attribute_id, file_offset, tile_compressed_size); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_tile_from_file_var_cmp_gzip( attribute_id, file_offset, tile_compressed_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot prepare variable tile for reading (gzip); MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Error if(rc != TILEDB_RS_OK) @@ -2428,6 +2499,7 @@ int ReadState::prepare_tile_for_reading_var_cmp_none( return TILEDB_RS_ERR; } } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI if(mpi_io_read_from_file( array_->config()->mpi_comm(), filename, file_offset + full_tile_size, @@ -2436,6 +2508,14 @@ int ReadState::prepare_tile_for_reading_var_cmp_none( tiledb_rs_errmsg = tiledb_ut_errmsg; return TILEDB_RS_ERR; } +#else + // Error: MPI not supported + std::string errmsg = + "Cannot prepare variable tile for reading; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif } tile_var_size = end_tile_var_offset - tile_s[0]; } else { // Last tile @@ -2499,20 +2579,34 @@ int ReadState::READ_FROM_TILE( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int read_method = array_->config()->read_method(); + +#ifdef HAVE_MPI MPI_Comm* mpi_comm = array_->config()->mpi_comm(); - if(read_method == TILEDB_IO_READ) +#endif + + if(read_method == TILEDB_IO_READ) { rc = read_from_file( filename, tiles_file_offsets_[attribute_id] + tile_offset, buffer, bytes_to_copy); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_from_file( mpi_comm, filename, tiles_file_offsets_[attribute_id] + tile_offset, buffer, bytes_to_copy); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot read from tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -2545,20 +2639,33 @@ int ReadState::READ_FROM_TILE_VAR( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int read_method = array_->config()->read_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = array_->config()->mpi_comm(); - if(read_method == TILEDB_IO_READ) +#endif + + if(read_method == TILEDB_IO_READ) { rc = read_from_file( filename, tiles_var_file_offsets_[attribute_id] + tile_offset, buffer, bytes_to_copy); - else if(read_method == TILEDB_IO_MPI) + } else if(read_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_read_from_file( mpi_comm, filename, tiles_var_file_offsets_[attribute_id] + tile_offset, buffer, bytes_to_copy); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot read from variable tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_rs_errmsg = TILEDB_RS_ERRMSG + errmsg; + return TILEDB_RS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { diff --git a/core/src/fragment/write_state.cc b/core/src/fragment/write_state.cc index cab2032d..93b85643 100644 --- a/core/src/fragment/write_state.cc +++ b/core/src/fragment/write_state.cc @@ -192,7 +192,9 @@ int WriteState::sync() { const ArraySchema* array_schema = fragment_->array()->array_schema(); const std::vector& attribute_ids = fragment_->array()->attribute_ids(); int write_method = fragment_->array()->config()->write_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); +#endif std::string filename; int rc; @@ -202,12 +204,21 @@ int WriteState::sync() { filename = fragment_->fragment_name() + "/" + array_schema->attribute(attribute_ids[i]) + TILEDB_FILE_SUFFIX; - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); - else +#else + // Error: MPI not supported + std::string errmsg = "Cannot sync; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } else { assert(0); + } // Handle error if(rc != TILEDB_UT_OK) { @@ -221,12 +232,21 @@ int WriteState::sync() { fragment_->fragment_name() + "/" + array_schema->attribute(attribute_ids[i]) + "_var" + TILEDB_FILE_SUFFIX; - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); - else +#else + // Error: MPI not supported + std::string errmsg = "Cannot sync; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } else { assert(0); + } } // Handle error @@ -238,12 +258,21 @@ int WriteState::sync() { // Sync fragment directory filename = fragment_->fragment_name(); - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); - else +#else + // Error: MPI not supported + std::string errmsg = "Cannot sync; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } else { assert(0); + } // Handle error if(rc != TILEDB_UT_OK) { @@ -259,19 +288,30 @@ int WriteState::sync_attribute(const std::string& attribute) { // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); int write_method = fragment_->array()->config()->write_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); +#endif int attribute_id = array_schema->attribute_id(attribute); std::string filename; int rc; // Sync attribute filename = fragment_->fragment_name() + "/" + attribute + TILEDB_FILE_SUFFIX; - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); - else +#else + // Error: MPI not supported + std::string errmsg = "Cannot sync attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } else { assert(0); + } // Handle error if(rc != TILEDB_UT_OK) { @@ -284,12 +324,21 @@ int WriteState::sync_attribute(const std::string& attribute) { filename = fragment_->fragment_name() + "/" + attribute + "_var" + TILEDB_FILE_SUFFIX; - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); - else +#else + // Error: MPI not supported + std::string errmsg = "Cannot sync attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } else { assert(0); + } } // Handle error @@ -300,12 +349,21 @@ int WriteState::sync_attribute(const std::string& attribute) { // Sync fragment directory filename = fragment_->fragment_name(); - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); - else +#else + // Error: MPI not supported + std::string errmsg = "Cannot sync attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } else { assert(0); + } // Handle error if(rc != TILEDB_UT_OK) { @@ -423,17 +481,26 @@ int WriteState::compress_and_write_tile(int attribute_id) { // Write segment to file int rc = TILEDB_UT_OK; int write_method = fragment_->array()->config()->write_method(); - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), tile_compressed_, tile_compressed_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( fragment_->array()->config()->mpi_comm(), filename.c_str(), tile_compressed_, tile_compressed_size); +#else + // Error: MPI not supported + std::string errmsg = "Cannot compress and write tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -498,17 +565,27 @@ int WriteState::compress_and_write_tile_var(int attribute_id) { // Write segment to file int rc = TILEDB_UT_OK; int write_method = fragment_->array()->config()->write_method(); - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), tile_compressed_, tile_compressed_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( fragment_->array()->config()->mpi_comm(), filename.c_str(), tile_compressed_, tile_compressed_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot compress and write variable tile; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -811,17 +888,27 @@ int WriteState::write_dense_attr_cmp_none( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int write_method = fragment_->array()->config()->write_method(); - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), buffer, buffer_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( fragment_->array()->config()->mpi_comm(), filename.c_str(), buffer, buffer_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot write dense attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -945,18 +1032,30 @@ int WriteState::write_dense_attr_var_cmp_none( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int write_method = fragment_->array()->config()->write_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); - if(write_method == TILEDB_IO_WRITE) +#endif + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), buffer_var, buffer_var_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( mpi_comm, filename.c_str(), buffer_var, buffer_var_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot write dense variable attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -977,17 +1076,27 @@ int WriteState::write_dense_attr_var_cmp_none( filename = fragment_->fragment_name() + "/" + array_schema->attribute(attribute_id) + TILEDB_FILE_SUFFIX; - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), shifted_buffer, buffer_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( mpi_comm, filename.c_str(), shifted_buffer, buffer_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot write dense variable attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Clean up free(shifted_buffer); @@ -1261,18 +1370,30 @@ int WriteState::write_sparse_attr_cmp_none( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int write_method = fragment_->array()->config()->write_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); - if(write_method == TILEDB_IO_WRITE) +#endif + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), buffer, buffer_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( mpi_comm, filename.c_str(), buffer, buffer_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot write sparse attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -1405,18 +1526,30 @@ int WriteState::write_sparse_attr_var_cmp_none( TILEDB_FILE_SUFFIX; int rc = TILEDB_UT_OK; int write_method = fragment_->array()->config()->write_method(); +#ifdef HAVE_MPI MPI_Comm* mpi_comm = fragment_->array()->config()->mpi_comm(); - if(write_method == TILEDB_IO_WRITE) +#endif + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), buffer_var, buffer_var_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( mpi_comm, filename.c_str(), buffer_var, buffer_var_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot write sparse variable attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Error if(rc != TILEDB_UT_OK) { @@ -1437,17 +1570,27 @@ int WriteState::write_sparse_attr_var_cmp_none( filename = fragment_->fragment_name() + "/" + array_schema->attribute(attribute_id) + TILEDB_FILE_SUFFIX; - if(write_method == TILEDB_IO_WRITE) + if(write_method == TILEDB_IO_WRITE) { rc = write_to_file( filename.c_str(), shifted_buffer, buffer_size); - else if(write_method == TILEDB_IO_MPI) + } else if(write_method == TILEDB_IO_MPI) { +#ifdef HAVE_MPI rc = mpi_io_write_to_file( mpi_comm, filename.c_str(), shifted_buffer, buffer_size); +#else + // Error: MPI not supported + std::string errmsg = + "Cannot write sparse variable attribute; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; +#endif + } // Clean up free(shifted_buffer); diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 081dc2d3..7dd811d0 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -635,6 +635,7 @@ bool is_workspace(const std::string& dir) { return false; } +#ifdef HAVE_MPI int mpi_io_read_from_file( const MPI_Comm* mpi_comm, const std::string& filename, @@ -804,6 +805,7 @@ int mpi_io_sync( // Success return TILEDB_UT_OK; } +#endif #ifdef HAVE_OPENMP int mutex_destroy(omp_lock_t* mtx) { diff --git a/core/src/storage_manager/config.cc b/core/src/storage_manager/config.cc index 2f05a80a..c4dc159d 100644 --- a/core/src/storage_manager/config.cc +++ b/core/src/storage_manager/config.cc @@ -47,7 +47,9 @@ Config::Config() { home_ = ""; read_method_ = TILEDB_IO_MMAP; write_method_ = TILEDB_IO_WRITE; +#ifdef HAVE_MPI mpi_comm_ = NULL; +#endif } Config::~Config() { @@ -62,7 +64,9 @@ Config::~Config() { void Config::init( const char* home, +#ifdef HAVE_MPI MPI_Comm* mpi_comm, +#endif int read_method, int write_method) { // Initialize home @@ -71,8 +75,10 @@ void Config::init( else home_ = home; +#ifdef HAVE_MPI // Initialize MPI communicator mpi_comm_ = mpi_comm; +#endif // Initialize read method read_method_ = read_method; @@ -99,9 +105,11 @@ const std::string& Config::home() const { return home_; } +#ifdef HAVE_MPI MPI_Comm* Config::mpi_comm() const { return mpi_comm_; } +#endif int Config::read_method() const { return read_method_; diff --git a/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc b/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc index 04986dd1..4604ddfb 100644 --- a/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc +++ b/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc @@ -34,12 +34,13 @@ */ #include "c_api.h" -#include #include #include +#ifdef HAVE_MPI +#include int main(int argc, char** argv) { // Initialize MPI and get rank @@ -124,3 +125,12 @@ int main(int argc, char** argv) { return 0; } +#else + +int main() { + printf("MPI not supported."); + + return 0; +} + +#endif From b8fb32208ee1d15b758eefd26153e59317c8dae6 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 26 Oct 2016 16:52:52 -0400 Subject: [PATCH 28/57] Minor typo. --- examples/src/tiledb_array_parallel_read_dense_2.cc | 2 +- examples/src/tiledb_array_parallel_read_mpi_io_dense.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/tiledb_array_parallel_read_dense_2.cc b/examples/src/tiledb_array_parallel_read_dense_2.cc index 1d05070e..b878b497 100644 --- a/examples/src/tiledb_array_parallel_read_dense_2.cc +++ b/examples/src/tiledb_array_parallel_read_dense_2.cc @@ -164,7 +164,7 @@ void parallel_read( #else int main() { - printf("OpenMP not supported."); + printf("OpenMP not supported.\n"); return 0; } diff --git a/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc b/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc index 4604ddfb..e7e73fc9 100644 --- a/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc +++ b/examples/src/tiledb_array_parallel_read_mpi_io_dense.cc @@ -128,7 +128,7 @@ int main(int argc, char** argv) { #else int main() { - printf("MPI not supported."); + printf("MPI not supported.\n"); return 0; } From a9b1ed82701af0236f5b0b709e0e0928809a42be Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 1 Nov 2016 13:30:18 -0400 Subject: [PATCH 29/57] Finished reading in the presence of empty regions --- core/include/array/array_read_state.h | 59 +- core/include/fragment/read_state.h | 12 + core/include/misc/utils.h | 15 + core/src/array/array.cc | 47 +- core/src/array/array_read_state.cc | 962 +++++++++++++++--- core/src/array/array_sorted_read_state.cc | 13 +- core/src/array/array_sorted_write_state.cc | 12 +- core/src/fragment/read_state.cc | 15 +- core/src/misc/utils.cc | 29 + examples/src/tiledb_array_read_dense_1.cc | 2 + .../src/tiledb_array_read_sorted_dense.cc | 1 - 11 files changed, 980 insertions(+), 187 deletions(-) diff --git a/core/include/array/array_read_state.h b/core/include/array/array_read_state.h index 56dc8a44..c8c6ccd5 100644 --- a/core/include/array/array_read_state.h +++ b/core/include/array/array_read_state.h @@ -292,7 +292,23 @@ class ArrayReadState { * Copies the cell ranges calculated in the current read round into the * targeted attribute buffer. * - * @template T The coordinates type. + * @param attribute_id The id of the targeted attribute. + * @param buffer The buffer where the read copy be performed into. + * @param buffer_size The size (in bytes) of *buffer*. + * @param buffer_offset The offset in *buffer* where the copy will start from. + * @return TILEDB_ARS on success and TILEDB_ARS_ERR on error. + */ + int copy_cells( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset); + + /** + * Copies the cell ranges calculated in the current read round into the + * targeted attribute buffer. + * + * @template T The attribute type. * @param attribute_id The id of the targeted attribute. * @param buffer The buffer where the read copy be performed into. * @param buffer_size The size (in bytes) of *buffer*. @@ -310,7 +326,32 @@ class ArrayReadState { * Copies the cell ranges calculated in the current read round into the * targeted attribute buffer, focusing on a **variable-sized** attribute. * - * @template T The coordinates type. + * @param attribute_id The id of the targeted attribute. + * @param buffer The buffer where the read will be performed into - offsets of + * cells in *buffer_var*. + * @param buffer_size The size (in bytes) of *buffer*. + * @param buffer_offset The offset in *buffer* where the copy will start from. + * @param buffer_var The buffer where the copy will be performed into - actual + * variable-sized cell values. + * @param buffer_var_size The size (in bytes) of *buffer_var*. + * @param buffer_var_offset The offset in *buffer_var* where the copy will + * start from. + * @return TILEDB_ARS on success and TILEDB_ARS_ERR on error. + */ + int copy_cells_var( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + void* buffer_var, + size_t buffer_var_size, + size_t& buffer_var_offset); + + /** + * Copies the cell ranges calculated in the current read round into the + * targeted attribute buffer, focusing on a **variable-sized** attribute. + * + * @template T The attribute type. * @param attribute_id The id of the targeted attribute. * @param buffer The buffer where the read will be performed into - offsets of * cells in *buffer_var*. @@ -337,7 +378,7 @@ class ArrayReadState { * Copies the cell ranges calculated in the current read round into the * targeted attribute buffer, filling with special empty values. * - * @template T The coordinates type. + * @template T The attribute type. * @param attribute_id The id of the targeted attribute. * @param buffer The buffer where the copy will be performed into. * @param buffer_size The size (in bytes) of *buffer*. @@ -358,7 +399,7 @@ class ArrayReadState { * targeted attribute buffer, feeling with special empty values, and focusing * on a **variable-sized** attribute. * - * @template T The coordinates type. + * @template T The attribute type. * @param attribute_id The id of the targeted attribute. * @param buffer The buffer where the read will be performed into - offsets of * cells in *buffer_var*. @@ -383,6 +424,15 @@ class ArrayReadState { size_t& buffer_var_offset, const CellPosRange& cell_pos_range); + /** + * Returns a list of cell ranges accounting for the empty area in the overlap + * between the subarray query and the current overlapping tile. + * + * @return A list of cell ranges representing empty cells. + */ + template + FragmentCellRanges empty_fragment_cell_ranges() const; + /** * Gets the next fragment cell ranges that are relevant in the current read * round, focusing on the dense case. @@ -390,7 +440,6 @@ class ArrayReadState { * @template T The coordinates type. * @return TILEDB_ARS_OK on success and TILEDB_ARS_ERR on error. */ - template int get_next_fragment_cell_ranges_dense(); diff --git a/core/include/fragment/read_state.h b/core/include/fragment/read_state.h index 81ed32be..303dd398 100644 --- a/core/include/fragment/read_state.h +++ b/core/include/fragment/read_state.h @@ -149,6 +149,12 @@ class ReadState { /** Returns *true* if the read buffers overflowed for the input attribute. */ bool overflow(int attribute_id) const; + /** + * True if the fragment non-empty domain fully covers the subarray area of + * the current overlapping tile. + */ + bool subarray_area_covered() const; + @@ -393,6 +399,7 @@ class ReadState { std::vector fetched_tile_; /** The fragment the read state belongs to. */ const Fragment* fragment_; + /** Keeps track of whether each attribute is empty or not. */ std::vector is_empty_attribute_; /** * Last investigated tile coordinates. Applicable only to **sparse** fragments @@ -439,6 +446,11 @@ class ReadState { void* search_tile_overlap_subarray_; /** The positions of the currently investigated tile. */ int64_t search_tile_pos_; + /** + * True if the fragment non-empty domain fully covers the subarray area + * in the current overlapping tile. + */ + bool subarray_area_covered_; /** Internal buffer used in the case of compression. */ void* tile_compressed_; /** Allocated size for internal buffer used in the case of compression. */ diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index 1bb4d685..705a3793 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -353,6 +353,21 @@ bool intersect(const std::vector& v1, const std::vector& v2); */ bool is_array(const std::string& dir); +/** + * Checks if one range is fully contained in another. + * + * @template The domain type + * @param range_A The first range. + * @param range_B The second range. + * @param dim_num The number of dimensions. + * @return True if range_A is fully contained in range_B. + */ +template +bool is_contained( + const T* range_A, + const T* range_B, + int dim_num); + /** * Checks if the input is an existing directory. * diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 5fe315f3..2693355d 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -280,11 +280,26 @@ int Array::read(void** buffers, size_t* buffer_sizes) { return TILEDB_AR_ERR; } + // Check if there are no fragments + int buffer_i = 0; + int attribute_id_num = attribute_ids_.size(); + if(fragments_.size() == 0) { + for(int i=0; ivar_size(attribute_ids_[i])) + ++buffer_i; + else + buffer_i += 2; + } + return TILEDB_AR_OK; + } + // Handle sorted modes if(mode_ == TILEDB_ARRAY_READ_SORTED_COL || mode_ == TILEDB_ARRAY_READ_SORTED_ROW) { - int rc = array_sorted_read_state_->read(buffers, buffer_sizes); - if(rc == TILEDB_ASRS_OK) { + if(array_sorted_read_state_->read(buffers, buffer_sizes) == + TILEDB_ASRS_OK) { return TILEDB_AR_OK; } else { tiledb_ar_errmsg = tiledb_asrs_errmsg; @@ -296,33 +311,13 @@ int Array::read(void** buffers, size_t* buffer_sizes) { } int Array::read_default(void** buffers, size_t* buffer_sizes) { - int buffer_i = 0; - int attribute_id_num = attribute_ids_.size(); - bool success = false; - - // Check if there are no fragments - if(fragments_.size() == 0) { - for(int i=0; ivar_size(attribute_ids_[i])) - ++buffer_i; - else - buffer_i += 2; - } - success = true; - } else { - if(array_read_state_->read(buffers, buffer_sizes) == TILEDB_ARS_OK) - success = true; - } - - // Return - if(success) { - return TILEDB_AR_OK; - } else { + if(array_read_state_->read(buffers, buffer_sizes) != TILEDB_ARS_OK) { tiledb_ar_errmsg = tiledb_ars_errmsg; return TILEDB_AR_ERR; } + + // Success + return TILEDB_AR_OK; } bool Array::read_mode() const { diff --git a/core/src/array/array_read_state.cc b/core/src/array/array_read_state.cc index d7e8b77c..107d58d4 100644 --- a/core/src/array/array_read_state.cc +++ b/core/src/array/array_read_state.cc @@ -293,7 +293,8 @@ int ArrayReadState::compute_unsorted_fragment_cell_ranges_dense( return TILEDB_ARS_ERR; } // Insert fragment cell ranges to the result - unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); + if(fragment_cell_ranges.size() != 0) + unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); } else { // SPARSE FragmentCellRanges fragment_cell_ranges; FragmentCellRanges fragment_cell_ranges_tmp; @@ -316,7 +317,8 @@ int ArrayReadState::compute_unsorted_fragment_cell_ranges_dense( fragment_cell_ranges_tmp.end()); } while(!fragment_read_states_[i]->done() && fragment_read_states_[i]->mbr_overlaps_tile()); - unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); + if(fragment_cell_ranges.size() != 0) + unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); } } else { // Append an empty list @@ -324,6 +326,21 @@ int ArrayReadState::compute_unsorted_fragment_cell_ranges_dense( } } + // Check if some dense fragment completely covers the subarray + bool subarray_area_covered = false; + for(int i=0; idone() && + fragment_read_states_[i]->dense() && + fragment_read_states_[i]->subarray_area_covered()) { + subarray_area_covered = true; + break; + } + } + + // Add a fragment that accounts for the empty areas of the array + if(!subarray_area_covered) + unsorted_fragment_cell_ranges.push_back(empty_fragment_cell_ranges()); + // Success return TILEDB_ARS_OK; } @@ -386,6 +403,55 @@ int ArrayReadState::compute_unsorted_fragment_cell_ranges_sparse( return TILEDB_ARS_OK; } +int ArrayReadState::copy_cells( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset) { + // For easy reference + int type = array_schema_->type(attribute_id); + + // Invoke the proper templated function + int rc; + if(type == TILEDB_INT32) + rc = copy_cells( + attribute_id, + buffer, + buffer_size, + buffer_offset); + else if(type == TILEDB_INT64) + rc = copy_cells( + attribute_id, + buffer, + buffer_size, + buffer_offset); + else if(type == TILEDB_FLOAT32) + rc = copy_cells( + attribute_id, + buffer, + buffer_size, + buffer_offset); + else if(type == TILEDB_FLOAT64) + rc = copy_cells( + attribute_id, + buffer, + buffer_size, + buffer_offset); + else if(type == TILEDB_CHAR) + rc = copy_cells( + attribute_id, + buffer, + buffer_size, + buffer_offset); + + // Handle error + if(rc != TILEDB_ARS_OK) + return TILEDB_ARS_ERR; + + // Success + return TILEDB_ARS_OK; +} + template int ArrayReadState::copy_cells( int attribute_id, @@ -450,142 +516,654 @@ int ArrayReadState::copy_cells( read_round_done_[attribute_id] = false; } - // Success - return TILEDB_ARS_OK; + // Success + return TILEDB_ARS_OK; +} + +int ArrayReadState::copy_cells_var( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + void* buffer_var, + size_t buffer_var_size, + size_t& buffer_var_offset) { + // For easy reference + int type = array_schema_->type(attribute_id); + + // Invoke the proper templated function + int rc; + if(type == TILEDB_INT32) + rc = copy_cells_var( + attribute_id, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset); + else if(type == TILEDB_INT64) + rc = copy_cells_var( + attribute_id, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset); + else if(type == TILEDB_FLOAT32) + rc = copy_cells_var( + attribute_id, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset); + else if(type == TILEDB_FLOAT64) + rc = copy_cells_var( + attribute_id, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset); + else if(type == TILEDB_CHAR) + rc = copy_cells_var( + attribute_id, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset); + + // Handle error + if(rc != TILEDB_ARS_OK) + return TILEDB_ARS_ERR; + + // Success + return TILEDB_ARS_OK; +} + +template +int ArrayReadState::copy_cells_var( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + void* buffer_var, + size_t buffer_var_size, + size_t& buffer_var_offset) { + // For easy reference + int64_t pos = fragment_cell_pos_ranges_vec_pos_[attribute_id]; + FragmentCellPosRanges& fragment_cell_pos_ranges = + *fragment_cell_pos_ranges_vec_[pos]; + int64_t fragment_cell_pos_ranges_num = fragment_cell_pos_ranges.size(); + int fragment_id; // Fragment id + int64_t tile_pos; // Tile position in the fragment + + // Sanity check + assert(array_schema_->var_size(attribute_id)); + + // Copy the cell ranges one by one + for(int64_t i=0; i( + attribute_id, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset, + cell_pos_range); + if(overflow_[attribute_id]) + break; + else + continue; + } + + // Handle non-empty fragment + if(fragment_read_states_[fragment_id]->copy_cells_var( + attribute_id, + tile_pos, + buffer, + buffer_size, + buffer_offset, + buffer_var, + buffer_var_size, + buffer_var_offset, + cell_pos_range) != TILEDB_RS_OK) { + tiledb_ars_errmsg = tiledb_rs_errmsg; + return TILEDB_ARS_ERR; + } + + // Handle overflow + if(fragment_read_states_[fragment_id]->overflow(attribute_id)) { + overflow_[attribute_id] = true; + break; + } + } + + // Handle the case the read round is done for this attribute + if(!overflow_[attribute_id]) { + ++fragment_cell_pos_ranges_vec_pos_[attribute_id]; + read_round_done_[attribute_id] = true; + } else { + read_round_done_[attribute_id] = false; + } + + // Success + return TILEDB_ARS_OK; +} + +template<> +void ArrayReadState::copy_cells_with_empty( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + const CellPosRange& cell_pos_range) { + + // For easy reference + size_t cell_size = array_schema_->cell_size(attribute_id); + char* buffer_c = static_cast(buffer); + int cell_val_num = array_schema_->cell_val_num(attribute_id); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + if(buffer_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } + + // Sanity check + assert(!array_schema_->var_size(attribute_id)); + + // Calculate number of empty cells to write + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + + // Copy empty cells to buffer + int empty = TILEDB_EMPTY_INT32; + for(int64_t i=0; i +void ArrayReadState::copy_cells_with_empty( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + const CellPosRange& cell_pos_range) { + // For easy reference + size_t cell_size = array_schema_->cell_size(attribute_id); + char* buffer_c = static_cast(buffer); + int cell_val_num = array_schema_->cell_val_num(attribute_id); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + if(buffer_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } + + // Sanity check + assert(!array_schema_->var_size(attribute_id)); + + // Calculate number of empty cells to write + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + + // Copy empty cells to buffer + int64_t empty = TILEDB_EMPTY_INT64; + for(int64_t i=0; i +void ArrayReadState::copy_cells_with_empty( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + const CellPosRange& cell_pos_range) { + // For easy reference + size_t cell_size = array_schema_->cell_size(attribute_id); + char* buffer_c = static_cast(buffer); + int cell_val_num = array_schema_->cell_val_num(attribute_id); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + if(buffer_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } + + // Sanity check + assert(!array_schema_->var_size(attribute_id)); + + // Calculate number of empty cells to write + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + + // Copy empty cells to buffer + float empty = TILEDB_EMPTY_FLOAT32; + for(int64_t i=0; i +void ArrayReadState::copy_cells_with_empty( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + const CellPosRange& cell_pos_range) { + // For easy reference + size_t cell_size = array_schema_->cell_size(attribute_id); + char* buffer_c = static_cast(buffer); + int cell_val_num = array_schema_->cell_val_num(attribute_id); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + if(buffer_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } + + // Sanity check + assert(!array_schema_->var_size(attribute_id)); + + // Calculate number of empty cells to write + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + + // Copy empty cells to buffer + double empty = TILEDB_EMPTY_FLOAT64; + for(int64_t i=0; i +void ArrayReadState::copy_cells_with_empty( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + const CellPosRange& cell_pos_range) { + // For easy reference + size_t cell_size = array_schema_->cell_size(attribute_id); + char* buffer_c = static_cast(buffer); + int cell_val_num = array_schema_->cell_val_num(attribute_id); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + if(buffer_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } + + // Sanity check + assert(!array_schema_->var_size(attribute_id)); + + // Calculate number of empty cells to write + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + + // Copy empty cells to buffer + char empty = TILEDB_EMPTY_CHAR; + for(int64_t i=0; i +void ArrayReadState::copy_cells_with_empty_var( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + void* buffer_var, + size_t buffer_var_size, + size_t& buffer_var_offset, + const CellPosRange& cell_pos_range) { + // For easy reference + size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; + size_t cell_size_var = sizeof(int); + char* buffer_c = static_cast(buffer); + char* buffer_var_c = static_cast(buffer_var); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + size_t buffer_var_free_space = buffer_var_size - buffer_var_offset; + buffer_var_free_space = (buffer_var_free_space/cell_size_var)*cell_size_var; + + // Handle overflow + if(buffer_free_space == 0 || buffer_var_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } + + // Sanity check + assert(array_schema_->var_size(attribute_id)); + + // Calculate cell number to copy + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_left_to_copy_var = cell_num_left_to_copy * cell_size_var; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + size_t bytes_to_copy_var = + std::min(bytes_left_to_copy_var, buffer_var_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + int64_t cell_num_to_copy_var = bytes_to_copy_var / cell_size_var; + cell_num_to_copy = std::min(cell_num_to_copy, cell_num_to_copy_var); + + // Copy empty cells to buffers + int empty = TILEDB_EMPTY_INT32; + for(int64_t i=0; i -int ArrayReadState::copy_cells_var( +template<> +void ArrayReadState::copy_cells_with_empty_var( int attribute_id, void* buffer, size_t buffer_size, size_t& buffer_offset, void* buffer_var, size_t buffer_var_size, - size_t& buffer_var_offset) { + size_t& buffer_var_offset, + const CellPosRange& cell_pos_range) { // For easy reference - int64_t pos = fragment_cell_pos_ranges_vec_pos_[attribute_id]; - FragmentCellPosRanges& fragment_cell_pos_ranges = - *fragment_cell_pos_ranges_vec_[pos]; - int64_t fragment_cell_pos_ranges_num = fragment_cell_pos_ranges.size(); - int fragment_id; // Fragment id - int64_t tile_pos; // Tile position in the fragment + size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; + size_t cell_size_var = sizeof(int64_t); + char* buffer_c = static_cast(buffer); + char* buffer_var_c = static_cast(buffer_var); + + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + size_t buffer_var_free_space = buffer_var_size - buffer_var_offset; + buffer_var_free_space = (buffer_var_free_space/cell_size_var)*cell_size_var; + + // Handle overflow + if(buffer_free_space == 0 || buffer_var_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; + } // Sanity check assert(array_schema_->var_size(attribute_id)); - // Copy the cell ranges one by one - for(int64_t i=0; i( - attribute_id, - buffer, - buffer_size, - buffer_offset, - buffer_var, - buffer_var_size, - buffer_var_offset, - cell_pos_range); - if(overflow_[attribute_id]) - break; - else - continue; - } + // Copy empty cells to buffers + int64_t empty = TILEDB_EMPTY_INT64; + for(int64_t i=0; icopy_cells_var( - attribute_id, - tile_pos, - buffer, - buffer_size, - buffer_offset, - buffer_var, - buffer_var_size, - buffer_var_offset, - cell_pos_range) != TILEDB_RS_OK) { - tiledb_ars_errmsg = tiledb_rs_errmsg; - return TILEDB_ARS_ERR; - } + // Handle buffer overflow + if(empty_cells_written_[attribute_id] != cell_num_in_range) + overflow_[attribute_id] = true; + else // Done copying this range + empty_cells_written_[attribute_id] = 0; +} - // Handle overflow - if(fragment_read_states_[fragment_id]->overflow(attribute_id)) { - overflow_[attribute_id] = true; - break; - } - } +template<> +void ArrayReadState::copy_cells_with_empty_var( + int attribute_id, + void* buffer, + size_t buffer_size, + size_t& buffer_offset, + void* buffer_var, + size_t buffer_var_size, + size_t& buffer_var_offset, + const CellPosRange& cell_pos_range) { + // For easy reference + size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; + size_t cell_size_var = sizeof(float); + char* buffer_c = static_cast(buffer); + char* buffer_var_c = static_cast(buffer_var); - // Handle the case the read round is done for this attribute - if(!overflow_[attribute_id]) { - ++fragment_cell_pos_ranges_vec_pos_[attribute_id]; - read_round_done_[attribute_id] = true; - } else { - read_round_done_[attribute_id] = false; + // Calculate free space in buffer + size_t buffer_free_space = buffer_size - buffer_offset; + buffer_free_space = (buffer_free_space / cell_size) * cell_size; + size_t buffer_var_free_space = buffer_var_size - buffer_var_offset; + buffer_var_free_space = (buffer_var_free_space/cell_size_var)*cell_size_var; + + // Handle overflow + if(buffer_free_space == 0 || buffer_var_free_space == 0) { // Overflow + overflow_[attribute_id] = true; + return; } - // Success - return TILEDB_ARS_OK; + // Sanity check + assert(array_schema_->var_size(attribute_id)); + + // Calculate cell number to copy + int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; + int64_t cell_num_left_to_copy = + cell_num_in_range - empty_cells_written_[attribute_id]; + size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_left_to_copy_var = cell_num_left_to_copy * cell_size_var; + size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + size_t bytes_to_copy_var = + std::min(bytes_left_to_copy_var, buffer_var_free_space); + int64_t cell_num_to_copy = bytes_to_copy / cell_size; + int64_t cell_num_to_copy_var = bytes_to_copy_var / cell_size_var; + cell_num_to_copy = std::min(cell_num_to_copy, cell_num_to_copy_var); + + // Copy empty cells to buffers + float empty = TILEDB_EMPTY_FLOAT32; + for(int64_t i=0; i -void ArrayReadState::copy_cells_with_empty( +template<> +void ArrayReadState::copy_cells_with_empty_var( int attribute_id, void* buffer, size_t buffer_size, size_t& buffer_offset, + void* buffer_var, + size_t buffer_var_size, + size_t& buffer_var_offset, const CellPosRange& cell_pos_range) { // For easy reference - size_t cell_size = array_schema_->cell_size(attribute_id); + size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; + size_t cell_size_var = sizeof(double); char* buffer_c = static_cast(buffer); + char* buffer_var_c = static_cast(buffer_var); // Calculate free space in buffer size_t buffer_free_space = buffer_size - buffer_offset; buffer_free_space = (buffer_free_space / cell_size) * cell_size; - if(buffer_free_space == 0) { // Overflow - overflow_[attribute_id] = true; + size_t buffer_var_free_space = buffer_var_size - buffer_var_offset; + buffer_var_free_space = (buffer_var_free_space/cell_size_var)*cell_size_var; + + // Handle overflow + if(buffer_free_space == 0 || buffer_var_free_space == 0) { // Overflow + overflow_[attribute_id] = true; return; } // Sanity check - assert(!array_schema_->var_size(attribute_id)); + assert(array_schema_->var_size(attribute_id)); - // Calculate number of empty cells to write + // Calculate cell number to copy int64_t cell_num_in_range = cell_pos_range.second - cell_pos_range.first + 1; int64_t cell_num_left_to_copy = cell_num_in_range - empty_cells_written_[attribute_id]; size_t bytes_left_to_copy = cell_num_left_to_copy * cell_size; + size_t bytes_left_to_copy_var = cell_num_left_to_copy * cell_size_var; size_t bytes_to_copy = std::min(bytes_left_to_copy, buffer_free_space); + size_t bytes_to_copy_var = + std::min(bytes_left_to_copy_var, buffer_var_free_space); int64_t cell_num_to_copy = bytes_to_copy / cell_size; + int64_t cell_num_to_copy_var = bytes_to_copy_var / cell_size_var; + cell_num_to_copy = std::min(cell_num_to_copy, cell_num_to_copy_var); - // Get the empty value - int type = array_schema_->type(attribute_id); - void* empty_cell = malloc(cell_size); - if(type == TILEDB_INT32) { - int empty_cell_v = TILEDB_EMPTY_INT32; - memcpy(empty_cell, &empty_cell_v, cell_size); - } else if(type == TILEDB_INT64) { - int64_t empty_cell_v = TILEDB_EMPTY_INT64; - memcpy(empty_cell, &empty_cell_v, cell_size); - } else if(type == TILEDB_FLOAT32) { - float empty_cell_v = TILEDB_EMPTY_FLOAT32; - memcpy(empty_cell, &empty_cell_v, cell_size); - } else if(type == TILEDB_FLOAT64) { - double empty_cell_v = TILEDB_EMPTY_FLOAT64; - memcpy(empty_cell, &empty_cell_v, cell_size); - } else if(type == TILEDB_CHAR) { - char empty_cell_v = TILEDB_EMPTY_CHAR; - memcpy(empty_cell, &empty_cell_v, cell_size); - } - - // Copy empty cells to buffer + // Copy empty cells to buffers + double empty = TILEDB_EMPTY_FLOAT64; for(int64_t i=0; i -void ArrayReadState::copy_cells_with_empty_var( +template<> +void ArrayReadState::copy_cells_with_empty_var( int attribute_id, void* buffer, size_t buffer_size, @@ -610,6 +1185,7 @@ void ArrayReadState::copy_cells_with_empty_var( const CellPosRange& cell_pos_range) { // For easy reference size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; + size_t cell_size_var = sizeof(char); char* buffer_c = static_cast(buffer); char* buffer_var_c = static_cast(buffer_var); @@ -617,6 +1193,7 @@ void ArrayReadState::copy_cells_with_empty_var( size_t buffer_free_space = buffer_size - buffer_offset; buffer_free_space = (buffer_free_space / cell_size) * cell_size; size_t buffer_var_free_space = buffer_var_size - buffer_var_offset; + buffer_var_free_space = (buffer_var_free_space/cell_size_var)*cell_size_var; // Handle overflow if(buffer_free_space == 0 || buffer_var_free_space == 0) { // Overflow @@ -624,32 +1201,6 @@ void ArrayReadState::copy_cells_with_empty_var( return; } - // Get the empty value - int type = array_schema_->type(attribute_id); - void* empty_cell = malloc(cell_size); - size_t cell_size_var; - if(type == TILEDB_INT32) { - int empty_cell_v = TILEDB_EMPTY_INT32; - memcpy(empty_cell, &empty_cell_v, cell_size); - cell_size_var = sizeof(int); - } else if(type == TILEDB_INT64) { - int64_t empty_cell_v = TILEDB_EMPTY_INT64; - memcpy(empty_cell, &empty_cell_v, cell_size); - cell_size_var = sizeof(int64_t); - } else if(type == TILEDB_FLOAT32) { - float empty_cell_v = TILEDB_EMPTY_FLOAT32; - memcpy(empty_cell, &empty_cell_v, cell_size); - cell_size_var = sizeof(float); - } else if(type == TILEDB_FLOAT64) { - double empty_cell_v = TILEDB_EMPTY_FLOAT64; - memcpy(empty_cell, &empty_cell_v, cell_size); - cell_size_var = sizeof(double); - } else if(type == TILEDB_CHAR) { - char empty_cell_v = TILEDB_EMPTY_CHAR; - memcpy(empty_cell, &empty_cell_v, cell_size); - cell_size_var = sizeof(char); - } - // Sanity check assert(array_schema_->var_size(attribute_id)); @@ -667,6 +1218,7 @@ void ArrayReadState::copy_cells_with_empty_var( cell_num_to_copy = std::min(cell_num_to_copy, cell_num_to_copy_var); // Copy empty cells to buffers + char empty = TILEDB_EMPTY_CHAR; for(int64_t i=0; i +ArrayReadState::FragmentCellRanges +ArrayReadState::empty_fragment_cell_ranges() const { + // For easy reference + int dim_num = array_schema_->dim_num(); + int cell_order = array_schema_->cell_order(); + size_t cell_range_size = 2*coords_size_; + const T* subarray = static_cast(array_->subarray()); + const T* tile_coords = (const T*) subarray_tile_coords_; + + // To return + FragmentInfo fragment_info = FragmentInfo(-1, -1); + FragmentCellRanges fragment_cell_ranges; + + // Compute the tile subarray + T* tile_subarray = new T[2*dim_num]; + array_schema_->get_tile_subarray(tile_coords, tile_subarray); + + // Compute overlap of tile subarray with non-empty fragment domain + T* query_tile_overlap_subarray = new T[2*dim_num]; + int overlap = array_schema_->subarray_overlap( + subarray, + tile_subarray, + query_tile_overlap_subarray); + + // Contiguous cells, single cell range + if(overlap == 1 || overlap == 3) { + void* cell_range = malloc(cell_range_size); + T* cell_range_T = static_cast(cell_range); + for(int i=0; i(cell_range); + for(int i=0; i 0 && coords[i] > query_tile_overlap_subarray[2*i+1]) { + coords[i] = query_tile_overlap_subarray[2*i]; + ++coords[--i]; + } + } + } else if(cell_order == TILEDB_COL_MAJOR) { // COLUMN + while(coords[dim_num-1] <= + query_tile_overlap_subarray[2*(dim_num-1)+1]) { + // Make a cell range representing a slab + void* cell_range = malloc(cell_range_size); + T* cell_range_T = static_cast(cell_range); + for(int i=dim_num-1; i>0; --i) { + cell_range_T[i] = coords[i]; + cell_range_T[dim_num+i] = coords[i]; + } + cell_range_T[0] = query_tile_overlap_subarray[0]; + cell_range_T[dim_num] = query_tile_overlap_subarray[1]; + + // Insert the new range into the result vector + fragment_cell_ranges.push_back( + FragmentCellRange(fragment_info, cell_range)); + + // Advance coordinates + i=1; + ++coords[i]; + while(i query_tile_overlap_subarray[2*i+1]) { + coords[i] = query_tile_overlap_subarray[2*i]; + ++coords[++i]; + } + } + } else { + assert(0); + } + + // Clean up + delete [] coords; + } // Clean up - free(empty_cell); + delete [] tile_subarray; + delete [] query_tile_overlap_subarray; + + // Return + return fragment_cell_ranges; } template @@ -1048,7 +1708,7 @@ int ArrayReadState::read_dense_attr( for(;;) { // Continue copying from the previous unfinished read round if(!read_round_done_[attribute_id]) - if(copy_cells( + if(copy_cells( attribute_id, buffer, buffer_size, @@ -1078,13 +1738,13 @@ int ArrayReadState::read_dense_attr( } // Copy cells to buffers - if(copy_cells( - attribute_id, + if(copy_cells( + attribute_id, buffer, buffer_size, buffer_offset) != TILEDB_ARS_OK) return TILEDB_ARS_ERR; - + // Check for buffer overflow if(overflow_[attribute_id]) { buffer_size = buffer_offset; @@ -1140,7 +1800,7 @@ int ArrayReadState::read_dense_attr_var( for(;;) { // Continue copying from the previous unfinished read round if(!read_round_done_[attribute_id]) - if(copy_cells_var( + if(copy_cells_var( attribute_id, buffer, buffer_size, @@ -1175,7 +1835,7 @@ int ArrayReadState::read_dense_attr_var( } // Copy cells to buffers - if(copy_cells_var( + if(copy_cells_var( attribute_id, buffer, buffer_size, @@ -1306,7 +1966,7 @@ int ArrayReadState::read_sparse_attr( for(;;) { // Continue copying from the previous unfinished read round if(!read_round_done_[attribute_id]) - if(copy_cells( + if(copy_cells( attribute_id, buffer, buffer_size, @@ -1336,7 +1996,7 @@ int ArrayReadState::read_sparse_attr( } // Copy cells to buffers - if(copy_cells( + if(copy_cells( attribute_id, buffer, buffer_size, @@ -1412,7 +2072,7 @@ int ArrayReadState::read_sparse_attr_var( for(;;) { // Continue copying from the previous unfinished read round if(!read_round_done_[attribute_id]) - if(copy_cells_var( + if(copy_cells_var( attribute_id, buffer, buffer_size, @@ -1447,7 +2107,7 @@ int ArrayReadState::read_sparse_attr_var( } // Copy cells to buffers - if(copy_cells_var( + if(copy_cells_var( attribute_id, buffer, buffer_size, @@ -1470,11 +2130,14 @@ template int ArrayReadState::sort_fragment_cell_ranges( std::vector& unsorted_fragment_cell_ranges, FragmentCellRanges& fragment_cell_ranges) const { + // For easy reference + int fragment_num = (int) unsorted_fragment_cell_ranges.size(); + // Sanity check - assert(fragment_num_ > 0); + assert(fragment_num > 0); // Trivial case - single fragment - if(fragment_num_ == 1) { + if(fragment_num == 1) { fragment_cell_ranges = unsorted_fragment_cell_ranges[0]; unsorted_fragment_cell_ranges.clear(); return TILEDB_ARS_OK; @@ -1499,10 +2162,10 @@ int ArrayReadState::sort_fragment_cell_ranges( } // Initialization of book-keeping for unsorted ranges - int64_t* rlen = new int64_t[fragment_num_]; - int64_t* rid = new int64_t[fragment_num_]; + int64_t* rlen = new int64_t[fragment_num]; + int64_t* rid = new int64_t[fragment_num]; int fid = 0; - for(int i=0; i*, std::vector* >, SmallerPQFragmentCellRange > pq(array_schema_); - for(int i=0; i( array_schema_, @@ -1544,7 +2208,9 @@ int ArrayReadState::sort_fragment_cell_ranges( if(pq.empty()) { popped->export_to(result); fragment_cell_ranges.push_back(result); - fid = popped->fragment_id_; + fid = (popped->fragment_id_ != -1) ? + popped->fragment_id_ : + fragment_num-1; delete popped; if(rid[fid] == rlen[fid]) { @@ -1586,7 +2252,9 @@ int ArrayReadState::sort_fragment_cell_ranges( pq.push(trimmed_top); } else { // Get the next range from the top fragment - fid = trimmed_top->fragment_id_; + fid = (trimmed_top->fragment_id_ != -1) ? + trimmed_top->fragment_id_ : + fragment_num-1; if(rid[fid] != rlen[fid]) { pq_fragment_cell_range = new PQFragmentCellRange( array_schema_, @@ -1601,7 +2269,9 @@ int ArrayReadState::sort_fragment_cell_ranges( } } else { // Get the next range from the top fragment - fid = top->fragment_id_; + fid = (top->fragment_id_ != -1) ? + top->fragment_id_ : + fragment_num-1; if(rid[fid] != rlen[fid]) { pq_fragment_cell_range = new PQFragmentCellRange( array_schema_, @@ -1638,7 +2308,9 @@ int ArrayReadState::sort_fragment_cell_ranges( pq.push(extra_popped); } else { // Get the next range from popped fragment - fid = popped->fragment_id_; + fid = (popped->fragment_id_ != -1) ? + popped->fragment_id_ : + fragment_num-1; if(rid[fid] != rlen[fid]) { pq_fragment_cell_range = new PQFragmentCellRange( array_schema_, diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 079f4178..697bdc4a 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -483,7 +483,9 @@ void ArraySortedReadState::advance_cell_slab_col(int aid) { current_coords[d] += cell_slab_num; int64_t dim_overflow; for(int i=0; i0; --i) { - dim_overflow = current_coords[i] / (tile_slab[2*i+1]-tile_slab[2*i]+1); + dim_overflow = + (current_coords[i] - tile_slab[2*i]) / + (tile_slab[2*i+1]-tile_slab[2*i]+1); current_coords[i-1] += dim_overflow; current_coords[i] -= dim_overflow * (tile_slab[2*i+1]-tile_slab[2*i]+1); } @@ -603,7 +607,7 @@ void *ArraySortedReadState::aio_done(void* data) { // Manage the mutexes and conditions asrs->release_aio(id); } - + return NULL; } @@ -1588,9 +1592,6 @@ void ArraySortedReadState::handle_copy_requests_sparse() { // Sort the cell positions if(copy_tile_slab_done()) { - -std::cout << "resetting...\n"; - reset_tile_slab_state(); sort_cell_pos(); } diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 57d1be2d..992e69a4 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -136,6 +136,7 @@ ArraySortedWriteState::~ArraySortedWriteState() { aio_thread_canceled_ = true; for(int i=0; i<2; ++i) release_copy(i); + // Wait for thread to be destroyed while(aio_thread_running_); @@ -336,7 +337,9 @@ void ArraySortedWriteState::advance_cell_slab_col(int aid) { current_coords[d] += cell_slab_num; int64_t dim_overflow; for(int i=0; i0; --i) { - dim_overflow = current_coords[i] / (tile_slab[2*i+1]-tile_slab[2*i]+1); + dim_overflow = + (current_coords[i] - tile_slab[2*i]) / + (tile_slab[2*i+1]-tile_slab[2*i]+1); current_coords[i-1] += dim_overflow; current_coords[i] -= dim_overflow * (tile_slab[2*i+1]-tile_slab[2*i]+1); } @@ -1270,6 +1275,7 @@ void ArraySortedWriteState::init_aio_requests() { // For easy reference int mode = array_->mode(); int tile_order = array_->array_schema()->tile_order(); + const void* subarray = array_->subarray(); bool separate_fragments = (mode == TILEDB_ARRAY_WRITE_SORTED_COL && tile_order == TILEDB_ROW_MAJOR) || (mode == TILEDB_ARRAY_WRITE_SORTED_ROW && tile_order == TILEDB_COL_MAJOR); @@ -1282,7 +1288,7 @@ void ArraySortedWriteState::init_aio_requests() { aio_request_[i].buffer_sizes_ = copy_state_.buffer_offsets_[i]; aio_request_[i].buffers_ = copy_state_.buffers_[i]; aio_request_[i].mode_ = TILEDB_ARRAY_WRITE; - aio_request_[i].subarray_ = (separate_fragments) ? tile_slab_[i] : NULL; + aio_request_[i].subarray_ = (separate_fragments) ? tile_slab_[i] : subarray; aio_request_[i].completion_handle_ = aio_done; aio_request_[i].completion_data_ = &(aio_data_[i]); aio_request_[i].overflow_ = NULL; diff --git a/core/src/fragment/read_state.cc b/core/src/fragment/read_state.cc index d6c6fa5c..fd1e3583 100644 --- a/core/src/fragment/read_state.cc +++ b/core/src/fragment/read_state.cc @@ -224,6 +224,10 @@ bool ReadState::overflow(int attribute_id) const { return overflow_[attribute_id]; } +bool ReadState::subarray_area_covered() const { + return subarray_area_covered_; +} + @@ -610,6 +614,7 @@ int ReadState::get_fragment_cell_ranges_dense( cell_range_T[dim_num + i] = search_tile_overlap_subarray[2*i+1]; } + // Insert the new range into the result vector fragment_cell_ranges.push_back( FragmentCellRange(fragment_info, cell_range)); } else { // Non-contiguous cells, multiple ranges @@ -836,7 +841,7 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { const T* domain = static_cast(book_keeping_->domain()); const T* non_empty_domain = static_cast(book_keeping_->non_empty_domain()); - + // Compute the tile subarray T* tile_subarray = new T[2*dim_num]; array_schema_->get_tile_subarray(tile_coords, tile_subarray); @@ -851,6 +856,7 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { if(!tile_domain_overlap) { // No overlap with the input tile search_tile_overlap_ = 0; + subarray_area_covered_ = false; } else { // Overlap with the input tile // Find the search tile position T* tile_coords_norm = new T[dim_num]; @@ -874,6 +880,13 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { tile_domain_overlap_subarray, static_cast(search_tile_overlap_subarray_)); + // Check if expanded fragment domain fully covers the tile + subarray_area_covered_ = + is_contained( + query_tile_overlap_subarray, + tile_domain_overlap_subarray, + dim_num); + // Clean up delete [] query_tile_overlap_subarray; } diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 7dd811d0..b7dd632b 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -559,6 +559,18 @@ bool is_array(const std::string& dir) { return false; } +template +bool is_contained( + const T* range_A, + const T* range_B, + int dim_num) { + for(int i=0; i range_B[2*i+1]) + return false; + + return true; +} + bool is_dir(const std::string& dir) { struct stat st; return stat(dir.c_str(), &st) == 0 && S_ISDIR(st.st_mode); @@ -1398,6 +1410,23 @@ template bool intersect( const std::vector& v1, const std::vector& v2); +template bool is_contained( + const int* range_A, + const int* range_B, + int dim_num); +template bool is_contained( + const int64_t* range_A, + const int64_t* range_B, + int dim_num); +template bool is_contained( + const float* range_A, + const float* range_B, + int dim_num); +template bool is_contained( + const double* range_A, + const double* range_B, + int dim_num); + template bool is_unary_subarray(const int* subarray, int dim_num); template bool is_unary_subarray(const int64_t* subarray, int dim_num); template bool is_unary_subarray(const float* subarray, int dim_num); diff --git a/examples/src/tiledb_array_read_dense_1.cc b/examples/src/tiledb_array_read_dense_1.cc index 7c3ce4b3..a5278ebb 100644 --- a/examples/src/tiledb_array_read_dense_1.cc +++ b/examples/src/tiledb_array_read_dense_1.cc @@ -77,6 +77,8 @@ int main() { : buffer_sizes[2] - buffer_a2[i]; printf("\t %4.*s", int(var_size), &buffer_var_a2[buffer_a2[i]]); printf("\t\t (%5.1f, %5.1f)\n", buffer_a3[2*i], buffer_a3[2*i+1]); + } else { + printf("\t\t Empty cell\n"); } } diff --git a/examples/src/tiledb_array_read_sorted_dense.cc b/examples/src/tiledb_array_read_sorted_dense.cc index 5b4a9b8d..92b5beb7 100644 --- a/examples/src/tiledb_array_read_sorted_dense.cc +++ b/examples/src/tiledb_array_read_sorted_dense.cc @@ -60,7 +60,6 @@ int main() { void* buffers[] = { buffer_a1 }; size_t buffer_sizes[] = { sizeof(buffer_a1) }; - // Loop until no overflow printf(" a1\n----\n"); do { From faa1035b6a43956d4d50e1a64be5b4d7da6924bb Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 9 Nov 2016 18:49:21 -0500 Subject: [PATCH 30/57] Bug fix in sorted reads with overflow --- core/include/array/array_sorted_read_state.h | 40 ++++++++++++++++++++ core/src/array/array_sorted_read_state.cc | 16 ++++++-- examples/src/tiledb_array_read_dense_2.cc | 2 +- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index cdb56485..71ffeee4 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -335,6 +335,15 @@ class ArraySortedReadState { /** The number of dimensions in the array. */ int dim_num_; + /** Flag indicating whether the read is done or an overflow occurred. */ + bool done_or_overflow_; + + /** The done or overflow mutex condition. */ + pthread_cond_t done_or_overflow_cond_; + + /** The done or overflow mutex. */ + pthread_mutex_t done_or_overflow_mtx_; + /** * Used only in the sparse case. It is true if the coordinates are not asked * by the user and, thus, TileDB had to append them as an extra attribute @@ -462,6 +471,9 @@ class ArraySortedReadState { /** Sets the flag of wait_copy_[id] to true. */ void block_copy(int id); + /** Sets the flag of done_or_overflow_ to true. */ + void block_done_or_overflow(); + /** Sets the flag of resume_copy_ to true. */ void block_overflow(); @@ -847,6 +859,13 @@ class ArraySortedReadState { */ int lock_copy_mtx(); + /** + * Locks the done or overflow mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int lock_done_or_overflow_mtx(); + /** * Locks the overflow mutex. * @@ -973,6 +992,13 @@ class ArraySortedReadState { */ int release_copy(int id); + /** + * Signals the done or overflow condition. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int release_done_or_overflow(); + /** * Signals the overflow condition. * @@ -1039,6 +1065,13 @@ class ArraySortedReadState { */ int unlock_copy_mtx(); + /** + * Unlocks the done or overflow mutex. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int unlock_done_or_overflow_mtx(); + /** * Unlocks the overflow mutex. * @@ -1073,6 +1106,13 @@ class ArraySortedReadState { */ int wait_aio(int id); + /** + * Waits until the read is done or there is a buffer overflow. + * + * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. + */ + int wait_done_or_overflow(); + /** * Waits until there is no buffer overflow. * diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 697bdc4a..842e38e5 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -268,7 +268,8 @@ int ArraySortedReadState::read(void** buffers, size_t* buffer_sizes) { // Resume the copy request handling if(resume_copy_) { - block_copy(copy_id_); + block_copy(1); + block_copy(0); release_aio(copy_id_); release_overflow(); } @@ -1108,7 +1109,7 @@ void *ArraySortedReadState::copy_handler(void* context) { asrs->handle_copy_requests_dense(); else assert(0); - } else { // SPARSE + } else { // SPARSE if(coords_type == TILEDB_INT32) asrs->handle_copy_requests_sparse(); else if(coords_type == TILEDB_INT64) @@ -1565,7 +1566,8 @@ void ArraySortedReadState::handle_copy_requests_dense() { if(overflow()) { block_overflow(); block_aio(copy_id_); - release_copy(copy_id_); + release_copy(0); + release_copy(1); wait_overflow(); continue; } @@ -2828,6 +2830,10 @@ int ArraySortedReadState::wait_copy(int id) { } int ArraySortedReadState::wait_overflow() { + // Lock overflow mutex + if(lock_overflow_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + // Wait to be signaled while(overflow()) { if(pthread_cond_wait(&overflow_cond_, &overflow_mtx_)) { @@ -2838,6 +2844,10 @@ int ArraySortedReadState::wait_overflow() { } } + // Unlock overflow mutex + if(unlock_overflow_mtx() != TILEDB_ASRS_OK) + return TILEDB_ASRS_ERR; + // Success return TILEDB_ASRS_OK; } diff --git a/examples/src/tiledb_array_read_dense_2.cc b/examples/src/tiledb_array_read_dense_2.cc index 38bfc216..51e2d406 100644 --- a/examples/src/tiledb_array_read_dense_2.cc +++ b/examples/src/tiledb_array_read_dense_2.cc @@ -78,7 +78,7 @@ int main() { // Finalize the array tiledb_array_finalize(tiledb_array); - /* Finalize context. */ + // Finalize context tiledb_ctx_finalize(tiledb_ctx); return 0; From c3228ec910203165c39468a243b9332b44315ec5 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 9 Nov 2016 18:52:23 -0500 Subject: [PATCH 31/57] cleaning up dead code --- core/include/array/array_sorted_read_state.h | 40 -------------------- 1 file changed, 40 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index 71ffeee4..cdb56485 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -335,15 +335,6 @@ class ArraySortedReadState { /** The number of dimensions in the array. */ int dim_num_; - /** Flag indicating whether the read is done or an overflow occurred. */ - bool done_or_overflow_; - - /** The done or overflow mutex condition. */ - pthread_cond_t done_or_overflow_cond_; - - /** The done or overflow mutex. */ - pthread_mutex_t done_or_overflow_mtx_; - /** * Used only in the sparse case. It is true if the coordinates are not asked * by the user and, thus, TileDB had to append them as an extra attribute @@ -471,9 +462,6 @@ class ArraySortedReadState { /** Sets the flag of wait_copy_[id] to true. */ void block_copy(int id); - /** Sets the flag of done_or_overflow_ to true. */ - void block_done_or_overflow(); - /** Sets the flag of resume_copy_ to true. */ void block_overflow(); @@ -859,13 +847,6 @@ class ArraySortedReadState { */ int lock_copy_mtx(); - /** - * Locks the done or overflow mutex. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ - int lock_done_or_overflow_mtx(); - /** * Locks the overflow mutex. * @@ -992,13 +973,6 @@ class ArraySortedReadState { */ int release_copy(int id); - /** - * Signals the done or overflow condition. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ - int release_done_or_overflow(); - /** * Signals the overflow condition. * @@ -1065,13 +1039,6 @@ class ArraySortedReadState { */ int unlock_copy_mtx(); - /** - * Unlocks the done or overflow mutex. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ - int unlock_done_or_overflow_mtx(); - /** * Unlocks the overflow mutex. * @@ -1106,13 +1073,6 @@ class ArraySortedReadState { */ int wait_aio(int id); - /** - * Waits until the read is done or there is a buffer overflow. - * - * @return TILEDB_ASRS_OK for success and TILEDB_ASRS_ERR for error. - */ - int wait_done_or_overflow(); - /** * Waits until there is no buffer overflow. * From f09f8caac467b35a1a5c3be57361aa72759d274d Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 22 Nov 2016 19:42:29 -0500 Subject: [PATCH 32/57] Bug fix in sorted reads --- core/src/array/array.cc | 2 +- core/src/array/array_sorted_read_state.cc | 54 +++++++++++++++++++--- core/src/array/array_sorted_write_state.cc | 2 +- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 2693355d..3924e22a 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -1101,7 +1101,7 @@ int Array::aio_push_request(AIO_Request* aio_request) { // Set the request status *aio_request->status_ = TILEDB_AIO_INPROGRESS; - // Lock AIO mutext + // Lock AIO mutex if(pthread_mutex_lock(&aio_mtx_)) { std::string errmsg = "Cannot lock AIO mutex"; PRINT_ERROR(errmsg); diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 842e38e5..402be064 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -1765,6 +1765,12 @@ int ArraySortedReadState::lock_overflow_mtx() { template bool ArraySortedReadState::next_tile_slab_dense_col() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -1847,6 +1853,12 @@ bool ArraySortedReadState::next_tile_slab_dense_col() { template bool ArraySortedReadState::next_tile_slab_dense_row() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -1925,6 +1937,12 @@ bool ArraySortedReadState::next_tile_slab_dense_row() { template bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -1993,6 +2011,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { template<> bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -2062,6 +2086,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { template<> bool ArraySortedReadState::next_tile_slab_sparse_col() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -2131,6 +2161,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { template bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -2195,6 +2231,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { template<> bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -2261,6 +2303,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { template<> bool ArraySortedReadState::next_tile_slab_sparse_row() { + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // Quick check if done if(read_tile_slabs_done_) return false; @@ -2515,12 +2563,6 @@ int ArraySortedReadState::read_sparse_sorted_row() { } int ArraySortedReadState::read_tile_slab() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // We need to exit if the copy did no complete (due to overflow) if(resume_copy_) { resume_aio_ = true; diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 992e69a4..88cedd0a 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -1732,7 +1732,7 @@ int ArraySortedWriteState::send_aio_request(int aio_id) { // Send the AIO request to the clone array if(array_clone->aio_write(&(aio_request_[aio_id])) != TILEDB_AR_OK) { - // TODO: get error message: tiledb_asws_errmsg = tiledb_ar_msg; + tiledb_asws_errmsg = tiledb_ar_errmsg; return TILEDB_ASWS_ERR; } From 5e865a8fbed5f4ea9a32fd485dd858fecc8d3e76 Mon Sep 17 00:00:00 2001 From: spapadop Date: Thu, 8 Dec 2016 16:00:07 -0500 Subject: [PATCH 33/57] Fixed bug in sorted reads/writes --- core/include/array/array.h | 2 +- core/include/array/array_sorted_read_state.h | 2 +- core/include/array/array_sorted_write_state.h | 8 ++++---- core/src/array/array.cc | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/include/array/array.h b/core/include/array/array.h index dd578d44..18b97d96 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -453,7 +453,7 @@ class Array { /** Indicates whether the AIO thread was canceled or not. */ bool aio_thread_canceled_; /** Indicates whether the AIO thread was created or not. */ - bool aio_thread_created_; + volatile bool aio_thread_created_; /** An array clone, used in AIO requests. */ Array* array_clone_; /** The array schema. */ diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index cdb56485..fe263e84 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -330,7 +330,7 @@ class ArraySortedReadState { bool copy_thread_canceled_; /** True if the copy thread is running. */ - bool copy_thread_running_; + volatile bool copy_thread_running_; /** The number of dimensions in the array. */ int dim_num_; diff --git a/core/include/array/array_sorted_write_state.h b/core/include/array/array_sorted_write_state.h index f8fd78d7..e96a369d 100644 --- a/core/include/array/array_sorted_write_state.h +++ b/core/include/array/array_sorted_write_state.h @@ -224,14 +224,14 @@ class ArraySortedWriteState { /** The status of the AIO requests.*/ int aio_status_[2]; - /** The thread tha handles all the AIO in the background. */ + /** The thread that handles all the AIO in the background. */ pthread_t aio_thread_; - /** True if the copy thread is canceled. */ + /** True if the AIO thread is canceled. */ bool aio_thread_canceled_; - /** True if the copy thread is running. */ - bool aio_thread_running_; + /** True if the AIO thread is running. */ + volatile bool aio_thread_running_; /** The array this sorted read state belongs to. */ Array* array_; diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 3924e22a..9afb55d5 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -113,7 +113,7 @@ void Array::aio_handle_requests() { AIO_Request* aio_next_request; // Initiate infinite loop - while(1) { + for(;;) { // Lock AIO mutext if(pthread_mutex_lock(&aio_mtx_)) { std::string errmsg = "Cannot lock AIO mutex"; From 87b8cb73ac6e6f91c3ee579cfd9cc9af482240b9 Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 16 Dec 2016 18:29:06 -0500 Subject: [PATCH 34/57] Bug fix with dense fragments that cover part of the domain --- core/src/array/array_sorted_read_state.cc | 14 +++++++------- core/src/fragment/read_state.cc | 23 ++++++++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 402be064..c262503c 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -134,6 +134,13 @@ ArraySortedReadState::ArraySortedReadState( } ArraySortedReadState::~ArraySortedReadState() { + // Cancel copy thread + copy_thread_canceled_ = true; + for(int i=0; i<2; ++i) + release_aio(i); + // Wait for thread to be destroyed + while(copy_thread_running_); + // Clean up free(subarray_); free(tile_coords_); @@ -164,13 +171,6 @@ ArraySortedReadState::~ArraySortedReadState() { free_tile_slab_state(); free_tile_slab_info(); - // Cancel copy thread - copy_thread_canceled_ = true; - for(int i=0; i<2; ++i) - release_aio(i); - // Wait for thread to be destroyed - while(copy_thread_running_); - // Destroy conditions and mutexes for(int i=0; i<2; ++i) { if(pthread_cond_destroy(&(aio_cond_[i]))) { diff --git a/core/src/fragment/read_state.cc b/core/src/fragment/read_state.cc index fd1e3583..6f7c3171 100644 --- a/core/src/fragment/read_state.cc +++ b/core/src/fragment/read_state.cc @@ -869,18 +869,26 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { // Compute overlap of the query subarray with tile T* query_tile_overlap_subarray = new T[2*dim_num]; array_schema_->subarray_overlap( - subarray, - tile_subarray, - query_tile_overlap_subarray); + subarray, + tile_subarray, + query_tile_overlap_subarray); // Compute the overlap of the previous results with the non-empty domain + T* search_tile_overlap_subarray = (T*) search_tile_overlap_subarray_; + array_schema_->subarray_overlap( + query_tile_overlap_subarray, + tile_domain_overlap_subarray, + search_tile_overlap_subarray); + + // Find the type of the search tile overlap + T* temp = new T[2*dim_num]; search_tile_overlap_ = array_schema_->subarray_overlap( - query_tile_overlap_subarray, - tile_domain_overlap_subarray, - static_cast(search_tile_overlap_subarray_)); + search_tile_overlap_subarray, + tile_subarray, + temp); - // Check if expanded fragment domain fully covers the tile + // Check if fragment fully covers the tile subarray_area_covered_ = is_contained( query_tile_overlap_subarray, @@ -889,6 +897,7 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { // Clean up delete [] query_tile_overlap_subarray; + delete [] temp; } // Clean up From 9b19a9892e12cf573641c3ed50f48382c8326d07 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 21 Dec 2016 20:25:55 -0500 Subject: [PATCH 35/57] Bug fix in array_read_state.cc: wrong memory allocation in sort_fragment_cell_ranges in the case of multiple dense fragments and a subarray that falls in 'empty' space. --- core/src/array/array_read_state.cc | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/core/src/array/array_read_state.cc b/core/src/array/array_read_state.cc index 107d58d4..2a7aca8f 100644 --- a/core/src/array/array_read_state.cc +++ b/core/src/array/array_read_state.cc @@ -293,8 +293,7 @@ int ArrayReadState::compute_unsorted_fragment_cell_ranges_dense( return TILEDB_ARS_ERR; } // Insert fragment cell ranges to the result - if(fragment_cell_ranges.size() != 0) - unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); + unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); } else { // SPARSE FragmentCellRanges fragment_cell_ranges; FragmentCellRanges fragment_cell_ranges_tmp; @@ -317,8 +316,7 @@ int ArrayReadState::compute_unsorted_fragment_cell_ranges_dense( fragment_cell_ranges_tmp.end()); } while(!fragment_read_states_[i]->done() && fragment_read_states_[i]->mbr_overlaps_tile()); - if(fragment_cell_ranges.size() != 0) - unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); + unsorted_fragment_cell_ranges.push_back(fragment_cell_ranges); } } else { // Append an empty list @@ -2133,12 +2131,23 @@ int ArrayReadState::sort_fragment_cell_ranges( // For easy reference int fragment_num = (int) unsorted_fragment_cell_ranges.size(); + // Calculate the number of non-empty unsorted fragment range lists + int non_empty = 0; + int first_non_empty = -1; + for(int i=0; i 0); + assert(non_empty > 0); // Trivial case - single fragment if(fragment_num == 1) { - fragment_cell_ranges = unsorted_fragment_cell_ranges[0]; + fragment_cell_ranges = unsorted_fragment_cell_ranges[first_non_empty]; unsorted_fragment_cell_ranges.clear(); return TILEDB_ARS_OK; } From c95fc1bc2f73f8e7913c78e086f19fe899c08dc1 Mon Sep 17 00:00:00 2001 From: kdatta Date: Fri, 16 Dec 2016 22:02:40 -0800 Subject: [PATCH 36/57] Added unit tests for sorted writes and reads for dense and sparse arrays --- Makefile | 37 +- test/src/c_api/c_api_dense_array_spec.cc | 918 ++++++++++++++++++++++ test/src/c_api/c_api_sparse_array_spec.cc | 403 ++++++++++ test/src/c_api/c_api_spec.cc | 455 ----------- 4 files changed, 1348 insertions(+), 465 deletions(-) create mode 100644 test/src/c_api/c_api_dense_array_spec.cc create mode 100644 test/src/c_api/c_api_sparse_array_spec.cc delete mode 100644 test/src/c_api/c_api_spec.cc diff --git a/Makefile b/Makefile index 0dab7862..a7968726 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ endif # --- Configuration flags --- # CPPFLAGS = -std=gnu++11 -fPIC -fvisibility=hidden \ - -D_FILE_OFFSET_BITS=64 + -D_FILE_OFFSET_BITS=64 # For the Travis integration ifdef TRAVIS @@ -63,6 +63,9 @@ endif # --- Compilers --- # CXX = g++ +# --- GTest Filters --- # +GTEST_FILTER='*' + # --- Directories --- # CORE_INCLUDE_DIR = core/include CORE_INCLUDE_SUBDIRS = $(wildcard core/include/*) @@ -102,19 +105,32 @@ ifeq ($(BUILD),release) EXAMPLES_OBJ_DIR = $(EXAMPLES_OBJ_REL_DIR) EXAMPLES_BIN_DIR = $(EXAMPLES_BIN_REL_DIR) endif -TEST_SRC_SUBDIRS = $(wildcard test/src/*) +TEST_INCLUDE_DIR = test/include +TEST_INCLUDE_SUBDIRS = $(wildcard test/include/*) TEST_SRC_DIR = test/src -TEST_OBJ_DIR = test/obj -TEST_BIN_DIR = test/bin +TEST_SRC_SUBDIRS = $(wildcard test/src/*) +TEST_OBJ_DEB_DIR = test/obj/debug +TEST_BIN_DEB_DIR = test/bin/debug +ifeq ($(BUILD),debug) + TEST_OBJ_DIR = $(TEST_OBJ_DEB_DIR) + TEST_BIN_DIR = $(TEST_BIN_DEB_DIR) +endif +TEST_OBJ_REL_DIR = test/obj/release +TEST_BIN_REL_DIR = test/bin/release +ifeq ($(BUILD),release) + TEST_OBJ_DIR = $(TEST_OBJ_REL_DIR) + TEST_BIN_DIR = $(TEST_BIN_REL_DIR) +endif DOXYGEN_DIR = doxygen DOXYGEN_MAINPAGE = $(DOXYGEN_DIR)/mainpage.dox # --- Paths --- # -INCLUDE_PATHS = +INCLUDE_PATHS = -I/home/kdatta1/workspace/googletest/googletest/include CORE_INCLUDE_PATHS = $(addprefix -I, $(CORE_INCLUDE_SUBDIRS)) EXAMPLES_INCLUDE_PATHS = -I$(EXAMPLES_INCLUDE_DIR) TEST_INCLUDE_PATHS = $(addprefix -I, $(CORE_INCLUDE_SUBDIRS)) -LIBRARY_PATHS = +TEST_INCLUDE_PATHS += $(addprefix -I, $(TEST_INCLUDE_SUBDIRS)) +LIBRARY_PATHS = -L/home/kdatta1/workspace/googletest/googletest ifdef TRAVIS LIBRARY_PATHS += --coverage @@ -144,6 +160,7 @@ EXAMPLES_OBJ := $(patsubst $(EXAMPLES_SRC_DIR)/%.cc,\ $(EXAMPLES_OBJ_DIR)/%.o, $(EXAMPLES_SRC)) EXAMPLES_BIN := $(patsubst $(EXAMPLES_SRC_DIR)/%.cc,\ $(EXAMPLES_BIN_DIR)/%, $(EXAMPLES_SRC)) +TEST_INCLUDE := $(foreach D,$(TEST_INCLUDE_SUBDIRS),$D/*.h) TEST_SRC := $(wildcard $(foreach D,$(TEST_SRC_SUBDIRS),$D/*.cc)) TEST_OBJ := $(patsubst $(TEST_SRC_DIR)/%.cc, $(TEST_OBJ_DIR)/%.o, $(TEST_SRC)) @@ -167,7 +184,7 @@ doc: doxyfile.inc test: libtiledb $(TEST_BIN_DIR)/tiledb_test @echo "Running TileDB tests" - @$(TEST_BIN_DIR)/tiledb_test + @$(TEST_BIN_DIR)/tiledb_test --gtest_filter=$(GTEST_FILTER) clean: clean_core clean_libtiledb \ clean_test clean_doc clean_examples @@ -280,8 +297,8 @@ $(TEST_OBJ_DIR)/%.o: $(TEST_SRC_DIR)/%.cc @mkdir -p $(dir $@) @echo "Compiling $<" @$(CXX) $(CPPFLAGS) $(OPENMP_FLAG) $(TEST_INCLUDE_PATHS) \ - $(INCLUDE_PATHS) -c $< -o $@ - @$(CXX) -MM $(TEST_INCLUDE_PATHS) \ + $(INCLUDE_PATHS) $(PTHREADLIB) -c $< -o $@ + @$(CXX) -MM $(TEST_INCLUDE_PATHS) $(PTHREADLIB) \ $(CORE_INCLUDE_PATHS) $(INCLUDE_PATHS) $< > $(@:.o=.d) @mv -f $(@:.o=.d) $(@:.o=.d.tmp) @sed 's|.*:|$@:|' < $(@:.o=.d.tmp) > $(@:.o=.d) @@ -292,7 +309,7 @@ $(TEST_OBJ_DIR)/%.o: $(TEST_SRC_DIR)/%.cc $(TEST_BIN_DIR)/tiledb_test: $(TEST_OBJ) $(CORE_LIB_DIR)/libtiledb.a @mkdir -p $(TEST_BIN_DIR) @echo "Creating test_cmd" - @$(CXX) -std=gnu++11 -o $@ $^ $(LIBRARY_PATHS) $(MPILIB) $(ZLIB) \ + @$(CXX) -o $@ $^ $(LIBRARY_PATHS) $(MPILIB) $(ZLIB) \ $(PTHREADLIB) $(OPENSSLLIB) $(GTESTLIB) $(OPENMP_FLAG) # --- Cleaning --- # diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc new file mode 100644 index 00000000..e399486d --- /dev/null +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -0,0 +1,918 @@ +/** + * Copyright (c) 2016 Massachusetts Institute of Technology and Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Tests of C API for read/write/update operations for + * dense arrays + */ + +#include +#include "c_api.h" +#include +#include +#include +#include +#include +#include + +/** + * Test fixture for dense array operations. + * The Setup() and TearDown() methods are called + * after each test is called and destroyed respectively. + * In these methods, we create and delete the array + */ +class DenseArrayTestFixture: public testing::Test { + const std::string WORKSPACE = ".__workspace/"; + const std::string ARRAY_100x100_10x10 = "dense_test_100x100_10x10"; + const int ARRAY_RANK_2D = 2; + +public: + // Array schema object under test + TileDB_ArraySchema schema; + // TileDB context + TileDB_CTX* tiledb_ctx; + // Array name is initialized with the workspace folder + std::string arrayName; + + /** + * Default constructor used to create a temporary + * TileDB workspace in the current working directory + * before all tests are called. User must have write + * permissions to this directory + */ + DenseArrayTestFixture(); + + /** + * Default destructor removes the temporary + * TileDB workspace and destroys the TileDB + * context + */ + ~DenseArrayTestFixture(); + + /** + * Set the array name for the current test + */ + void setArrayName(const char *); + + /** + * Generate a test buffer to full up the dense array where + * each cell value = row index * total number of columns + col index + */ + int **generate_2Dbuffer( + const int, const int); + + /** + * Generate a 1D buffer containing the cell values + * of a 2D array + */ + int *generate_1Dbuffer( + const int, const int); + + /** + * Create the test dense array with given tile extents + */ + int create_dense_array_2D( + const long dim0_tile_extent, + const long dim1_tile_extent, + const long dim0_lo, + const long dim0_hi, + const long dim1_lo, + const long dim1_hi, + const int capacity, + const bool enable_compression, + const int cell_order, + const int tile_order); + + /** + * Load the array chunk by chunk. The buffer is initialized + * with row_id*DIM1+col_id values. Tile extents or chunk + * sizes are defined in the create_dense_array_2D + */ + int write_dense_array_by_chunks( + const int64_t dim0, + const int64_t dim1, + const int64_t chunkDim0, + const int64_t chunkDim1); + + /** + * Load the array in a sorted row-major manner using + * a buffer which is ordered in the global cell order. + * The buffer is initialized cell values as + * row_id*DIM1+col_id values. Tile extents or chunk + * sizes are defined in the create_dense_array_2D + */ + int write_dense_array_sorted_2D( + const int64_t dim0, + const int64_t dim1, + const int64_t chunkDim0, + const int64_t chunkDim1, + const int write_mode); + + int write_dense_array_sorted_range_2D( + int64_t *subarray, + int write_mode, + size_t buffer_sizes[], + int* buffer); + + /** + * Update random locations in the dense array + * These locations are recorded and later + * used to validate reads + */ + int update_dense_array_2D( + const int dim0, + const int dim1, + int length, + int srand_key, + int *buffer_a1, + int64_t *buffer_coords, + const void* buffers[], + size_t buffer_sizes[2]); + + /** + * Read cell values of a dense array for a given + * range and test whether it matches the value + * row_id*DIM1+col_id + */ + int * read_dense_array( + const int64_t dim0_lo, + const int64_t dim0_hi, + const int64_t dim1_lo, + const int64_t dim1_hi, + const int read_mode); + + /** + * Not a member-function. A global + * stand-alone checker to compare two buffers + */ + static bool check_buffer( + const int *before, + const int *after, + const int *buffer_a1, + const int64_t *buffer_coords, + const int64_t dim0, + const int64_t dim1, + const int64_t chunkDim0, + const int64_t chunkDim1, + const int length); + + /** + * Code here will be called immediately after the constructor (right + * before each test). + */ + virtual void SetUp(); + + /** + * Code here will be called immediately after each test + * (right before the destructor). + */ + virtual void TearDown(); +}; + +DenseArrayTestFixture::DenseArrayTestFixture() { + // Initialize context with the default configuration parameters + tiledb_ctx_init(&tiledb_ctx, NULL); + if (tiledb_workspace_create(tiledb_ctx, WORKSPACE.c_str()) + != TILEDB_OK) { + exit(EXIT_FAILURE); + } +} + +DenseArrayTestFixture::~DenseArrayTestFixture() { + // Finalize TileDB context + tiledb_ctx_finalize(tiledb_ctx); + + // Remove the temporary workspace + std::string command = "rm -rf "; + command.append(WORKSPACE); + int rc = system(command.c_str()); + assert(rc == 0); +} + +void DenseArrayTestFixture::SetUp() { + // Reset the random number generator + srand(0); +} + +void DenseArrayTestFixture::TearDown() { + // delete currently tested array + if (arrayName.empty()) return; + + tiledb_delete( + (const TileDB_CTX*)this->tiledb_ctx, + this->arrayName.c_str()); + arrayName.clear(); +} + +void DenseArrayTestFixture::setArrayName(const char *name) { + this->arrayName.append(WORKSPACE); + this->arrayName.append(name); +} + +int **DenseArrayTestFixture::generate_2Dbuffer( + const int dim0, + const int dim1) { + int **buffer = new int * [dim0]; + for (int i = 0; i < dim0; ++i) { + buffer[i] = new int [dim1]; + for (int j = 0; j < dim1; ++j) { + buffer[i][j] = i * dim1 + j; + } + } + return buffer; +} + +int *DenseArrayTestFixture::generate_1Dbuffer( + const int dim0, + const int dim1) { + int *buffer = new int [dim0*dim1]; + for (int i = 0;i < dim0; ++i) + for (int j = 0;j < dim1; ++j) + buffer[i*dim1+j] = i*dim1+j; + return buffer; +} + +int DenseArrayTestFixture::create_dense_array_2D( + const long dim0_tile_extent, + const long dim1_tile_extent, + const long dim0_lo, + const long dim0_hi, + const long dim1_lo, + const long dim1_hi, + const int capacity, + const bool enable_compression, + const int cell_order, + const int tile_order) { + + // Prepare and set the array schema object and data structures + const int attribute_num = 1; + const char* attributes[] = { "ATTR_INT32" }; + const char* dimensions[] = { "X", "Y" }; + int64_t domain[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; + int64_t tile_extents[] = { dim0_tile_extent, dim1_tile_extent }; + const int types[] = { TILEDB_INT32, TILEDB_INT64 }; + int compression[sizeof(dimensions)]; + + if (!enable_compression) { + compression[0] = TILEDB_NO_COMPRESSION; + compression[1] = TILEDB_NO_COMPRESSION; + } else { + compression[0] = TILEDB_GZIP; + compression[1] = TILEDB_GZIP; + } + const int dense = 1; + + tiledb_array_set_schema( + &schema, + arrayName.c_str(), + attributes, + attribute_num, + capacity, + cell_order, + NULL, + compression, + dense, + dimensions, + ARRAY_RANK_2D, + domain, + 4*sizeof(int64_t), + tile_extents, + 2*sizeof(int64_t), + tile_order, + types); + + // Create the array + int ret = tiledb_array_create(tiledb_ctx, &schema); + return ret; +} // end of create_dense_array + +int DenseArrayTestFixture::write_dense_array_by_chunks( + const int64_t dim0, + const int64_t dim1, + const int64_t chunkDim0, + const int64_t chunkDim1) { + + int ret = 0; + int **buffer = generate_2Dbuffer(dim0, dim1); + int64_t segmentSize = chunkDim0 * chunkDim1; + int * buffer_a1 = new int [segmentSize]; + for (int i = 0; i < segmentSize; ++i) + buffer_a1[i] = 0; + + /* Initialize the array in WRITE mode. */ + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + TILEDB_ARRAY_WRITE, + NULL, // No range - entire domain + NULL, // No projection - all attributes + 0); // Meaningless when "attributes" is NULL + + const void* buffers[ARRAY_RANK_2D]; + buffers[0] = buffer_a1; + size_t bufferSizes[ARRAY_RANK_2D]; + int64_t index = 0L; + size_t writeSize = 0L; + for (int i = 0; i < dim0; i += chunkDim0) { + for (int j = 0; j < dim1; j += chunkDim1) { + long tile_rows = ((i + chunkDim0) < dim0) ? chunkDim0 : (dim0 - i); + long tile_cols = ((j + chunkDim1) < dim1) ? chunkDim1 : (dim1 - j); + int k,l; + for (k = 0; k < tile_rows; ++k) { + for (l = 0; l < tile_cols; ++l) { + index = uint64_t(k * tile_cols + l); + buffer_a1[index] = buffer[uint64_t(i + k)][uint64_t(j + l)]; + } + } + writeSize = k*l* sizeof(int); + + bufferSizes[0] = { writeSize }; + ret = tiledb_array_write(tiledb_array, buffers, bufferSizes); + if (ret != TILEDB_OK) { + return ret; + } + } + } + + /* Finalize the array. */ + ret = tiledb_array_finalize(tiledb_array); + return ret; +} // end of write_dense_array_by_chunks + +int DenseArrayTestFixture::write_dense_array_sorted_2D( + const int64_t dim0, + const int64_t dim1, + const int64_t chunkDim0, + const int64_t chunkDim1, + const int write_mode) { + + int ret = 0; + int *buffer = generate_1Dbuffer(dim0, dim1); + + // Set the subarray for sorted writes + int64_t subarray[] = { 0, dim0-1, 0, dim1-1 }; + + /* Initialize the array in WRITE mode. */ + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + write_mode, + subarray, + NULL, // No projection - all attributes + 1); // Meaningless when "attributes" is NULL + + const void *buffers[] = { buffer }; + const size_t buffer_sizes[] = { dim0*dim1*sizeof(int) }; + + ret = tiledb_array_write( + tiledb_array, + buffers, + buffer_sizes); + + /* Finalize the array. */ + ret = tiledb_array_finalize( + tiledb_array); + + delete(buffer); + return ret; +} // end of write_dense_array_sorted_2D + +int DenseArrayTestFixture::write_dense_array_sorted_range_2D( + int64_t *subarray, + int write_mode, + size_t buffer_sizes[], + int* buffer) { + + int ret = 0; + const char *attributes[] = { "ATTR_INT32" }; + + /* Initialize the array in WRITE mode. */ + TileDB_Array* tiledb_array; + ret = tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + write_mode, + subarray, + attributes, + 1); + assert(ret == TILEDB_OK); + + const void * buffers[] = { buffer }; + ret = tiledb_array_write(tiledb_array, buffers, buffer_sizes); + assert(ret == TILEDB_OK); + + /* Finalize the array. */ + ret = tiledb_array_finalize(tiledb_array); + assert(ret == TILEDB_OK); + + return ret; +} + +int DenseArrayTestFixture::update_dense_array_2D( + const int dim0, + const int dim1, + int length, + int srand_key, + int *buffer_a1, + int64_t *buffer_coords, + const void* buffers[], + size_t buffer_sizes[2]) { + + /* Subset over attribute "a1" and the coordinates. */ + const char* attributes[] = { "ATTR_INT32", TILEDB_COORDS }; + + /* Initialize the array in WRITE mode. */ + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + TILEDB_ARRAY_WRITE_UNSORTED, + NULL, // No range - entire domain + attributes, // No projection - all attributes + 2); // Meaningless when "attributes" is NULL + + /* Populate attribute buffers with some arbitrary values. */ + // Random updates + srand(srand_key); + int64_t d0, d1, x; + int64_t coords_index = 0L; + std::map my_map; + std::map::iterator it; + my_map.clear(); + for (int i = 0; i < length; ++i) { + std::ostringstream rand_stream; + do { + std::ostringstream rand_stream; + d0 = rand() % dim0; + d1 = rand() % dim1; + x = rand(); + rand_stream << d0 << "," << d1; + it = my_map.find(rand_stream.str()); + } while (it != my_map.end()); + rand_stream << d0 << "," << d1; + my_map[rand_stream.str()] = x; + buffer_coords[coords_index++] = d0; + buffer_coords[coords_index++] = d1; + buffer_a1[i] = x; + } + + /* Write to array. */ + int ret = tiledb_array_write(tiledb_array, buffers, buffer_sizes); + + if (ret != TILEDB_OK) { + return ret; + } + + /* Finalize the array. */ + ret = tiledb_array_finalize(tiledb_array); + return ret; +} // end of update_array + +int * DenseArrayTestFixture::read_dense_array( + const int64_t dim0_lo, + const int64_t dim0_hi, + const int64_t dim1_lo, + const int64_t dim1_hi, + const int read_mode) { + + /* Initialize a range. */ + const int64_t range[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; + + /* Subset over attribute "a1". */ + const char* attributes[] = { "ATTR_INT32" }; + + /* Initialize the array in READ mode. */ + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + read_mode, + range, + attributes, + 1); + + /* Prepare cell buffers for attributes "a1" and "a2". */ + size_t dim0 = dim0_hi - dim0_lo + 1; + size_t dim1 = dim1_hi - dim1_lo + 1; + size_t size = dim0*dim1; + int *buffer_a1 = new int [size]; + void* buffers[] = { buffer_a1 }; + size_t buffer_sizes[1] = { size*sizeof(int) }; + + /* Read from array. */ + int ret = tiledb_array_read(tiledb_array, buffers, buffer_sizes); + + if (ret != TILEDB_OK) { + return NULL; + } + + /* Finalize the array. */ + tiledb_array_finalize(tiledb_array); + return buffer_a1; +} // end of read_dense_array + +bool DenseArrayTestFixture::check_buffer( + const int *before, + const int *after, + const int *buffer_a1, + const int64_t *buffer_coords, + const int64_t dim0, + const int64_t dim1, + const int64_t chunkDim0, + const int64_t chunkDim1, + const int length) { + + int l,r; + bool fail = false; + int count = 0; + for (int64_t i = 0; i < dim0*dim1; ++i) { + l = before[i]; + r = after[i]; + + if (l!=r) { + bool found = false; + for (int k = 0; k < length; ++k) { + if (r==buffer_a1[k] && (l/dim1)==buffer_coords[2*k] && + (l%dim1)==buffer_coords[2*k+1]) { + found = true; + count++; + } + } + if (!found) { + fail = true; + } + } + } + + if (count != length) { + fail = true; + } + + return fail; +} + + +///////////////////////////// +// Test definitions follow // +///////////////////////////// + +/** + * Test random updates in a dense array + */ +TEST_F(DenseArrayTestFixture, test_random_updates) { + int64_t dim0 = 100; + int64_t dim1 = 100; + int64_t chunkDim0 = 10; + int64_t chunkDim1 = 10; + int64_t dim0_lo = 0; + int64_t dim0_hi = 99; + int64_t dim1_lo = 0; + int64_t dim1_hi = 99; + int capacity = 0; // 0 means use default capacity + int cell_order = TILEDB_ROW_MAJOR; + int tile_order = TILEDB_ROW_MAJOR; + + setArrayName("dense_test_100x100_10x10"); + + // Create a dense integer array 100x100 with 10x10 tiles/chunks + create_dense_array_2D( + chunkDim0, + chunkDim1, + dim0_lo, + dim0_hi, + dim1_lo, + dim1_hi, + capacity, + false, + cell_order, + tile_order); + + // Write array cells with value = row id * COLUMNS + col id + // to disk via TileDB Storage Manager + write_dense_array_by_chunks( + dim0, + dim1, + chunkDim0, + chunkDim1); + + // Read the entire array back to memory + int *before_update = read_dense_array( + dim0_lo, + dim0_hi, + dim1_lo, + dim1_hi, + TILEDB_ARRAY_READ); + + // Update random 100 elements with random seed = 7 + int length = 100; + int srand_key = 7; + // Prepare cell buffers for attributes "ATTR_INT32" + int *buffer_a1 = new int [length]; + int64_t *buffer_coords = new int64_t [2*length]; + const void* buffers[] = { buffer_a1, buffer_coords}; + size_t buffer_sizes[2] = { length*sizeof(int), 2*length*sizeof(int64_t) }; + + update_dense_array_2D( + dim0, + dim1, + length, + srand_key, + buffer_a1, + buffer_coords, + buffers, + buffer_sizes); + + // Read the entire array back to memory after update + int *after_update = + read_dense_array( + dim0_lo, + dim0_hi, + dim1_lo, + dim1_hi, + TILEDB_ARRAY_READ); + + // Compare array before and after array to check whether the randomly + // generated elements are written to the correct positions + bool fail = check_buffer( + before_update, + after_update, + buffer_a1, + buffer_coords, + dim0, + dim1, + chunkDim0, + chunkDim1, + length); + + EXPECT_FALSE(fail); +} + +/** + * Test sorted writes to a dense array with both cells and tiles + * ordered in a row-major fashion + */ +TEST_F(DenseArrayTestFixture, test_sorted_writes_row_major_tile_order) { + int64_t dim0 = 10000; + int64_t dim1 = 10000; + int64_t chunkDim0 = 1000; + int64_t chunkDim1 = 100; + int64_t dim0_lo = 0; + int64_t dim0_hi = dim0-1; + int64_t dim1_lo = 0; + int64_t dim1_hi = dim1-1; + int capacity = 0; // 0 means use default capacity + int cell_order = TILEDB_ROW_MAJOR; + int tile_order = TILEDB_ROW_MAJOR; + + setArrayName("dense_test_10000x10000_1000x100"); + + /** + * Create a dense integer array + */ + create_dense_array_2D( + chunkDim0, + chunkDim1, + 0, + dim0-1, + 0, + dim1-1, + capacity, + false, + cell_order, + tile_order); + + /** + * Write array cells with value = row id * COLUMNS + col id + * to disk via TileDB Storage Manager + */ + int ret = write_dense_array_sorted_2D( + dim0, + dim1, + chunkDim0, + chunkDim1, + TILEDB_ARRAY_WRITE_SORTED_ROW); + assert(ret==TILEDB_OK); + + /** + * Reading the array with read mode = TILEDB_ARRAY_READ + * will return the contiguous region on disk + * (chunk by chunk). Hence, check the buffer contents + * chunk by chunk and test the validity of sorted write + */ + int *after_write = read_dense_array( + dim0_lo, + dim0_hi, + dim1_lo, + dim1_hi, + TILEDB_ARRAY_READ); + + int64_t tiles[] = { (dim0/chunkDim0), (dim1/chunkDim1) }; + int64_t top_left[2]; + int index = 0; + + /** + * Traversing tiles in row major order + */ + for (int ti = 0; ti < tiles[0]; ++ti) { + top_left[0] = ti*chunkDim0; + for (int tj = 0; tj < tiles[1]; ++tj) { + top_left[1] = tj*chunkDim1; + for (int i = top_left[0]; i < top_left[0]+chunkDim0; ++i) { + for (int j = top_left[1]; j < top_left[1]+chunkDim1; ++j) { + EXPECT_EQ(after_write[index++], (i*dim1+j)); + } + } + } + } + + delete[] after_write; +} // end of test_sorted_writes_row_major_tile_order + + +/** + * Test is to randomly read subregions of the array and + * check with corresponding value set by row_id*dim1+col_id + * Top left corner is always 4,4 + * Test runs through 100 iterations to choose random + * width and height of the subregions + */ +TEST_F(DenseArrayTestFixture, test_random_sorted_reads) { + int64_t dim0 = 5000; + int64_t dim1 = 10000; + int64_t chunkDim0 = 100; + int64_t chunkDim1 = 100; + int64_t dim0_lo = 0; + int64_t dim0_hi = dim0-1; + int64_t dim1_lo = 0; + int64_t dim1_hi = dim1-1; + int capacity = 0; // 0 means use default capacity + int cell_order = TILEDB_ROW_MAJOR; + int tile_order = TILEDB_ROW_MAJOR; + + setArrayName("dense_test_5000x10000_100x100"); + + // Create a dense integer array + create_dense_array_2D( + chunkDim0, + chunkDim1, + dim0_lo, + dim0_hi, + dim1_lo, + dim1_hi, + capacity, + false, + cell_order, + tile_order); + + // Write array cells with value = row id * COLUMNS + col id + // to disk chunk by chunk + write_dense_array_by_chunks( + dim0, + dim1, + chunkDim0, + chunkDim1); + + // Test is to randomly read sub-regions of the array + // and check with corresponding value set by + // row_id*dim1+col_id + // Top left corner is always 4,4 + int64_t d0_lo = 4; + int64_t d0_hi = 0; + int64_t d1_lo = 4; + int64_t d1_hi = 0; + int64_t height = 0, width = 0; + + for (int iter = 0; iter < 100; ++iter) { + height = rand() % (dim0 - d0_lo); + width = rand() % (dim1 - d1_lo); + d0_hi = d0_lo + height; + d1_hi = d1_lo + width; + int index = 0; + + int *buffer = read_dense_array( + d0_lo, + d0_hi, + d1_lo, + d1_hi, + TILEDB_ARRAY_READ_SORTED_ROW); + + for (int i = d0_lo; i <= d0_hi; ++i) { + for (int j = d1_lo; j <= d1_hi; ++j) { + EXPECT_EQ(buffer[index], i*dim1+j); + if (buffer[index] != (i*dim1+j)) { + std::cout << "mismatch: " << i + << "," << j << "=" << buffer[index] << "!=" + << ((i*dim1+j)) << "\n"; + return; + } + index++; + } + } + } +} // end of test_random_sorted_reads + + +/** + * Test is to randomly write regions of the 2D array and + * read them back to validate the writes + * Test runs through 100 iterations to choose random + * width and height of the regions + */ +TEST_F(DenseArrayTestFixture, test_random_sorted_writes) { + int64_t dim[2] = { 100, 100 }; + int64_t tile_extents[2] = { 10, 10 }; + int64_t dim_ranges[2][2] = + { + { 0, dim[0]-1 }, + { 0, dim[1]-1 } + }; + int capacity = 0; // 0 means use default capacity + int cell_order = TILEDB_ROW_MAJOR; + int tile_order = TILEDB_ROW_MAJOR; + + setArrayName("dense_test_5000x10000_100x100"); + + // Create a dense integer array + create_dense_array_2D( + tile_extents[0], + tile_extents[1], + dim_ranges[0][0], + dim_ranges[0][1], + dim_ranges[1][0], + dim_ranges[1][1], + capacity, + false, + cell_order, + tile_order); + + int iterations = 10; + int64_t d0[2], d1[2]; + + for (int i = 0; i < iterations; ++i) { + std::cout << "iteration: " << i << "\n"; + d0[0] = rand() % dim[0]; + d1[0] = rand() % dim[1]; + d0[1] = d0[0] + rand() % (dim[0] - d0[0]); + d1[1] = d1[0] + rand() % (dim[1] - d1[0]); + + int64_t subarray[] = { d0[0], d0[1], d1[0], d1[1] }; + std::cout << "subarray: " << subarray[0] << "," + << subarray[1] << "," << subarray[2] << "," + << subarray[3] << "\n"; + size_t query_size[2] = { (size_t)(d0[1] - d0[0] + 1), + (size_t)(d1[1] - d1[0] + 1) }; + size_t buffer_size = query_size[0] * query_size[1]; + + int *buffer = new int [buffer_size]; + size_t index = 0; + + for (size_t r = 0; r < query_size[0]; ++r) + for (size_t c = 0; c < query_size[1]; ++c) + buffer[index++] = - (rand() % 999999); + + write_dense_array_sorted_range_2D( + subarray, + TILEDB_ARRAY_WRITE_SORTED_ROW, + query_size, + buffer); + + int *out_buffer = read_dense_array( + subarray[0], + subarray[1], + subarray[2], + subarray[3], + TILEDB_ARRAY_READ_SORTED_ROW); + + for (index = 0; index < buffer_size; ++index) + EXPECT_EQ(buffer[index], out_buffer[index]); + + delete [] buffer; + delete [] out_buffer; + } +} diff --git a/test/src/c_api/c_api_sparse_array_spec.cc b/test/src/c_api/c_api_sparse_array_spec.cc new file mode 100644 index 00000000..b42ef36c --- /dev/null +++ b/test/src/c_api/c_api_sparse_array_spec.cc @@ -0,0 +1,403 @@ +/** + * Copyright (c) 2016 Massachusetts Institute of Technology and Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Tests of C API for read/write/update operations for + * sparse arrays + */ + +#include +#include "c_api.h" +#include +#include +#include +#include +#include +#include + +class SparseArrayTestFixture: public testing::Test { + const std::string WORKSPACE = ".__workspace/"; + const std::string ARRAY_100x100 = "sparse_test_100x100_10x10"; + const int ARRAY_RANK_2D = 2; + +public: + // Array schema object under test + TileDB_ArraySchema schema; + // TileDB context + TileDB_CTX* tiledb_ctx; + // Array name is initialized with the workspace folder + std::string arrayName; + + /** + * Create the test dense array with given tile extents + */ + int create_sparse_array_2D( + const long dim0_tile_extent, + const long dim1_tile_extent, + const long dim0_lo, + const long dim0_hi, + const long dim1_lo, + const long dim1_hi, + const int capacity, + int cell_order, + int tile_order, + const bool enable_compression); + + /** + * Load the array in a sorted row-major manner using + * a buffer which is ordered in the global cell order. + * The buffer is initialized cell values as + * row_id*DIM1+col_id values. Tile extents or chunk + * sizes are defined in the create_sparse_array_2D + */ + int write_sparse_array_unsorted_2D( + const int64_t dim0, + const int64_t dim1); + + /** + * Read cell values of a sparse array for a given + * range and test whether it matches the value + * row_id*DIM1+col_id + */ + int * read_sparse_array_2D( + const int64_t dim0_lo, + const int64_t dim0_hi, + const int64_t dim1_lo, + const int64_t dim1_hi, + const int read_mode); + + /** + * Default constructor used to create a temporary + * TileDB workspace in the current working directory + * before all tests are called. User must have write + * permissions to this directory + */ + SparseArrayTestFixture(); + + /** + * Default destructor removes the temporary + * TileDB workspace and destroys the TileDB + * context + */ + ~SparseArrayTestFixture(); + + /** + * Code here will be called immediately after the constructor (right + * before each test). + */ + virtual void SetUp() { + // do Nothing + } + + /** + * Code here will be called immediately after each test + * (right before the destructor). + */ + virtual void TearDown(); + + /** + * Sets the object member array name + * For now each test creates its own + * array. Later, we can share this + * across multiple tests + */ + void setArrayName(const char *name); + +}; // end of SparseArrayTestFixture + +SparseArrayTestFixture::SparseArrayTestFixture() { + // Initialize context with the default configuration parameters + tiledb_ctx_init(&tiledb_ctx, NULL); + if (tiledb_workspace_create(tiledb_ctx, WORKSPACE.c_str()) + != TILEDB_OK) { + exit(EXIT_FAILURE); + } +} + +SparseArrayTestFixture::~SparseArrayTestFixture() { + // Finalize TileDB context + tiledb_ctx_finalize(tiledb_ctx); + + // Remove the temporary workspace + std::string command = "rm -rf "; + command.append(WORKSPACE); + int rc = system(command.c_str()); + assert(rc == 0); +} + +void SparseArrayTestFixture::TearDown() { + // delete currently tested array + if (arrayName.empty()) return; + + tiledb_delete( + tiledb_ctx, + arrayName.c_str()); + arrayName.clear(); +} + +int SparseArrayTestFixture::create_sparse_array_2D( + const long dim0_tile_extent, + const long dim1_tile_extent, + const long dim0_lo, + const long dim0_hi, + const long dim1_lo, + const long dim1_hi, + const int capacity, + const int cell_order, + const int tile_order, + const bool enable_compression) { + + // Prepare and set the array schema object and data structures + const int attribute_num = 1; + const char* attributes[] = { "ATTR_INT32" }; + const char* dimensions[] = { "X", "Y" }; + int64_t domain[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; + int64_t tile_extents[] = { dim0_tile_extent, dim1_tile_extent }; + const int types[] = { TILEDB_INT32, TILEDB_INT64 }; + int compression[sizeof(dimensions)]; + + if (!enable_compression) { + compression[0] = TILEDB_NO_COMPRESSION; + compression[1] = TILEDB_NO_COMPRESSION; + } else { + compression[0] = TILEDB_GZIP; + compression[1] = TILEDB_GZIP; + } + const int dense = 0; + + tiledb_array_set_schema( + &schema, + arrayName.c_str(), + attributes, + attribute_num, + capacity, + cell_order, + NULL, + compression, + dense, + dimensions, + ARRAY_RANK_2D, + domain, + 4*sizeof(int64_t), + tile_extents, + 2*sizeof(int64_t), + tile_order, + types); + + // Create the array + int ret = tiledb_array_create(tiledb_ctx, &schema); + + return ret; +} // end of create_sparse_array_2D + +void SparseArrayTestFixture::setArrayName(const char *name) { + this->arrayName.append(WORKSPACE); + this->arrayName.append(name); +} + +int SparseArrayTestFixture::write_sparse_array_unsorted_2D( + const int64_t dim0, + const int64_t dim1) { + + int ret = 0; + + // Generate the data and coordinates for sparse write + int64_t size = dim0*dim1; + int * buffer_attr = new int [size]; + int64_t * buffer_coords = new int64_t [2*size]; + int64_t coords_index = 0L; + for (int64_t i = 0; i < dim0; ++i) { + for (int64_t j = 0; j < dim1; ++j) { + buffer_attr[i*dim1+j] = i*dim1+j; + buffer_coords[2*coords_index] = i; + buffer_coords[2*coords_index+1] = j; + coords_index++; + } + } + + /* Initialize the array in WRITE mode. */ + TileDB_Array* tiledb_array; + ret = tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + TILEDB_ARRAY_WRITE_UNSORTED, + NULL, // No range - entire domain + NULL, // No projection - all attributes + 0); // Meaningless when "attributes" is NULL + + assert(ret == TILEDB_OK); + + const void* buffers[ARRAY_RANK_2D]; + buffers[0] = buffer_attr; + buffers[1] = buffer_coords; + + size_t bufferSizes[ARRAY_RANK_2D]; + bufferSizes[0] = { (size_t)size*sizeof(int) }; + bufferSizes[1] = { (size_t)2*size*sizeof(int64_t) }; + + ret = tiledb_array_write(tiledb_array, buffers, bufferSizes); + + if (ret != TILEDB_OK) { + return ret; + } + + /* Finalize the array. */ + ret = tiledb_array_finalize(tiledb_array); + return ret; +} // end of write_dense_array_by_chunks + +int * SparseArrayTestFixture::read_sparse_array_2D( + const int64_t dim0_lo, + const int64_t dim0_hi, + const int64_t dim1_lo, + const int64_t dim1_hi, + const int read_mode) { + + /* Initialize a range. */ + const int64_t range[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; + + /* Subset over attribute "a1". */ + const char* attributes[] = { "ATTR_INT32" }; + + /* Initialize the array in READ mode. */ + TileDB_Array* tiledb_array; + int ret = tiledb_array_init( + tiledb_ctx, + &tiledb_array, + arrayName.c_str(), + read_mode, + range, + attributes, + 1); + assert(ret == TILEDB_OK); + + /* Prepare cell buffers for attributes "a1" and "a2". */ + int64_t d0 = dim0_hi - dim0_lo + 1; + int64_t d1 = dim1_hi - dim1_lo + 1; + int64_t size = d0*d1; + int *buffer_a1 = new int [size]; + void* buffers[] = { buffer_a1 }; + size_t buffer_sizes[1] = { size*sizeof(int) }; + + /* Read from array. */ + ret = tiledb_array_read(tiledb_array, buffers, buffer_sizes); + + if (ret != TILEDB_OK) { + return NULL; + } + + /* Finalize the array. */ + tiledb_array_finalize(tiledb_array); + + return buffer_a1; +} // end of read_sparse_array_2D + + +/** + * Test is to randomly read subregions of the array and + * check with corresponding value set by row_id*dim1+col_id + * Top left corner is always 4,4 + * Test runs through 100 iterations to choose random + * width and height of the subregions + */ +TEST_F(SparseArrayTestFixture, test_random_sorted_reads) { + int64_t dim0 = 5000; + int64_t dim1 = 1000; + int64_t chunkDim0 = 100; + int64_t chunkDim1 = 100; + int64_t dim0_lo = 0; + int64_t dim0_hi = dim0-1; + int64_t dim1_lo = 0; + int64_t dim1_hi = dim1-1; + int capacity = 0; // 0 means use default capacity + int cell_order = TILEDB_ROW_MAJOR; + int tile_order = TILEDB_ROW_MAJOR; + bool enable_compression = false; + + setArrayName("sparse_test_5000x1000_100x100"); + + // Create a dense integer array + create_sparse_array_2D( + chunkDim0, + chunkDim1, + dim0_lo, + dim0_hi, + dim1_lo, + dim1_hi, + capacity, + cell_order, + tile_order, + enable_compression); + + // Write array cells with value = row id * COLUMNS + col id + // to disk chunk by chunk + write_sparse_array_unsorted_2D(dim0, dim1); + + // Test is to randomly read sub-regions of the array + // and check with corresponding value set by + // row_id*dim1+col_id + // Top left corner is always 4,4 + int64_t d0_lo = 4; + int64_t d0_hi = 0; + int64_t d1_lo = 4; + int64_t d1_hi = 0; + int64_t height = 0, width = 0; + + for (int iter = 0; iter < 20; ++iter) { + height = rand() % (dim0 - d0_lo); + width = rand() % (dim1 - d1_lo); + d0_hi = d0_lo + height; + d1_hi = d1_lo + width; + int index = 0; + + int *buffer = read_sparse_array_2D( + d0_lo, + d0_hi, + d1_lo, + d1_hi, + TILEDB_ARRAY_READ_SORTED_ROW); + + if (!buffer) { + std::cerr << "ERROR: NULL buffer returned. " + << "Check TileDB array path " + << arrayName << "\n"; + FAIL(); + } + + for (int i = d0_lo; i <= d0_hi; ++i) { + for (int j = d1_lo; j <= d1_hi; ++j) { + EXPECT_EQ(buffer[index], i*dim1+j); + if (buffer[index] != (i*dim1+j)) { + std::cerr << "mismatch: " << i + << "," << j << "=" << buffer[index] << "!=" + << ((i*dim1+j)) << "\n"; + return; + } + index++; + } + } + } // end of random for-loop +} // end of test_random_sorted_reads + + + diff --git a/test/src/c_api/c_api_spec.cc b/test/src/c_api/c_api_spec.cc deleted file mode 100644 index efc6450a..00000000 --- a/test/src/c_api/c_api_spec.cc +++ /dev/null @@ -1,455 +0,0 @@ -/** - * Copyright (c) 2016 Massachusetts Institute of Technology and Intel Corp. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * Tests to check read/write/update operations for - * dense and sparse TileDB arrays via the C API - */ - -#include -#include "c_api.h" -#include -#include -#include -#include -#include -#include - -class TileDBAPITest: public testing::Test { - const std::string WORKSPACE = ".__workspace/"; - const std::string ARRAY_100x100 = "dense_test_100x100_10x10"; - const int ARRAY_RANK = 2; - -public: - // Array schema object under test - TileDB_ArraySchema schema; - // TileDB context - TileDB_CTX* tiledb_ctx; - // Array name is initialized with the workspace folder - std::string arrayName; - - int **generate_buffer( - const int, const int); - int create_dense_array( - const long dim0_tile_extent, - const long dim1_tile_extent, - const long dim0_lo, - const long dim0_hi, - const long dim1_lo, - const long dim1_hi, - const int capacity); - int write_dense_array( - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1); - int update_dense_array( - const int dim0, - const int dim1, - int length, - int srand_key, - int *buffer_a1, - int64_t *buffer_coords, - const void* buffers[], - size_t buffer_sizes[2]); - int * read_dense_array( - const int64_t dim0_lo, - const int64_t dim0_hi, - const int64_t dim1_lo, - const int64_t dim1_hi); - - virtual void SetUp() { - // Initialize context with the default configuration parameters - tiledb_ctx_init(&tiledb_ctx, NULL); - if (tiledb_workspace_create( - tiledb_ctx, - WORKSPACE.c_str()) != TILEDB_OK) { - exit(EXIT_FAILURE); - } - - arrayName.append(WORKSPACE); - arrayName.append(ARRAY_100x100); - } - - virtual void TearDown() { - // Finalize TileDB context - tiledb_ctx_finalize(tiledb_ctx); - - // Remove the temporary workspace - std::string command = "rm -rf "; - command.append(WORKSPACE); - int rc = system(command.c_str()); - ASSERT_EQ(rc, 0); - } -}; -/** - * Generate a test buffer to full up the dense array where - * each cell value = row index * total number of columns + col index - */ -int **TileDBAPITest::generate_buffer(const int dim0, const int dim1) { - int **buffer = new int * [dim0]; - for (int i = 0; i < dim0; ++i) { - buffer[i] = new int [dim1]; - for (int j = 0; j < dim1; ++j) { - buffer[i][j] = i * dim1 + j; - } - } - return buffer; -} - -/** - * Create the test 100x100 dense array with tile sizes = 10x10 -**/ -int TileDBAPITest::create_dense_array( - const long dim0_tile_extent, - const long dim1_tile_extent, - const long dim0_lo, - const long dim0_hi, - const long dim1_lo, - const long dim1_hi, - const int capacity) { - - // Prepare and set the array schema object and data structures - const int attribute_num = 1; - const char* attributes[] = { "ATTR_INT32" }; - const char* dimensions[] = { "X", "Y" }; - int64_t domain[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; - int64_t tile_extents[] = { dim0_tile_extent, dim1_tile_extent }; - const int types[] = { TILEDB_INT32, TILEDB_INT64 }; - const int compression[] = - { TILEDB_NO_COMPRESSION, TILEDB_NO_COMPRESSION }; - const int dense = 1; - - tiledb_array_set_schema( - &schema, - arrayName.c_str(), - attributes, - attribute_num, - capacity, - TILEDB_ROW_MAJOR, - NULL, - compression, - dense, - dimensions, - ARRAY_RANK, - domain, - 4*sizeof(int64_t), - tile_extents, - 2*sizeof(int64_t), - 0, - types); - - // Create the array - int ret = tiledb_array_create(tiledb_ctx, &schema); - return ret; -} // end of create_dense_array - -/** - * Load the array with the buffer initialized with generatedBuffer logic - * to the database - */ -int TileDBAPITest::write_dense_array( - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1) { - - int ret = 0; - int **buffer = generate_buffer(dim0, dim1); - int64_t segmentSize = chunkDim0 * chunkDim1; - int * buffer_a1 = new int [segmentSize]; - for (int i = 0; i < segmentSize; ++i) - buffer_a1[i] = 0; - - /* Initialize the array in WRITE mode. */ - TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - TILEDB_ARRAY_WRITE, - NULL, // No range - entire domain - NULL, // No projection - all attributes - 0); // Meaningless when "attributes" is NULL - - const void* buffers[ARRAY_RANK]; - buffers[0] = buffer_a1; - size_t bufferSizes[ARRAY_RANK]; - int64_t index = 0L; - size_t writeSize = 0L; - for (int i = 0; i < dim0; i += chunkDim0) { - for (int j = 0; j < dim1; j += chunkDim1) { - long tile_rows = ((i + chunkDim0) < dim0) ? chunkDim0 : (dim0 - i); - long tile_cols = ((j + chunkDim1) < dim1) ? chunkDim1 : (dim1 - j); - int k,l; - for (k = 0; k < tile_rows; ++k) { - for (l = 0; l < tile_cols; ++l) { - index = uint64_t(k * tile_cols + l); - buffer_a1[index] = buffer[uint64_t(i + k)][uint64_t(j + l)]; - } - } - writeSize = k*l* sizeof(int); - - bufferSizes[0] = { writeSize }; - ret = tiledb_array_write(tiledb_array, buffers, bufferSizes); - if (ret != TILEDB_OK) { - return ret; - } - } - } - - /* Finalize the array. */ - ret = tiledb_array_finalize(tiledb_array); - return ret; -} // end of write_dense_array - -int TileDBAPITest::update_dense_array( - const int dim0, - const int dim1, - int length, - int srand_key, - int *buffer_a1, - int64_t *buffer_coords, - const void* buffers[], - size_t buffer_sizes[2]) { - - /* Subset over attribute "a1" and the coordinates. */ - const char* attributes[] = { "ATTR_INT32", TILEDB_COORDS }; - - /* Initialize the array in WRITE mode. */ - TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - TILEDB_ARRAY_WRITE_UNSORTED, - NULL, // No range - entire domain - attributes, // No projection - all attributes - 2); // Meaningless when "attributes" is NULL - - /* Populate attribute buffers with some arbitrary values. */ - // Random updates - srand(srand_key); - int64_t d0, d1, x; - int64_t coords_index = 0L; - std::map my_map; - std::map::iterator it; - my_map.clear(); - for (int i = 0; i < length; ++i) { - std::ostringstream rand_stream; - do { - std::ostringstream rand_stream; - d0 = rand() % dim0; - d1 = rand() % dim1; - x = rand(); - rand_stream << d0 << "," << d1; - it = my_map.find(rand_stream.str()); - } while (it != my_map.end()); - rand_stream << d0 << "," << d1; - my_map[rand_stream.str()] = x; - buffer_coords[coords_index++] = d0; - buffer_coords[coords_index++] = d1; - buffer_a1[i] = x; - } - - /* Write to array. */ - int ret = tiledb_array_write( - tiledb_array, - buffers, - buffer_sizes); - - if (ret != TILEDB_OK) { - return ret; - } - - /* Finalize the array. */ - ret = tiledb_array_finalize(tiledb_array); - return ret; -} // end of update_array - -/** - * Read the elements of the array into buffers for a - * given range - */ -int * TileDBAPITest::read_dense_array( - const int64_t dim0_lo, - const int64_t dim0_hi, - const int64_t dim1_lo, - const int64_t dim1_hi) { - - /* Initialize a range. */ - const int64_t range[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; - - /* Subset over attribute "a1". */ - const char* attributes[] = { "ATTR_INT32" }; - - /* Initialize the array in READ mode. */ - TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - TILEDB_ARRAY_READ, - range, - attributes, - 1); - - /* Prepare cell buffers for attributes "a1" and "a2". */ - size_t dim0 = dim0_hi - dim0_lo + 1; - size_t dim1 = dim1_hi - dim1_lo + 1; - size_t size = dim0*dim1; - int *buffer_a1 = new int [size]; - void* buffers[] = { buffer_a1 }; - size_t buffer_sizes[1] = { size*sizeof(int) }; - - /* Read from array. */ - int ret = tiledb_array_read(tiledb_array, buffers, buffer_sizes); - - if (ret != TILEDB_OK) { - return NULL; - } - - /* Finalize the array. */ - tiledb_array_finalize(tiledb_array); - return buffer_a1; -} // end of read_dense_array - - -/** - * Stand-alone checker to compare two buffers - */ -bool check_buffer( - const int *before, - const int *after, - const int *buffer_a1, - const int64_t *buffer_coords, - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1, - const int length) { - - int l,r; - bool fail = false; - int count = 0; - for (int64_t i = 0; i < dim0*dim1; ++i) { - l = before[i]; - r = after[i]; - - if (l!=r) { - bool found = false; - for (int k = 0; k < length; ++k) { - if (r==buffer_a1[k] && (l/dim1)==buffer_coords[2*k] && - (l%dim1)==buffer_coords[2*k+1]) { - found = true; - count++; - } - } - if (!found) { - fail = true; - } - } - } - - if (count != length) { - fail = true; - } - - return fail; -} -TEST_F(TileDBAPITest, DenseArrayRandomUpdates) { - int64_t dim0 = 100; - int64_t dim1 = 100; - int64_t chunkDim0 = 10; - int64_t chunkDim1 = 10; - int64_t dim0_lo = 0; - int64_t dim0_hi = 99; - int64_t dim1_lo = 0; - int64_t dim1_hi = 99; - int capacity = 0; // 0 means use default capacity - - // Create a dense integer array 100x100 with 10x10 tiles/chunks - create_dense_array( - chunkDim0, - chunkDim1, - 0, - dim0-1, - 0, - dim1-1, - capacity); - - // Write array cells with value = row id * COLUMNS + col id - // to disk via TileDB Storage Manager - write_dense_array( - dim0, - dim1, - chunkDim0, - chunkDim1); - - // Read the entire array back to memory - int *before_update = read_dense_array( - dim0_lo, - dim0_hi, - dim1_lo, - dim1_hi); - - // Update random 100 elements with random seed = 7 - int length = 100; - int srand_key = 7; - // Prepare cell buffers for attributes "ATTR_INT32" - int *buffer_a1 = new int [length]; - int64_t *buffer_coords = new int64_t [2*length]; - const void* buffers[] = { buffer_a1, buffer_coords}; - size_t buffer_sizes[2] = { length*sizeof(int), 2*length*sizeof(int64_t) }; - - update_dense_array( - dim0, - dim1, - length, - srand_key, - buffer_a1, - buffer_coords, - buffers, - buffer_sizes); - - // Read the entire array back to memory after update - int *after_update = read_dense_array( - dim0_lo, - dim0_hi, - dim1_lo, - dim1_hi); - - // Compare array before and after array to check whether the randomly - // generated elements are written to the correct positions - bool fail = check_buffer( - before_update, - after_update, - buffer_a1, - buffer_coords, - dim0, - dim1, - chunkDim0, - chunkDim1, - length); - - ASSERT_EQ(fail, false); -} From 992746a3a2a0d6f5e9da2d7851be345146be0b85 Mon Sep 17 00:00:00 2001 From: kdatta Date: Fri, 16 Dec 2016 22:09:54 -0800 Subject: [PATCH 37/57] removed local paths from Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a7968726..8e98f024 100644 --- a/Makefile +++ b/Makefile @@ -125,12 +125,12 @@ DOXYGEN_DIR = doxygen DOXYGEN_MAINPAGE = $(DOXYGEN_DIR)/mainpage.dox # --- Paths --- # -INCLUDE_PATHS = -I/home/kdatta1/workspace/googletest/googletest/include +INCLUDE_PATHS = CORE_INCLUDE_PATHS = $(addprefix -I, $(CORE_INCLUDE_SUBDIRS)) EXAMPLES_INCLUDE_PATHS = -I$(EXAMPLES_INCLUDE_DIR) TEST_INCLUDE_PATHS = $(addprefix -I, $(CORE_INCLUDE_SUBDIRS)) TEST_INCLUDE_PATHS += $(addprefix -I, $(TEST_INCLUDE_SUBDIRS)) -LIBRARY_PATHS = -L/home/kdatta1/workspace/googletest/googletest +LIBRARY_PATHS = ifdef TRAVIS LIBRARY_PATHS += --coverage From ba54bf85418a2f1c69f83ec0ff3a15c98b9e35e2 Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 23 Dec 2016 15:11:19 -0500 Subject: [PATCH 38/57] Bug fixes: (i) corrected calculation of search tile overlap in ReadState::get_next_overlapping_tile_dense, (ii) fixed sort algorithm in multi-fragment reads, (iii) fixed calculation of number of cells in a cell slab in ArraySortedWriteState. --- core/src/array/array_read_state.cc | 80 ++++++++++++---------- core/src/array/array_sorted_write_state.cc | 20 +----- core/src/fragment/read_state.cc | 52 ++++++++------ test/src/c_api/c_api_dense_array_spec.cc | 12 ++-- 4 files changed, 81 insertions(+), 83 deletions(-) diff --git a/core/src/array/array_read_state.cc b/core/src/array/array_read_state.cc index 2a7aca8f..80840355 100644 --- a/core/src/array/array_read_state.cc +++ b/core/src/array/array_read_state.cc @@ -210,6 +210,7 @@ int ArrayReadState::compute_fragment_cell_pos_ranges( T* cell_range = static_cast(fragment_cell_ranges[i].second); cell_pos_range.first = array_schema_->get_cell_pos(cell_range); cell_pos_range.second = array_schema_->get_cell_pos(&cell_range[dim_num]); + // Insert into the result fragment_cell_pos_ranges.push_back(fragment_cell_pos_range); } else { // SPARSE @@ -705,10 +706,11 @@ void ArrayReadState::copy_cells_with_empty( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -753,10 +755,11 @@ void ArrayReadState::copy_cells_with_empty( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -801,10 +804,11 @@ void ArrayReadState::copy_cells_with_empty( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -849,10 +853,11 @@ void ArrayReadState::copy_cells_with_empty( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -897,10 +902,11 @@ void ArrayReadState::copy_cells_with_empty( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -964,10 +970,11 @@ void ArrayReadState::copy_cells_with_empty_var( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -1031,10 +1038,11 @@ void ArrayReadState::copy_cells_with_empty_var( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) { overflow_[attribute_id] = true; - else // Done copying this range + } else { // Done copying this range empty_cells_written_[attribute_id] = 0; + } } template<> @@ -1232,7 +1240,7 @@ void ArrayReadState::copy_cells_with_empty_var( empty_cells_written_[attribute_id] += cell_num_to_copy; // Handle buffer overflow - if(empty_cells_written_[attribute_id] != cell_num_in_range) + if(empty_cells_written_[attribute_id] != cell_num_in_range) overflow_[attribute_id] = true; else // Done copying this range empty_cells_written_[attribute_id] = 0; @@ -2306,31 +2314,29 @@ int ArrayReadState::sort_fragment_cell_ranges( } // Potentially split the popped range - if(!pq.empty()) { - if(popped->must_be_split(top)) { - // Split the popped range - extra_popped = new PQFragmentCellRange( + if(!pq.empty() && popped->must_be_split(top)) { + // Split the popped range + extra_popped = new PQFragmentCellRange( + array_schema_, + &fragment_read_states_); + popped->split(top, extra_popped, tile_domain); + // Re-instert the extra popped range into the queue + pq.push(extra_popped); + } else { + // Get the next range from popped fragment + fid = (popped->fragment_id_ != -1) ? + popped->fragment_id_ : + fragment_num-1; + if(rid[fid] != rlen[fid]) { + pq_fragment_cell_range = new PQFragmentCellRange( array_schema_, &fragment_read_states_); - popped->split(top, extra_popped, tile_domain); - // Re-instert the extra popped range into the queue - pq.push(extra_popped); - } else { - // Get the next range from popped fragment - fid = (popped->fragment_id_ != -1) ? - popped->fragment_id_ : - fragment_num-1; - if(rid[fid] != rlen[fid]) { - pq_fragment_cell_range = new PQFragmentCellRange( - array_schema_, - &fragment_read_states_); - pq_fragment_cell_range->import_from( - unsorted_fragment_cell_ranges[fid][rid[fid]]); - pq.push(pq_fragment_cell_range); - ++rid[fid]; - } + pq_fragment_cell_range->import_from( + unsorted_fragment_cell_ranges[fid][rid[fid]]); + pq.push(pq_fragment_cell_range); + ++rid[fid]; } - } + } // Insert the final popped range into the results popped->export_to(result); diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 88cedd0a..2932b9d4 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -466,19 +466,11 @@ void ArraySortedWriteState::calculate_cell_slab_info_col_col( // For easy reference int anum = (int) attribute_ids_.size(); const T* range_overlap = (const T*) tile_slab_info_[id].range_overlap_[tid]; - const T* tile_domain = (const T*) tile_domain_; const T* tile_extents = (const T*) array_->array_schema()->tile_extents(); - int64_t tile_num, cell_num; + int64_t cell_num; // Calculate number of cells in cell slab cell_num = range_overlap[1] - range_overlap[0] + 1; - for(int i=0; iarray_schema()->tile_extents(); - int64_t tile_num, cell_num; + int64_t cell_num; // Calculate number of cells in cell slab cell_num = range_overlap[2*(dim_num_-1)+1] - range_overlap[2*(dim_num_-1)] +1; - for(int i=dim_num_-1; i>0; --i) { - tile_num = tile_domain[2*i+1] - tile_domain[2*i] + 1; - if(tile_num == 1) - cell_num *= range_overlap[2*(i-1)+1] - range_overlap[2*(i-1)] + 1; - else - break; - } tile_slab_info_[id].cell_slab_num_[tid] = cell_num; // Calculate size of a cell slab per attribute diff --git a/core/src/fragment/read_state.cc b/core/src/fragment/read_state.cc index 6f7c3171..60417928 100644 --- a/core/src/fragment/read_state.cc +++ b/core/src/fragment/read_state.cc @@ -875,29 +875,37 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { // Compute the overlap of the previous results with the non-empty domain T* search_tile_overlap_subarray = (T*) search_tile_overlap_subarray_; - array_schema_->subarray_overlap( - query_tile_overlap_subarray, - tile_domain_overlap_subarray, - search_tile_overlap_subarray); - - // Find the type of the search tile overlap - T* temp = new T[2*dim_num]; - search_tile_overlap_ = + bool overlap = array_schema_->subarray_overlap( - search_tile_overlap_subarray, - tile_subarray, - temp); + query_tile_overlap_subarray, + tile_domain_overlap_subarray, + search_tile_overlap_subarray); - // Check if fragment fully covers the tile - subarray_area_covered_ = - is_contained( - query_tile_overlap_subarray, - tile_domain_overlap_subarray, - dim_num); + if(!overlap) { + search_tile_overlap_ = 0; + subarray_area_covered_ = false; + } else { + // Find the type of the search tile overlap + T* temp = new T[2*dim_num]; + search_tile_overlap_ = + array_schema_->subarray_overlap( + search_tile_overlap_subarray, + tile_subarray, + temp); + + // Check if fragment fully covers the tile + subarray_area_covered_ = + is_contained( + query_tile_overlap_subarray, + tile_domain_overlap_subarray, + dim_num); + + // Clean up + delete [] temp; + } // Clean up delete [] query_tile_overlap_subarray; - delete [] temp; } // Clean up @@ -936,10 +944,10 @@ void ReadState::get_next_overlapping_tile_sparse() { mbr, static_cast(search_tile_overlap_subarray_)); - if(!search_tile_overlap_) - ++search_tile_pos_; - else - return; + if(!search_tile_overlap_) + ++search_tile_pos_; + else + return; } } diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index e399486d..6ca732ed 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -45,7 +45,7 @@ class DenseArrayTestFixture: public testing::Test { const std::string ARRAY_100x100_10x10 = "dense_test_100x100_10x10"; const int ARRAY_RANK_2D = 2; -public: + public: // Array schema object under test TileDB_ArraySchema schema; // TileDB context @@ -834,6 +834,10 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_reads) { index++; } } + + // Clean up + delete [] buffer; + } } // end of test_random_sorted_reads @@ -875,16 +879,12 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_writes) { int64_t d0[2], d1[2]; for (int i = 0; i < iterations; ++i) { - std::cout << "iteration: " << i << "\n"; d0[0] = rand() % dim[0]; d1[0] = rand() % dim[1]; d0[1] = d0[0] + rand() % (dim[0] - d0[0]); d1[1] = d1[0] + rand() % (dim[1] - d1[0]); int64_t subarray[] = { d0[0], d0[1], d1[0], d1[1] }; - std::cout << "subarray: " << subarray[0] << "," - << subarray[1] << "," << subarray[2] << "," - << subarray[3] << "\n"; size_t query_size[2] = { (size_t)(d0[1] - d0[0] + 1), (size_t)(d1[1] - d1[0] + 1) }; size_t buffer_size = query_size[0] * query_size[1]; @@ -909,7 +909,7 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_writes) { subarray[3], TILEDB_ARRAY_READ_SORTED_ROW); - for (index = 0; index < buffer_size; ++index) + for (index = 0; index < buffer_size; ++index) EXPECT_EQ(buffer[index], out_buffer[index]); delete [] buffer; From 53e96392663a524df54ef413c8f1523915e20464 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 26 Dec 2016 13:40:59 -0500 Subject: [PATCH 39/57] Modifying the creation of a fragment name to incorporate also the MAC address in addition to the thread id and timestamp (very important for the case TileDB is used on a parallel file system). --- core/include/misc/utils.h | 6 ++ core/src/array/array.cc | 14 ++++- core/src/misc/utils.cc | 79 ++++++++++++++++++++++++ test/src/c_api/c_api_dense_array_spec.cc | 3 +- 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index 705a3793..92fb92ee 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -277,6 +277,12 @@ std::vector get_dirs(const std::string& dir); /** Returns the names of the fragments inside the input directory. */ std::vector get_fragment_dirs(const std::string& dir); +/** + * Returns the MAC address of the machine as a 12-char string, e.g., + * 00332a0b8c64. Returns an empty string upon error. + */ +std::string get_mac_addr(); + /** * GZIPs the input buffer and stores the result in the output buffer, returning * the size of compressed data. diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 9afb55d5..604cbc28 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -1197,15 +1197,25 @@ std::string Array::new_fragment_name() const { memcpy(&tid, &self, std::min(sizeof(self), sizeof(tid))); char fragment_name[TILEDB_NAME_MAX_LEN]; + // Get MAC address + std::string mac = get_mac_addr(); + if(mac == "") + return ""; + + // Generate fragment name int n = sprintf( fragment_name, - "%s/.__%llu_%llu", + "%s/.__%s%llu_%llu", array_schema_->array_name().c_str(), + mac.c_str(), tid, ms); - if(n <0) + + // Handle error + if(n<0) return ""; + // Return return fragment_name; } diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index b7dd632b..e9758745 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -38,9 +38,23 @@ #include #include #include +#include #include +#include #include +#include #include + +#if defined(__APPLE__) && defined(__MACH__) + #include + #include + #include + #include + #include + #include +#endif + +#include #include #include #include @@ -429,6 +443,71 @@ std::vector get_fragment_dirs(const std::string& dir) { return dirs; } +#if defined(__APPLE__) && defined(__MACH__) +std::string get_mac_addr() { + int mib[6]; + char mac[13]; + size_t len; + char *buf; + unsigned char *ptr; + struct if_msghdr *ifm; + struct sockaddr_dl *sdl; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + if((mib[5] = if_nametoindex("en0") == 0) || + (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)) { + std::string errmsg = "Cannot get MAC address"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return ""; + } + + buf = (char*) malloc(len); + if(sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + std::string errmsg = "Cannot get MAC address"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return ""; + } + + ifm = (struct if_msghdr *)buf; + sdl = (struct sockaddr_dl *)(ifm + 1); + ptr = (unsigned char *)LLADDR(sdl); + for(int i=0; i<6; ++i) + sprintf(mac + 2*i, "%02x", *(ptr+i)); + mac[12] ='\0'; + + free(buf); + return mac; +} +#else +std::string get_mac_addr() { + struct ifreq s; + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + char mac[13]; + + strcpy(s.ifr_name, "eth0"); + if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) { + for (int i = 0; i < 6; ++i) + sprintf(mac + 2*i, "%02x", (unsigned char) s.ifr_addr.sa_data[i]); + mac[12] = '\0'; + close(fd); + + return mac; + } else { // Error + close(fd); + std::string errmsg = "Cannot get MAC address"; + PRINT_ERROR(errmsg); + tiledb_ut_errmsg = TILEDB_UT_ERRMSG + errmsg; + return ""; + } +} +#endif + ssize_t gzip( unsigned char* in, size_t in_size, diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index 6ca732ed..8f3ab7e2 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -21,8 +21,7 @@ */ /** - * Tests of C API for read/write/update operations for - * dense arrays + * Tests of C API for read/write/update operations for dense arrays. */ #include From dc1bbb56caa2c8a8f90d6fec29e6dd0a298ae2e3 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 26 Dec 2016 14:07:59 -0500 Subject: [PATCH 40/57] Fixes on MAC address retrieval for MAC OSX. --- core/src/array/array_read_state.cc | 4 ++++ core/src/misc/utils.cc | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/array/array_read_state.cc b/core/src/array/array_read_state.cc index 80840355..55456662 100644 --- a/core/src/array/array_read_state.cc +++ b/core/src/array/array_read_state.cc @@ -442,6 +442,8 @@ int ArrayReadState::copy_cells( buffer, buffer_size, buffer_offset); + else + rc = TILEDB_ARS_ERR; // Handle error if(rc != TILEDB_ARS_OK) @@ -577,6 +579,8 @@ int ArrayReadState::copy_cells_var( buffer_var, buffer_var_size, buffer_var_offset); + else + rc = TILEDB_ARS_ERR; // Handle error if(rc != TILEDB_ARS_OK) diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index e9758745..33abf27c 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -52,9 +52,10 @@ #include #include #include +#else +#include #endif -#include #include #include #include @@ -458,7 +459,7 @@ std::string get_mac_addr() { mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; - if((mib[5] = if_nametoindex("en0") == 0) || + if(((mib[5] = if_nametoindex("en0")) == 0) || (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)) { std::string errmsg = "Cannot get MAC address"; PRINT_ERROR(errmsg); From d7d858f4ffae42f675ac18579fcb483801bcc7f7 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 26 Dec 2016 17:36:49 -0500 Subject: [PATCH 41/57] Edited the array schema test spec --- test/include/c_api/c_api_array_schema_spec.h | 96 ++++++++++ test/src/array/array_schema_spec.cc | 174 ------------------ test/src/c_api/c_api_array_schema_spec.cc | 175 +++++++++++++++++++ test/src/c_api/c_api_dense_array_spec.cc | 2 +- 4 files changed, 272 insertions(+), 175 deletions(-) create mode 100644 test/include/c_api/c_api_array_schema_spec.h delete mode 100644 test/src/array/array_schema_spec.cc create mode 100644 test/src/c_api/c_api_array_schema_spec.cc diff --git a/test/include/c_api/c_api_array_schema_spec.h b/test/include/c_api/c_api_array_schema_spec.h new file mode 100644 index 00000000..c38483f6 --- /dev/null +++ b/test/include/c_api/c_api_array_schema_spec.h @@ -0,0 +1,96 @@ +/** + * @file c_api_array_schema_spec.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Declarations for testing the C API array schema spec. + */ + +#ifndef __C_API_ARRAY_SCHEMA_SPEC_H__ +#define __C_API_ARRAY_SCHEMA_SPEC_H__ + +#include "c_api.h" +#include + + +/** Test fixture for the array schema. */ +class ArraySchemaTestFixture: public testing::Test { + + public: + /* ********************************* */ + /* CONSTANTS */ + /* ********************************* */ + + /** Workspace folder name. */ + const std::string WORKSPACE = ".__workspace/"; + /** + * Array name. + * Format: (x_x). + */ + const std::string ARRAYNAME = "dense_test_100x100_10x10"; + + + + + /* ********************************* */ + /* GTEST FUNCTIONS */ + /* ********************************* */ + + /** Test initialization. */ + virtual void SetUp(); + + /** Test finalization. */ + virtual void TearDown(); + + + + + /* ********************************* */ + /* PUBLIC METHODS */ + /* ********************************* */ + + /** + * Creates a dense array. + * + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int create_dense_array(); + + + /* ********************************* */ + /* PUBLIC ATTRIBUTES */ + /* ********************************* */ + + /** Array name. */ + std::string array_name_; + /** Array schema object under test. */ + TileDB_ArraySchema array_schema_; + /** TileDB context. */ + TileDB_CTX* tiledb_ctx_; +}; + +#endif diff --git a/test/src/array/array_schema_spec.cc b/test/src/array/array_schema_spec.cc deleted file mode 100644 index 0a11f5fd..00000000 --- a/test/src/array/array_schema_spec.cc +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Copyright (c) 2016 Massachusetts Institute of Technology and Intel Corp. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * Tests to check array schema are serialized/deserialized correctly - * to/from the array storage - */ - -#include -#include -#include "c_api.h" - -class ArraySchemaTest: public testing::Test { - -public: - const std::string WORKSPACE = ".__workspace/"; - const std::string ARRAYNAME = "dense_test_100x100_10x10"; - - // Array schema object under test - TileDB_ArraySchema test_schema; - // TileDB context - TileDB_CTX* tiledb_ctx; - // Array name is initialized with the workspace folder - std::string array_name; - - int create_dense_array(); - - virtual void SetUp() { - // Initialize context with the default configuration parameters - tiledb_ctx_init(&tiledb_ctx, NULL); - - if (tiledb_workspace_create( - tiledb_ctx, - WORKSPACE.c_str()) != TILEDB_OK) { - exit(EXIT_FAILURE); - } - - array_name.append(WORKSPACE); - array_name.append(ARRAYNAME); - } - - virtual void TearDown() { - // Finalize TileDB context - tiledb_ctx_finalize(tiledb_ctx); - - // Remove the temporary workspace - std::string command = "rm -rf "; - command.append(WORKSPACE); - int rc = system(command.c_str()); - ASSERT_EQ(rc, 0); - } -}; - -int ArraySchemaTest::create_dense_array() { - const char* attributes[] = { "ATTR_INT32" }; - const char* dimensions[] = { "X", "Y" }; - int64_t domain[] = { 0, 99, 0, 99 }; - int64_t tile_extents[] = { 10, 10 }; - const int types[] = { TILEDB_INT32, TILEDB_INT64 }; - const int compression[] = - { TILEDB_NO_COMPRESSION, TILEDB_NO_COMPRESSION }; - - tiledb_array_set_schema( - // The array schema structure - &test_schema, - // Array name - array_name.c_str(), - // Attributes - attributes, - // Number of attributes - 1, - // Capacity - 1000, - // Cell order - TILEDB_COL_MAJOR, - // Number of cell values per attribute (NULL means 1 everywhere) - NULL, - // Compression - compression, - // Dense array - 1, - // Dimensions - dimensions, - // Number of dimensions - 2, - // Domain - domain, - // Domain length in bytes - 100*sizeof(int64_t), - // Tile extents (no regular tiles defined) - tile_extents, - // Tile extents in bytes - 10*sizeof(int64_t), - // Tile order (0 means ignore in sparse arrays and default in dense) - 0, - // Types - types - ); - - /* Create the array. */ - return tiledb_array_create(tiledb_ctx, &test_schema); -} - -/***************************/ -/********** TESTS **********/ -/***************************/ -TEST_F(ArraySchemaTest, DenseSchemaTest) { - - if (create_dense_array() != TILEDB_OK) { - EXPECT_EQ(0, 1); - } - - TileDB_ArraySchema schemaFromDisk; - tiledb_array_load_schema(tiledb_ctx, array_name.c_str(), &schemaFromDisk); - - const int size = 1024; - char *cwd = new char [size]; - char *ptr = getcwd(cwd, size); - - // If error reading the current working directory, fail the test - if (ptr == NULL) { - ASSERT_EQ(0, 1); - } - - std::string full_array_path; - full_array_path.append(cwd); - full_array_path.append("/"); - full_array_path.append(test_schema.array_name_); - - ASSERT_STREQ(schemaFromDisk.array_name_, full_array_path.c_str()); - - ASSERT_EQ(schemaFromDisk.attribute_num_, test_schema.attribute_num_); - ASSERT_EQ(schemaFromDisk.dim_num_, test_schema.dim_num_); - ASSERT_EQ(schemaFromDisk.capacity_, test_schema.capacity_); - ASSERT_EQ(schemaFromDisk.cell_order_, test_schema.cell_order_); - ASSERT_EQ(schemaFromDisk.tile_order_, test_schema.tile_order_); - ASSERT_EQ(schemaFromDisk.dense_, test_schema.dense_); - ASSERT_STREQ(schemaFromDisk.attributes_[0], test_schema.attributes_[0]); - - ASSERT_EQ(schemaFromDisk.compression_[0], test_schema.compression_[0]); - ASSERT_EQ(schemaFromDisk.compression_[1], test_schema.compression_[1]); - - ASSERT_EQ(schemaFromDisk.types_[0], test_schema.types_[0]); - ASSERT_EQ(schemaFromDisk.types_[1], test_schema.types_[1]); - - int* lhs_tile_extents = static_cast(schemaFromDisk.tile_extents_); - int* rhs_tile_extents = static_cast(test_schema.tile_extents_); - - ASSERT_EQ(lhs_tile_extents[0], rhs_tile_extents[0]); - - // Free array schema - tiledb_array_free_schema(&schemaFromDisk); -} - - diff --git a/test/src/c_api/c_api_array_schema_spec.cc b/test/src/c_api/c_api_array_schema_spec.cc new file mode 100644 index 00000000..42fe744b --- /dev/null +++ b/test/src/c_api/c_api_array_schema_spec.cc @@ -0,0 +1,175 @@ +/** + * @file c_api_array_schema_spec.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Tests for the C API array schema spec. + */ + +#include "c_api_array_schema_spec.h" +#include "utils.h" +#include + +void ArraySchemaTestFixture::SetUp() { + int rc; + + // Initialize context + rc = tiledb_ctx_init(&tiledb_ctx_, NULL); + ASSERT_EQ(rc, TILEDB_OK); + + // Create workspace + rc = tiledb_workspace_create(tiledb_ctx_, WORKSPACE.c_str()); + ASSERT_EQ(rc, TILEDB_OK); + + // Set array name + array_name_ = WORKSPACE + ARRAYNAME; +} + +void ArraySchemaTestFixture::TearDown() { + int rc; + + // Finalize TileDB context + rc = tiledb_ctx_finalize(tiledb_ctx_); + ASSERT_EQ(rc, TILEDB_OK); + + // Remove the temporary workspace + std::string command = "rm -rf "; + command.append(WORKSPACE); + rc = system(command.c_str()); + ASSERT_EQ(rc, 0); + + // Free array schema + rc = tiledb_array_free_schema(&array_schema_); + ASSERT_EQ(rc, TILEDB_OK); +} + +int ArraySchemaTestFixture::create_dense_array() { + // Initialization s + int rc; + const char* attributes[] = { "ATTR_INT32" }; + const char* dimensions[] = { "X", "Y" }; + int64_t domain[] = { 0, 99, 0, 99 }; + int64_t tile_extents[] = { 10, 10 }; + const int types[] = { TILEDB_INT32, TILEDB_INT64 }; + const int compression[] = { TILEDB_NO_COMPRESSION, TILEDB_NO_COMPRESSION }; + + // Set array schema + rc = tiledb_array_set_schema( + // The array schema structure + &array_schema_, + // Array name + array_name_.c_str(), + // Attributes + attributes, + // Number of attributes + 1, + // Capacity + 1000, + // Cell order + TILEDB_COL_MAJOR, + // Number of cell values per attribute (NULL means 1 everywhere) + NULL, + // Compression + compression, + // Dense array + 1, + // Dimensions + dimensions, + // Number of dimensions + 2, + // Domain + domain, + // Domain length in bytes + 4*sizeof(int64_t), + // Tile extents (no regular tiles defined) + tile_extents, + // Tile extents in bytes + 2*sizeof(int64_t), + // Tile order (0 means ignore in sparse arrays and default in dense) + 0, + // Types + types + ); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + /* Create the array. */ + return tiledb_array_create(tiledb_ctx_, &array_schema_); +} + + + + +/* ****************************** */ +/* TESTS */ +/* ****************************** */ +TEST_F(ArraySchemaTestFixture, test_array_schema) { + // Auxiliary + int rc; + TileDB_ArraySchema array_schema_disk; + + // Create array + rc = create_dense_array(); + ASSERT_EQ(rc, TILEDB_OK); + + // Load array schema from the disk + rc = tiledb_array_load_schema( + tiledb_ctx_, + array_name_.c_str(), + &array_schema_disk); + ASSERT_EQ(rc, TILEDB_OK); + + // Get real array path + std::string array_name_real = real_dir(array_name_); + ASSERT_STRNE(array_name_real.c_str(), ""); + + // Tests + ASSERT_STREQ(array_schema_disk.array_name_, array_name_real.c_str()); + ASSERT_EQ(array_schema_disk.attribute_num_, array_schema_.attribute_num_); + ASSERT_EQ(array_schema_disk.dim_num_, array_schema_.dim_num_); + ASSERT_EQ(array_schema_disk.capacity_, array_schema_.capacity_); + ASSERT_EQ(array_schema_disk.cell_order_, array_schema_.cell_order_); + ASSERT_EQ(array_schema_disk.tile_order_, array_schema_.tile_order_); + ASSERT_EQ(array_schema_disk.dense_, array_schema_.dense_); + ASSERT_STREQ(array_schema_disk.attributes_[0], array_schema_.attributes_[0]); + ASSERT_EQ(array_schema_disk.compression_[0], array_schema_.compression_[0]); + ASSERT_EQ(array_schema_disk.compression_[1], array_schema_.compression_[1]); + ASSERT_EQ(array_schema_disk.types_[0], array_schema_.types_[0]); + ASSERT_EQ(array_schema_disk.types_[1], array_schema_.types_[1]); + + int* tile_extents_disk = static_cast(array_schema_disk.tile_extents_); + int* tile_extents = static_cast(array_schema_.tile_extents_); + + ASSERT_EQ(tile_extents_disk[0], tile_extents[0]); + ASSERT_EQ(tile_extents_disk[1], tile_extents[1]); + + // Free array schema + rc = tiledb_array_free_schema(&array_schema_disk); + ASSERT_EQ(rc, TILEDB_OK); +} + + diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index 8f3ab7e2..9478e769 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -384,7 +384,7 @@ int DenseArrayTestFixture::write_dense_array_sorted_2D( 1); // Meaningless when "attributes" is NULL const void *buffers[] = { buffer }; - const size_t buffer_sizes[] = { dim0*dim1*sizeof(int) }; + const size_t buffer_sizes[] = { (size_t) (dim0*dim1*sizeof(int)) }; ret = tiledb_array_write( tiledb_array, From de5c316639d3760207ea8ce99954be711efe455e Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 26 Dec 2016 18:37:12 -0500 Subject: [PATCH 42/57] Added progress bar in tests. --- core/include/misc/progress_bar.h | 115 ++++++++++++++++++++++ core/src/misc/progress_bar.cc | 96 ++++++++++++++++++ test/src/c_api/c_api_array_schema_spec.cc | 22 +++-- test/src/c_api/c_api_dense_array_spec.cc | 6 ++ 4 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 core/include/misc/progress_bar.h create mode 100644 core/src/misc/progress_bar.cc diff --git a/core/include/misc/progress_bar.h b/core/include/misc/progress_bar.h new file mode 100644 index 00000000..207f4ff9 --- /dev/null +++ b/core/include/misc/progress_bar.h @@ -0,0 +1,115 @@ +/** + * @file progress_bar.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file defines class ProgressBar. + */ + +#ifndef __PROGRESS_BAR_H__ +#define __PROGRESS_BAR_H__ + +#include + +/** The default complete amount of the bar. */ +#define PB_COMPLETE 1.0 +/** The default filler character of the bar. */ +#define PB_FILLER '=' +/** The default maximum length of the bar. */ +#define PB_MAX_LENGTH 30 +/** The increase in the incomplete/complete ratio before the next print. */ +#define PB_RATIO_STEP 0.01 + + + +/** Implements a simple progress bar printed in standard output. */ +class ProgressBar { + public: + /* ********************************* */ + /* CONSTRUCTORS & DESTRUCTORS */ + /* ********************************* */ + + /** + * Constructor. + * + * @param complete The amount at which the bar must reach its maximum length. + * @param max_length The visual length of the bar. + * @param The character that fills the bar. + */ + ProgressBar( + double complete = PB_COMPLETE, + int max_length = PB_MAX_LENGTH, + char filler = PB_FILLER); + + /** Destructor. */ + ~ProgressBar(); + + + + + /* ********************************* */ + /* METHODS */ + /* ********************************* */ + + /** + * "Loads" the progress bar with the input amount, which may trigger drawing + * the current progress on the standard output. + */ + void load(double amount); + + + private: + /* ********************************* */ + /* PRIVATE ATTRIBUTES */ + /* ********************************* */ + + /** The amount at which the bar reaches its maximum length. */ + double complete_; + /** The character that fills the bar. */ + char filler_; + /** The current amount accummulated towards completion. */ + double incomplete_; + /** The incomplete/complete ratio upon the last print. */ + double last_ratio_; + /** The bar current length. */ + int length_; + /** The bar maximum length. */ + int max_length_; + /** The current ratio incomplete/complete. */ + double ratio_; + + + + /* ********************************* */ + /* PRIVATE METHODS */ + /* ********************************* */ + + /** Prints the bar with its current status. */ + void print(); +}; + +#endif diff --git a/core/src/misc/progress_bar.cc b/core/src/misc/progress_bar.cc new file mode 100644 index 00000000..a539e7cd --- /dev/null +++ b/core/src/misc/progress_bar.cc @@ -0,0 +1,96 @@ +/** + * @file progress_bar.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file implements class ProgressBar. + */ + +#include "progress_bar.h" +#include + + + + +/* ****************************** */ +/* CONSTRUCTORS & DESTRUCTORS */ +/* ****************************** */ + +ProgressBar::ProgressBar(double complete, int max_length, char filler) { + complete_ = complete; + filler_ = filler; + length_ = 0; + incomplete_ = 0; + last_ratio_ = 0; + max_length_ = max_length; + ratio_ = 0; +} + +ProgressBar::~ProgressBar() { +} + + + + +/* ****************************** */ +/* METHODS */ +/* ****************************** */ + +void ProgressBar::load(double amount) { + incomplete_ += amount; + if(incomplete_ > complete_) + incomplete_ = complete_; + + ratio_ = (incomplete_ / complete_); + length_ = ratio_ * max_length_; + + // Print bar + if(ratio_ - last_ratio_ > PB_RATIO_STEP) { + print(); + last_ratio_ = ratio_; + } +} + + + + +/* ****************************** */ +/* PRIVATE METHODS */ +/* ****************************** */ + +void ProgressBar::print() { + fprintf(stdout, "%3d%% [", (int)(ratio_ * 100)); + + for(int i=0; i + + void ArraySchemaTestFixture::SetUp() { + // Error code int rc; // Initialize context @@ -50,6 +53,7 @@ void ArraySchemaTestFixture::SetUp() { } void ArraySchemaTestFixture::TearDown() { + // Error code int rc; // Finalize TileDB context @@ -127,22 +131,32 @@ int ArraySchemaTestFixture::create_dense_array() { /* ****************************** */ /* TESTS */ /* ****************************** */ + +/** + * Tests the array schema creation and retrieval. + */ TEST_F(ArraySchemaTestFixture, test_array_schema) { - // Auxiliary + // Error code int rc; - TileDB_ArraySchema array_schema_disk; // Create array rc = create_dense_array(); ASSERT_EQ(rc, TILEDB_OK); // Load array schema from the disk + TileDB_ArraySchema array_schema_disk; rc = tiledb_array_load_schema( tiledb_ctx_, array_name_.c_str(), &array_schema_disk); ASSERT_EQ(rc, TILEDB_OK); + // For easy reference + int64_t* tile_extents_disk = + static_cast(array_schema_disk.tile_extents_); + int64_t* tile_extents = + static_cast(array_schema_.tile_extents_); + // Get real array path std::string array_name_real = real_dir(array_name_); ASSERT_STRNE(array_name_real.c_str(), ""); @@ -160,10 +174,6 @@ TEST_F(ArraySchemaTestFixture, test_array_schema) { ASSERT_EQ(array_schema_disk.compression_[1], array_schema_.compression_[1]); ASSERT_EQ(array_schema_disk.types_[0], array_schema_.types_[0]); ASSERT_EQ(array_schema_disk.types_[1], array_schema_.types_[1]); - - int* tile_extents_disk = static_cast(array_schema_disk.tile_extents_); - int* tile_extents = static_cast(array_schema_.tile_extents_); - ASSERT_EQ(tile_extents_disk[0], tile_extents[0]); ASSERT_EQ(tile_extents_disk[1], tile_extents[1]); diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index 9478e769..70749fe8 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -26,6 +26,7 @@ #include #include "c_api.h" +#include "progress_bar.h" #include #include #include @@ -807,6 +808,8 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_reads) { int64_t d1_hi = 0; int64_t height = 0, width = 0; + ProgressBar* progress_bar = new ProgressBar(); + for (int iter = 0; iter < 100; ++iter) { height = rand() % (dim0 - d0_lo); width = rand() % (dim1 - d1_lo); @@ -837,7 +840,10 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_reads) { // Clean up delete [] buffer; + progress_bar->load(1.0/100); } + + delete progress_bar; } // end of test_random_sorted_reads From 9b0498b102cdb809f4c1ea19ee9514aefc5dad69 Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 27 Dec 2016 18:07:10 -0500 Subject: [PATCH 43/57] Edited c_api_dense_array_spec tests --- test/include/c_api/c_api_dense_array_spec.h | 240 ++++ test/src/c_api/c_api_array_schema_spec.cc | 10 + test/src/c_api/c_api_dense_array_spec.cc | 1419 +++++++++---------- 3 files changed, 885 insertions(+), 784 deletions(-) create mode 100644 test/include/c_api/c_api_dense_array_spec.h diff --git a/test/include/c_api/c_api_dense_array_spec.h b/test/include/c_api/c_api_dense_array_spec.h new file mode 100644 index 00000000..356eedbe --- /dev/null +++ b/test/include/c_api/c_api_dense_array_spec.h @@ -0,0 +1,240 @@ +/** + * @file c_api_dense_array_spec.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Declarations for testing the C API dense array spec. + */ + +#ifndef __C_API_DENSE_ARRAY_SPEC_H__ +#define __C_API_DENSE_ARRAY_SPEC_H__ + +#include "c_api.h" +#include + + + +/** Test fixture for dense array operations. */ +class DenseArrayTestFixture: public testing::Test { + + public: + /* ********************************* */ + /* CONSTANTS */ + /* ********************************* */ + /** Workspace folder name. */ + const std::string WORKSPACE = ".__workspace/"; + + + + + /* ********************************* */ + /* GTEST FUNCTIONS */ + /* ********************************* */ + + /** Test initialization. */ + virtual void SetUp(); + + /** Test finalization. */ + virtual void TearDown(); + + + + + /* ********************************* */ + /* PUBLIC METHODS */ + /* ********************************* */ + + /** + * Checks two buffers, one before and one after the updates. The updates + * are given as function inputs and facilitate the check. + * + * @param buffer_before The buffer before the updates. + * @param buffer_after The buffer after the updates. + * @param buffer_updates_a1 The updated attribute values. + * @param buffer_updates_coords The coordinates where the updates occurred. + * @param domain_size_0 The domain size of the first dimension. + * @param domain_size_1 The domain size of the second dimension. + * @param update_num The number of updates. + * @return True on success and false on error. + */ + static bool check_buffer_after_updates( + const int* buffer_before, + const int* buffer_after, + const int* buffer_updates_a1, + const int64_t* buffer_updates_coords, + const int64_t domain_size_0, + const int64_t domain_size_1, + const int64_t update_num); + + /** + * Creates a 2D dense array. + * + * @param tile_extent_0 The tile extent along the first dimension. + * @param tile_extent_1 The tile extent along the second dimension. + * @param domain_0_lo The smallest value of the first dimension domain. + * @param domain_0_hi The largest value of the first dimension domain. + * @param domain_1_lo The smallest value of the second dimension domain. + * @param domain_1_hi The largest value of the second dimension domain. + * @param capacity The tile capacity. + * @param enable_compression If true, then GZIP compression is used. + * @param cell_order The cell order. + * @param tile_order The tile order. + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int create_dense_array_2D( + const int64_t tile_extent_0, + const int64_t tile_extent_1, + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int64_t capacity, + const bool enable_compression, + const int cell_order, + const int tile_order); + + /** + * Generates a 1D buffer containing the cell values of a 2D array. + * Each cell value equals (row index * total number of columns + col index). + * + * @param domain_size_0 The domain size of the first dimension. + * @param domain_size_1 The domain size of the second dimension. + * @return The created buffer of size domain_size_0*domain_size_1 integers. + * Note that the function creates the buffer with 'new'. Make sure + * to delete the returned buffer in the caller function. + */ + int* generate_1D_int_buffer( + const int64_t domain_size_0, + const int64_t domain_size_1); + + /** + * Generates a 2D buffer containing the cell values of a 2D array. + * Each cell value equals (row index * total number of columns + col index). + * @param domain_size_0 The domain size of the first dimension. + * @param domain_size_1 The domain size of the second dimension. + * @return The created 2D buffer. Note that the function creates the buffer + * with 'new'. Make sure to delete the returned buffer in the caller + * function. + */ + int** generate_2D_buffer( + const int64_t domain_size_0, + const int64_t domain_size_1); + + /** + * Reads a subarray oriented by the input boundaries and outputs the buffer + * containing the attribute values of the corresponding cells. + * + * @param domain_0_lo The smallest value of the first dimension domain to + * be read. + * @param domain_0_hi The largest value of the first dimension domain to + * be read. + * @param domain_1_lo The smallest value of the second dimension domain to + * be read. + * @param domain_1_hi The largest value of the second dimension domain to + * be read. + * @param read_mode The read mode. + * @return The buffer with the read values. Note that this function is + * creating the buffer with 'new'. Therefore, make sure to properly delete + * it in the caller. On error, it returns NULL. + */ + int* read_dense_array_2D( + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int read_mode); + + /** Sets the array name for the current test. */ + void set_array_name(const char *); + + /** + * Updates random locations in a dense array with the input domain sizes. + * + * @param domain_size_0 The domain size of the first dimension. + * @param domain_size_1 The domain size of the second dimension. + * @param udpate_num The number of updates to be performed. + * @param seed The seed for the random generator. + * @param buffers The buffers to be dispatched to the write command. + * @param buffer_sizes The buffer sizes to be dispatched to the write command. + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int update_dense_array_2D( + const int64_t domain_size_0, + const int64_t domain_size_1, + int64_t update_num, + int seed, + void** buffers, + const size_t* buffer_sizes); + + /** + * Write to a 2D dense array tile by tile. The buffer is initialized + * with row_id*domain_size_1+col_id values. + * + * @param domain_size_0 The domain size of the first dimension. + * @param domain_size_1 The domain size of the second dimension. + * @param tile_extent_0 The tile extent along the first dimension. + * @param tile_extent_1 The tile extent along the second dimension. + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int write_dense_array_by_tiles( + const int64_t domain_size_0, + const int64_t domain_size_1, + const int64_t tile_extent_0, + const int64_t tile_extent_1); + + /** + * Writes a 2D dense subarray. + * + * @param subarray The subarray to focus on, given as a vector of low, high + * values. + * @param write_mode The write mode. + * @param buffer The attribute buffer to be populated and written. + * @param buffer_sizes The buffer sizes to be dispatched to the write command. + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int write_dense_subarray_2D( + int64_t* subarray, + int write_mode, + int* buffer, + size_t* buffer_sizes); + + + + + /* ********************************* */ + /* PUBLIC ATTRIBUTES */ + /* ********************************* */ + + /** Array name. */ + std::string array_name_; + /** Array schema object under test. */ + TileDB_ArraySchema array_schema_; + /** TileDB context. */ + TileDB_CTX* tiledb_ctx_; +}; + +#endif diff --git a/test/src/c_api/c_api_array_schema_spec.cc b/test/src/c_api/c_api_array_schema_spec.cc index fd2178d6..be139a5e 100644 --- a/test/src/c_api/c_api_array_schema_spec.cc +++ b/test/src/c_api/c_api_array_schema_spec.cc @@ -35,6 +35,9 @@ #include +/* ****************************** */ +/* GTEST FUNCTIONS */ +/* ****************************** */ void ArraySchemaTestFixture::SetUp() { // Error code @@ -71,6 +74,13 @@ void ArraySchemaTestFixture::TearDown() { ASSERT_EQ(rc, TILEDB_OK); } + + + +/* ****************************** */ +/* PUBLIC METHODS */ +/* ****************************** */ + int ArraySchemaTestFixture::create_dense_array() { // Initialization s int rc; diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index 70749fe8..fe155da7 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -1,31 +1,36 @@ /** - * Copyright (c) 2016 Massachusetts Institute of Technology and Intel Corp. + * @file c_api_dense_array_spec.cc * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * @section LICENSE * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. + * The MIT License * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * Tests of C API for read/write/update operations for dense arrays. + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Tests of C API for dense array operations. */ -#include -#include "c_api.h" +#include "c_api_dense_array_spec.h" #include "progress_bar.h" #include #include @@ -34,890 +39,736 @@ #include #include -/** - * Test fixture for dense array operations. - * The Setup() and TearDown() methods are called - * after each test is called and destroyed respectively. - * In these methods, we create and delete the array - */ -class DenseArrayTestFixture: public testing::Test { - const std::string WORKSPACE = ".__workspace/"; - const std::string ARRAY_100x100_10x10 = "dense_test_100x100_10x10"; - const int ARRAY_RANK_2D = 2; - - public: - // Array schema object under test - TileDB_ArraySchema schema; - // TileDB context - TileDB_CTX* tiledb_ctx; - // Array name is initialized with the workspace folder - std::string arrayName; - - /** - * Default constructor used to create a temporary - * TileDB workspace in the current working directory - * before all tests are called. User must have write - * permissions to this directory - */ - DenseArrayTestFixture(); - - /** - * Default destructor removes the temporary - * TileDB workspace and destroys the TileDB - * context - */ - ~DenseArrayTestFixture(); - - /** - * Set the array name for the current test - */ - void setArrayName(const char *); - - /** - * Generate a test buffer to full up the dense array where - * each cell value = row index * total number of columns + col index - */ - int **generate_2Dbuffer( - const int, const int); - - /** - * Generate a 1D buffer containing the cell values - * of a 2D array - */ - int *generate_1Dbuffer( - const int, const int); - - /** - * Create the test dense array with given tile extents - */ - int create_dense_array_2D( - const long dim0_tile_extent, - const long dim1_tile_extent, - const long dim0_lo, - const long dim0_hi, - const long dim1_lo, - const long dim1_hi, - const int capacity, - const bool enable_compression, - const int cell_order, - const int tile_order); - - /** - * Load the array chunk by chunk. The buffer is initialized - * with row_id*DIM1+col_id values. Tile extents or chunk - * sizes are defined in the create_dense_array_2D - */ - int write_dense_array_by_chunks( - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1); - - /** - * Load the array in a sorted row-major manner using - * a buffer which is ordered in the global cell order. - * The buffer is initialized cell values as - * row_id*DIM1+col_id values. Tile extents or chunk - * sizes are defined in the create_dense_array_2D - */ - int write_dense_array_sorted_2D( - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1, - const int write_mode); - - int write_dense_array_sorted_range_2D( - int64_t *subarray, - int write_mode, - size_t buffer_sizes[], - int* buffer); - - /** - * Update random locations in the dense array - * These locations are recorded and later - * used to validate reads - */ - int update_dense_array_2D( - const int dim0, - const int dim1, - int length, - int srand_key, - int *buffer_a1, - int64_t *buffer_coords, - const void* buffers[], - size_t buffer_sizes[2]); - - /** - * Read cell values of a dense array for a given - * range and test whether it matches the value - * row_id*DIM1+col_id - */ - int * read_dense_array( - const int64_t dim0_lo, - const int64_t dim0_hi, - const int64_t dim1_lo, - const int64_t dim1_hi, - const int read_mode); - - /** - * Not a member-function. A global - * stand-alone checker to compare two buffers - */ - static bool check_buffer( - const int *before, - const int *after, - const int *buffer_a1, - const int64_t *buffer_coords, - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1, - const int length); - - /** - * Code here will be called immediately after the constructor (right - * before each test). - */ - virtual void SetUp(); - - /** - * Code here will be called immediately after each test - * (right before the destructor). - */ - virtual void TearDown(); -}; - -DenseArrayTestFixture::DenseArrayTestFixture() { - // Initialize context with the default configuration parameters - tiledb_ctx_init(&tiledb_ctx, NULL); - if (tiledb_workspace_create(tiledb_ctx, WORKSPACE.c_str()) - != TILEDB_OK) { - exit(EXIT_FAILURE); - } -} -DenseArrayTestFixture::~DenseArrayTestFixture() { - // Finalize TileDB context - tiledb_ctx_finalize(tiledb_ctx); - // Remove the temporary workspace - std::string command = "rm -rf "; - command.append(WORKSPACE); - int rc = system(command.c_str()); - assert(rc == 0); -} +/* ****************************** */ +/* GTEST FUNCTIONS */ +/* ****************************** */ void DenseArrayTestFixture::SetUp() { // Reset the random number generator srand(0); + + // Error code + int rc; + + // Initialize context + rc = tiledb_ctx_init(&tiledb_ctx_, NULL); + ASSERT_EQ(rc, TILEDB_OK); + + // Create workspace + rc = tiledb_workspace_create(tiledb_ctx_, WORKSPACE.c_str()); + ASSERT_EQ(rc, TILEDB_OK); } void DenseArrayTestFixture::TearDown() { - // delete currently tested array - if (arrayName.empty()) return; + // Error code + int rc; - tiledb_delete( - (const TileDB_CTX*)this->tiledb_ctx, - this->arrayName.c_str()); - arrayName.clear(); -} + // Finalize TileDB context + rc = tiledb_ctx_finalize(tiledb_ctx_); + ASSERT_EQ(rc, TILEDB_OK); -void DenseArrayTestFixture::setArrayName(const char *name) { - this->arrayName.append(WORKSPACE); - this->arrayName.append(name); + // Remove the temporary workspace + std::string command = "rm -rf "; + command.append(WORKSPACE); + rc = system(command.c_str()); + ASSERT_EQ(rc, 0); } -int **DenseArrayTestFixture::generate_2Dbuffer( - const int dim0, - const int dim1) { - int **buffer = new int * [dim0]; - for (int i = 0; i < dim0; ++i) { - buffer[i] = new int [dim1]; - for (int j = 0; j < dim1; ++j) { - buffer[i][j] = i * dim1 + j; + + + +/* ****************************** */ +/* PUBLIC METHODS */ +/* ****************************** */ + +bool DenseArrayTestFixture::check_buffer_after_updates( + const int* buffer_before, + const int* buffer_after, + const int* buffer_updates_a1, + const int64_t *buffer_updates_coords, + const int64_t domain_size_0, + const int64_t domain_size_1, + const int64_t update_num) { + // Initializations + int l,r; + int64_t cell_num = domain_size_0*domain_size_1; + + // Check the contents of the buffers cell by cell + for(int64_t i = 0; i < cell_num; ++i) { + l = buffer_before[i]; + r = buffer_after[i]; + + // If they are not the same, check if it is due to an update + if(l!=r) { + bool found = false; + for(int64_t k = 0; k < update_num; ++k) { + // The difference is due to an update + if(r == buffer_updates_a1[k] && + (l/domain_size_1) == buffer_updates_coords[2*k] && + (l%domain_size_1) == buffer_updates_coords[2*k+1]) { + found = true; + break; + } + } + + // The difference is not due to an update + if(!found) + return false; } } - return buffer; -} -int *DenseArrayTestFixture::generate_1Dbuffer( - const int dim0, - const int dim1) { - int *buffer = new int [dim0*dim1]; - for (int i = 0;i < dim0; ++i) - for (int j = 0;j < dim1; ++j) - buffer[i*dim1+j] = i*dim1+j; - return buffer; + // Success + return true; } int DenseArrayTestFixture::create_dense_array_2D( - const long dim0_tile_extent, - const long dim1_tile_extent, - const long dim0_lo, - const long dim0_hi, - const long dim1_lo, - const long dim1_hi, - const int capacity, - const bool enable_compression, - const int cell_order, - const int tile_order) { + const int64_t tile_extent_0, + const int64_t tile_extent_1, + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int64_t capacity, + const bool enable_compression, + const int cell_order, + const int tile_order) { + // Error code + int rc; // Prepare and set the array schema object and data structures const int attribute_num = 1; const char* attributes[] = { "ATTR_INT32" }; const char* dimensions[] = { "X", "Y" }; - int64_t domain[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; - int64_t tile_extents[] = { dim0_tile_extent, dim1_tile_extent }; + int64_t domain[] = { domain_0_lo, domain_0_hi, domain_1_lo, domain_1_hi }; + int64_t tile_extents[] = { tile_extent_0, tile_extent_1 }; const int types[] = { TILEDB_INT32, TILEDB_INT64 }; - int compression[sizeof(dimensions)]; + int compression[2]; + const int dense = 1; - if (!enable_compression) { - compression[0] = TILEDB_NO_COMPRESSION; - compression[1] = TILEDB_NO_COMPRESSION; + if(!enable_compression) { + compression[0] = TILEDB_NO_COMPRESSION; + compression[1] = TILEDB_NO_COMPRESSION; } else { - compression[0] = TILEDB_GZIP; - compression[1] = TILEDB_GZIP; + compression[0] = TILEDB_GZIP; + compression[1] = TILEDB_GZIP; } - const int dense = 1; - tiledb_array_set_schema( - &schema, - arrayName.c_str(), - attributes, - attribute_num, - capacity, - cell_order, - NULL, - compression, - dense, - dimensions, - ARRAY_RANK_2D, - domain, - 4*sizeof(int64_t), - tile_extents, - 2*sizeof(int64_t), - tile_order, - types); + // Set the array schema + rc = tiledb_array_set_schema( + &array_schema_, + array_name_.c_str(), + attributes, + attribute_num, + capacity, + cell_order, + NULL, + compression, + dense, + dimensions, + 2, + domain, + 4*sizeof(int64_t), + tile_extents, + 2*sizeof(int64_t), + tile_order, + types); + if(rc != TILEDB_OK) + return TILEDB_ERR; // Create the array - int ret = tiledb_array_create(tiledb_ctx, &schema); - return ret; -} // end of create_dense_array - -int DenseArrayTestFixture::write_dense_array_by_chunks( - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1) { - - int ret = 0; - int **buffer = generate_2Dbuffer(dim0, dim1); - int64_t segmentSize = chunkDim0 * chunkDim1; - int * buffer_a1 = new int [segmentSize]; - for (int i = 0; i < segmentSize; ++i) - buffer_a1[i] = 0; - - /* Initialize the array in WRITE mode. */ - TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - TILEDB_ARRAY_WRITE, - NULL, // No range - entire domain - NULL, // No projection - all attributes - 0); // Meaningless when "attributes" is NULL - - const void* buffers[ARRAY_RANK_2D]; - buffers[0] = buffer_a1; - size_t bufferSizes[ARRAY_RANK_2D]; - int64_t index = 0L; - size_t writeSize = 0L; - for (int i = 0; i < dim0; i += chunkDim0) { - for (int j = 0; j < dim1; j += chunkDim1) { - long tile_rows = ((i + chunkDim0) < dim0) ? chunkDim0 : (dim0 - i); - long tile_cols = ((j + chunkDim1) < dim1) ? chunkDim1 : (dim1 - j); - int k,l; - for (k = 0; k < tile_rows; ++k) { - for (l = 0; l < tile_cols; ++l) { - index = uint64_t(k * tile_cols + l); - buffer_a1[index] = buffer[uint64_t(i + k)][uint64_t(j + l)]; - } - } - writeSize = k*l* sizeof(int); + rc = tiledb_array_create(tiledb_ctx_, &array_schema_); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Free array schema + rc = tiledb_array_free_schema(&array_schema_); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Success + return TILEDB_OK; +} + +int* DenseArrayTestFixture::generate_1D_int_buffer( + const int64_t domain_size_0, + const int64_t domain_size_1) { + // Create buffer + int *buffer = new int[domain_size_0 * domain_size_1]; + + // Populate buffer + for(int64_t i = 0; i < domain_size_0; ++i) + for(int64_t j = 0; j < domain_size_1; ++j) + buffer[i*domain_size_1+j] = i * domain_size_1 + j; + + // Return + return buffer; +} - bufferSizes[0] = { writeSize }; - ret = tiledb_array_write(tiledb_array, buffers, bufferSizes); - if (ret != TILEDB_OK) { - return ret; - } +int** DenseArrayTestFixture::generate_2D_buffer( + const int64_t domain_size_0, + const int64_t domain_size_1) { + // Create buffer + int **buffer = new int*[domain_size_1]; + + // Populate buffer + for(int64_t i = 0; i < domain_size_0; ++i) { + buffer[i] = new int [domain_size_1]; + for(int64_t j = 0; j < domain_size_1; ++j) { + buffer[i][j] = i * domain_size_1 + j; } } - /* Finalize the array. */ - ret = tiledb_array_finalize(tiledb_array); - return ret; -} // end of write_dense_array_by_chunks - -int DenseArrayTestFixture::write_dense_array_sorted_2D( - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1, - const int write_mode) { + // Return + return buffer; +} - int ret = 0; - int *buffer = generate_1Dbuffer(dim0, dim1); +int* DenseArrayTestFixture::read_dense_array_2D( + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int read_mode) { + // Error code + int rc; - // Set the subarray for sorted writes - int64_t subarray[] = { 0, dim0-1, 0, dim1-1 }; + // Initialize a range + const int64_t range[] = {domain_0_lo, domain_0_hi, domain_1_lo, domain_1_hi}; - /* Initialize the array in WRITE mode. */ - TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - write_mode, - subarray, - NULL, // No projection - all attributes - 1); // Meaningless when "attributes" is NULL - - const void *buffers[] = { buffer }; - const size_t buffer_sizes[] = { (size_t) (dim0*dim1*sizeof(int)) }; - - ret = tiledb_array_write( - tiledb_array, - buffers, - buffer_sizes); - - /* Finalize the array. */ - ret = tiledb_array_finalize( - tiledb_array); - - delete(buffer); - return ret; -} // end of write_dense_array_sorted_2D - -int DenseArrayTestFixture::write_dense_array_sorted_range_2D( - int64_t *subarray, - int write_mode, - size_t buffer_sizes[], - int* buffer) { - - int ret = 0; - const char *attributes[] = { "ATTR_INT32" }; + // Subset over a specific attribute + const char* attributes[] = { "ATTR_INT32" }; - /* Initialize the array in WRITE mode. */ + // Initialize the array in the input mode TileDB_Array* tiledb_array; - ret = tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - write_mode, - subarray, - attributes, - 1); - assert(ret == TILEDB_OK); - - const void * buffers[] = { buffer }; - ret = tiledb_array_write(tiledb_array, buffers, buffer_sizes); - assert(ret == TILEDB_OK); - - /* Finalize the array. */ - ret = tiledb_array_finalize(tiledb_array); - assert(ret == TILEDB_OK); + rc = tiledb_array_init( + tiledb_ctx_, + &tiledb_array, + array_name_.c_str(), + read_mode, + range, + attributes, + 1); + if(rc != TILEDB_OK) + return NULL; + + // Prepare the buffers that will store the result + int64_t domain_size_0 = domain_0_hi - domain_0_lo + 1; + int64_t domain_size_1 = domain_1_hi - domain_1_lo + 1; + int64_t cell_num = domain_size_0 * domain_size_1; + int* buffer_a1 = new int[cell_num]; + void* buffers[] = { buffer_a1 }; + size_t buffer_size_a1 = cell_num * sizeof(int); + size_t buffer_sizes[] = { buffer_size_a1 }; + + // Read from array + rc = tiledb_array_read(tiledb_array, buffers, buffer_sizes); + if(rc != TILEDB_OK) + return NULL; + + // Finalize the array + rc = tiledb_array_finalize(tiledb_array); + if(rc != TILEDB_OK) + return NULL; + + // Success - return the created buffer + return buffer_a1; +} - return ret; +void DenseArrayTestFixture::set_array_name(const char *name) { + array_name_ = WORKSPACE + name; } int DenseArrayTestFixture::update_dense_array_2D( - const int dim0, - const int dim1, - int length, - int srand_key, - int *buffer_a1, - int64_t *buffer_coords, - const void* buffers[], - size_t buffer_sizes[2]) { - - /* Subset over attribute "a1" and the coordinates. */ + const int64_t domain_size_0, + const int64_t domain_size_1, + int64_t update_num, + int seed, + void** buffers, + const size_t* buffer_sizes) { + // Error code + int rc; + + // For easy reference + int* buffer_a1 = (int*) buffers[0]; + int64_t* buffer_coords = (int64_t*) buffers[1]; + + // Specify attributes to be written const char* attributes[] = { "ATTR_INT32", TILEDB_COORDS }; - /* Initialize the array in WRITE mode. */ + // Initialize the array TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - TILEDB_ARRAY_WRITE_UNSORTED, - NULL, // No range - entire domain - attributes, // No projection - all attributes - 2); // Meaningless when "attributes" is NULL - - /* Populate attribute buffers with some arbitrary values. */ - // Random updates - srand(srand_key); - int64_t d0, d1, x; + rc = tiledb_array_init( + tiledb_ctx_, + &tiledb_array, + array_name_.c_str(), + TILEDB_ARRAY_WRITE_UNSORTED, + NULL, + attributes, + 2); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Populate buffers with random updates + srand(seed); + int64_t x, y, v; int64_t coords_index = 0L; std::map my_map; std::map::iterator it; my_map.clear(); - for (int i = 0; i < length; ++i) { + for(int64_t i = 0; i < update_num; ++i) { std::ostringstream rand_stream; do { std::ostringstream rand_stream; - d0 = rand() % dim0; - d1 = rand() % dim1; - x = rand(); - rand_stream << d0 << "," << d1; + x = rand() % domain_size_0; + y = rand() % domain_size_1; + v = rand(); + rand_stream << x << "," << y; it = my_map.find(rand_stream.str()); } while (it != my_map.end()); - rand_stream << d0 << "," << d1; - my_map[rand_stream.str()] = x; - buffer_coords[coords_index++] = d0; - buffer_coords[coords_index++] = d1; - buffer_a1[i] = x; + rand_stream << x << "," << y; + my_map[rand_stream.str()] = v; + buffer_coords[coords_index++] = x; + buffer_coords[coords_index++] = y; + buffer_a1[i] = v; } - /* Write to array. */ - int ret = tiledb_array_write(tiledb_array, buffers, buffer_sizes); - - if (ret != TILEDB_OK) { - return ret; - } - - /* Finalize the array. */ - ret = tiledb_array_finalize(tiledb_array); - return ret; -} // end of update_array - -int * DenseArrayTestFixture::read_dense_array( - const int64_t dim0_lo, - const int64_t dim0_hi, - const int64_t dim1_lo, - const int64_t dim1_hi, - const int read_mode) { - - /* Initialize a range. */ - const int64_t range[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; - - /* Subset over attribute "a1". */ - const char* attributes[] = { "ATTR_INT32" }; - - /* Initialize the array in READ mode. */ - TileDB_Array* tiledb_array; - tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - read_mode, - range, - attributes, - 1); - - /* Prepare cell buffers for attributes "a1" and "a2". */ - size_t dim0 = dim0_hi - dim0_lo + 1; - size_t dim1 = dim1_hi - dim1_lo + 1; - size_t size = dim0*dim1; - int *buffer_a1 = new int [size]; - void* buffers[] = { buffer_a1 }; - size_t buffer_sizes[1] = { size*sizeof(int) }; - - /* Read from array. */ - int ret = tiledb_array_read(tiledb_array, buffers, buffer_sizes); - - if (ret != TILEDB_OK) { - return NULL; - } - - /* Finalize the array. */ - tiledb_array_finalize(tiledb_array); - return buffer_a1; -} // end of read_dense_array - -bool DenseArrayTestFixture::check_buffer( - const int *before, - const int *after, - const int *buffer_a1, - const int64_t *buffer_coords, - const int64_t dim0, - const int64_t dim1, - const int64_t chunkDim0, - const int64_t chunkDim1, - const int length) { - - int l,r; - bool fail = false; - int count = 0; - for (int64_t i = 0; i < dim0*dim1; ++i) { - l = before[i]; - r = after[i]; - - if (l!=r) { - bool found = false; - for (int k = 0; k < length; ++k) { - if (r==buffer_a1[k] && (l/dim1)==buffer_coords[2*k] && - (l%dim1)==buffer_coords[2*k+1]) { - found = true; - count++; + // Write to array + rc = tiledb_array_write( + tiledb_array, + (const void**) buffers, + buffer_sizes); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Finalize the array + rc = tiledb_array_finalize(tiledb_array); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Success + return TILEDB_OK; +} + +int DenseArrayTestFixture::write_dense_array_by_tiles( + const int64_t domain_size_0, + const int64_t domain_size_1, + const int64_t tile_extent_0, + const int64_t tile_extent_1) { + // Error code + int rc; + + // Initialize the array + TileDB_Array* tiledb_array; + rc = tiledb_array_init( + tiledb_ctx_, + &tiledb_array, + array_name_.c_str(), + TILEDB_ARRAY_WRITE, + NULL, + NULL, + 0); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Other initializations + int** buffer = generate_2D_buffer(domain_size_0, domain_size_1); + int64_t cell_num_in_tile = tile_extent_0 * tile_extent_1; + int* buffer_a1 = new int[cell_num_in_tile]; + for(int64_t i = 0; i < cell_num_in_tile; ++i) + buffer_a1[i] = 0; + const void* buffers[2]; + buffers[0] = buffer_a1; + size_t buffer_sizes[2]; + int64_t index = 0L; + size_t buffer_size = 0L; + + // Populate and write tile by tile + for(int64_t i = 0; i < domain_size_0; i += tile_extent_0) { + for(int64_t j = 0; j < domain_size_1; j += tile_extent_1) { + int64_t tile_rows = + ((i + tile_extent_0) < domain_size_0) + ? tile_extent_0 + : (domain_size_0 - i); + int64_t tile_cols = + ((j + tile_extent_1) < domain_size_1) + ? tile_extent_1 + : (domain_size_1 - j); + int64_t k,l; + for(k = 0; k < tile_rows; ++k) { + for(l = 0; l < tile_cols; ++l) { + index = uint64_t(k * tile_cols + l); + buffer_a1[index] = buffer[uint64_t(i + k)][uint64_t(j + l)]; } } - if (!found) { - fail = true; + buffer_size = k*l*sizeof(int); + buffer_sizes[0] = { buffer_size }; + rc = tiledb_array_write(tiledb_array, buffers, buffer_sizes); + if(rc != TILEDB_OK) { + for(int64_t i=0; iload(1.0/100); + // Update progress bar + progress_bar->load(1.0/iter_num); } + // Delete progress bar delete progress_bar; -} // end of test_random_sorted_reads +} /** - * Test is to randomly write regions of the 2D array and - * read them back to validate the writes - * Test runs through 100 iterations to choose random - * width and height of the regions + * Tests random 2D subarray writes. */ TEST_F(DenseArrayTestFixture, test_random_sorted_writes) { - int64_t dim[2] = { 100, 100 }; - int64_t tile_extents[2] = { 10, 10 }; - int64_t dim_ranges[2][2] = - { - { 0, dim[0]-1 }, - { 0, dim[1]-1 } - }; - int capacity = 0; // 0 means use default capacity + // Error code + int rc; + + // Parameters used in this test + int64_t domain_size_0 = 100; + int64_t domain_size_1 = 100; + int64_t tile_extent_0 = 10; + int64_t tile_extent_1 = 10; + int64_t domain_0_lo = 0; + int64_t domain_0_hi = domain_size_0-1; + int64_t domain_1_lo = 0; + int64_t domain_1_hi = domain_size_1-1; + int64_t capacity = 0; // 0 means use default capacity int cell_order = TILEDB_ROW_MAJOR; int tile_order = TILEDB_ROW_MAJOR; + int iter_num = 100; + + // Set array name + set_array_name("dense_test_100x100_10x10"); - setArrayName("dense_test_5000x10000_100x100"); + // Create a progress bar + ProgressBar* progress_bar = new ProgressBar(); // Create a dense integer array - create_dense_array_2D( - tile_extents[0], - tile_extents[1], - dim_ranges[0][0], - dim_ranges[0][1], - dim_ranges[1][0], - dim_ranges[1][1], - capacity, - false, - cell_order, - tile_order); - - int iterations = 10; + rc = create_dense_array_2D( + tile_extent_0, + tile_extent_1, + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi, + capacity, + false, + cell_order, + tile_order); + EXPECT_EQ(rc, TILEDB_OK); + + // Write random subarray, then read it back and check int64_t d0[2], d1[2]; + for(int i = 0; i < iter_num; ++i) { + // Create subarray + d0[0] = rand() % domain_size_0; + d1[0] = rand() % domain_size_1; + d0[1] = d0[0] + rand() % (domain_size_0 - d0[0]); + d1[1] = d1[0] + rand() % (domain_size_1 - d1[0]); + int64_t subarray[] = { d0[0], d0[1], d1[0], d1[1] }; - for (int i = 0; i < iterations; ++i) { - d0[0] = rand() % dim[0]; - d1[0] = rand() % dim[1]; - d0[1] = d0[0] + rand() % (dim[0] - d0[0]); - d1[1] = d1[0] + rand() % (dim[1] - d1[0]); + // Prepare buffers + int64_t subarray_length[2] = { d0[1] - d0[0] + 1, d1[1] - d1[0] + 1 }; + int64_t cell_num_in_subarray = subarray_length[0] * subarray_length[1]; + int *buffer = new int[cell_num_in_subarray]; + int64_t index = 0; + size_t buffer_size = cell_num_in_subarray*sizeof(int); + size_t buffer_sizes[] = { buffer_size }; + for(int64_t r = 0; r < subarray_length[0]; ++r) + for(int64_t c = 0; c < subarray_length[1]; ++c) + buffer[index++] = - (rand() % 999999); - int64_t subarray[] = { d0[0], d0[1], d1[0], d1[1] }; - size_t query_size[2] = { (size_t)(d0[1] - d0[0] + 1), - (size_t)(d1[1] - d1[0] + 1) }; - size_t buffer_size = query_size[0] * query_size[1]; + // Write 2D subarray + rc = write_dense_subarray_2D( + subarray, + TILEDB_ARRAY_WRITE_SORTED_ROW, + buffer, + buffer_sizes); + EXPECT_EQ(rc, TILEDB_OK); + + // Read back the same subarray + int* read_buffer = + read_dense_array_2D( + subarray[0], + subarray[1], + subarray[2], + subarray[3], + TILEDB_ARRAY_READ_SORTED_ROW); + EXPECT_TRUE(read_buffer != NULL); + + // Check the two buffers + for(index = 0; index < cell_num_in_subarray; ++index) + EXPECT_EQ(buffer[index], read_buffer[index]); + + // Clean up + delete [] buffer; + delete [] read_buffer; + + // Update progress bar + progress_bar->load(1.0/iter_num); + } - int *buffer = new int [buffer_size]; - size_t index = 0; + // Delete progress bar + delete progress_bar; +} - for (size_t r = 0; r < query_size[0]; ++r) - for (size_t c = 0; c < query_size[1]; ++c) - buffer[index++] = - (rand() % 999999); +/** + * Test random updates in a 2D dense array. + */ +TEST_F(DenseArrayTestFixture, test_random_updates) { + // Error code + int rc; + + // Parameters used in this test + int64_t domain_size_0 = 100; + int64_t domain_size_1 = 100; + int64_t tile_extent_0 = 10; + int64_t tile_extent_1 = 10; + int64_t domain_0_lo = 0; + int64_t domain_0_hi = domain_size_0-1; + int64_t domain_1_lo = 0; + int64_t domain_1_hi = domain_size_1-1; + int64_t capacity = 0; // 0 means use default capacity + int cell_order = TILEDB_ROW_MAJOR; + int tile_order = TILEDB_ROW_MAJOR; + int64_t update_num = 100; + int seed = 7; - write_dense_array_sorted_range_2D( - subarray, - TILEDB_ARRAY_WRITE_SORTED_ROW, - query_size, - buffer); + // Set array name + set_array_name("dense_test_100x100_10x10"); - int *out_buffer = read_dense_array( - subarray[0], - subarray[1], - subarray[2], - subarray[3], - TILEDB_ARRAY_READ_SORTED_ROW); + // Create a dense integer array + rc = create_dense_array_2D( + tile_extent_0, + tile_extent_1, + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi, + capacity, + false, + cell_order, + tile_order); + EXPECT_EQ(rc, TILEDB_OK); - for (index = 0; index < buffer_size; ++index) - EXPECT_EQ(buffer[index], out_buffer[index]); + // Write array cells with value = row id * COLUMNS + col id + // to disk tile by tile + rc = write_dense_array_by_tiles( + domain_size_0, + domain_size_1, + tile_extent_0, + tile_extent_1); + EXPECT_EQ(rc, TILEDB_OK); - delete [] buffer; - delete [] out_buffer; - } + // Read the entire array back to memory + int *before_update = + read_dense_array_2D( + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi, + TILEDB_ARRAY_READ); + EXPECT_TRUE(before_update != NULL); + + // Prepare random updates + int *buffer_a1 = new int[update_num]; + int64_t *buffer_coords = new int64_t[2*update_num]; + void* buffers[] = { buffer_a1, buffer_coords}; + size_t buffer_sizes[2]; + buffer_sizes[0] = update_num*sizeof(int); + buffer_sizes[1] = 2*update_num*sizeof(int64_t); + + rc = update_dense_array_2D( + domain_size_0, + domain_size_1, + update_num, + seed, + buffers, + buffer_sizes); + EXPECT_EQ(rc, TILEDB_OK); + + // Read the entire array back to memory after update + int *after_update = + read_dense_array_2D( + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi, + TILEDB_ARRAY_READ); + EXPECT_TRUE(after_update != NULL); + + // Compare array before and after + bool success = + check_buffer_after_updates( + before_update, + after_update, + buffer_a1, + buffer_coords, + domain_size_0, + domain_size_1, + update_num); + EXPECT_TRUE(success); + + // Clean up + delete [] before_update; + delete [] after_update; + delete [] buffer_a1; + delete [] buffer_coords; } + From 9a60897e34338d643837ffdc98c3370c3f10143b Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 27 Dec 2016 18:52:26 -0500 Subject: [PATCH 44/57] Edited c_api_sparse_array_spec tests. --- test/include/c_api/c_api_dense_array_spec.h | 2 +- test/include/c_api/c_api_sparse_array_spec.h | 150 +++++ test/src/c_api/c_api_dense_array_spec.cc | 17 +- test/src/c_api/c_api_sparse_array_spec.cc | 578 +++++++++---------- 4 files changed, 431 insertions(+), 316 deletions(-) create mode 100644 test/include/c_api/c_api_sparse_array_spec.h diff --git a/test/include/c_api/c_api_dense_array_spec.h b/test/include/c_api/c_api_dense_array_spec.h index 356eedbe..df9169a5 100644 --- a/test/include/c_api/c_api_dense_array_spec.h +++ b/test/include/c_api/c_api_dense_array_spec.h @@ -40,11 +40,11 @@ /** Test fixture for dense array operations. */ class DenseArrayTestFixture: public testing::Test { - public: /* ********************************* */ /* CONSTANTS */ /* ********************************* */ + /** Workspace folder name. */ const std::string WORKSPACE = ".__workspace/"; diff --git a/test/include/c_api/c_api_sparse_array_spec.h b/test/include/c_api/c_api_sparse_array_spec.h new file mode 100644 index 00000000..1307406a --- /dev/null +++ b/test/include/c_api/c_api_sparse_array_spec.h @@ -0,0 +1,150 @@ +/** + * @file c_api_sparse_array_spec.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Declarations for testing the C API sparse array spec. + */ + +#ifndef __C_API_SPARSE_ARRAY_SPEC_H__ +#define __C_API_SPARSE_ARRAY_SPEC_H__ + +#include "c_api.h" +#include + +class SparseArrayTestFixture: public testing::Test { + public: + /* ********************************* */ + /* CONSTANTS */ + /* ********************************* */ + + /** Workspace folder name. */ + const std::string WORKSPACE = ".__workspace/"; + + + + + /* ********************************* */ + /* GTEST FUNCTIONS */ + /* ********************************* */ + + /** Test initialization. */ + virtual void SetUp(); + + /** Test finalization. */ + virtual void TearDown(); + + + + + /* ********************************* */ + /* PUBLIC METHODS */ + /* ********************************* */ + + /** + * Creates a 2D sparse array. + * + * @param tile_extent_0 The tile extent along the first dimension. + * @param tile_extent_1 The tile extent along the second dimension. + * @param domain_0_lo The smallest value of the first dimension domain. + * @param domain_0_hi The largest value of the first dimension domain. + * @param domain_1_lo The smallest value of the second dimension domain. + * @param domain_1_hi The largest value of the second dimension domain. + * @param capacity The tile capacity. + * @param enable_compression If true, then GZIP compression is used. + * @param cell_order The cell order. + * @param tile_order The tile order. + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int create_sparse_array_2D( + const int64_t tile_extent_0, + const int64_t tile_extent_1, + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int64_t capacity, + const bool enable_compression, + const int cell_order, + const int tile_order); + + /** + * Reads a subarray oriented by the input boundaries and outputs the buffer + * containing the attribute values of the corresponding cells. + * + * @param domain_0_lo The smallest value of the first dimension domain to + * be read. + * @param domain_0_hi The largest value of the first dimension domain to + * be read. + * @param domain_1_lo The smallest value of the second dimension domain to + * be read. + * @param domain_1_hi The largest value of the second dimension domain to + * be read. + * @param read_mode The read mode. + * @return The buffer with the read values. Note that this function is + * creating the buffer with 'new'. Therefore, make sure to properly delete + * it in the caller. On error, it returns NULL. + */ + int* read_sparse_array_2D( + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int read_mode); + + /** Sets the array name for the current test. */ + void set_array_name(const char *); + + /** + * Write random values in unsorted mode. The buffer is initialized with each + * cell being equalt to row_id*domain_size_1+col_id. + * + * @param domain_size_0 The domain size of the first dimension. + * @param domain_size_1 The domain size of the second dimension. + * @return TILEDB_OK on success and TILEDB_ERR on error. + */ + int write_sparse_array_unsorted_2D( + const int64_t domain_size_0, + const int64_t domain_size_1); + + + + + /* ********************************* */ + /* PUBLIC ATTRIBUTES */ + /* ********************************* */ + + /** Array name. */ + std::string array_name_; + /** Array schema object under test. */ + TileDB_ArraySchema array_schema_; + /** TileDB context. */ + TileDB_CTX* tiledb_ctx_; + +}; + +#endif diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index fe155da7..3215fc64 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -233,8 +233,13 @@ int* DenseArrayTestFixture::read_dense_array_2D( // Error code int rc; - // Initialize a range - const int64_t range[] = {domain_0_lo, domain_0_hi, domain_1_lo, domain_1_hi}; + // Initialize a subarray + const int64_t subarray[] = { + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi + }; // Subset over a specific attribute const char* attributes[] = { "ATTR_INT32" }; @@ -246,7 +251,7 @@ int* DenseArrayTestFixture::read_dense_array_2D( &tiledb_array, array_name_.c_str(), read_mode, - range, + subarray, attributes, 1); if(rc != TILEDB_OK) @@ -475,7 +480,7 @@ int DenseArrayTestFixture::write_dense_subarray_2D( * Tests 100 random 2D subarrays and checks if the value of each cell is equal * to row_id*dim1+col_id. Top left corner is always 4,4. */ -TEST_F(DenseArrayTestFixture, test_random_sorted_reads) { +TEST_F(DenseArrayTestFixture, test_random_dense_sorted_reads) { // Error code int rc; @@ -575,7 +580,7 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_reads) { /** * Tests random 2D subarray writes. */ -TEST_F(DenseArrayTestFixture, test_random_sorted_writes) { +TEST_F(DenseArrayTestFixture, test_random_dense_sorted_writes) { // Error code int rc; @@ -671,7 +676,7 @@ TEST_F(DenseArrayTestFixture, test_random_sorted_writes) { /** * Test random updates in a 2D dense array. */ -TEST_F(DenseArrayTestFixture, test_random_updates) { +TEST_F(DenseArrayTestFixture, test_random_dense_updates) { // Error code int rc; diff --git a/test/src/c_api/c_api_sparse_array_spec.cc b/test/src/c_api/c_api_sparse_array_spec.cc index b42ef36c..b1b7e4e0 100644 --- a/test/src/c_api/c_api_sparse_array_spec.cc +++ b/test/src/c_api/c_api_sparse_array_spec.cc @@ -1,316 +1,264 @@ /** - * Copyright (c) 2016 Massachusetts Institute of Technology and Intel Corp. + * @file c_api_sparse_array_spec.cc * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * @section LICENSE * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. + * The MIT License * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * Tests of C API for read/write/update operations for - * sparse arrays + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Tests of C API for sparse array operations. */ -#include -#include "c_api.h" +#include "c_api_sparse_array_spec.h" +#include "progress_bar.h" +#include #include +#include #include #include -#include #include -#include -class SparseArrayTestFixture: public testing::Test { - const std::string WORKSPACE = ".__workspace/"; - const std::string ARRAY_100x100 = "sparse_test_100x100_10x10"; - const int ARRAY_RANK_2D = 2; - -public: - // Array schema object under test - TileDB_ArraySchema schema; - // TileDB context - TileDB_CTX* tiledb_ctx; - // Array name is initialized with the workspace folder - std::string arrayName; - - /** - * Create the test dense array with given tile extents - */ - int create_sparse_array_2D( - const long dim0_tile_extent, - const long dim1_tile_extent, - const long dim0_lo, - const long dim0_hi, - const long dim1_lo, - const long dim1_hi, - const int capacity, - int cell_order, - int tile_order, - const bool enable_compression); - - /** - * Load the array in a sorted row-major manner using - * a buffer which is ordered in the global cell order. - * The buffer is initialized cell values as - * row_id*DIM1+col_id values. Tile extents or chunk - * sizes are defined in the create_sparse_array_2D - */ - int write_sparse_array_unsorted_2D( - const int64_t dim0, - const int64_t dim1); - - /** - * Read cell values of a sparse array for a given - * range and test whether it matches the value - * row_id*DIM1+col_id - */ - int * read_sparse_array_2D( - const int64_t dim0_lo, - const int64_t dim0_hi, - const int64_t dim1_lo, - const int64_t dim1_hi, - const int read_mode); - - /** - * Default constructor used to create a temporary - * TileDB workspace in the current working directory - * before all tests are called. User must have write - * permissions to this directory - */ - SparseArrayTestFixture(); - - /** - * Default destructor removes the temporary - * TileDB workspace and destroys the TileDB - * context - */ - ~SparseArrayTestFixture(); - - /** - * Code here will be called immediately after the constructor (right - * before each test). - */ - virtual void SetUp() { - // do Nothing - } - /** - * Code here will be called immediately after each test - * (right before the destructor). - */ - virtual void TearDown(); - - /** - * Sets the object member array name - * For now each test creates its own - * array. Later, we can share this - * across multiple tests - */ - void setArrayName(const char *name); - -}; // end of SparseArrayTestFixture - -SparseArrayTestFixture::SparseArrayTestFixture() { - // Initialize context with the default configuration parameters - tiledb_ctx_init(&tiledb_ctx, NULL); - if (tiledb_workspace_create(tiledb_ctx, WORKSPACE.c_str()) - != TILEDB_OK) { - exit(EXIT_FAILURE); - } + + +/* ****************************** */ +/* GTEST FUNCTIONS */ +/* ****************************** */ + +void SparseArrayTestFixture::SetUp() { + // Error code + int rc; + + // Initialize context + rc = tiledb_ctx_init(&tiledb_ctx_, NULL); + ASSERT_EQ(rc, TILEDB_OK); + + // Create workspace + rc = tiledb_workspace_create(tiledb_ctx_, WORKSPACE.c_str()); + ASSERT_EQ(rc, TILEDB_OK); } -SparseArrayTestFixture::~SparseArrayTestFixture() { +void SparseArrayTestFixture::TearDown() { + // Error code + int rc; + // Finalize TileDB context - tiledb_ctx_finalize(tiledb_ctx); + rc = tiledb_ctx_finalize(tiledb_ctx_); + ASSERT_EQ(rc, TILEDB_OK); // Remove the temporary workspace std::string command = "rm -rf "; command.append(WORKSPACE); - int rc = system(command.c_str()); - assert(rc == 0); + rc = system(command.c_str()); + ASSERT_EQ(rc, 0); } -void SparseArrayTestFixture::TearDown() { - // delete currently tested array - if (arrayName.empty()) return; - tiledb_delete( - tiledb_ctx, - arrayName.c_str()); - arrayName.clear(); -} + + +/* ****************************** */ +/* PUBLIC METHODS */ +/* ****************************** */ int SparseArrayTestFixture::create_sparse_array_2D( - const long dim0_tile_extent, - const long dim1_tile_extent, - const long dim0_lo, - const long dim0_hi, - const long dim1_lo, - const long dim1_hi, - const int capacity, - const int cell_order, - const int tile_order, - const bool enable_compression) { + const int64_t tile_extent_0, + const int64_t tile_extent_1, + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int64_t capacity, + const bool enable_compression, + const int cell_order, + const int tile_order) { + // Error code + int rc; // Prepare and set the array schema object and data structures const int attribute_num = 1; const char* attributes[] = { "ATTR_INT32" }; const char* dimensions[] = { "X", "Y" }; - int64_t domain[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; - int64_t tile_extents[] = { dim0_tile_extent, dim1_tile_extent }; + int64_t domain[] = { domain_0_lo, domain_0_hi, domain_1_lo, domain_1_hi }; + int64_t tile_extents[] = { tile_extent_0, tile_extent_1 }; const int types[] = { TILEDB_INT32, TILEDB_INT64 }; - int compression[sizeof(dimensions)]; + int compression[2]; + const int dense = 0; - if (!enable_compression) { + if(!enable_compression) { compression[0] = TILEDB_NO_COMPRESSION; compression[1] = TILEDB_NO_COMPRESSION; } else { compression[0] = TILEDB_GZIP; compression[1] = TILEDB_GZIP; } - const int dense = 0; - tiledb_array_set_schema( - &schema, - arrayName.c_str(), - attributes, - attribute_num, - capacity, - cell_order, - NULL, - compression, - dense, - dimensions, - ARRAY_RANK_2D, - domain, - 4*sizeof(int64_t), - tile_extents, - 2*sizeof(int64_t), - tile_order, - types); + // Set the array schema + rc = tiledb_array_set_schema( + &array_schema_, + array_name_.c_str(), + attributes, + attribute_num, + capacity, + cell_order, + NULL, + compression, + dense, + dimensions, + 2, + domain, + 4*sizeof(int64_t), + tile_extents, + 2*sizeof(int64_t), + tile_order, + types); + if(rc != TILEDB_OK) + return TILEDB_ERR; // Create the array - int ret = tiledb_array_create(tiledb_ctx, &schema); + rc = tiledb_array_create(tiledb_ctx_, &array_schema_); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Free array schema + rc = tiledb_array_free_schema(&array_schema_); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Success + return TILEDB_OK; +} - return ret; -} // end of create_sparse_array_2D +int* SparseArrayTestFixture::read_sparse_array_2D( + const int64_t domain_0_lo, + const int64_t domain_0_hi, + const int64_t domain_1_lo, + const int64_t domain_1_hi, + const int read_mode) { + // Error code + int rc; + + // Initialize a subarray + const int64_t subarray[] = { + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi + }; + + // Subset over a specific attribute + const char* attributes[] = { "ATTR_INT32" }; -void SparseArrayTestFixture::setArrayName(const char *name) { - this->arrayName.append(WORKSPACE); - this->arrayName.append(name); -} + // Initialize the array in the input mode + TileDB_Array* tiledb_array; + rc = tiledb_array_init( + tiledb_ctx_, + &tiledb_array, + array_name_.c_str(), + read_mode, + subarray, + attributes, + 1); + if(rc != TILEDB_OK) + return NULL; -int SparseArrayTestFixture::write_sparse_array_unsorted_2D( - const int64_t dim0, - const int64_t dim1) { + // Prepare the buffers that will store the result + int64_t domain_size_0 = domain_0_hi - domain_0_lo + 1; + int64_t domain_size_1 = domain_1_hi - domain_1_lo + 1; + int64_t cell_num = domain_size_0 * domain_size_1; + int* buffer_a1 = new int[cell_num]; + void* buffers[] = { buffer_a1 }; + size_t buffer_size_a1 = cell_num * sizeof(int); + size_t buffer_sizes[] = { buffer_size_a1 }; + + // Read from array + rc = tiledb_array_read(tiledb_array, buffers, buffer_sizes); + if(rc != TILEDB_OK) + return NULL; - int ret = 0; + // Finalize the array + rc = tiledb_array_finalize(tiledb_array); + if(rc != TILEDB_OK) + return NULL; - // Generate the data and coordinates for sparse write - int64_t size = dim0*dim1; - int * buffer_attr = new int [size]; - int64_t * buffer_coords = new int64_t [2*size]; + // Success - return the created buffer + return buffer_a1; +} + +void SparseArrayTestFixture::set_array_name(const char *name) { + array_name_ = WORKSPACE + name; +} + +int SparseArrayTestFixture::write_sparse_array_unsorted_2D( + const int64_t domain_size_0, + const int64_t domain_size_1) { + // Error code + int rc; + + // Generate random attribute values and coordinates for sparse write + int64_t cell_num = domain_size_0*domain_size_1; + int* buffer_a1 = new int[cell_num]; + int64_t* buffer_coords = new int64_t[2*cell_num]; int64_t coords_index = 0L; - for (int64_t i = 0; i < dim0; ++i) { - for (int64_t j = 0; j < dim1; ++j) { - buffer_attr[i*dim1+j] = i*dim1+j; + for (int64_t i = 0; i < domain_size_0; ++i) { + for (int64_t j = 0; j < domain_size_1; ++j) { + buffer_a1[i*domain_size_1+j] = i*domain_size_1+j; buffer_coords[2*coords_index] = i; buffer_coords[2*coords_index+1] = j; coords_index++; } } - /* Initialize the array in WRITE mode. */ + // Initialize the array TileDB_Array* tiledb_array; - ret = tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - TILEDB_ARRAY_WRITE_UNSORTED, - NULL, // No range - entire domain - NULL, // No projection - all attributes - 0); // Meaningless when "attributes" is NULL - - assert(ret == TILEDB_OK); - - const void* buffers[ARRAY_RANK_2D]; - buffers[0] = buffer_attr; - buffers[1] = buffer_coords; + rc = tiledb_array_init( + tiledb_ctx_, + &tiledb_array, + array_name_.c_str(), + TILEDB_ARRAY_WRITE_UNSORTED, + NULL, + NULL, + 0); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Write to array + const void* buffers[] = { buffer_a1, buffer_coords }; + size_t buffer_sizes[2]; + buffer_sizes[0] = cell_num*sizeof(int); + buffer_sizes[1] = 2*cell_num*sizeof(int64_t); + rc = tiledb_array_write(tiledb_array, buffers, buffer_sizes); + if(rc != TILEDB_OK) + return TILEDB_ERR; + + // Clean up + delete [] buffer_a1; + delete [] buffer_coords; + + // Finalize the array and return + return tiledb_array_finalize(tiledb_array); +} - size_t bufferSizes[ARRAY_RANK_2D]; - bufferSizes[0] = { (size_t)size*sizeof(int) }; - bufferSizes[1] = { (size_t)2*size*sizeof(int64_t) }; - - ret = tiledb_array_write(tiledb_array, buffers, bufferSizes); - - if (ret != TILEDB_OK) { - return ret; - } - - /* Finalize the array. */ - ret = tiledb_array_finalize(tiledb_array); - return ret; -} // end of write_dense_array_by_chunks - -int * SparseArrayTestFixture::read_sparse_array_2D( - const int64_t dim0_lo, - const int64_t dim0_hi, - const int64_t dim1_lo, - const int64_t dim1_hi, - const int read_mode) { - - /* Initialize a range. */ - const int64_t range[] = { dim0_lo, dim0_hi, dim1_lo, dim1_hi }; - - /* Subset over attribute "a1". */ - const char* attributes[] = { "ATTR_INT32" }; - - /* Initialize the array in READ mode. */ - TileDB_Array* tiledb_array; - int ret = tiledb_array_init( - tiledb_ctx, - &tiledb_array, - arrayName.c_str(), - read_mode, - range, - attributes, - 1); - assert(ret == TILEDB_OK); - - /* Prepare cell buffers for attributes "a1" and "a2". */ - int64_t d0 = dim0_hi - dim0_lo + 1; - int64_t d1 = dim1_hi - dim1_lo + 1; - int64_t size = d0*d1; - int *buffer_a1 = new int [size]; - void* buffers[] = { buffer_a1 }; - size_t buffer_sizes[1] = { size*sizeof(int) }; - - /* Read from array. */ - ret = tiledb_array_read(tiledb_array, buffers, buffer_sizes); - - if (ret != TILEDB_OK) { - return NULL; - } - - /* Finalize the array. */ - tiledb_array_finalize(tiledb_array); - - return buffer_a1; -} // end of read_sparse_array_2D /** @@ -320,84 +268,96 @@ int * SparseArrayTestFixture::read_sparse_array_2D( * Test runs through 100 iterations to choose random * width and height of the subregions */ -TEST_F(SparseArrayTestFixture, test_random_sorted_reads) { - int64_t dim0 = 5000; - int64_t dim1 = 1000; - int64_t chunkDim0 = 100; - int64_t chunkDim1 = 100; - int64_t dim0_lo = 0; - int64_t dim0_hi = dim0-1; - int64_t dim1_lo = 0; - int64_t dim1_hi = dim1-1; - int capacity = 0; // 0 means use default capacity +TEST_F(SparseArrayTestFixture, test_random_sparse_sorted_reads) { + // Error code + int rc; + + // Parameters used in this test + int64_t domain_size_0 = 5000; + int64_t domain_size_1 = 1000; + int64_t tile_extent_0 = 100; + int64_t tile_extent_1 = 100; + int64_t domain_0_lo = 0; + int64_t domain_0_hi = domain_size_0-1; + int64_t domain_1_lo = 0; + int64_t domain_1_hi = domain_size_1-1; + int64_t capacity = 0; // 0 means use default capacity int cell_order = TILEDB_ROW_MAJOR; int tile_order = TILEDB_ROW_MAJOR; - bool enable_compression = false; + int iter_num = 100; + + // Set array name + set_array_name("sparse_test_5000x1000_100x100"); - setArrayName("sparse_test_5000x1000_100x100"); + // Create a progress bar + ProgressBar* progress_bar = new ProgressBar(); // Create a dense integer array - create_sparse_array_2D( - chunkDim0, - chunkDim1, - dim0_lo, - dim0_hi, - dim1_lo, - dim1_hi, - capacity, - cell_order, - tile_order, - enable_compression); + rc = create_sparse_array_2D( + tile_extent_0, + tile_extent_1, + domain_0_lo, + domain_0_hi, + domain_1_lo, + domain_1_hi, + capacity, + false, + cell_order, + tile_order); + EXPECT_EQ(rc, TILEDB_OK); // Write array cells with value = row id * COLUMNS + col id - // to disk chunk by chunk - write_sparse_array_unsorted_2D(dim0, dim1); + // to disk + write_sparse_array_unsorted_2D(domain_size_0, domain_size_1); - // Test is to randomly read sub-regions of the array - // and check with corresponding value set by - // row_id*dim1+col_id - // Top left corner is always 4,4 + // Test random subarrays and check with corresponding value set by + // row_id*dim1+col_id. Top left corner is always 4,4. int64_t d0_lo = 4; int64_t d0_hi = 0; int64_t d1_lo = 4; int64_t d1_hi = 0; int64_t height = 0, width = 0; - for (int iter = 0; iter < 20; ++iter) { - height = rand() % (dim0 - d0_lo); - width = rand() % (dim1 - d1_lo); + for(int iter = 0; iter < iter_num; ++iter) { + height = rand() % (domain_size_0 - d0_lo); + width = rand() % (domain_size_1 - d1_lo); d0_hi = d0_lo + height; d1_hi = d1_lo + width; - int index = 0; + int64_t index = 0; + // Read subarray int *buffer = read_sparse_array_2D( d0_lo, d0_hi, d1_lo, d1_hi, TILEDB_ARRAY_READ_SORTED_ROW); - - if (!buffer) { - std::cerr << "ERROR: NULL buffer returned. " - << "Check TileDB array path " - << arrayName << "\n"; - FAIL(); - } - - for (int i = d0_lo; i <= d0_hi; ++i) { - for (int j = d1_lo; j <= d1_hi; ++j) { - EXPECT_EQ(buffer[index], i*dim1+j); - if (buffer[index] != (i*dim1+j)) { - std::cerr << "mismatch: " << i + EXPECT_TRUE(buffer != NULL); + + // Check + for(int64_t i = d0_lo; i <= d0_hi; ++i) { + for(int64_t j = d1_lo; j <= d1_hi; ++j) { + EXPECT_EQ(buffer[index], i*domain_size_1+j); + if (buffer[index] != (i*domain_size_1+j)) { + std::cout << "mismatch: " << i << "," << j << "=" << buffer[index] << "!=" - << ((i*dim1+j)) << "\n"; + << ((i*domain_size_1+j)) << "\n"; return; } - index++; + ++index; } } - } // end of random for-loop -} // end of test_random_sorted_reads + + // Clean up + delete [] buffer; + + // Update progress bar + progress_bar->load(1.0/iter_num); + } + + // Delete progress bar + delete progress_bar; +} From e73e2aaf688eae8793aa2192991eb85e61ffcbf1 Mon Sep 17 00:00:00 2001 From: spapadop Date: Wed, 28 Dec 2016 17:04:20 -0500 Subject: [PATCH 45/57] Fixing bug when creating the copy/aio thread in array_sorted_read/write_state.cc, respectively (it has to be created before the mutex initializations). --- core/include/array/array_sorted_read_state.h | 2 +- core/include/array/array_sorted_write_state.h | 6 ++-- core/src/array/array_sorted_read_state.cc | 26 ++++++++--------- core/src/array/array_sorted_write_state.cc | 28 +++++++++---------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/core/include/array/array_sorted_read_state.h b/core/include/array/array_sorted_read_state.h index fe263e84..b7ea02ab 100644 --- a/core/include/array/array_sorted_read_state.h +++ b/core/include/array/array_sorted_read_state.h @@ -327,7 +327,7 @@ class ArraySortedReadState { pthread_t copy_thread_; /** True if the copy thread is canceled. */ - bool copy_thread_canceled_; + volatile bool copy_thread_canceled_; /** True if the copy thread is running. */ volatile bool copy_thread_running_; diff --git a/core/include/array/array_sorted_write_state.h b/core/include/array/array_sorted_write_state.h index e96a369d..9647f995 100644 --- a/core/include/array/array_sorted_write_state.h +++ b/core/include/array/array_sorted_write_state.h @@ -228,7 +228,7 @@ class ArraySortedWriteState { pthread_t aio_thread_; /** True if the AIO thread is canceled. */ - bool aio_thread_canceled_; + volatile bool aio_thread_canceled_; /** True if the AIO thread is running. */ volatile bool aio_thread_running_; @@ -569,13 +569,13 @@ class ArraySortedWriteState { void calculate_tile_slab_info_row(int id); /** - * Function called by the copy thread. + * Function called by the AIO thread. * * @param context This is practically the ArraySortedWriteState object for * which the function is called (typically *this* is passed to this * argument by the caller). */ - static void *copy_handler(void* context); + static void *aio_handler(void* context); /** * Copies a tile slab from the user buffers into the local buffers, diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index c262503c..e3943457 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -303,19 +303,6 @@ int ArraySortedReadState::init() { // Create AIO requests init_aio_requests(); - // Create the thread that will be handling all the copying - if(pthread_create( - ©_thread_, - NULL, - ArraySortedReadState::copy_handler, - this)) { - std::string errmsg = "Cannot create AIO thread"; - PRINT_ERROR(errmsg); - tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; - return TILEDB_ASRS_ERR; - } - copy_thread_running_ = true; - // Initialize the mutexes and conditions if(pthread_mutex_init(&aio_mtx_, NULL)) { std::string errmsg = "Cannot initialize IO mutex"; @@ -446,6 +433,19 @@ int ArraySortedReadState::init() { assert(0); } + // Create the thread that will be handling all the copying + if(pthread_create( + ©_thread_, + NULL, + ArraySortedReadState::copy_handler, + this)) { + std::string errmsg = "Cannot create AIO thread"; + PRINT_ERROR(errmsg); + tiledb_asrs_errmsg = TILEDB_ASRS_ERRMSG + errmsg; + return TILEDB_ASRS_ERR; + } + copy_thread_running_ = true; + // Success return TILEDB_ASRS_OK; } diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 2932b9d4..4c0e640e 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -173,19 +173,6 @@ ArraySortedWriteState::~ArraySortedWriteState() { /* ****************************** */ int ArraySortedWriteState::init() { - // Create the thread that will be handling all the copying - if(pthread_create( - &aio_thread_, - NULL, - ArraySortedWriteState::copy_handler, - this)) { - std::string errmsg = "Cannot create AIO thread"; - PRINT_ERROR(errmsg); - tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; - return TILEDB_ASWS_ERR; - } - aio_thread_running_ = true; - // Initialize the mutexes and conditions if(pthread_mutex_init(&aio_mtx_, NULL)) { std::string errmsg = "Cannot initialize IO mutex"; @@ -271,6 +258,19 @@ int ArraySortedWriteState::init() { assert(0); } + // Create the thread that will be handling all the asynchronous IOs + if(pthread_create( + &aio_thread_, + NULL, + ArraySortedWriteState::aio_handler, + this)) { + std::string errmsg = "Cannot create AIO thread"; + PRINT_ERROR(errmsg); + tiledb_asws_errmsg = TILEDB_ASWS_ERRMSG + errmsg; + return TILEDB_ASWS_ERR; + } + aio_thread_running_ = true; + // Success return TILEDB_ASWS_OK; } @@ -741,7 +741,7 @@ void ArraySortedWriteState::calculate_tile_slab_info_row(int id) { } } -void *ArraySortedWriteState::copy_handler(void* context) { +void *ArraySortedWriteState::aio_handler(void* context) { // For easy reference ArraySortedWriteState* asws = (ArraySortedWriteState*) context; From f4fc6ffd10147b95dbdbb481e7bd078b9ce6ba4b Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 30 Dec 2016 14:24:32 -0500 Subject: [PATCH 46/57] Minor fix in Makefile to properly handle VERBOSE error printouts --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8e98f024..9dae1363 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ endif # --- Verbose mode handler --- # VERBOSE = ifeq ($(VERBOSE),1) - CPPFLAGS += -DNVERBOSE + CPPFLAGS += -DVERBOSE endif # --- Use parallel sort --- # @@ -160,7 +160,7 @@ EXAMPLES_OBJ := $(patsubst $(EXAMPLES_SRC_DIR)/%.cc,\ $(EXAMPLES_OBJ_DIR)/%.o, $(EXAMPLES_SRC)) EXAMPLES_BIN := $(patsubst $(EXAMPLES_SRC_DIR)/%.cc,\ $(EXAMPLES_BIN_DIR)/%, $(EXAMPLES_SRC)) -TEST_INCLUDE := $(foreach D,$(TEST_INCLUDE_SUBDIRS),$D/*.h) +TEST_INCLUDE := $(foreach D,$(TEST_INCLUDE_SUBDIRS),$D/*.h) TEST_SRC := $(wildcard $(foreach D,$(TEST_SRC_SUBDIRS),$D/*.cc)) TEST_OBJ := $(patsubst $(TEST_SRC_DIR)/%.cc, $(TEST_OBJ_DIR)/%.o, $(TEST_SRC)) From 9180f21ec939bd97337ed5b5945590b3d1fec6bf Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 30 Dec 2016 14:26:47 -0500 Subject: [PATCH 47/57] Important bug fix with pthreads: we must ALWAYS pthread_join a terminated thread. Otherwise, the terminated thread does not release its resources. This can cause all sorts of problems (a typical error is that we will reach the OS limit for thread creation and we will not be able to create a new thread). --- core/src/array/array.cc | 24 +++++++++++- core/src/array/array_sorted_read_state.cc | 15 +++++--- core/src/array/array_sorted_write_state.cc | 19 +++++++--- core/src/storage_manager/storage_manager.cc | 2 +- test/include/c_api/c_api_array_schema_spec.h | 2 + test/src/c_api/c_api_array_schema_spec.cc | 14 +++++-- test/src/c_api/c_api_dense_array_spec.cc | 39 +++++++++++--------- test/src/c_api/c_api_sparse_array_spec.cc | 27 +++++++++----- 8 files changed, 100 insertions(+), 42 deletions(-) diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 604cbc28..1b185e65 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -1138,10 +1138,24 @@ int Array::aio_thread_create() { return TILEDB_AR_OK; // Create the thread that will be handling all AIO requests - if(pthread_create(&aio_thread_, NULL, Array::aio_handler, this)) { + int rc; + if((rc=pthread_create(&aio_thread_, NULL, Array::aio_handler, this))) { std::string errmsg = "Cannot create AIO thread"; PRINT_ERROR(errmsg); tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; + +switch(rc) { + case EAGAIN: + std::cout << "EAGAIN\n"; + break; + case EINVAL: + std::cout << "EINVAL\n"; + break; + case EPERM: + std::cout << "EPERM\n"; + break; +} + return TILEDB_AR_ERR; } @@ -1184,6 +1198,14 @@ int Array::aio_thread_destroy() { // Wait for cancelation to take place while(aio_thread_created_); + // Join with the terminated thread + if(pthread_join(aio_thread_, NULL)) { + std::string errmsg = "Cannot join AIO thread"; + PRINT_ERROR(errmsg); + tiledb_ar_errmsg = TILEDB_AR_ERRMSG + errmsg; + return TILEDB_AR_ERR; + } + // Success return TILEDB_AR_OK; } diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index e3943457..51dad65a 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -141,6 +141,9 @@ ArraySortedReadState::~ArraySortedReadState() { // Wait for thread to be destroyed while(copy_thread_running_); + // Join with the terminated thread + pthread_join(copy_thread_, NULL); + // Clean up free(subarray_); free(tile_coords_); @@ -276,16 +279,17 @@ int ArraySortedReadState::read(void** buffers, size_t* buffer_sizes) { // Call the appropriate templated read int type = array_->array_schema()->coords_type(); - if(type == TILEDB_INT32) + if(type == TILEDB_INT32) { return read(); - else if(type == TILEDB_INT64) + } else if(type == TILEDB_INT64) { return read(); - else if(type == TILEDB_FLOAT32) + } else if(type == TILEDB_FLOAT32) { return read(); - else if(type == TILEDB_FLOAT64) + } else if(type == TILEDB_FLOAT64) { return read(); - else + } else { assert(0); + } } @@ -2391,6 +2395,7 @@ int ArraySortedReadState::read() { return read_sparse_sorted_row(); } else { assert(0); // The code should never reach here + return TILEDB_ASRS_ERR; } } diff --git a/core/src/array/array_sorted_write_state.cc b/core/src/array/array_sorted_write_state.cc index 4c0e640e..50c089fe 100644 --- a/core/src/array/array_sorted_write_state.cc +++ b/core/src/array/array_sorted_write_state.cc @@ -140,6 +140,9 @@ ArraySortedWriteState::~ArraySortedWriteState() { // Wait for thread to be destroyed while(aio_thread_running_); + // Join with the terminated thread + pthread_join(aio_thread_, NULL); + // Destroy conditions and mutexes for(int i=0; i<2; ++i) { if(pthread_cond_destroy(&(aio_cond_[i]))) { @@ -290,12 +293,14 @@ int ArraySortedWriteState::write( // Call the appropriate templated read int type = array_->array_schema()->coords_type(); - if(type == TILEDB_INT32) + if(type == TILEDB_INT32) { return write(); - else if(type == TILEDB_INT64) + } else if(type == TILEDB_INT64) { return write(); - else + } else { assert(0); + return TILEDB_ASWS_ERR; + } // Success return TILEDB_ASWS_OK; @@ -1533,12 +1538,14 @@ int ArraySortedWriteState::write() { // For easy reference int mode = array_->mode(); - if(mode == TILEDB_ARRAY_WRITE_SORTED_COL) + if(mode == TILEDB_ARRAY_WRITE_SORTED_COL) { return write_sorted_col(); - else if(mode == TILEDB_ARRAY_WRITE_SORTED_ROW) + } else if(mode == TILEDB_ARRAY_WRITE_SORTED_ROW) { return write_sorted_row(); - else + } else { assert(0); // The code should never reach here + return TILEDB_ASWS_ERR; + } } template diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 4f96c2d7..1839ca55 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -614,7 +614,7 @@ int StorageManager::array_init( } // Success - return TILEDB_SM_OK; + return TILEDB_SM_OK; } int StorageManager::array_finalize(Array* array) { diff --git a/test/include/c_api/c_api_array_schema_spec.h b/test/include/c_api/c_api_array_schema_spec.h index c38483f6..9f96f221 100644 --- a/test/include/c_api/c_api_array_schema_spec.h +++ b/test/include/c_api/c_api_array_schema_spec.h @@ -89,6 +89,8 @@ class ArraySchemaTestFixture: public testing::Test { std::string array_name_; /** Array schema object under test. */ TileDB_ArraySchema array_schema_; + /** True if the array schema is set. */ + bool array_schema_set_; /** TileDB context. */ TileDB_CTX* tiledb_ctx_; }; diff --git a/test/src/c_api/c_api_array_schema_spec.cc b/test/src/c_api/c_api_array_schema_spec.cc index be139a5e..407c01ce 100644 --- a/test/src/c_api/c_api_array_schema_spec.cc +++ b/test/src/c_api/c_api_array_schema_spec.cc @@ -42,6 +42,9 @@ void ArraySchemaTestFixture::SetUp() { // Error code int rc; + + // Array schema not set yet + array_schema_set_ = false; // Initialize context rc = tiledb_ctx_init(&tiledb_ctx_, NULL); @@ -70,8 +73,10 @@ void ArraySchemaTestFixture::TearDown() { ASSERT_EQ(rc, 0); // Free array schema - rc = tiledb_array_free_schema(&array_schema_); - ASSERT_EQ(rc, TILEDB_OK); + if(array_schema_set_) { + rc = tiledb_array_free_schema(&array_schema_); + ASSERT_EQ(rc, TILEDB_OK); + } } @@ -131,7 +136,10 @@ int ArraySchemaTestFixture::create_dense_array() { if(rc != TILEDB_OK) return TILEDB_ERR; - /* Create the array. */ + // Remember that the array schema is set + array_schema_set_ = true; + + // Create the array return tiledb_array_create(tiledb_ctx_, &array_schema_); } diff --git a/test/src/c_api/c_api_dense_array_spec.cc b/test/src/c_api/c_api_dense_array_spec.cc index 3215fc64..498f2995 100644 --- a/test/src/c_api/c_api_dense_array_spec.cc +++ b/test/src/c_api/c_api_dense_array_spec.cc @@ -210,7 +210,7 @@ int** DenseArrayTestFixture::generate_2D_buffer( const int64_t domain_size_0, const int64_t domain_size_1) { // Create buffer - int **buffer = new int*[domain_size_1]; + int **buffer = new int*[domain_size_0]; // Populate buffer for(int64_t i = 0; i < domain_size_0; ++i) { @@ -268,13 +268,17 @@ int* DenseArrayTestFixture::read_dense_array_2D( // Read from array rc = tiledb_array_read(tiledb_array, buffers, buffer_sizes); - if(rc != TILEDB_OK) + if(rc != TILEDB_OK) { + delete [] buffer_a1; return NULL; + } // Finalize the array rc = tiledb_array_finalize(tiledb_array); - if(rc != TILEDB_OK) + if(rc != TILEDB_OK) { + delete [] buffer_a1; return NULL; + } // Success - return the created buffer return buffer_a1; @@ -410,6 +414,7 @@ int DenseArrayTestFixture::write_dense_array_by_tiles( buffer_sizes[0] = { buffer_size }; rc = tiledb_array_write(tiledb_array, buffers, buffer_sizes); if(rc != TILEDB_OK) { + tiledb_array_finalize(tiledb_array); for(int64_t i=0; iattribute(attribute_ids[i]) + TILEDB_FILE_SUFFIX; if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } } else if(write_method == TILEDB_IO_MPI) { #ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } #else // Error: MPI not supported std::string errmsg = "Cannot sync; MPI not supported"; @@ -220,12 +231,6 @@ int WriteState::sync() { assert(0); } - // Handle error - if(rc != TILEDB_UT_OK) { - tiledb_ws_errmsg = tiledb_ut_errmsg; - return TILEDB_WS_ERR; - } - // Only for variable-size attributes (they have an extra file) if(array_schema->var_size(attribute_ids[i])) { filename = @@ -234,15 +239,25 @@ int WriteState::sync() { TILEDB_FILE_SUFFIX; if(write_method == TILEDB_IO_WRITE) { rc = ::sync(filename.c_str()); + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } } else if(write_method == TILEDB_IO_MPI) { #ifdef HAVE_MPI rc = mpi_io_sync(mpi_comm, filename.c_str()); + // Handle error + if(rc != TILEDB_UT_OK) { + tiledb_ws_errmsg = tiledb_ut_errmsg; + return TILEDB_WS_ERR; + } #else - // Error: MPI not supported - std::string errmsg = "Cannot sync; MPI not supported"; - PRINT_ERROR(errmsg); - tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; - return TILEDB_WS_ERR; + // Error: MPI not supported + std::string errmsg = "Cannot sync; MPI not supported"; + PRINT_ERROR(errmsg); + tiledb_ws_errmsg = TILEDB_WS_ERRMSG + errmsg; + return TILEDB_WS_ERR; #endif } else { assert(0); diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index 33abf27c..d480b390 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -848,14 +848,14 @@ int mpi_io_sync( // Open file MPI_File fh; int rc; - if(is_dir(filename)) // DIRECTORY + if(is_dir(filename)) // DIRECTORY rc = MPI_File_open( *mpi_comm, filename, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); - else // FILE + else if(is_file(filename) // FILE rc = MPI_File_open( *mpi_comm, filename, @@ -863,6 +863,8 @@ int mpi_io_sync( MPI_MODE_CREATE | MPI_MODE_SEQUENTIAL, MPI_INFO_NULL, &fh); + else + return TILEDB_UT_OK; // If file does not exist, exit // Handle error if(rc) { @@ -1179,10 +1181,12 @@ bool starts_with(const std::string& value, const std::string& prefix) { int sync(const char* filename) { // Open file int fd; - if(is_dir(filename)) // DIRECTORY + if(is_dir(filename)) // DIRECTORY fd = open(filename, O_RDONLY, S_IRWXU); - else // FILE + else if(is_file(filename)) // FILE fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU); + else + return TILEDB_UT_OK; // If file does not exist, exit // Handle error if(fd == -1) { diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 1839ca55..883d89fe 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -635,7 +635,7 @@ int StorageManager::array_finalize(Array* array) { if(rc_close != TILEDB_SM_OK) return TILEDB_SM_ERR; if(rc_finalize != TILEDB_AR_OK) { - tiledb_sm_errmsg = tiledb_as_errmsg; + tiledb_sm_errmsg = tiledb_ar_errmsg; return TILEDB_SM_ERR; } From 0ec3a291d93860e12ab51546d1b30b2e01e63283 Mon Sep 17 00:00:00 2001 From: spapadop Date: Fri, 30 Dec 2016 20:02:26 -0500 Subject: [PATCH 50/57] Bug fix in sorted reads for sparse arrays. We were calculating wrong the number of buffers due to the extra coordinates buffer needed for the sorting. --- core/src/array/array_sorted_read_state.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index 7ab9b2bc..fd85d3c8 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -1325,7 +1325,7 @@ void ArraySortedReadState::copy_tile_slab_sparse(int aid, int bid) { // Calculate new local buffer offset local_buffer_offset = cell_pos_[current_cell_pos] * cell_size; - + // Copy cell slab memcpy( buffer + buffer_offset, @@ -1610,7 +1610,8 @@ void ArraySortedReadState::handle_copy_requests_sparse() { if(overflow()) { block_overflow(); block_aio(copy_id_); - release_copy(copy_id_); + release_copy(0); + release_copy(1); wait_overflow(); continue; } @@ -2513,7 +2514,8 @@ int ArraySortedReadState::read_sparse_sorted_col() { wait_copy(copy_id); // Assign the true buffer sizes - for(int i=0; i Date: Mon, 2 Jan 2017 14:35:08 -0500 Subject: [PATCH 51/57] Bug fix in sorted reads in the case of user buffer overflow --- core/src/array/array_sorted_read_state.cc | 96 +++++++++++------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/core/src/array/array_sorted_read_state.cc b/core/src/array/array_sorted_read_state.cc index fd85d3c8..d01b753b 100644 --- a/core/src/array/array_sorted_read_state.cc +++ b/core/src/array/array_sorted_read_state.cc @@ -1771,12 +1771,6 @@ int ArraySortedReadState::lock_overflow_mtx() { template bool ArraySortedReadState::next_tile_slab_dense_col() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -1787,6 +1781,12 @@ bool ArraySortedReadState::next_tile_slab_dense_col() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -1859,12 +1859,6 @@ bool ArraySortedReadState::next_tile_slab_dense_col() { template bool ArraySortedReadState::next_tile_slab_dense_row() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -1875,6 +1869,12 @@ bool ArraySortedReadState::next_tile_slab_dense_row() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -1943,12 +1943,6 @@ bool ArraySortedReadState::next_tile_slab_dense_row() { template bool ArraySortedReadState::next_tile_slab_sparse_col() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -1959,6 +1953,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -2017,12 +2017,6 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { template<> bool ArraySortedReadState::next_tile_slab_sparse_col() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -2033,6 +2027,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const float* subarray = (const float*) subarray_; @@ -2092,12 +2092,6 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { template<> bool ArraySortedReadState::next_tile_slab_sparse_col() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -2108,6 +2102,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const double* subarray = (const double*) subarray_; @@ -2167,12 +2167,6 @@ bool ArraySortedReadState::next_tile_slab_sparse_col() { template bool ArraySortedReadState::next_tile_slab_sparse_row() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -2183,6 +2177,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const T* subarray = static_cast(subarray_); @@ -2237,12 +2237,6 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { template<> bool ArraySortedReadState::next_tile_slab_sparse_row() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -2253,6 +2247,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const float* subarray = (const float*) subarray_; @@ -2309,12 +2309,6 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { template<> bool ArraySortedReadState::next_tile_slab_sparse_row() { - // Wait for the previous copy on aio_id_ buffer to be consumed - wait_copy(aio_id_); - - // Block copy - block_copy(aio_id_); - // Quick check if done if(read_tile_slabs_done_) return false; @@ -2325,6 +2319,12 @@ bool ArraySortedReadState::next_tile_slab_sparse_row() { return true; } + // Wait for the previous copy on aio_id_ buffer to be consumed + wait_copy(aio_id_); + + // Block copy + block_copy(aio_id_); + // For easy reference const ArraySchema* array_schema = array_->array_schema(); const double* subarray = (const double*) subarray_; From a6b168d2c585d4319ce818d87bb8d9e3abb3b8e8 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 2 Jan 2017 15:59:12 -0500 Subject: [PATCH 52/57] Adding new examples. --- .../src/tiledb_array_write_sorted_dense.cc | 12 ++-- examples/src/tiledb_catching_errors.cc | 59 +++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 examples/src/tiledb_catching_errors.cc diff --git a/examples/src/tiledb_array_write_sorted_dense.cc b/examples/src/tiledb_array_write_sorted_dense.cc index a7218703..ba740535 100644 --- a/examples/src/tiledb_array_write_sorted_dense.cc +++ b/examples/src/tiledb_array_write_sorted_dense.cc @@ -41,7 +41,7 @@ int main() { tiledb_ctx_init(&tiledb_ctx, NULL); // Set the subarray where the write will focus on - int64_t subarray[] = { 2, 4, 2, 4 }; + int64_t subarray[] = { 3, 4, 2, 4 }; // Initialize array TileDB_Array* tiledb_array; @@ -55,13 +55,13 @@ int main() { 0); // Number of attributes // Prepare cell buffers - int buffer_a1[] = { 3, 6, 7, 9, 12, 13, 11, 14, 15 }; - size_t buffer_a2[] = { 0, 4, 7, 11, 13, 14, 16, 20, 23 }; - const char buffer_var_a2[] = "ddddggghhhhjjmnnllllooopppp"; + int buffer_a1[] = { 9, 12, 13, 11, 14, 15 }; + size_t buffer_a2[] = { 0, 2, 3, 5, 9, 12 }; + const char buffer_var_a2[] = "jjmnnllllooopppp"; float buffer_a3[] = { - 3.1, 3.2, 6.1, 6.2, 7.1, 7.2, 9.1, 9.2, 12.1, 12.2, - 13.1, 13.2, 11.1, 11.2, 14.1, 14.2, 15.1, 15.2 + 9.1, 9.2, 12.1, 12.2, 13.1, 13.2, + 11.1, 11.2, 14.1, 14.2, 15.1, 15.2 }; const void* buffers[] = { buffer_a1, buffer_a2, buffer_var_a2, buffer_a3 }; size_t buffer_sizes[] = diff --git a/examples/src/tiledb_catching_errors.cc b/examples/src/tiledb_catching_errors.cc new file mode 100644 index 00000000..1cfb0e84 --- /dev/null +++ b/examples/src/tiledb_catching_errors.cc @@ -0,0 +1,59 @@ +/** + * @file tiledb_catching_errors.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2016 MIT and Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This examples shows how to catch errors. + */ + +#include "c_api.h" +#include + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Create a workspace + int rc = tiledb_workspace_create(tiledb_ctx, "my_workspace"); + if(rc == TILEDB_OK) + printf("Workspace created successfully!\n"); + else if(rc == TILEDB_ERR) + printf("%s\n", tiledb_errmsg); + + // Create the same workspace again - ERROR + rc = tiledb_workspace_create(tiledb_ctx, "my_workspace"); + if(rc == TILEDB_OK) + printf("Workspace created successfully!\n"); + else if(rc == TILEDB_ERR) + printf("%s\n", tiledb_errmsg); // Print the TileDB error message + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} From d5aac2175588581e2b7410ecca251333726ad665 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 2 Jan 2017 17:45:51 -0500 Subject: [PATCH 53/57] Minor documentation edit. --- core/include/c_api/c_api.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/core/include/c_api/c_api.h b/core/include/c_api/c_api.h index 49a25047..1e271d3e 100755 --- a/core/include/c_api/c_api.h +++ b/core/include/c_api/c_api.h @@ -494,14 +494,19 @@ TILEDB_EXPORT int tiledb_array_write( const size_t* buffer_sizes); /** - * Performs a read operation on an array, which must be initialized with mode - * TILEDB_ARRAY_READ, TILEDB_ARRAY_READ_SORTED_COL or - * TILEDB_ARRAY_READ_SORTED_ROW. The function retrieves the result cells that - * lie inside the subarray specified in tiledb_array_init() or - * tiledb_array_reset_subarray(). The results are written in input buffers - * provided by the user, which are also allocated by the user. Note that the - * results are written in the buffers in the same order they appear on the - * disk, which leads to maximum performance. + * Performs a read operation on an array. + * The array must be initialized in one of the following read modes, + * each of which has a different behaviour: + * - TILEDB_ARRAY_READ: \n + * In this mode, the cell values are stored in the buffers respecting + * the cell order on the disk (specified in the array schema). This mode + * leads to the best performance. + * - TILEDB_ARRAY_READ_SORTED_COL: \n + * In this mode, the cell values are stored in the buffers in column-major + * order with respect to the subarray used upon array initialization. + * - TILEDB_ARRAY_READ_SORTED_ROW: \n + * In this mode, the cell values are stored in the buffer in row-major + * order with respect to the subarray used upon array initialization. * * @param tiledb_array The TileDB array. * @param buffers An array of buffers, one for each attribute. These must be From 90b6c0fb85f3b3326d34215164feb0c12a0db0c0 Mon Sep 17 00:00:00 2001 From: spapadop Date: Mon, 2 Jan 2017 18:54:03 -0500 Subject: [PATCH 54/57] Minor documentation edit. --- core/include/array/array.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/include/array/array.h b/core/include/array/array.h index 18b97d96..682a1904 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -540,7 +540,8 @@ class Array { /** * Returns a new fragment name, which is in the form:
- * .___ + * .___. For instance, + * __00332a0b8c6426153_1458759561320 * * Note that this is a temporary name, initiated by a new write process. * After the new fragmemt is finalized, the array will change its name From 189ca675669e2ccb372e2a96e12c514800ef675d Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 3 Jan 2017 12:13:05 -0500 Subject: [PATCH 55/57] Renaming example files. --- ...y_read_sorted_dense.cc => tiledb_array_read_dense_sorted.cc} | 2 +- ...read_sorted_sparse.cc => tiledb_array_read_sparse_sorted.cc} | 2 +- ...write_sorted_dense.cc => tiledb_array_write_dense_sorted.cc} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename examples/src/{tiledb_array_read_sorted_dense.cc => tiledb_array_read_dense_sorted.cc} (98%) rename examples/src/{tiledb_array_read_sorted_sparse.cc => tiledb_array_read_sparse_sorted.cc} (98%) rename examples/src/{tiledb_array_write_sorted_dense.cc => tiledb_array_write_dense_sorted.cc} (98%) diff --git a/examples/src/tiledb_array_read_sorted_dense.cc b/examples/src/tiledb_array_read_dense_sorted.cc similarity index 98% rename from examples/src/tiledb_array_read_sorted_dense.cc rename to examples/src/tiledb_array_read_dense_sorted.cc index 92b5beb7..2bceab19 100644 --- a/examples/src/tiledb_array_read_sorted_dense.cc +++ b/examples/src/tiledb_array_read_dense_sorted.cc @@ -1,5 +1,5 @@ /** - * @file tiledb_array_read_sorted_dense.cc + * @file tiledb_array_read_dense_sorted.cc * * @section LICENSE * diff --git a/examples/src/tiledb_array_read_sorted_sparse.cc b/examples/src/tiledb_array_read_sparse_sorted.cc similarity index 98% rename from examples/src/tiledb_array_read_sorted_sparse.cc rename to examples/src/tiledb_array_read_sparse_sorted.cc index 62e9495e..0581de4f 100644 --- a/examples/src/tiledb_array_read_sorted_sparse.cc +++ b/examples/src/tiledb_array_read_sparse_sorted.cc @@ -1,5 +1,5 @@ /** - * @file tiledb_array_read_sorted_sparse.cc + * @file tiledb_array_read_sparse_sorted.cc * * @section LICENSE * diff --git a/examples/src/tiledb_array_write_sorted_dense.cc b/examples/src/tiledb_array_write_dense_sorted.cc similarity index 98% rename from examples/src/tiledb_array_write_sorted_dense.cc rename to examples/src/tiledb_array_write_dense_sorted.cc index ba740535..bed76024 100644 --- a/examples/src/tiledb_array_write_sorted_dense.cc +++ b/examples/src/tiledb_array_write_dense_sorted.cc @@ -1,5 +1,5 @@ /** - * @file tiledb_array_write_sorted_dense.cc + * @file tiledb_array_write_dense_sorted.cc * * @section LICENSE * From d34d81a0e66a11fdd8712b82313fad237eade4f9 Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 3 Jan 2017 14:47:53 -0500 Subject: [PATCH 56/57] Minor typo that was creating a compilation error when MPI is activated --- core/src/misc/utils.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index d480b390..272a5336 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -855,7 +855,7 @@ int mpi_io_sync( MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); - else if(is_file(filename) // FILE + else if(is_file(filename)) // FILE rc = MPI_File_open( *mpi_comm, filename, From 70d367f4f25434735da1ab7f8ecc6ae863fbb0a7 Mon Sep 17 00:00:00 2001 From: spapadop Date: Tue, 3 Jan 2017 14:49:47 -0500 Subject: [PATCH 57/57] Minor edits in the outputs of some examples --- examples/src/tiledb_array_parallel_write_dense_2.cc | 2 +- examples/src/tiledb_array_read_dense_2.cc | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/src/tiledb_array_parallel_write_dense_2.cc b/examples/src/tiledb_array_parallel_write_dense_2.cc index 2fc4a6b0..e29daa36 100644 --- a/examples/src/tiledb_array_parallel_write_dense_2.cc +++ b/examples/src/tiledb_array_parallel_write_dense_2.cc @@ -185,7 +185,7 @@ void parallel_write( #include int main() { - printf("OpenMP not supported."); + printf("OpenMP not supported.\n"); return 0; } diff --git a/examples/src/tiledb_array_read_dense_2.cc b/examples/src/tiledb_array_read_dense_2.cc index 51e2d406..d5094ec4 100644 --- a/examples/src/tiledb_array_read_dense_2.cc +++ b/examples/src/tiledb_array_read_dense_2.cc @@ -72,7 +72,10 @@ int main() { // Print cell values int64_t result_num = buffer_sizes[0] / sizeof(int); for(int i=0; i