From b2dddb1d3284e7537a766d398d28ffba1ae45102 Mon Sep 17 00:00:00 2001 From: Dylan Hutchison Date: Wed, 13 Apr 2016 15:31:26 -0700 Subject: [PATCH 1/7] fix compiler warning --- core/src/array/array.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/array/array.cc b/core/src/array/array.cc index a66271c5..8dc7fd12 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -530,7 +530,7 @@ void Array::sort_fragment_names( if(stripped_fragment_name[j] == '_') { t_str = stripped_fragment_name.substr( j+1,stripped_fragment_name_size-j); - sscanf(t_str.c_str(), "%lld", &t); + sscanf(t_str.c_str(), "%lld", (long long int*)&t); t_pos_vec[i] = std::pair(t, i); break; } From 9cb5ee4151048735ebcbdc5837e0180f36ed95a7 Mon Sep 17 00:00:00 2001 From: Joshua Blum Date: Thu, 14 Apr 2016 10:35:29 -0400 Subject: [PATCH 2/7] Copy edits for README --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f84bbdb5..f6d579bc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -The TileDB documentation for users is hosted as -a Github wiki: https://github.com/Intel-HLS/TileDB/wiki +# TileDB -TileDB official website: http://istc-bigdata.org/tiledb +[![Travis](https://img.shields.io/travis/Intel-HLS/TileDB.svg?maxAge=2592000)](https://travis-ci.org/Intel-HLS/TileDB) + +The TileDB documentation for users is hosted as a [Github +wiki](https://github.com/Intel-HLS/TileDB/wiki). + +[TileDB official website](http://istc-bigdata.org/tiledb). From 2b1d463d08bc15b73e255e979cf7d6eafdfff788 Mon Sep 17 00:00:00 2001 From: Stavros Papadopoulos Date: Mon, 11 Apr 2016 08:41:09 -0400 Subject: [PATCH 3/7] Implemented thread-safety for TileDB. New features: - Implemented thread-safety for pthreads and OpenMP - Added examples for implementing simultaneous reads and writes with pthreads and OpenMP Minor C API changes: - Changed array_consolidate and metadata_consolidate to take as input the array/metadata name instead of an initialized tileDB object Bug fixes: - Eliminated some memory leaks with valgrind - Fixed small bug in function utils.cc::is_unary_subarray - Fixed bug in array_consolidate and metadata_consolidate observed only under NFS (thanks to @fmdippolito) Other minor changes: - Removed all compiler warnings - Added some string length checks for all the names used as inputs in the C API - Changed the fragment name convention such that the first number in the name is the thread id, instead of the process id --- Makefile | 7 +- README.md | 3 +- core/include/array/array.h | 20 +- core/include/array/array_iterator.h | 3 + core/include/array/array_schema.h | 2 +- core/include/c_api/c_api.h | 13 +- core/include/fragment/book_keeping.h | 32 +- core/include/fragment/fragment.h | 15 +- core/include/fragment/read_state.h | 2 +- core/include/metadata/metadata.h | 5 + core/include/metadata/metadata_iterator.h | 7 +- core/include/misc/utils.h | 66 ++ .../include/storage_manager/storage_manager.h | 235 ++++++- core/src/array/array.cc | 217 ++++--- core/src/array/array_iterator.cc | 9 +- core/src/array/array_read_state.cc | 41 +- core/src/array/array_schema.cc | 30 +- core/src/c_api/c_api.cc | 138 ++++- core/src/fragment/book_keeping.cc | 131 ++-- core/src/fragment/fragment.cc | 81 +-- core/src/fragment/read_state.cc | 12 - core/src/fragment/write_state.cc | 27 +- core/src/metadata/metadata.cc | 53 +- core/src/metadata/metadata_iterator.cc | 9 +- core/src/misc/hilbert_curve.cc | 2 +- core/src/misc/utils.cc | 86 ++- core/src/storage_manager/storage_manager.cc | 584 +++++++++++++++--- examples/src/tiledb_array_consolidate.cc | 41 +- examples/src/tiledb_array_create_dense.cc | 2 +- examples/src/tiledb_array_create_sparse.cc | 2 +- examples/src/tiledb_array_iterator_dense.cc | 2 +- examples/src/tiledb_array_iterator_sparse.cc | 2 +- .../src/tiledb_array_parallel_read_dense_1.cc | 165 +++++ .../src/tiledb_array_parallel_read_dense_2.cc | 164 +++++ .../tiledb_array_parallel_read_sparse_1.cc | 146 +++++ .../tiledb_array_parallel_read_sparse_2.cc | 146 +++++ .../tiledb_array_parallel_write_dense_1.cc | 185 ++++++ .../tiledb_array_parallel_write_dense_2.cc | 180 ++++++ .../tiledb_array_parallel_write_sparse_1.cc | 156 +++++ .../tiledb_array_parallel_write_sparse_2.cc | 149 +++++ examples/src/tiledb_array_primitive.cc | 2 +- examples/src/tiledb_array_read_dense_1.cc | 4 +- examples/src/tiledb_array_read_dense_2.cc | 2 +- examples/src/tiledb_array_read_dense_3.cc | 4 +- examples/src/tiledb_array_read_sparse_1.cc | 4 +- examples/src/tiledb_array_read_sparse_2.cc | 2 +- examples/src/tiledb_array_update_dense_1.cc | 2 +- examples/src/tiledb_array_update_dense_2.cc | 2 +- examples/src/tiledb_array_update_sparse_1.cc | 2 +- examples/src/tiledb_array_update_sparse_2.cc | 2 +- examples/src/tiledb_array_write_dense_1.cc | 2 +- examples/src/tiledb_array_write_dense_2.cc | 6 +- examples/src/tiledb_array_write_sparse_1.cc | 2 +- examples/src/tiledb_array_write_sparse_2.cc | 8 +- examples/src/tiledb_array_write_sparse_3.cc | 2 +- examples/src/tiledb_array_write_sparse_4.cc | 2 +- examples/src/tiledb_clear_delete_move.cc | 2 +- examples/src/tiledb_ls.cc | 5 +- examples/src/tiledb_ls_workspaces.cc | 6 +- examples/src/tiledb_metadata_consolidate.cc | 19 +- examples/src/tiledb_metadata_iterator.cc | 2 +- examples/src/tiledb_metadata_primitive.cc | 2 +- examples/src/tiledb_metadata_read.cc | 35 +- examples/src/tiledb_metadata_update.cc | 2 +- examples/src/tiledb_metadata_write.cc | 2 +- examples/src/tiledb_workspace_group_create.cc | 2 +- test/src/array/array_schema_spec.cc | 3 +- test/src/c_api/c_api_spec.cc | 3 +- 68 files changed, 2735 insertions(+), 566 deletions(-) create mode 100644 examples/src/tiledb_array_parallel_read_dense_1.cc create mode 100644 examples/src/tiledb_array_parallel_read_dense_2.cc create mode 100644 examples/src/tiledb_array_parallel_read_sparse_1.cc create mode 100644 examples/src/tiledb_array_parallel_read_sparse_2.cc create mode 100644 examples/src/tiledb_array_parallel_write_dense_1.cc create mode 100644 examples/src/tiledb_array_parallel_write_dense_2.cc create mode 100644 examples/src/tiledb_array_parallel_write_sparse_1.cc create mode 100644 examples/src/tiledb_array_parallel_write_sparse_2.cc diff --git a/Makefile b/Makefile index 700263c1..bbc8d4c8 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ ifeq ($(BUILD),release) endif ifeq ($(BUILD),debug) - CPPFLAGS += -DDEBUG -gdwarf-3 -g3 + CPPFLAGS += -DDEBUG -gdwarf-3 -g3 -Wall endif # --- Verbose mode handler --- # @@ -239,7 +239,8 @@ clean_libtiledb: $(EXAMPLES_OBJ_DIR)/%.o: $(EXAMPLES_SRC_DIR)/%.cc @mkdir -p $(EXAMPLES_OBJ_DIR) @echo "Compiling $<" - @$(CXX) $(CPPFLAGS) $(INCLUDE_PATHS) $(EXAMPLES_INCLUDE_PATHS) \ + @$(CXX) $(CPPFLAGS) -fopenmp $(INCLUDE_PATHS) \ + $(EXAMPLES_INCLUDE_PATHS) \ $(CORE_INCLUDE_PATHS) -c $< -o $@ @$(CXX) -MM $(EXAMPLES_INCLUDE_PATHS) \ $(CORE_INCLUDE_PATHS) $< > $(@:.o=.d) @@ -273,7 +274,7 @@ clean_examples: $(TEST_OBJ_DIR)/%.o: $(TEST_SRC_DIR)/%.cc @mkdir -p $(dir $@) @echo "Compiling $<" - @$(CXX) $(CPPFLAGS) $(TEST_INCLUDE_PATHS) -c $< -o $@ + @$(CXX) $(CPPFLAGS) -fopenmp $(TEST_INCLUDE_PATHS) -c $< -o $@ @$(CXX) -MM $(TEST_INCLUDE_PATHS) \ $(CORE_INCLUDE_PATHS) $< > $(@:.o=.d) @mv -f $(@:.o=.d) $(@:.o=.d.tmp) diff --git a/README.md b/README.md index f6d579bc..9bff79e2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # TileDB -[![Travis](https://img.shields.io/travis/Intel-HLS/TileDB.svg?maxAge=2592000)](https://travis-ci.org/Intel-HLS/TileDB) +[![Travis](https://img.shields.io/travis/Intel-HLS/TileDB.svg?maxAge=2592000)] +(https://travis-ci.org/Intel-HLS/TileDB) The TileDB documentation for users is hosted as a [Github wiki](https://github.com/Intel-HLS/TileDB/wiki). diff --git a/core/include/array/array.h b/core/include/array/array.h index 39f499fa..b11884f9 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -35,6 +35,7 @@ #include "array_read_state.h" #include "array_schema.h" +#include "book_keeping.h" #include "constants.h" #include "fragment.h" @@ -167,6 +168,9 @@ class Array { * Initializes a TileDB array object. * * @param array_schema The array schema. + * @param fragment_names The names of the fragments of the array. + * @param book_keeping The book-keeping structures of the fragments + * of the array. * @param mode The mode of the array. It must be one of the following: * - TILEDB_ARRAY_WRITE * - TILEDB_ARRAY_WRITE_UNSORTED @@ -184,6 +188,8 @@ class Array { */ int init( const ArraySchema* array_schema, + const std::vector& fragment_names, + const std::vector& book_keeping, int mode, const char** attributes, int attribute_num, @@ -299,21 +305,21 @@ class Array { * After the new fragmemt is finalized, the array will change its name * by removing the leading '.' character. * - * @return A new special fragment name. + * @return A new special fragment name on success, or "" (empty string) on + * error. */ std::string new_fragment_name() const; /** * Opens the existing fragments in TILEDB_ARRAY_READ_MODE. * + * @param fragment_names The vector with the fragment names. + * @param book_keeping The book-keeping of the array fragments. * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. */ - int open_fragments(); - - /** - * Appropriately sorts the fragment names based on their name timestamps. - */ - void sort_fragment_names(std::vector& fragment_names) const; + int open_fragments( + const std::vector& fragment_names, + const std::vector& book_keeping); }; #endif diff --git a/core/include/array/array_iterator.h b/core/include/array/array_iterator.h index c2de5335..b1b0b613 100644 --- a/core/include/array/array_iterator.h +++ b/core/include/array/array_iterator.h @@ -71,6 +71,9 @@ class ArrayIterator { /* ACCESSORS */ /* ********************************* */ + /** Return the array name. */ + const std::string& array_name() const; + /** * Checks if the the iterator has reached its end. * diff --git a/core/include/array/array_schema.h b/core/include/array/array_schema.h index 465aa040..04a0ab44 100644 --- a/core/include/array/array_schema.h +++ b/core/include/array/array_schema.h @@ -511,7 +511,7 @@ class ArraySchema { * may be a sub-domain of the array domain). * @param tile_coords The tile coordinates. * @return The tile position of *tile_coords* along the tile order of the - * array inside the input domain. + * array inside the input domain, or TILEDB_AS_ERR on error. */ template int64_t get_tile_pos( diff --git a/core/include/c_api/c_api.h b/core/include/c_api/c_api.h index 3859f976..19a19545 100755 --- a/core/include/c_api/c_api.h +++ b/core/include/c_api/c_api.h @@ -462,10 +462,13 @@ TILEDB_EXPORT int tiledb_array_overflow( /** * Consolidates the fragments of an array into a single fragment. * - * @param tiledb_array The TileDB array to be consolidated. + * @param tiledb_ctx The TileDB context. + * @param array The name of the TileDB array to be consolidated. * @return TILEDB_OK on success, and TILEDB_ERR on error. */ -TILEDB_EXPORT int tiledb_array_consolidate(const TileDB_Array* tiledb_array); +TILEDB_EXPORT int tiledb_array_consolidate( + const TileDB_CTX* tiledb_ctx, + const char* array); /** * Finalizes a TileDB array, properly freeing its memory space. @@ -819,11 +822,13 @@ TILEDB_EXPORT int tiledb_metadata_overflow( /** * Consolidates the fragments of a metadata object into a single fragment. * - * @param tiledb_metadata The TileDB metadata to be consolidated. + * @param tiledb_ctx The TileDB context. + * @param metadata The name of the TileDB metadata to be consolidated. * @return TILEDB_OK on success, and TILEDB_ERR on error. */ TILEDB_EXPORT int tiledb_metadata_consolidate( - const TileDB_Metadata* tiledb_metadata); + const TileDB_CTX* tiledb_ctx, + const char* metadata); /** * Finalizes a TileDB metadata object, properly freeing the memory space. diff --git a/core/include/fragment/book_keeping.h b/core/include/fragment/book_keeping.h index 9ef652a2..45fefece 100644 --- a/core/include/fragment/book_keeping.h +++ b/core/include/fragment/book_keeping.h @@ -33,7 +33,8 @@ #ifndef __BOOK_KEEPING_H__ #define __BOOK_KEEPING_H__ -#include "fragment.h" +#include "array_schema.h" +#include "constants.h" #include #include @@ -53,8 +54,6 @@ -class Fragment; - /** Stores the book-keeping structures of a fragment. */ class BookKeeping { public: @@ -65,9 +64,16 @@ class BookKeeping { /** * Constructor. * - * @param fragment The fragment the book-keeping structure belongs to. + * @param array_schema The array schema. + * @param dense True if the fragment is dense, and false otherwise. + * @param fragment_name The name of the fragment this book-keeping belongs to. + * @param mode The mode in which the fragment was initialized in. */ - BookKeeping(const Fragment* fragment); + BookKeeping( + const ArraySchema* array_schema, + bool dense, + const std::string& fragment_name, + int mode); /** Destructor. */ ~BookKeeping(); @@ -85,6 +91,12 @@ class BookKeeping { /** Returns the number of cells in the tile at the input position. */ int64_t cell_num(int64_t tile_pos) const; + /** + * Returns ture if the corresponding fragment is dense, and false if it + * is sparse. + */ + bool dense() const; + /** Returns the (expanded) domain in which the fragment is constrained. */ const void* domain() const; @@ -202,8 +214,12 @@ class BookKeeping { /* PRIVATE ATTRIBUTES */ /* ********************************* */ + /** The array schema */ + const ArraySchema* array_schema_; /** The first and last coordinates of each tile. */ std::vector bounding_coords_; + /** True if the fragment is dense, and false if it is sparse. */ + bool dense_; /** * The (expanded) domain in which the fragment is constrained. "Expanded" * means that the domain is enlarged minimally to coincide with tile @@ -211,12 +227,14 @@ class BookKeeping { * type of the domain must be the same as the type of the array coordinates. */ void* domain_; - /** The fragment the book-keeping belongs to. */ - const Fragment* fragment_; + /** The name of the fragment the book-keeping belongs to. */ + std::string fragment_name_; /** Number of cells in the last tile (meaningful only in the sparse case). */ int64_t last_tile_cell_num_; /** The MBRs (applicable only to the sparse case with irregular tiles). */ std::vector mbrs_; + /** The mode in which the fragment was initialized. */ + int mode_; /** The offsets of the next tile for each attribute. */ std::vector next_tile_offsets_; /** The offsets of the next variable tile for each attribute. */ diff --git a/core/include/fragment/fragment.h b/core/include/fragment/fragment.h index 4e28c8bf..2613a46b 100644 --- a/core/include/fragment/fragment.h +++ b/core/include/fragment/fragment.h @@ -36,7 +36,6 @@ #include "array.h" #include "array_schema.h" #include "book_keeping.h" -#include "constants.h" #include "read_state.h" #include "write_state.h" #include @@ -125,11 +124,10 @@ class Fragment { int finalize(); /** - * Initializes a fragment. + * Initializes a fragment in write mode. * * @param fragment_name The name that will be given to the fragment. * @param mode The fragment mode. It can be one of the following: - * - TILEDB_READ * - TILEDB_WRITE * - TILEDB_WRITE_UNSORTED * @param subarray The subarray the fragment is constrained on. @@ -140,6 +138,17 @@ class Fragment { int mode, const void* subarray); + /** + * Initializes a fragment in read mode. + * + * @param fragment_name The name that will be given to the fragment. + * @param book_keeping The book-keeping of the fragment. + * @return TILEDB_FG_OK on success and TILEDB_FG_ERR on error. + */ + int init( + const std::string& fragment_name, + BookKeeping* book_keeping); + /** Resets the read state (typically to start a new read). */ void reset_read_state(); diff --git a/core/include/fragment/read_state.h b/core/include/fragment/read_state.h index 753430ae..4510c990 100644 --- a/core/include/fragment/read_state.h +++ b/core/include/fragment/read_state.h @@ -53,7 +53,7 @@ -class BookKeeping; +class Fragment; /** Stores the state necessary when reading cells from a fragment. */ class ReadState { diff --git a/core/include/metadata/metadata.h b/core/include/metadata/metadata.h index 8baf1f50..4444842f 100644 --- a/core/include/metadata/metadata.h +++ b/core/include/metadata/metadata.h @@ -134,6 +134,9 @@ class Metadata { * Initializes a TileDB metadata object. * * @param array_schema This essentially encapsulates the metadata schema. + * @param fragment_names The names of the fragments of the array. + * @param book_keeping The book-keeping structures of the fragments + * of the array. * @param mode The mode of the metadata. It must be one of the following: * - TILEDB_METADATA_WRITE * - TILEDB_METADATA_READ @@ -146,6 +149,8 @@ class Metadata { */ int init( const ArraySchema* array_schema, + const std::vector& fragment_names, + const std::vector& book_keeping, int mode, const char** attributes, int attribute_num); diff --git a/core/include/metadata/metadata_iterator.h b/core/include/metadata/metadata_iterator.h index 4ba5b972..3c811305 100644 --- a/core/include/metadata/metadata_iterator.h +++ b/core/include/metadata/metadata_iterator.h @@ -69,6 +69,9 @@ class MetadataIterator { /* ACCESSORS */ /* ********************************* */ + /** Return the metadata name. */ + const std::string& metadata_name() const; + /** * Checks if the the iterator has reached its end. * @@ -134,8 +137,10 @@ class MetadataIterator { private: // PRIVATE ATTRIBUTES - // TODO + /** The array iterator that implements the metadata iterator. */ ArrayIterator* array_it_; + /** The metadata this iterator belongs to. */ + Metadata* metadata_; }; #endif diff --git a/core/include/misc/utils.h b/core/include/misc/utils.h index 0393be36..6025f956 100644 --- a/core/include/misc/utils.h +++ b/core/include/misc/utils.h @@ -33,6 +33,8 @@ #ifndef __UTILS_H__ #define __UTILS_H__ +#include +#include #include #include @@ -384,6 +386,70 @@ bool is_unary_subarray(const T* subarray, int dim_num); */ bool is_workspace(const std::string& dir); +/** + * Destroys an OpenMP mutex. + * + * @param mtx The mutex to be destroyed. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_destroy(omp_lock_t* mtx); + +/** + * Destroys a pthread mutex. + * + * @param mtx The mutex to be destroyed. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_destroy(pthread_mutex_t* mtx); + +/** + * Initializes an OpenMP mutex. + * + * @param mtx The mutex to be initialized. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_init(omp_lock_t* mtx); + +/** + * Initializes a pthread mutex. + * + * @param mtx The mutex to be initialized. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_init(pthread_mutex_t* mtx); + +/** + * Locks an OpenMP mutex. + * + * @param mtx The mutex to be locked. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_lock(omp_lock_t* mtx); + +/** + * Locks a pthread mutex. + * + * @param mtx The mutex to be locked. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_lock(pthread_mutex_t* mtx); + +/** + * Unlocks an OpenMP mutex. + * + * @param mtx The mutex to be unlocked. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_unlock(omp_lock_t* mtx); + +/** + * Unlocks a pthread mutex. + * + * @param mtx The mutex to be unlocked. + * @return TILEDB_UT_OK for success, and TILEDB_UT_ERR for error. + */ +int mutex_unlock(pthread_mutex_t* mtx); + /** * Returns the parent directory of the input directory. * diff --git a/core/include/storage_manager/storage_manager.h b/core/include/storage_manager/storage_manager.h index 8a0f5822..c3855944 100755 --- a/core/include/storage_manager/storage_manager.h +++ b/core/include/storage_manager/storage_manager.h @@ -40,6 +40,9 @@ #include "metadata.h" #include "metadata_iterator.h" #include "metadata_schema_c.h" +#include +#include +#include #include /* ********************************* */ @@ -68,6 +71,9 @@ class StorageManager { /** The operation type on the master catalog (insertion or deletion). */ enum MasterCatalogOp {TILEDB_SM_MC_INS, TILEDB_SM_MC_DEL}; + /** Implements an open array entry. */ + class OpenArray; + /* ********************************* */ /* CONSTRUCTORS & DESTRUCTORS */ /* ********************************* */ @@ -82,6 +88,13 @@ class StorageManager { /* MUTATORS */ /* ********************************* */ + /** + * Finalizes the storage manager, properly freeing memory. + * + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int finalize(); + /** * Initializes the storage manager. This function create the TileDB home * directory, which by default is "~/.tiledb/". If the user home directory @@ -109,7 +122,7 @@ class StorageManager { * or metadata directory. * @return TILEDB_SM_OK for succes, and TILEDB_SM_ERR for error. */ - int workspace_create(const std::string& workspace) const; + int workspace_create(const std::string& workspace); /** * Lists all TileDB workspaces, copying their directory names in the input @@ -129,7 +142,7 @@ class StorageManager { */ int ls_workspaces( char** workspaces, - int& workspace_num) const; + int& workspace_num); @@ -155,6 +168,14 @@ class StorageManager { /* ARRAY */ /* ********************************* */ + /** + * Consolidates the fragments of an array into a single fragment. + * + * @param array_dir The name of the array to be consolidated. + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int array_consolidate(const char* array_dir); + /** * Creates a new TileDB array. * @@ -212,7 +233,7 @@ class StorageManager { int mode, const void* subarray, const char** attributes, - int attribute_num) const; + int attribute_num); /** * Finalizes an array, properly freeing the memory space. @@ -220,7 +241,7 @@ class StorageManager { * @param array The array to be finalized. * @return TILEDB_SM_OK on success, and TILEDB_SM_ERR on error. */ - int array_finalize(Array* array) const; + int array_finalize(Array* array); /** * Initializes an array iterator for reading cells, potentially constraining @@ -258,7 +279,7 @@ class StorageManager { const char** attributes, int attribute_num, void** buffers, - size_t* buffer_sizes) const; + size_t* buffer_sizes); /** * Finalizes an array iterator, properly freeing the allocating memory space. @@ -266,7 +287,7 @@ class StorageManager { * @param tiledb_array_it The TileDB array iterator to be finalized. * @return TILEDB_SM_OK on success, and TILEDB_SM_ERR on error. */ - int array_iterator_finalize(ArrayIterator* array_it) const; + int array_iterator_finalize(ArrayIterator* array_it); @@ -275,6 +296,14 @@ class StorageManager { /* METADATA */ /* ********************************* */ + /** + * Consolidates the fragments of a metadata object into a single fragment. + * + * @param metadata_dir The name of the metadata to be consolidated. + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int metadata_consolidate(const char* metadata_dir); + /** * Creates a new TileDB metadata object. * @@ -323,7 +352,7 @@ class StorageManager { const char* metadata_dir, int mode, const char** attributes, - int attribute_num) const; + int attribute_num); /** * Finalizes a TileDB metadata object, properly freeing the memory space. @@ -331,7 +360,7 @@ class StorageManager { * @param tiledb_metadata The metadata to be finalized. * @return TILEDB_SM_OK on success, and TILEDB_SM_ERR on error. */ - int metadata_finalize(Metadata* metadata) const; + int metadata_finalize(Metadata* metadata); /** * Initializes a metadata iterator, potentially constraining it @@ -366,7 +395,7 @@ class StorageManager { const char** attributes, int attribute_num, void** buffers, - size_t* buffer_sizes) const; + size_t* buffer_sizes); /** * Finalizes the iterator, properly freeing the allocating memory space. @@ -374,7 +403,7 @@ class StorageManager { * @param tiledb_metadata_it The TileDB metadata iterator. * @return TILEDB_SM_OK on success, and TILEDB_SM_ERR on error. */ - int metadata_iterator_finalize(MetadataIterator* metadata_it) const; + int metadata_iterator_finalize(MetadataIterator* metadata_it); @@ -425,7 +454,7 @@ class StorageManager { * @param dir The directory to be deleted. * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int delete_entire(const std::string& dir) const; + int delete_entire(const std::string& dir); /** * Moves a TileDB directory (workspace, group, array or metadata). @@ -434,7 +463,7 @@ class StorageManager { * @param new_dir The new directory. * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int move(const std::string& old_dir, const std::string& new_dir) const; + int move(const std::string& old_dir, const std::string& new_dir); private: /* ********************************* */ @@ -443,6 +472,12 @@ class StorageManager { /** The directory of the master catalog. */ std::string master_catalog_dir_; + /** OpneMP mutex for creating/deleting an OpenArray object. */ + omp_lock_t open_array_omp_mtx_; + /** Pthread mutex for creating/deleting an OpenArray object. */ + pthread_mutex_t open_array_pthread_mtx_; + /** Stores the currently open arrays. */ + std::map open_arrays_; /** The TileDB home directory. */ std::string tiledb_home_; @@ -459,6 +494,16 @@ class StorageManager { */ int array_clear(const std::string& array) const; + /** + * Decrements the number of times the input array is initialized. If this + * number reaches 0, the it deletes the open array entry (and hence clears + * the schema and fragment book-keeping of the array). + * + * @param array The array name. + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int array_close(const std::string& array); + /** * Deletes a TileDB array entirely. * @@ -467,6 +512,44 @@ class StorageManager { */ int array_delete(const std::string& array) const; + /** + * Gets the names of the existing fragments of an array. + * + * @param array The input array. + * @param fragment_names The fragment names to be returned. + * @return void + */ + void array_get_fragment_names( + const std::string& array, + std::vector& fragment_names); + + /** + * Gets an open array entry for the array being initialized. If this + * is the first time the array is initialized, then the function creates + * a new open array entry for this array. + * + * @param array The array name. + * @param open_array The open array entry to be returned. + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int array_get_open_array_entry( + const std::string& array, + OpenArray*& open_array); + + /** + * Loads the book-keeping structures of all the fragments of an array from the + * disk, allocating appropriate memory space for them. + * + * @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. + * @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); + /** * Moves a TileDB array. * @@ -478,6 +561,22 @@ class StorageManager { const std::string& old_array, const std::string& new_array) const; + /** + * 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. + * + * @param array_schema The array schema. + * @param mode The mode in which the array is being initialized. + * @param open_array The open array entry that is retrieved. + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int array_open( + const ArraySchema* array_schema, + int mode, + OpenArray*& open_array); + /** * It sets the TileDB configuration parameters from a file. * @@ -515,7 +614,7 @@ class StorageManager { */ int create_master_catalog_entry( const std::string& workspace, - MasterCatalogOp op) const; + MasterCatalogOp op); /** * Creates a special workspace file inside the workpace directory. @@ -552,13 +651,13 @@ class StorageManager { int group_move( const std::string& old_group, const std::string& new_group) const; - + /** * Consolidates the fragments of the master catalog. * * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int master_catalog_consolidate() const; + int master_catalog_consolidate(); /** * Create a master catalog, which keeps information about the TileDB @@ -597,6 +696,44 @@ class StorageManager { const std::string& old_metadata, const std::string& new_metadata) const; + /** + * Destroys all the mutexes. + * + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int mutex_destroy(); + + /** + * Initializes all the mutexes. + * + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int mutex_init(); + + /** + * Locks all the mutexes. + * + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int mutex_lock(); + + /** + * Unlocks all the mutexes. + * + * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. + */ + int mutex_unlock(); + + /** + * Appropriately sorts the fragment names based on their name timestamps. + * The result is stored in the input vector. + * + * @param fragment_names The fragment names to be sorted. This will also hold + * the result of the function after termination. + * @return void + */ + void sort_fragment_names(std::vector& fragment_names) const; + /** * Clears a TileDB workspace. The workspace will still exist after the * execution of the function, but it will be empty (i.e., as if it was just @@ -613,7 +750,7 @@ class StorageManager { * @param workspace The workspace to be deleted. * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int workspace_delete(const std::string& workspace) const; + int workspace_delete(const std::string& workspace); /** * Moves a TileDB workspace. @@ -624,7 +761,71 @@ class StorageManager { */ int workspace_move( const std::string& old_workspace, - const std::string& new_workspace) const; + const std::string& new_workspace); }; +/** + * Stores information about an open array. An array is open if it has been + * initialized once (withour being finalized). The difference with array + * initialization is that an array can be initialized multiple times, + * but opened only once. This structure maintains the information that + * can be used by multiple array objects that initialize the same array, + * in order to avoid replication and speed-up performance (e.g., array + * schema and book-keeping). + */ +class StorageManager::OpenArray { + public: + // ATTRIBUTES + + /** The book-keeping structures for all the fragments of the array. */ + std::vector book_keeping_; + /** + * A counter for the number of times the array has been initialized after + * it was opened. + */ + int cnt_; + /** The names of the fragments of the open array. */ + std::vector fragment_names_; + /** + * An OpenMP mutex used to lock the array when loading the array schema and + * the book-keeping structures from the disk. + */ + omp_lock_t omp_mtx_; + /** + * A pthread mutex used to lock the array when loading the array schema and + * the book-keeping structures from the disk. + */ + pthread_mutex_t pthread_mtx_; + + // FUNCTIONS + + /** + * Destroys the mutexes. + * + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int mutex_destroy(); + + /** + * Initializes the mutexes. + * + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int mutex_init(); + + /** + * Locks the mutexes. + * + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int mutex_lock(); + + /** + * Unlocks the mutexes. + * + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int mutex_unlock(); +}; + #endif diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 8dc7fd12..19acb660 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -36,8 +36,9 @@ #include #include #include -#include +#include #include +#include #include /* ****************************** */ @@ -58,19 +59,6 @@ # define PRINT_WARNING(x) do { } while(0) #endif -#ifdef GNU_PARALLEL - #include - #define SORT_LIB __gnu_parallel -#else - #include - #define SORT_LIB std -#endif - -#define SORT_2(first, last) SORT_LIB::sort((first), (last)) -#define SORT_3(first, last, comp) SORT_LIB::sort((first), (last), (comp)) -#define GET_MACRO(_1, _2, _3, NAME, ...) NAME -#define SORT(...) GET_MACRO(__VA_ARGS__, SORT_3, SORT_2)(__VA_ARGS__) - @@ -85,9 +73,10 @@ Array::Array() { } Array::~Array() { - for(int i=0; i::iterator it = fragments_.begin(); + for(; it != fragments_.end(); ++it) + if(*it != NULL) + delete *it; if(array_schema_ != NULL) delete array_schema_; @@ -181,17 +170,18 @@ const void* Array::subarray() const { /* ****************************** */ int Array::consolidate() { - // Reinit with all attributes and whole domain - finalize(); - init(array_schema_, TILEDB_ARRAY_READ, NULL, 0, NULL); - // Trivial case if(fragments_.size() == 1) return TILEDB_AS_OK; + // 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* new_fragment = new Fragment(this); - if(new_fragment->init(new_fragment_name(), TILEDB_ARRAY_WRITE, subarray_) != + if(new_fragment->init(new_fragment_name, TILEDB_ARRAY_WRITE, subarray_) != TILEDB_FG_OK) return TILEDB_AR_ERR; @@ -205,18 +195,22 @@ int Array::consolidate() { } // Finalize new fragment - new_fragment->finalize(); + int rc = new_fragment->finalize(); delete new_fragment; + if(rc != TILEDB_FG_OK) + return TILEDB_AR_ERR; // Delete old fragments - for(int i=0; ifinalize() != TILEDB_FG_OK) return TILEDB_AR_ERR; - if(delete_dir(fragments_[i]->fragment_name()) != TILEDB_UT_OK) - return TILEDB_AR_ERR; - + std::string fragment_name = fragments_[i]->fragment_name(); delete fragments_[i]; + + if(delete_dir(fragment_name) != TILEDB_UT_OK) + return TILEDB_AR_ERR; } fragments_.clear(); @@ -269,24 +263,41 @@ int Array::consolidate( } // Read and write attribute until there is no overflow + int rc_write = TILEDB_FG_OK; + int rc_read = TILEDB_FG_OK; do { // Read - if(read(buffers, buffer_sizes) != TILEDB_AR_OK) - return TILEDB_AR_ERR; + rc_read = read(buffers, buffer_sizes); + if(rc_read != TILEDB_FG_OK) + break; + // Write - if(new_fragment->write( - (const void**) buffers, - (const size_t*) buffer_sizes) != TILEDB_FG_OK) - return TILEDB_AR_ERR; + rc_write = new_fragment->write( + (const void**) buffers, + (const size_t*) buffer_sizes); + if(rc_write != TILEDB_FG_OK) + break; } while(overflow(attribute_id)); - // Success - return TILEDB_AR_OK; + // Clean up + for(int i=0; ifinalize(); if(rc != TILEDB_FG_OK) break; @@ -307,6 +318,8 @@ int Array::finalize() { int Array::init( const ArraySchema* array_schema, + const std::vector& fragment_names, + const std::vector& book_keeping, int mode, const char** attributes, int attribute_num, @@ -336,9 +349,16 @@ int Array::init( // unless in TILEDB_WRITE_UNSORTED mode attributes_vec.pop_back(); } else { // Custom attributes + // Get attributes for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_AR_ERR; + } attributes_vec.push_back(attributes[i]); } + // Sanity check on duplicates if(has_duplicates(attributes_vec)) { PRINT_ERROR("Cannot initialize array; Duplicate attributes"); @@ -346,9 +366,6 @@ int Array::init( } } - // Set array schema - array_schema_ = array_schema; - // Set attribute ids if(array_schema->get_attribute_ids(attributes_vec, attribute_ids_) == TILEDB_AS_ERR) @@ -357,17 +374,30 @@ int Array::init( // 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) { + // 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) + if(fragment->init(new_fragment_name, mode_, subarray) != TILEDB_FG_OK) { + array_schema_ = NULL; return TILEDB_AR_ERR; + } } else if(mode_ == TILEDB_ARRAY_READ) { - if(open_fragments() != TILEDB_AR_OK) + if(open_fragments(fragment_names, book_keeping) != TILEDB_AR_OK) { + array_schema_ = NULL; return TILEDB_AR_ERR; - array_read_state_ = new ArrayReadState(this); + } + array_read_state_ = new ArrayReadState(this); } // Return @@ -384,9 +414,16 @@ int Array::reset_attributes( if(array_schema_->dense()) // Remove coordinates attribute for dense attributes_vec.pop_back(); } else { // Custom attributes + // Copy attribute names for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_AR_ERR; + } attributes_vec.push_back(attributes[i]); } + // Sanity check on duplicates if(has_duplicates(attributes_vec)) { PRINT_ERROR("Cannot reset attributes; Duplicate attributes"); @@ -420,7 +457,8 @@ int Array::reset_subarray(const void* subarray) { memcpy(subarray_, subarray, subarray_size); // Re-initialize the read state of the fragments - for(int i=0; ireset_read_state(); // Re-initialize array read state @@ -444,9 +482,15 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { // Create and initialize a new fragment if(fragments_.size() == 0) { + // 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) + if(fragment->init(new_fragment_name, mode_, subarray_) != TILEDB_FG_OK) return TILEDB_AR_ERR; } @@ -474,75 +518,44 @@ int Array::write(const void** buffers, const size_t* buffer_sizes) { /* ****************************** */ std::string Array::new_fragment_name() const { - std::stringstream fragment_name; struct timeval tp; gettimeofday(&tp, NULL); uint64_t ms = (uint64_t) tp.tv_sec * 1000L + tp.tv_usec / 1000; - fragment_name << array_schema_->array_name() << "/.__" - << getpid() << "_" << ms; - - return fragment_name.str(); + pthread_t self = pthread_self(); + uint64_t tid = 0; + memcpy(&tid, &self, std::min(sizeof(self), sizeof(tid))); + char fragment_name[TILEDB_NAME_MAX_LEN]; + + int n = sprintf( + fragment_name, + "%s/.__%llu_%llu", + array_schema_->array_name().c_str(), + tid, + ms); + if(n <0) + return ""; + + return fragment_name; } -int Array::open_fragments() { - // Get directory names in the array folder - std::vector dirs = - get_fragment_dirs(array_schema_->array_name()); +int Array::open_fragments( + const std::vector& fragment_names, + const std::vector& book_keeping) { + // Sanity check + assert(fragment_names.size() == book_keeping.size()); - // Sort the fragment names - sort_fragment_names(dirs); // Create a fragment object for each fragment directory - for(int i=0; iinit(dirs[i], mode_, NULL) != TILEDB_FG_OK) - return TILEDB_AR_ERR; - } + int fragment_num = fragment_names.size(); + for(int i=0; iinit(fragment_names[i], book_keeping[i]) != TILEDB_FG_OK) + return TILEDB_AR_ERR; } // Success return TILEDB_AR_OK; } -void Array::sort_fragment_names( - std::vector& fragment_names) const { - // Initializations - int fragment_num = fragment_names.size(); - std::string t_str; - int64_t stripped_fragment_name_size, t; - std::vector > t_pos_vec; - t_pos_vec.resize(fragment_num); - - // Get the timestamp for each fragment - for(int i=0; i(t, i); - break; - } - } - } - - // Sort the names based on the timestamps - SORT(t_pos_vec.begin(), t_pos_vec.end()); - std::vector fragment_names_sorted; - fragment_names_sorted.resize(fragment_num); - for(int i=0; iarray_schema()->array_name(); +} + bool ArrayIterator::end() const { return end_; } @@ -234,7 +238,8 @@ int ArrayIterator::next() { buffer_sizes_[i] = 0; } int buffer_i; - for(int i=0; i int ArrayReadState::compute_unsorted_fragment_cell_ranges_dense( FragmentCellRanges& unsorted_fragment_cell_ranges) { - // For easy reference - const ArraySchema* array_schema = array_->array_schema(); - size_t coords_size = array_schema->coords_size(); - // Compute cell ranges for all fragments for(int i=0; idone()) { @@ -384,7 +381,6 @@ int ArrayReadState::copy_cells( // For easy reference const ArraySchema* array_schema = array_->array_schema(); int64_t pos = fragment_cell_pos_ranges_vec_pos_[attribute_id]; - size_t coords_size = array_schema->coords_size(); FragmentCellPosRanges& fragment_cell_pos_ranges = fragment_cell_pos_ranges_vec_[pos]; int64_t fragment_cell_pos_ranges_num = fragment_cell_pos_ranges.size(); @@ -396,7 +392,6 @@ int ArrayReadState::copy_cells( // Copy the cell ranges one by one for(int64_t i=0; iarray_schema(); int64_t pos = fragment_cell_pos_ranges_vec_pos_[attribute_id]; - size_t coords_size = array_schema->coords_size(); FragmentCellPosRanges& fragment_cell_pos_ranges = fragment_cell_pos_ranges_vec_[pos]; int64_t fragment_cell_pos_ranges_num = fragment_cell_pos_ranges.size(); @@ -544,9 +538,6 @@ void ArrayReadState::copy_cells_with_empty( // Sanity check assert(!array_schema->var_size(attribute_id)); - // For each cell position range, copy the respective cells to the buffer - size_t start_offset, end_offset; - // 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 = @@ -902,7 +893,6 @@ void ArrayReadState::init_subarray_tile_coords() { const ArraySchema* array_schema = array_->array_schema(); 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* subarray = static_cast(array_->subarray()); @@ -1066,7 +1056,7 @@ int ArrayReadState::read_dense_attr( // Prepare the cell ranges for the next read round if(fragment_cell_pos_ranges_vec_pos_[attribute_id] >= - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { // Get next cell ranges if(get_next_fragment_cell_ranges_dense() != TILEDB_ARS_OK) return TILEDB_ARS_ERR; @@ -1075,7 +1065,7 @@ int ArrayReadState::read_dense_attr( // Check if read is done if(done_ && fragment_cell_pos_ranges_vec_pos_[attribute_id] == - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { buffer_size = buffer_offset; return TILEDB_ARS_OK; } @@ -1161,7 +1151,7 @@ int ArrayReadState::read_dense_attr_var( // Prepare the cell ranges for the next read round if(fragment_cell_pos_ranges_vec_pos_[attribute_id] >= - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { // Get next cell ranges if(get_next_fragment_cell_ranges_dense() != TILEDB_ARS_OK) return TILEDB_ARS_ERR; @@ -1170,7 +1160,7 @@ int ArrayReadState::read_dense_attr_var( // Check if read is done if(done_ && fragment_cell_pos_ranges_vec_pos_[attribute_id] == - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { buffer_size = buffer_offset; buffer_var_size = buffer_var_offset; return TILEDB_ARS_OK; @@ -1324,7 +1314,7 @@ int ArrayReadState::read_sparse_attr( // Prepare the cell ranges for the next read round if(fragment_cell_pos_ranges_vec_pos_[attribute_id] >= - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { // Get next cell ranges if(get_next_fragment_cell_ranges_sparse() != TILEDB_ARS_OK) return TILEDB_ARS_ERR; @@ -1333,7 +1323,7 @@ int ArrayReadState::read_sparse_attr( // Check if read is done if(done_ && fragment_cell_pos_ranges_vec_pos_[attribute_id] == - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { buffer_size = buffer_offset; return TILEDB_ARS_OK; } @@ -1433,7 +1423,7 @@ int ArrayReadState::read_sparse_attr_var( // Prepare the cell ranges for the next read round if(fragment_cell_pos_ranges_vec_pos_[attribute_id] >= - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { // Get next overlapping tiles if(get_next_fragment_cell_ranges_sparse() != TILEDB_ARS_OK) return TILEDB_ARS_ERR; @@ -1442,7 +1432,7 @@ int ArrayReadState::read_sparse_attr_var( // Check if read is done if(done_ && fragment_cell_pos_ranges_vec_pos_[attribute_id] == - fragment_cell_pos_ranges_vec_.size()) { + int64_t(fragment_cell_pos_ranges_vec_.size())) { buffer_size = buffer_offset; buffer_var_size = buffer_var_offset; return TILEDB_ARS_OK; @@ -1567,6 +1557,8 @@ int ArrayReadState::sort_fragment_cell_ranges( trimmed_top_range, coords_retrieved)) { free(trimmed_top_range); + free(top_range); + free(popped_range); return TILEDB_ARS_ERR; } if(coords_retrieved) @@ -1574,11 +1566,10 @@ int ArrayReadState::sort_fragment_cell_ranges( else free(trimmed_top_range); } - } else { // Simply discard top and get a new one - free(top.second); - } + } - // Get a new top + // Discard top and get a new one + free(top.second); pq.pop(); top = pq.top(); top_fragment_i = top.first.first; @@ -1691,7 +1682,7 @@ int ArrayReadState::sort_fragment_cell_ranges( free(pq.top().second); pq.pop(); } - for(int i=0; i @@ -1781,16 +1787,20 @@ size_t ArraySchema::compute_type_size(int i) const { // Sanity check assert(i>= 0 && i <= attribute_num_); - if(types_[i] == TILEDB_CHAR) + if(types_[i] == TILEDB_CHAR) { return sizeof(char); - else if(types_[i] == TILEDB_INT32) + } else if(types_[i] == TILEDB_INT32) { return sizeof(int); - else if(types_[i] == TILEDB_INT64) + } else if(types_[i] == TILEDB_INT64) { return sizeof(int64_t); - else if(types_[i] == TILEDB_FLOAT32) + } else if(types_[i] == TILEDB_FLOAT32) { return sizeof(float); - else if(types_[i] == TILEDB_FLOAT64) + } else if(types_[i] == TILEDB_FLOAT64) { return sizeof(double); + } else { // The program should never reach this point + assert(0); + return 0; + } } template diff --git a/core/src/c_api/c_api.cc b/core/src/c_api/c_api.cc index e9e638d4..b5bcd8d8 100644 --- a/core/src/c_api/c_api.cc +++ b/core/src/c_api/c_api.cc @@ -56,11 +56,19 @@ /* CONTEXT */ /* ****************************** */ -typedef struct TileDB_CTX{ +typedef struct TileDB_CTX { StorageManager* storage_manager_; } TileDB_CTX; int tiledb_ctx_init(TileDB_CTX** tiledb_ctx, const char* config_filename) { + // Check config filename length + if(config_filename != NULL) { + if(strlen(config_filename) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid filename length"); + return TILEDB_ERR; + } + } + // Initialize context *tiledb_ctx = (TileDB_CTX*) malloc(sizeof(struct TileDB_CTX)); if(*tiledb_ctx == NULL) { @@ -69,7 +77,7 @@ int tiledb_ctx_init(TileDB_CTX** tiledb_ctx, const char* config_filename) { return TILEDB_ERR; } - // Create TileDB storage manager + // Create storage manager (*tiledb_ctx)->storage_manager_ = new StorageManager(); if((*tiledb_ctx)->storage_manager_->init(config_filename) != TILEDB_SM_OK) return TILEDB_ERR; @@ -79,14 +87,23 @@ int tiledb_ctx_init(TileDB_CTX** tiledb_ctx, const char* config_filename) { int tiledb_ctx_finalize(TileDB_CTX* tiledb_ctx) { // Trivial case - if(tiledb_ctx == NULL || tiledb_ctx->storage_manager_ == NULL) + if(tiledb_ctx == NULL) return TILEDB_OK; - // Delete TileDB storage manager + // Finalize storage manager + int rc = TILEDB_OK; + if(tiledb_ctx->storage_manager_ != NULL) + rc = tiledb_ctx->storage_manager_->finalize(); + + // Clean up delete tiledb_ctx->storage_manager_; + free(tiledb_ctx); - // Success - return TILEDB_OK; + // Return + if(rc == TILEDB_SM_OK) + return TILEDB_OK; + else + return TILEDB_ERR; } @@ -155,6 +172,12 @@ int tiledb_workspace_create( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check workspace name length + if(workspace == NULL || strlen(workspace) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid workspace name length"); + return TILEDB_ERR; + } + // Create the workspace if(tiledb_ctx->storage_manager_->workspace_create(workspace) != TILEDB_SM_OK) return TILEDB_ERR; @@ -176,6 +199,12 @@ int tiledb_group_create( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check group name length + if(group == NULL || strlen(group) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid group name length"); + return TILEDB_ERR; + } + // Create the group if(tiledb_ctx->storage_manager_->group_create(group) != TILEDB_SM_OK) return TILEDB_ERR; @@ -221,6 +250,10 @@ int tiledb_array_set_schema( // Set array name size_t array_name_len = strlen(array_name); + if(array_name == NULL || array_name_len > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid array name length"); + return TILEDB_ERR; + } tiledb_array_schema->array_name_ = (char*) malloc(array_name_len+1); strcpy(tiledb_array_schema->array_name_, array_name); @@ -230,6 +263,10 @@ int tiledb_array_set_schema( (char**) malloc(attribute_num*sizeof(char*)); for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_ERR; + } tiledb_array_schema->attributes_[i] = (char*) malloc(attribute_len+1); strcpy(tiledb_array_schema->attributes_[i], attributes[i]); } @@ -239,6 +276,10 @@ int tiledb_array_set_schema( tiledb_array_schema->dimensions_ = (char**) malloc(dim_num*sizeof(char*)); for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_ERR; + } tiledb_array_schema->dimensions_[i] = (char*) malloc(dimension_len+1); strcpy(tiledb_array_schema->dimensions_[i], dimensions[i]); } @@ -290,6 +331,9 @@ int tiledb_array_set_schema( for(int i=0; icompression_[i] = compression[i]; } + + // Success + return TILEDB_OK; } int tiledb_array_create( @@ -336,6 +380,12 @@ int tiledb_array_init( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check array name length + if(array == NULL || strlen(array) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid array name length"); + return TILEDB_ERR; + } + // Allocate memory for the array struct *tiledb_array = (TileDB_Array*) malloc(sizeof(struct TileDB_Array)); @@ -429,6 +479,12 @@ int tiledb_array_load_schema( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check array name length + if(array == NULL || strlen(array) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid array name length"); + return TILEDB_ERR; + } + // Get the array schema ArraySchema* array_schema; if(tiledb_ctx->storage_manager_->array_load_schema(array, array_schema) != @@ -551,13 +607,17 @@ int tiledb_array_overflow( return (int) tiledb_array->array_->overflow(attribute_id); } -int tiledb_array_consolidate(const TileDB_Array* tiledb_array) { - // Sanity check - if(!sanity_check(tiledb_array)) +int tiledb_array_consolidate( + const TileDB_CTX* tiledb_ctx, + const char* array) { + // Check array name length + if(array == NULL || strlen(array) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid array name length"); return TILEDB_ERR; + } // Consolidate - if(tiledb_array->array_->consolidate() != TILEDB_AR_OK) + if(tiledb_ctx->storage_manager_->array_consolidate(array) != TILEDB_SM_OK) return TILEDB_ERR; else return TILEDB_OK; @@ -717,6 +777,10 @@ int tiledb_metadata_set_schema( // Set metadata name size_t metadata_name_len = strlen(metadata_name); + if(metadata_name == NULL || metadata_name_len > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid metadata name length"); + return TILEDB_ERR; + } tiledb_metadata_schema->metadata_name_ = (char*) malloc(metadata_name_len+1); strcpy(tiledb_metadata_schema->metadata_name_, metadata_name); @@ -726,6 +790,10 @@ int tiledb_metadata_set_schema( (char**) malloc(attribute_num*sizeof(char*)); for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_ERR; + } tiledb_metadata_schema->attributes_[i] = (char*) malloc(attribute_len+1); strcpy(tiledb_metadata_schema->attributes_[i], attributes[i]); } @@ -869,6 +937,12 @@ int tiledb_metadata_load_schema( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check metadata name length + if(metadata == NULL || strlen(metadata) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid metadata name length"); + return TILEDB_ERR; + } + // Get the array schema ArraySchema* array_schema; if(tiledb_ctx->storage_manager_->metadata_load_schema( @@ -979,13 +1053,17 @@ int tiledb_metadata_overflow( } int tiledb_metadata_consolidate( - const TileDB_Metadata* tiledb_metadata) { - // Sanity check - if(!sanity_check(tiledb_metadata)) - return TILEDB_ERR; + const TileDB_CTX* tiledb_ctx, + const char* metadata) { + // Check metadata name length + if(metadata == NULL || strlen(metadata) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid metadata name length"); + return TILEDB_ERR; + } // Consolidate - if(tiledb_metadata->metadata_->consolidate() != TILEDB_MT_OK) + if(tiledb_ctx->storage_manager_->metadata_consolidate(metadata) != + TILEDB_SM_OK) return TILEDB_ERR; else return TILEDB_OK; @@ -1124,6 +1202,12 @@ int tiledb_clear( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check directory name length + if(dir == NULL || strlen(dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid directory name length"); + return TILEDB_ERR; + } + // Clear if(tiledb_ctx->storage_manager_->clear(dir) != TILEDB_SM_OK) return TILEDB_ERR; @@ -1138,6 +1222,12 @@ int tiledb_delete( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check directory name length + if(dir == NULL || strlen(dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid directory name length"); + return TILEDB_ERR; + } + // Delete if(tiledb_ctx->storage_manager_->delete_entire(dir) != TILEDB_SM_OK) return TILEDB_ERR; @@ -1153,6 +1243,18 @@ int tiledb_move( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check old directory name length + if(old_dir == NULL || strlen(old_dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid old directory name length"); + return TILEDB_ERR; + } + + // Check new directory name length + if(new_dir == NULL || strlen(new_dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid new directory name length"); + return TILEDB_ERR; + } + // Move if(tiledb_ctx->storage_manager_->move(old_dir, new_dir) != TILEDB_SM_OK) return TILEDB_ERR; @@ -1187,6 +1289,12 @@ int tiledb_ls( if(!sanity_check(tiledb_ctx)) return TILEDB_ERR; + // Check parent directory name length + if(parent_dir == NULL || strlen(parent_dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid parent directory name length"); + return TILEDB_ERR; + } + // List TileDB objects if(tiledb_ctx->storage_manager_->ls( parent_dir, diff --git a/core/src/fragment/book_keeping.cc b/core/src/fragment/book_keeping.cc index e1838582..e261bb06 100644 --- a/core/src/fragment/book_keeping.cc +++ b/core/src/fragment/book_keeping.cc @@ -67,8 +67,15 @@ /* CONSTRUCTORS & DESTRUCTORS */ /* ****************************** */ -BookKeeping::BookKeeping(const Fragment* fragment) - : fragment_(fragment) { +BookKeeping::BookKeeping( + const ArraySchema* array_schema, + bool dense, + const std::string& fragment_name, + int mode) + : array_schema_(array_schema), + dense_(dense), + fragment_name_(fragment_name), + mode_(mode) { domain_ = NULL; non_empty_domain_ = NULL; } @@ -80,11 +87,13 @@ BookKeeping::~BookKeeping() { if(non_empty_domain_ != NULL) free(non_empty_domain_); - for(int i=0; i& BookKeeping::bounding_coords() const { } int64_t BookKeeping::cell_num(int64_t tile_pos) const { - // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - - if(fragment_->dense()) { - return array_schema->cell_num_per_tile(); + if(dense_) { + return array_schema_->cell_num_per_tile(); } else { int64_t tile_num = this->tile_num(); if(tile_pos != tile_num-1) - return array_schema->capacity(); + return array_schema_->capacity(); else return last_tile_cell_num(); } } +bool BookKeeping::dense() const { + return dense_; +} + const void* BookKeeping::domain() const { return domain_; } @@ -132,9 +142,8 @@ const void* BookKeeping::non_empty_domain() const { } int64_t BookKeeping::tile_num() const { - if(fragment_->dense()) { - const ArraySchema* array_schema = fragment_->array()->array_schema(); - return array_schema->tile_num(domain_); + if(dense_) { + return array_schema_->tile_num(domain_); } else { return mbrs_.size(); } @@ -161,8 +170,7 @@ const std::vector >& BookKeeping::tile_var_sizes() const { void BookKeeping::append_bounding_coords(const void* bounding_coords) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - size_t bounding_coords_size = 2*array_schema->coords_size(); + size_t bounding_coords_size = 2*array_schema_->coords_size(); // Copy and append MBR void* new_bounding_coords = malloc(bounding_coords_size); @@ -172,8 +180,7 @@ void BookKeeping::append_bounding_coords(const void* bounding_coords) { void BookKeeping::append_mbr(const void* mbr) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - size_t mbr_size = 2*array_schema->coords_size(); + size_t mbr_size = 2*array_schema_->coords_size(); // Copy and append MBR void* new_mbr = malloc(mbr_size); @@ -232,17 +239,15 @@ void BookKeeping::append_tile_var_size( */ int BookKeeping::finalize() { // Nothing to do in READ mode - int mode = fragment_->mode(); - if(mode == TILEDB_ARRAY_READ) + if(mode_ == TILEDB_ARRAY_READ) return TILEDB_BK_OK; // Do nothing if the fragment directory does not exist (fragment empty) - std::string fragment_name = fragment_->fragment_name(); - if(!is_dir(fragment_name)) + if(!is_dir(fragment_name_)) return TILEDB_BK_OK; // Prepare file name - std::string filename = fragment_name + "/" + + std::string filename = fragment_name_ + "/" + TILEDB_BOOK_KEEPING_FILENAME + TILEDB_FILE_SUFFIX + TILEDB_GZIP_SUFFIX; @@ -293,25 +298,24 @@ int BookKeeping::finalize() { int BookKeeping::init(const void* non_empty_domain) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); // Sanity check assert(non_empty_domain_ == NULL); assert(domain_ == NULL); // Set non-empty domain - size_t domain_size = 2*array_schema->coords_size(); + size_t domain_size = 2*array_schema_->coords_size(); non_empty_domain_ = malloc(domain_size); if(non_empty_domain == NULL) - memcpy(non_empty_domain_, array_schema->domain(), domain_size); + memcpy(non_empty_domain_, array_schema_->domain(), domain_size); else memcpy(non_empty_domain_, non_empty_domain, domain_size); // Set expanded domain domain_ = malloc(domain_size); memcpy(domain_, non_empty_domain_, domain_size); - array_schema->expand_domain(domain_); + array_schema_->expand_domain(domain_); // Set last tile cell number last_tile_cell_num_ = 0; @@ -363,7 +367,7 @@ int BookKeeping::init(const void* non_empty_domain) { */ int BookKeeping::load() { // Prepare file name - std::string filename = fragment_->fragment_name() + "/" + + std::string filename = fragment_name_ + "/" + TILEDB_BOOK_KEEPING_FILENAME + TILEDB_FILE_SUFFIX + TILEDB_GZIP_SUFFIX; @@ -429,8 +433,7 @@ void BookKeeping::set_last_tile_cell_num(int64_t cell_num) { */ int BookKeeping::flush_bounding_coords(gzFile fd) const { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - size_t bounding_coords_size = 2*array_schema->coords_size(); + size_t bounding_coords_size = 2*array_schema_->coords_size(); int64_t bounding_coords_num = bounding_coords_.size(); // Write number of bounding coordinates @@ -441,9 +444,9 @@ int BookKeeping::flush_bounding_coords(gzFile fd) const { } // Write bounding coordinates - for(int i=0; iarray()->array_schema(); int64_t cell_num_per_tile = - fragment_->dense() ? array_schema->cell_num_per_tile() : - array_schema->capacity(); + dense_ ? array_schema_->cell_num_per_tile() : + array_schema_->capacity(); // Handle the case of zero int64_t last_tile_cell_num = @@ -484,8 +486,7 @@ int BookKeeping::flush_last_tile_cell_num(gzFile fd) const { */ int BookKeeping::flush_mbrs(gzFile fd) const { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - size_t mbr_size = 2*array_schema->coords_size(); + size_t mbr_size = 2*array_schema_->coords_size(); int64_t mbr_num = mbrs_.size(); // Write number of MBRs @@ -495,8 +496,8 @@ int BookKeeping::flush_mbrs(gzFile fd) const { } // Write MBRs - for(int i=0; iarray()->array_schema()->coords_size() * 2; + size_t domain_size = (non_empty_domain_ == NULL) + ? 0 + : array_schema_->coords_size() * 2; // Write non-empty domain size if(gzwrite(fd, &domain_size, sizeof(size_t)) != sizeof(size_t)) { @@ -521,7 +523,7 @@ int BookKeeping::flush_non_empty_domain(gzFile fd) const { // Write non-empty domain if(non_empty_domain_ != NULL) { - if(gzwrite(fd, non_empty_domain_, domain_size) != domain_size) { + if(gzwrite(fd, non_empty_domain_, domain_size) != int(domain_size)) { PRINT_ERROR("Cannot finalize book-keeping; Writing domain failed"); return TILEDB_BK_ERR; } @@ -541,8 +543,7 @@ int BookKeeping::flush_non_empty_domain(gzFile fd) const { */ int BookKeeping::flush_tile_offsets(gzFile fd) const { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); int64_t tile_offsets_num; // Write tile offsets for each attribute @@ -560,7 +561,7 @@ int BookKeeping::flush_tile_offsets(gzFile fd) const { // Write tile offsets if(gzwrite(fd, &tile_offsets_[i][0], tile_offsets_num * sizeof(off_t)) != - tile_offsets_num * sizeof(off_t)) { + int(tile_offsets_num * sizeof(off_t))) { PRINT_ERROR("Cannot finalize book-keeping; Writing tile offsets failed"); return TILEDB_BK_ERR; } @@ -580,8 +581,7 @@ int BookKeeping::flush_tile_offsets(gzFile fd) const { */ int BookKeeping::flush_tile_var_offsets(gzFile fd) const { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); int64_t tile_var_offsets_num; // Write tile offsets for each attribute @@ -602,7 +602,7 @@ int BookKeeping::flush_tile_var_offsets(gzFile fd) const { fd, &tile_var_offsets_[i][0], tile_var_offsets_num * sizeof(off_t)) != - tile_var_offsets_num * sizeof(off_t)) { + int(tile_var_offsets_num * sizeof(off_t))) { PRINT_ERROR("Cannot finalize book-keeping; Writing variable tile " "offsets failed"); return TILEDB_BK_ERR; @@ -623,8 +623,7 @@ int BookKeeping::flush_tile_var_offsets(gzFile fd) const { */ int BookKeeping::flush_tile_var_sizes(gzFile fd) const { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); int64_t tile_var_sizes_num; // Write tile sizes for each attribute @@ -645,7 +644,7 @@ int BookKeeping::flush_tile_var_sizes(gzFile fd) const { fd, &tile_var_sizes_[i][0], tile_var_sizes_num * sizeof(size_t)) != - tile_var_sizes_num * sizeof(size_t)) { + int(tile_var_sizes_num * sizeof(size_t))) { PRINT_ERROR("Cannot finalize book-keeping; Writing variable tile " "sizes failed"); return TILEDB_BK_ERR; @@ -662,8 +661,7 @@ int BookKeeping::flush_tile_var_sizes(gzFile fd) const { */ int BookKeeping::load_bounding_coords(gzFile fd) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - size_t bounding_coords_size = 2*array_schema->coords_size(); + size_t bounding_coords_size = 2*array_schema_->coords_size(); // Get number of bounding coordinates int64_t bounding_coords_num; @@ -679,7 +677,7 @@ int BookKeeping::load_bounding_coords(gzFile fd) { for(int64_t i=0; iarray()->array_schema(); - size_t mbr_size = 2*array_schema->coords_size(); + size_t mbr_size = 2*array_schema_->coords_size(); // Get number of MBRs int64_t mbr_num; @@ -728,7 +725,7 @@ int BookKeeping::load_mbrs(gzFile fd) { mbrs_.resize(mbr_num); for(int64_t i=0; iarray()->array_schema(); memcpy(domain_, non_empty_domain_, domain_size); - array_schema->expand_domain(domain_); + array_schema_->expand_domain(domain_); } // Success @@ -786,8 +782,7 @@ int BookKeeping::load_non_empty_domain(gzFile fd) { */ int BookKeeping::load_tile_offsets(gzFile fd) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); int64_t tile_offsets_num; // Allocate tile offsets @@ -808,7 +803,7 @@ int BookKeeping::load_tile_offsets(gzFile fd) { // Get tile offsets tile_offsets_[i].resize(tile_offsets_num); if(gzread(fd, &tile_offsets_[i][0], tile_offsets_num * sizeof(off_t)) != - tile_offsets_num * sizeof(off_t)) { + int(tile_offsets_num * sizeof(off_t))) { PRINT_ERROR("Cannot load book-keeping; Reading tile offsets failed"); return TILEDB_BK_ERR; } @@ -828,8 +823,7 @@ int BookKeeping::load_tile_offsets(gzFile fd) { */ int BookKeeping::load_tile_var_offsets(gzFile fd) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); int64_t tile_var_offsets_num; // Allocate tile offsets @@ -853,7 +847,7 @@ int BookKeeping::load_tile_var_offsets(gzFile fd) { fd, &tile_var_offsets_[i][0], tile_var_offsets_num * sizeof(off_t)) != - tile_var_offsets_num * sizeof(off_t)) { + int(tile_var_offsets_num * sizeof(off_t))) { PRINT_ERROR("Cannot load book-keeping; Reading variable tile " "offsets failed"); return TILEDB_BK_ERR; @@ -874,8 +868,7 @@ int BookKeeping::load_tile_var_offsets(gzFile fd) { */ int BookKeeping::load_tile_var_sizes(gzFile fd) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); + int attribute_num = array_schema_->attribute_num(); int64_t tile_var_sizes_num; // Allocate tile sizes @@ -899,7 +892,7 @@ int BookKeeping::load_tile_var_sizes(gzFile fd) { fd, &tile_var_sizes_[i][0], tile_var_sizes_num * sizeof(size_t)) != - tile_var_sizes_num * sizeof(size_t)) { + int(tile_var_sizes_num * sizeof(size_t))) { PRINT_ERROR("Cannot load book-keeping; Reading variable tile " "sizes failed"); return TILEDB_BK_ERR; diff --git a/core/src/fragment/fragment.cc b/core/src/fragment/fragment.cc index 7adf786a..2f346999 100644 --- a/core/src/fragment/fragment.cc +++ b/core/src/fragment/fragment.cc @@ -30,6 +30,7 @@ * This file implements the Fragment class. */ +#include "constants.h" #include "fragment.h" #include "utils.h" #include @@ -79,7 +80,7 @@ Fragment::~Fragment() { if(read_state_ != NULL) delete read_state_; - if(book_keeping_ != NULL) + if(book_keeping_ != NULL && mode_ != TILEDB_ARRAY_READ) delete book_keeping_; } @@ -163,51 +164,59 @@ int Fragment::init( const std::string& fragment_name, int mode, const void* subarray) { + // Sanity check + if(mode != TILEDB_ARRAY_WRITE && + mode != TILEDB_ARRAY_WRITE_UNSORTED) { + PRINT_ERROR("Cannot initialize fragment; Invalid mode"); + return TILEDB_FG_ERR; + } + // Set fragment name and mode fragment_name_ = fragment_name; mode_ = mode; // Check if the fragment is dense or not - if(mode == TILEDB_ARRAY_WRITE || - mode == TILEDB_ARRAY_WRITE_UNSORTED) { - dense_ = true; - // Check the attributes given upon initialization - const std::vector& attribute_ids = array_->attribute_ids(); - int id_num = attribute_ids.size(); - int attribute_num = array_->array_schema()->attribute_num(); - for(int i=0; i& attribute_ids = array_->attribute_ids(); + int id_num = attribute_ids.size(); + int attribute_num = array_->array_schema()->attribute_num(); + for(int i=0; iinit(subarray) != TILEDB_BK_OK) { - delete book_keeping_; - book_keeping_ = NULL; - write_state_ = NULL; - return TILEDB_FG_ERR; - } - write_state_ = new WriteState(this, book_keeping_); - } else if(mode == TILEDB_ARRAY_READ) { + // Initialize book-keeping and read/write state + book_keeping_ = + new BookKeeping( + array_->array_schema(), + dense_, + fragment_name, + mode_); + read_state_ = NULL; + if(book_keeping_->init(subarray) != TILEDB_BK_OK) { + delete book_keeping_; + book_keeping_ = NULL; write_state_ = NULL; - if(book_keeping_->load() != TILEDB_BK_OK) { - delete book_keeping_; - book_keeping_ = NULL; - return TILEDB_FG_ERR; - } - read_state_ = new ReadState(this, book_keeping_); + return TILEDB_FG_ERR; } + write_state_ = new WriteState(this, book_keeping_); + + // Success + return TILEDB_FG_OK; +} + +int Fragment::init( + const std::string& fragment_name, + BookKeeping* book_keeping) { + // Set member attributes + fragment_name_ = fragment_name; + mode_ = TILEDB_ARRAY_READ; + book_keeping_ = book_keeping; + dense_ = book_keeping_->dense(); + write_state_ = NULL; + read_state_ = new ReadState(this, book_keeping_); // Success return TILEDB_FG_OK; diff --git a/core/src/fragment/read_state.cc b/core/src/fragment/read_state.cc index 056c7c87..90d957f1 100644 --- a/core/src/fragment/read_state.cc +++ b/core/src/fragment/read_state.cc @@ -196,7 +196,6 @@ bool ReadState::done() const { void ReadState::get_bounding_coords(void* bounding_coords) const { // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); size_t coords_size = array_schema->coords_size(); int64_t pos = search_tile_pos_; assert(pos != -1); @@ -243,7 +242,6 @@ int ReadState::copy_cells( // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); size_t cell_size = array_schema->cell_size(attribute_id); // Fetch the attribute tile from disk if necessary @@ -320,7 +318,6 @@ int ReadState::copy_cells_var( const CellPosRange& cell_pos_range) { // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); - int attribute_num = array_schema->attribute_num(); size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; // Calculate free space in buffer @@ -489,7 +486,6 @@ int ReadState::get_enclosing_coords( const ArraySchema* array_schema = fragment_->array()->array_schema(); int attribute_num = array_schema->attribute_num(); int dim_num = array_schema->dim_num(); - int64_t cell_num = book_keeping_->cell_num(tile_i); size_t coords_size = array_schema->coords_size(); // Fetch the coordinates search tile from disk if necessary @@ -551,8 +547,6 @@ int ReadState::get_fragment_cell_pos_range_sparse( int attribute_num = array_schema->attribute_num(); int dim_num = array_schema->dim_num(); int64_t tile_i = fragment_info.second; - int64_t cell_num = book_keeping_->cell_num(tile_i); - size_t coords_size = array_schema->coords_size(); // Fetch the coordinates search tile from disk if necessary int compression = array_schema->compression(attribute_num); @@ -564,9 +558,6 @@ int ReadState::get_fragment_cell_pos_range_sparse( if(rc != TILEDB_RS_OK) return TILEDB_RS_ERR; - // For easy reference - const T* tile = static_cast(tiles_[attribute_num+1]); - // Compute the appropriate cell positions int64_t start_pos = get_cell_pos_at_or_after(cell_range); int64_t end_pos = get_cell_pos_at_or_before(&cell_range[dim_num]); @@ -816,7 +807,6 @@ void ReadState::get_next_overlapping_tile_dense(const T* tile_coords) { // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); int dim_num = array_schema->dim_num(); - size_t coords_size = array_schema->coords_size(); const T* tile_extents = static_cast(array_schema->tile_extents()); const T* array_domain = static_cast(array_schema->domain()); const T* subarray = static_cast(fragment_->array()->subarray()); @@ -878,7 +868,6 @@ void ReadState::get_next_overlapping_tile_sparse() { // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); - int dim_num = array_schema->dim_num(); const std::vector& mbrs = book_keeping_->mbrs(); const T* subarray = static_cast(fragment_->array()->subarray()); @@ -1043,7 +1032,6 @@ void ReadState::compute_bytes_to_copy( } // Calculate number of cells in the current tile for this attribute - const ArraySchema* array_schema = fragment_->array()->array_schema(); int64_t cell_num = book_keeping_->cell_num(fetched_tile_[attribute_id]); // Calculate bytes to copy from the variable tile diff --git a/core/src/fragment/write_state.cc b/core/src/fragment/write_state.cc index fb578a0d..8f674eba 100644 --- a/core/src/fragment/write_state.cc +++ b/core/src/fragment/write_state.cc @@ -134,12 +134,14 @@ WriteState::WriteState( WriteState::~WriteState() { // Free current tiles - for(int i=0; ifragment_name() + "/"; std::string filename = ""; // Go over var length attributes - for(int i=0; ivar_size(attribute_ids[i])) { filename = file_prefix + array_schema->attribute(attribute_ids[i]) + "_var" + TILEDB_FILE_SUFFIX; @@ -540,7 +543,6 @@ int WriteState::write_last_tile() { // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); int attribute_num = array_schema->attribute_num(); - size_t tile_size; // Send last MBR, bounding coordinates and tile cell number to book-keeping book_keeping_->append_mbr(mbr_); @@ -639,8 +641,6 @@ int WriteState::write_dense_attr_cmp_gzip( const void* buffer, size_t buffer_size) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); - size_t cell_size = array_schema->cell_size(attribute_id); size_t tile_size = fragment_->tile_size(attribute_id); // Initialize local tile buffer if needed @@ -787,7 +787,6 @@ int WriteState::write_dense_attr_var_cmp_gzip( const void* buffer_var, size_t buffer_var_size) { // For easy reference - const ArraySchema* array_schema = fragment_->array()->array_schema(); size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; int64_t cell_num_per_tile = fragment_->cell_num_per_tile(); size_t tile_size = cell_num_per_tile * cell_size; @@ -1029,8 +1028,6 @@ int WriteState::write_sparse_attr_cmp_none( // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); int attribute_num = array_schema->attribute_num(); - size_t cell_size = array_schema->cell_size(attribute_id); - int64_t buffer_cell_num = buffer_size / cell_size; // Update book-keeping if(attribute_id == attribute_num) @@ -1053,9 +1050,7 @@ int WriteState::write_sparse_attr_cmp_gzip( // For easy reference const ArraySchema* array_schema = fragment_->array()->array_schema(); int attribute_num = array_schema->attribute_num(); - size_t cell_size = array_schema->cell_size(attribute_id); size_t tile_size = fragment_->tile_size(attribute_id); - int64_t buffer_cell_num = buffer_size / cell_size; // Update book-keeping if(attribute_id == attribute_num) @@ -1491,7 +1486,7 @@ int WriteState::write_sparse_unsorted_attr_cmp_none( // Check number of cells in buffer int64_t buffer_cell_num = buffer_size / cell_size; - if(buffer_cell_num != cell_pos.size()) { + if(buffer_cell_num != int64_t(cell_pos.size())) { PRINT_ERROR(std::string("Cannot write sparse unsorted; Invalid number of " "cells in attribute '") + array_schema->attribute(attribute_id) + "'"); @@ -1555,7 +1550,7 @@ int WriteState::write_sparse_unsorted_attr_cmp_gzip( // Check number of cells in buffer int64_t buffer_cell_num = buffer_size / cell_size; - if(buffer_cell_num != cell_pos.size()) { + if(buffer_cell_num != int64_t(cell_pos.size())) { PRINT_ERROR(std::string("Cannot write sparse unsorted; Invalid number of " "cells in attribute '") + array_schema->attribute(attribute_id) + "'"); @@ -1648,13 +1643,12 @@ int WriteState::write_sparse_unsorted_attr_var_cmp_none( const ArraySchema* array_schema = fragment_->array()->array_schema(); size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; size_t cell_var_size; - const char* buffer_c = static_cast(buffer); const size_t* buffer_s = static_cast(buffer); const char* buffer_var_c = static_cast(buffer_var); // Check number of cells in buffer int64_t buffer_cell_num = buffer_size / cell_size; - if(buffer_cell_num != cell_pos.size()) { + if(buffer_cell_num != int64_t(cell_pos.size())) { PRINT_ERROR(std::string("Cannot write sparse unsorted variable; " "Invalid number of cells in attribute '") + array_schema->attribute(attribute_id) + "'"); @@ -1741,13 +1735,12 @@ int WriteState::write_sparse_unsorted_attr_var_cmp_gzip( const ArraySchema* array_schema = fragment_->array()->array_schema(); size_t cell_size = TILEDB_CELL_VAR_OFFSET_SIZE; size_t cell_var_size; - const char* buffer_c = static_cast(buffer); const size_t* buffer_s = static_cast(buffer); const char* buffer_var_c = static_cast(buffer_var); // Check number of cells in buffer int64_t buffer_cell_num = buffer_size / cell_size; - if(buffer_cell_num != cell_pos.size()) { + if(buffer_cell_num != int64_t(cell_pos.size())) { PRINT_ERROR(std::string("Cannot write sparse unsorted variable; " "Invalid number of cells in attribute '") + array_schema->attribute(attribute_id) + "'"); diff --git a/core/src/metadata/metadata.cc b/core/src/metadata/metadata.cc index e3ed75d9..33b80ed2 100644 --- a/core/src/metadata/metadata.cc +++ b/core/src/metadata/metadata.cc @@ -68,8 +68,6 @@ Metadata::Metadata() { } Metadata::~Metadata() { - if(array_ != NULL) - delete array_; } @@ -100,11 +98,12 @@ int Metadata::read(const char* key, void** buffers, size_t* buffer_sizes) { // Compute subarray for the read int subarray[8]; - int coords[4]; + unsigned int coords[4]; MD5((const unsigned char*) key, strlen(key)+1, (unsigned char*) coords); + for(int i=0; i<4; ++i) { - subarray[2*i] = coords[i]; - subarray[2*i+1] = coords[i]; + subarray[2*i] = int(coords[i]); + subarray[2*i+1] = int(coords[i]); } // Re-init sub array @@ -146,6 +145,8 @@ int Metadata::finalize() { int Metadata::init( const ArraySchema* array_schema, + const std::vector& fragment_names, + const std::vector& book_keeping, int mode, const char** attributes, int attribute_num) { @@ -165,8 +166,8 @@ int Metadata::init( char** array_attributes; int array_attribute_num; if(attributes == NULL) { - array_attribute_num = - (mode == TILEDB_METADATA_WRITE) ? array_schema->attribute_num() + 1 + array_attribute_num = + (mode == TILEDB_METADATA_WRITE) ? array_schema->attribute_num() + 1 : array_schema->attribute_num(); array_attributes = new char*[array_attribute_num]; for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_MT_ERR; + } array_attributes[i] = new char[attribute_len+1]; strcpy(array_attributes[i], attributes[i]); } @@ -196,6 +202,8 @@ int Metadata::init( array_ = new Array(); int rc = array_->init( array_schema, + fragment_names, + book_keeping, array_mode, (const char**) array_attributes, array_attribute_num, @@ -216,13 +224,15 @@ int Metadata::init( int Metadata::reset_attributes( const char** attributes, int attribute_num) { - // Set attributes + // For easy reference const ArraySchema* array_schema = array_->array_schema(); + + // Set attributes char** array_attributes; int array_attribute_num; if(attributes == NULL) { - array_attribute_num = - (mode_ == TILEDB_METADATA_WRITE) ? array_schema->attribute_num() + 1 + array_attribute_num = + (mode_ == TILEDB_METADATA_WRITE) ? array_schema->attribute_num() + 1 : array_schema->attribute_num(); array_attributes = new char*[array_attribute_num]; for(int i=0; i TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid attribute name length"); + return TILEDB_MT_ERR; + } array_attributes[i] = new char[attribute_len+1]; strcpy(array_attributes[i], attributes[i]); } @@ -248,13 +263,21 @@ int Metadata::reset_attributes( } } + // Reset attributes + int rc = array_->reset_attributes( + (const char**) array_attributes, + array_attribute_num); + // Clean up for(int i=0; iarray_name(); +} + bool MetadataIterator::end() const { return array_it_->end(); } @@ -101,6 +103,8 @@ int MetadataIterator::finalize() { int rc = array_it_->finalize(); delete array_it_; array_it_ = NULL; + delete metadata_; + metadata_ = NULL; if(rc != TILEDB_AIT_OK) return TILEDB_MIT_ERR; @@ -113,6 +117,7 @@ int MetadataIterator::init( void** buffers, size_t* buffer_sizes) { // Initialize an array iterator + metadata_ = metadata; array_it_ = new ArrayIterator(); if(array_it_->init(metadata->array(), buffers, buffer_sizes) != TILEDB_AIT_OK) { diff --git a/core/src/misc/hilbert_curve.cc b/core/src/misc/hilbert_curve.cc index 5969d5a9..20fff287 100755 --- a/core/src/misc/hilbert_curve.cc +++ b/core/src/misc/hilbert_curve.cc @@ -44,7 +44,7 @@ HilbertCurve::HilbertCurve(int bits, int dim_num) : bits_(bits), dim_num_(dim_num) { assert(dim_num >=0 && dim_num < HC_MAX_DIM); - assert(bits * dim_num <= sizeof(int64_t)*8); + assert(bits * dim_num <= int(sizeof(int64_t)*8)); } HilbertCurve::~HilbertCurve() { diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index c3083369..f19a9330 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -375,7 +375,8 @@ std::vector get_fragment_dirs(const std::string& dir) { while((next_file = readdir(c_dir))) { new_dir = dir + "/" + next_file->d_name; - if(is_fragment(new_dir)) + + if(is_fragment(new_dir)) dirs.push_back(new_dir); } @@ -393,7 +394,6 @@ ssize_t gzip( size_t out_size) { ssize_t ret; - unsigned have; z_stream strm; // Allocate deflate state @@ -435,7 +435,6 @@ int gunzip( size_t avail_out, size_t& out_size) { int ret; - unsigned have; z_stream strm; // Allocate deflate state @@ -522,7 +521,7 @@ bool is_file(const std::string& file) { bool is_fragment(const std::string& dir) { // Check existence - if(is_dir(dir) && + if(is_dir(dir) && is_file(dir + "/" + TILEDB_FRAGMENT_FILENAME)) return true; else @@ -569,9 +568,10 @@ bool is_positive_integer(const char* s) { template bool is_unary_subarray(const T* subarray, int dim_num) { - for(int i=0; i tokens, final_tokens; std::string token; - for(int i=1; i + #define SORT_LIB __gnu_parallel +#else + #include + #define SORT_LIB std +#endif + +#define SORT_2(first, last) SORT_LIB::sort((first), (last)) +#define SORT_3(first, last, comp) SORT_LIB::sort((first), (last), (comp)) +#define GET_MACRO(_1, _2, _3, NAME, ...) NAME +#define SORT(...) GET_MACRO(__VA_ARGS__, SORT_3, SORT_2)(__VA_ARGS__) + @@ -79,6 +92,10 @@ StorageManager::~StorageManager() { /* MUTATORS */ /* ****************************** */ +int StorageManager::finalize() { + return mutex_destroy(); +} + int StorageManager::init(const char* config_filename) { // Set configuration parameters if(config_filename == NULL) @@ -108,7 +125,6 @@ int StorageManager::init(const char* config_filename) { // Create the TileDB home directory if it does not exists, as well // as the master catalog. if(!is_dir(tiledb_home_)) { - if(create_dir(tiledb_home_) != TILEDB_UT_OK) return TILEDB_SM_ERR; @@ -116,8 +132,8 @@ int StorageManager::init(const char* config_filename) { return TILEDB_SM_ERR; } - // Success - return TILEDB_SM_OK; + // Initialize mutexes and return + return mutex_init(); } @@ -127,7 +143,7 @@ int StorageManager::init(const char* config_filename) { /* WORKSPACE */ /* ****************************** */ -int StorageManager::workspace_create(const std::string& workspace) const { +int StorageManager::workspace_create(const std::string& workspace) { // Check if the workspace is inside a workspace or another group std::string parent_dir = ::parent_dir(workspace); if(is_workspace(parent_dir) || @@ -157,7 +173,7 @@ int StorageManager::workspace_create(const std::string& workspace) const { int StorageManager::ls_workspaces( char** workspaces, - int& workspace_num) const { + int& workspace_num) { // Initialize the master catalog iterator const char* attributes[] = { TILEDB_KEY }; MetadataIterator* metadata_it; @@ -252,6 +268,31 @@ int StorageManager::group_create(const std::string& group) const { /* ARRAY */ /* ****************************** */ +int StorageManager::array_consolidate(const char* array_dir) { + // Create an array object + Array* array; + if(array_init( + array, + array_dir, + TILEDB_ARRAY_READ, + NULL, + NULL, + 0) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + // Consolidate array + int rc_consolidate = array->consolidate(); + + // Finalize array + int rc_finalize = array_finalize(array); + + // Return + if(rc_consolidate != TILEDB_AR_OK || rc_finalize != TILEDB_SM_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + int StorageManager::array_create(const ArraySchemaC* array_schema_c) const { // Initialize array schema ArraySchema* array_schema = new ArraySchema(); @@ -314,7 +355,7 @@ int StorageManager::array_create(const ArraySchema* array_schema) const { // Store the array schema ssize_t bytes_written = ::write(fd, array_schema_bin, array_schema_bin_size); - if(bytes_written != array_schema_bin_size) { + if(bytes_written != ssize_t(array_schema_bin_size)) { PRINT_ERROR(std::string("Cannot create array; ") + strerror(errno)); free(array_schema_bin); return TILEDB_SM_ERR; @@ -331,6 +372,55 @@ int StorageManager::array_create(const ArraySchema* array_schema) const { return TILEDB_SM_OK; } +void StorageManager::array_get_fragment_names( + const std::string& array, + std::vector& fragment_names) { + + // Get directory names in the array folder + fragment_names = get_fragment_dirs(real_dir(array)); + + // Sort the fragment names + sort_fragment_names(fragment_names); +} + +int StorageManager::array_load_book_keeping( + const ArraySchema* array_schema, + const std::vector& fragment_names, + std::vector& book_keeping) { + // For easy reference + int fragment_num = fragment_names.size(); + + // Initialization + book_keeping.resize(fragment_num); + + // Load the book-keeping for each fragment + for(int i=0; iload() != TILEDB_BK_OK) { + delete f_book_keeping; + return TILEDB_SM_ERR; + } + + // Append to the open array entry + book_keeping[i] = f_book_keeping; + } + + // Success + return TILEDB_SM_OK; +} + int StorageManager::array_load_schema( const char* array_dir, ArraySchema*& array_schema) const { @@ -396,38 +486,60 @@ int StorageManager::array_init( int mode, const void* subarray, const char** attributes, - int attribute_num) const { + int attribute_num) { + // Check array name length + if(array_dir == NULL || strlen(array_dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid array name length"); + return TILEDB_SM_ERR; + } + // Load array schema ArraySchema* array_schema; if(array_load_schema(array_dir, array_schema) != TILEDB_SM_OK) return TILEDB_SM_ERR; + // Open the array + OpenArray* open_array; + if(array_open(array_schema, mode, open_array) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + // Create Array object array = new Array(); - if(array->init(array_schema, mode, attributes, attribute_num, subarray) != - TILEDB_AR_OK) { + if(array->init( + array_schema, + open_array->fragment_names_, + open_array->book_keeping_, + mode, + attributes, + attribute_num, + subarray) != TILEDB_AR_OK) { + delete array_schema; delete array; array = NULL; + array_close(array_dir); return TILEDB_SM_ERR; } else { return TILEDB_SM_OK; } } -int StorageManager::array_finalize(Array* array) const { +int StorageManager::array_finalize(Array* array) { // If the array is NULL, do nothing if(array == NULL) return TILEDB_SM_OK; - // Finalize array - int rc = array->finalize(); + // Finalize and close the array + int rc_finalize = array->finalize(); + int rc_close = array_close(array->array_schema()->array_name()); + + // Clean up delete array; // Return - if(rc == TILEDB_AR_OK) - return TILEDB_SM_OK; - else + if(rc_close != TILEDB_SM_OK || rc_finalize != TILEDB_AR_OK) return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; } int StorageManager::array_iterator_init( @@ -437,29 +549,24 @@ int StorageManager::array_iterator_init( const char** attributes, int attribute_num, void** buffers, - size_t* buffer_sizes) const { - // Load array schema - ArraySchema* array_schema; - if(array_load_schema(array_dir, array_schema) != TILEDB_SM_OK) - return TILEDB_SM_ERR; - - // Create Array object - Array* array = new Array(); - if(array->init( - array_schema, - TILEDB_ARRAY_READ, - attributes, - attribute_num, - subarray) != TILEDB_AR_OK) { - delete array; + size_t* buffer_sizes) { + // Create Array object. This also creates/updates an open array entry + Array* array; + if(array_init( + array, + array_dir, + TILEDB_ARRAY_READ, + subarray, + attributes, + attribute_num) != TILEDB_SM_OK) { array_it = NULL; return TILEDB_SM_ERR; - } + } // Create ArrayIterator object array_it = new ArrayIterator(); if(array_it->init(array, buffers, buffer_sizes) != TILEDB_AIT_OK) { - delete array; + array_finalize(array); delete array_it; array_it = NULL; return TILEDB_SM_ERR; @@ -470,17 +577,21 @@ int StorageManager::array_iterator_init( } int StorageManager::array_iterator_finalize( - ArrayIterator* array_it) const { + ArrayIterator* array_it) { // If the array iterator is NULL, do nothing if(array_it == NULL) return TILEDB_SM_OK; - // Finalize array - int rc = array_it->finalize(); + // Finalize and close array + std::string array_name = array_it->array_name(); + int rc_finalize = array_it->finalize(); + int rc_close = array_close(array_name); + + // Clean up delete array_it; // Return - if(rc == TILEDB_AIT_OK) + if(rc_finalize == TILEDB_AIT_OK && rc_close == TILEDB_SM_OK) return TILEDB_SM_OK; else return TILEDB_SM_ERR; @@ -493,6 +604,54 @@ int StorageManager::array_iterator_finalize( /* METADATA */ /* ****************************** */ +int StorageManager::metadata_consolidate(const char* metadata_dir) { + // Load metadata schema + ArraySchema* array_schema; + if(metadata_load_schema(metadata_dir, array_schema) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + // Set attributes + char** attributes; + int attribute_num = array_schema->attribute_num(); + attributes = new char*[attribute_num+1]; + for(int i=0; iattribute(i).c_str(); + size_t attribute_len = strlen(attribute); + attributes[i] = new char[attribute_len+1]; + strcpy(attributes[i], attribute); + } + + // Create a metadata object + Metadata* metadata; + int rc_init = metadata_init( + metadata, + metadata_dir, + TILEDB_METADATA_READ, + (const char**) attributes, + attribute_num+1); + + // Clean up + for(int i=0; iconsolidate(); + + // Finalize metadata + int rc_finalize = metadata_finalize(metadata); + + // Return + if(rc_consolidate != TILEDB_MT_OK || rc_finalize != TILEDB_SM_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + int StorageManager::metadata_create( const MetadataSchemaC* metadata_schema_c) const { // Initialize array schema @@ -557,7 +716,7 @@ int StorageManager::metadata_create(const ArraySchema* array_schema) const { // Store the array schema ssize_t bytes_written = ::write(fd, array_schema_bin, array_schema_bin_size); - if(bytes_written != array_schema_bin_size) { + if(bytes_written != ssize_t(array_schema_bin_size)) { PRINT_ERROR(std::string("Cannot create metadata; ") + strerror(errno)); free(array_schema_bin); return TILEDB_SM_ERR; @@ -639,40 +798,63 @@ int StorageManager::metadata_init( const char* metadata_dir, int mode, const char** attributes, - int attribute_num) const { + int attribute_num) { + // Check metadata name length + if(metadata_dir == NULL || strlen(metadata_dir) > TILEDB_NAME_MAX_LEN) { + PRINT_ERROR("Invalid metadata name length"); + return TILEDB_SM_ERR; + } + // Load metadata schema ArraySchema* array_schema; if(metadata_load_schema(metadata_dir, array_schema) != TILEDB_SM_OK) return TILEDB_SM_ERR; + // Open the array that implements the metadata + OpenArray* open_array; + if(array_open(array_schema, mode, open_array) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + // Create metadata object metadata = new Metadata(); - int rc = metadata->init(array_schema, mode, attributes, attribute_num); + int rc = metadata->init( + array_schema, + open_array->fragment_names_, + open_array->book_keeping_, + mode, + attributes, + attribute_num); // Return if(rc != TILEDB_MT_OK) { + delete array_schema; delete metadata; metadata = NULL; + array_close(metadata_dir); return TILEDB_SM_ERR; } else { return TILEDB_SM_OK; } } -int StorageManager::metadata_finalize(Metadata* metadata) const { +int StorageManager::metadata_finalize(Metadata* metadata) { // If the metadata is NULL, do nothing if(metadata == NULL) return TILEDB_SM_OK; - // Finalize metadata - int rc = metadata->finalize(); + // Finalize the metadata and close the underlying array + std::string array_name = metadata->array_schema()->array_name(); + int rc_finalize = metadata->finalize(); + int rc_close = array_close(array_name); + + // Clean up delete metadata; // Return - if(rc == TILEDB_MT_OK) - return TILEDB_SM_OK; - else + if(rc_close != TILEDB_SM_OK || rc_finalize != TILEDB_MT_OK) return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; } int StorageManager::metadata_iterator_init( @@ -681,21 +863,15 @@ int StorageManager::metadata_iterator_init( const char** attributes, int attribute_num, void** buffers, - size_t* buffer_sizes) const { - // Load metadata schema - ArraySchema* array_schema; - if(metadata_load_schema(metadata_dir, array_schema) != TILEDB_SM_OK) - return TILEDB_SM_ERR; - + size_t* buffer_sizes) { // Create metadata object - Metadata* metadata = new Metadata(); - if(metadata->init( - array_schema, + Metadata* metadata; + if(metadata_init( + metadata, + metadata_dir, TILEDB_METADATA_READ, attributes, - attribute_num) != - TILEDB_MT_OK) { - delete metadata; + attribute_num) != TILEDB_SM_OK) { metadata_it = NULL; return TILEDB_SM_ERR; } @@ -703,7 +879,7 @@ int StorageManager::metadata_iterator_init( // Create MetadataIterator object metadata_it = new MetadataIterator(); if(metadata_it->init(metadata, buffers, buffer_sizes) != TILEDB_MIT_OK) { - delete metadata; + metadata_finalize(metadata); delete metadata_it; metadata_it = NULL; return TILEDB_SM_ERR; @@ -714,17 +890,21 @@ int StorageManager::metadata_iterator_init( } int StorageManager::metadata_iterator_finalize( - MetadataIterator* metadata_it) const { + MetadataIterator* metadata_it) { // If the metadata iterator is NULL, do nothing if(metadata_it == NULL) return TILEDB_SM_OK; - // Finalize metadata - int rc = metadata_it->finalize(); + // Close array and finalize metadata + std::string metadata_name = metadata_it->metadata_name(); + int rc_finalize = metadata_it->finalize(); + int rc_close = array_close(metadata_name); + + // Clean up delete metadata_it; // Return - if(rc == TILEDB_MIT_OK) + if(rc_finalize == TILEDB_MIT_OK && rc_close == TILEDB_SM_OK) return TILEDB_SM_OK; else return TILEDB_SM_ERR; @@ -827,7 +1007,7 @@ int StorageManager::clear(const std::string& dir) const { } } -int StorageManager::delete_entire(const std::string& dir) const { +int StorageManager::delete_entire(const std::string& dir) { if(is_workspace(dir)) { return workspace_delete(dir); } else if(is_group(dir)) { @@ -847,7 +1027,7 @@ int StorageManager::delete_entire(const std::string& dir) const { int StorageManager::move( const std::string& old_dir, - const std::string& new_dir) const { + const std::string& new_dir) { if(is_workspace(old_dir)) { return workspace_move(old_dir, new_dir); } else if(is_group(old_dir)) { @@ -924,6 +1104,61 @@ int StorageManager::array_clear( return TILEDB_SM_OK; } +int StorageManager::array_close(const std::string& array) { + // Lock mutexes + if(mutex_lock() != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + // Find the open array entry + std::map::iterator it = + open_arrays_.find(real_dir(array)); + + // Sanity check + if(it == open_arrays_.end()) { + PRINT_ERROR("Cannot close array; Open array entry not found"); + return TILEDB_SM_ERR; + } + + // Lock the mutex of the array + if(it->second->mutex_lock() != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + // Decrement counter + --(it->second->cnt_); + + // Delete open array entry if necessary + int rc_mtx_destroy = TILEDB_SM_OK; + if(it->second != NULL && 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) + delete *bit; + + // Unlock and destroy mutexes + it->second->mutex_unlock(); + rc_mtx_destroy = it->second->mutex_destroy(); + + // Free open array + delete it->second; + + // Delete open array entry + open_arrays_.erase(it); + } else { + // Unlock the mutex of the array + if(it->second->mutex_unlock() != TILEDB_SM_OK) + return TILEDB_SM_ERR; + } + + // Unlock mutexes + int rc_mtx_unlock = mutex_unlock(); + + // Return + if(rc_mtx_destroy != TILEDB_SM_OK || rc_mtx_unlock != TILEDB_SM_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + int StorageManager::array_delete( const std::string& array) const { // Clear the array @@ -938,6 +1173,33 @@ int StorageManager::array_delete( return TILEDB_SM_OK; } +int StorageManager::array_get_open_array_entry( + const std::string& array, + OpenArray*& open_array) { + // Lock mutexes + if(mutex_lock() != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + // Find the open array entry + std::map::iterator it = open_arrays_.find(array); + // Create and init entry if it does not exist + if(it == open_arrays_.end()) { + open_array = new OpenArray(); + open_array->cnt_ = 0; + open_array->book_keeping_ = std::vector(); + if(open_array->mutex_init() != TILEDB_SM_OK) { + open_array->mutex_unlock(); + return TILEDB_SM_ERR; + } + open_arrays_[array] = open_array; + } else { + open_array = it->second; + } + + // Unlock mutexes and return + return mutex_unlock(); +} + int StorageManager::array_move( const std::string& old_array, const std::string& new_array) const { @@ -979,6 +1241,47 @@ int StorageManager::array_move( return TILEDB_SM_OK; } +int StorageManager::array_open( + const ArraySchema* array_schema, + int mode, + OpenArray*& open_array) { + // For easy reference + std::string array_name = array_schema->array_name(); + + // Get the open array entry + if(array_get_open_array_entry(array_name, open_array) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + // Lock the mutex of the array + if(open_array->mutex_lock() != TILEDB_SM_OK) + return TILEDB_SM_ERR; + + if(mode == TILEDB_ARRAY_READ && + open_array->fragment_names_.size() == 0) { + // Get the fragment names + array_get_fragment_names(array_name, open_array->fragment_names_); + + // Load the book-keeping for each fragment + if(array_load_book_keeping( + array_schema, + open_array->fragment_names_, + open_array->book_keeping_) != TILEDB_SM_OK) { + open_array->mutex_unlock(); + return TILEDB_SM_ERR; + } + } + + // Increment counter + ++(open_array->cnt_); + + // Unlock the mutex of the array + if(open_array->mutex_unlock() != TILEDB_UT_OK) + return TILEDB_SM_ERR; + + // Success + return TILEDB_SM_OK; +} + int StorageManager::config_set(const char* config_filename) { // Success return TILEDB_SM_OK; @@ -1003,7 +1306,7 @@ int StorageManager::create_group_file(const std::string& group) const { int StorageManager::create_master_catalog_entry( const std::string& workspace, - MasterCatalogOp op) const { + MasterCatalogOp op) { // Get real workspace path std::string real_workspace = ::real_dir(workspace); @@ -1034,12 +1337,9 @@ int StorageManager::create_master_catalog_entry( return TILEDB_SM_ERR; // Finalize master catalog - if(metadata->finalize() != TILEDB_MT_OK) + if(metadata_finalize(metadata) != TILEDB_SM_OK) return TILEDB_SM_ERR; - // Clean up - delete metadata; - // Success return TILEDB_SM_OK; } @@ -1181,27 +1481,12 @@ int StorageManager::group_move( return TILEDB_SM_OK; } -int StorageManager::master_catalog_consolidate() const { - // Initialize master catalog - Metadata* metadata; - if(metadata_init( - metadata, - master_catalog_dir_.c_str(), - TILEDB_METADATA_READ, - NULL, - 0) != TILEDB_SM_OK) - return TILEDB_SM_ERR; - +int StorageManager::master_catalog_consolidate() { // Consolidate master catalog - if(metadata->consolidate() != TILEDB_MT_OK) - return TILEDB_SM_ERR; - - // Finalize master catalog - if(metadata->finalize() != TILEDB_MT_OK) + if(metadata_consolidate(master_catalog_dir_.c_str()) != TILEDB_SM_OK) return TILEDB_SM_ERR; - - // Success - return TILEDB_SM_OK; + else + return TILEDB_SM_OK; } int StorageManager::master_catalog_create() const { @@ -1338,6 +1623,86 @@ int StorageManager::metadata_move( return TILEDB_SM_OK; } +int StorageManager::mutex_destroy() { + int rc_omp_mtx = ::mutex_destroy(&open_array_omp_mtx_); + int rc_pthread_mtx = ::mutex_destroy(&open_array_pthread_mtx_); + + if(rc_pthread_mtx != TILEDB_UT_OK || rc_omp_mtx != TILEDB_UT_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + +int StorageManager::mutex_init() { + int rc_omp_mtx = ::mutex_init(&open_array_omp_mtx_); + int rc_pthread_mtx = ::mutex_init(&open_array_pthread_mtx_); + + if(rc_pthread_mtx != TILEDB_UT_OK || rc_omp_mtx != TILEDB_UT_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + +int StorageManager::mutex_lock() { + int rc_omp_mtx = ::mutex_lock(&open_array_omp_mtx_); + int rc_pthread_mtx = ::mutex_lock(&open_array_pthread_mtx_); + + if(rc_pthread_mtx != TILEDB_UT_OK || rc_omp_mtx != TILEDB_UT_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + +int StorageManager::mutex_unlock() { + int rc_omp_mtx = ::mutex_unlock(&open_array_omp_mtx_); + int rc_pthread_mtx = ::mutex_unlock(&open_array_pthread_mtx_); + + if(rc_pthread_mtx != TILEDB_UT_OK || rc_omp_mtx != TILEDB_UT_OK) + return TILEDB_SM_ERR; + else + return TILEDB_SM_OK; +} + +void StorageManager::sort_fragment_names( + std::vector& fragment_names) const { + // Initializations + int fragment_num = fragment_names.size(); + std::string t_str; + int64_t stripped_fragment_name_size, t; + std::vector > t_pos_vec; + t_pos_vec.resize(fragment_num); + + // Get the timestamp for each fragment + for(int i=0; i(t, i); + break; + } + } + } + + // Sort the names based on the timestamps + SORT(t_pos_vec.begin(), t_pos_vec.end()); + std::vector fragment_names_sorted; + fragment_names_sorted.resize(fragment_num); + for(int i=0; i int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_iterator_sparse.cc b/examples/src/tiledb_array_iterator_sparse.cc index f5844578..4999e031 100644 --- a/examples/src/tiledb_array_iterator_sparse.cc +++ b/examples/src/tiledb_array_iterator_sparse.cc @@ -34,7 +34,7 @@ #include int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_parallel_read_dense_1.cc b/examples/src/tiledb_array_parallel_read_dense_1.cc new file mode 100644 index 00000000..626ecd5e --- /dev/null +++ b/examples/src/tiledb_array_parallel_read_dense_1.cc @@ -0,0 +1,165 @@ +/** + * @file tiledb_array_parallel_read_dense_1.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 in parallel with pthreads. + */ + +#include "c_api.h" +#include +#include + + + + +// The function to be computed in parallel +void *parallel_read(void* args); + +// The arguments for each invocation of parallel_write +typedef struct _thread_data_t { + const TileDB_CTX* tiledb_ctx; + const char* array_name; + const void* subarray; + void** buffers; + size_t* buffer_sizes; + int count; +} thread_data_t; + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/dense_arrays/my_array_A"; + + // Prepare cell buffers + // --- Upper left tile --- + const int64_t subarray_1[] = { 1, 2, 1, 2 }; + int buffer_a1_1[4]; + void* buffers_1[] = { buffer_a1_1 }; + size_t buffer_sizes_1[] = { sizeof(buffer_a1_1) }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 1, 2, 3, 4 }; + int buffer_a1_2[4]; + void* buffers_2[] = { buffer_a1_2 }; + size_t buffer_sizes_2[] = { sizeof(buffer_a1_2) }; + // --- Lower left tile --- + const int64_t subarray_3[] = { 3, 4, 1, 2 }; + int buffer_a1_3[4]; + void* buffers_3[] = { buffer_a1_3 }; + size_t buffer_sizes_3[] = { sizeof(buffer_a1_3) }; + // --- Lower right tile --- + const int64_t subarray_4[] = { 3, 4, 3, 4 }; + int buffer_a1_4[4]; + void* buffers_4[] = { buffer_a1_4 }; + size_t buffer_sizes_4[] = { sizeof(buffer_a1_4) }; + + // Initialize 4 pthreads and corresponding data + pthread_t threads[4]; + thread_data_t thread_data[4]; + + // Write in parallel + for(int i=0; i<4; ++i) { + // Populate the thread data + thread_data[i].tiledb_ctx = tiledb_ctx; + thread_data[i].array_name = array_name; + if(i==0) { // First tile + thread_data[i].buffers = buffers_1; + thread_data[i].buffer_sizes = buffer_sizes_1; + thread_data[i].subarray = subarray_1; + } else if(i==1) { // Second tile + thread_data[i].buffers = buffers_2; + thread_data[i].buffer_sizes = buffer_sizes_2; + thread_data[i].subarray = subarray_2; + } else if(i==2) { // Third tile + thread_data[i].buffers = buffers_3; + thread_data[i].buffer_sizes = buffer_sizes_3; + thread_data[i].subarray = subarray_3; + } else if(i==3) { // Fourth tile + thread_data[i].buffers = buffers_4; + thread_data[i].buffer_sizes = buffer_sizes_4; + thread_data[i].subarray = subarray_4; + } + + // Create thread + pthread_create(&threads[i], NULL, parallel_read, &thread_data[i]); + } + + // Wait till all threads finish + for(int i=0; i<4; ++i) + pthread_join(threads[i], NULL); + + // Output result + int total_count = 0; + for(int i=0; i<4; ++i) + total_count += thread_data[i].count; + printf("Number of a1 values greater than 10: %d \n", total_count); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void *parallel_read(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Only attribute "a1" is needed + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + data->tiledb_ctx, // Context + &tiledb_array, // Array object + data->array_name, // Array name + TILEDB_ARRAY_READ, // Mode + data->subarray, // Subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Read from array + tiledb_array_read(tiledb_array, data->buffers, data->buffer_sizes); + + // Count number of a1 values greater than 10 + data->count = 0; + int* a1 = (int*) data->buffers[0]; + int num = data->buffer_sizes[0] / sizeof(int); + for(int i=0; i 10) + ++data->count; + } + + // Finalize array + tiledb_array_finalize(tiledb_array); + + return 0; +} + diff --git a/examples/src/tiledb_array_parallel_read_dense_2.cc b/examples/src/tiledb_array_parallel_read_dense_2.cc new file mode 100644 index 00000000..cc48abe6 --- /dev/null +++ b/examples/src/tiledb_array_parallel_read_dense_2.cc @@ -0,0 +1,164 @@ +/** + * @file tiledb_array_parallel_read_dense_2.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 in parallel with OpenMP. + */ + +#include "c_api.h" +#include +#include + + + + +// The function to be computed in parallel +void parallel_read( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void* subarray, + void** buffers, + size_t* buffer_sizes, + int* count); + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/dense_arrays/my_array_A"; + + // Prepare cell buffers + // --- Upper left tile --- + const int64_t subarray_1[] = { 1, 2, 1, 2 }; + int buffer_a1_1[4]; + void* buffers_1[] = { buffer_a1_1 }; + size_t buffer_sizes_1[] = { sizeof(buffer_a1_1) }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 1, 2, 3, 4 }; + int buffer_a1_2[4]; + void* buffers_2[] = { buffer_a1_2 }; + size_t buffer_sizes_2[] = { sizeof(buffer_a1_2) }; + // --- Lower left tile --- + const int64_t subarray_3[] = { 3, 4, 1, 2 }; + int buffer_a1_3[4]; + void* buffers_3[] = { buffer_a1_3 }; + size_t buffer_sizes_3[] = { sizeof(buffer_a1_3) }; + // --- Lower right tile --- + const int64_t subarray_4[] = { 3, 4, 3, 4 }; + int buffer_a1_4[4]; + void* buffers_4[] = { buffer_a1_4 }; + size_t buffer_sizes_4[] = { sizeof(buffer_a1_4) }; + + // Buffer to store the individual thread counts + int counts[4]; + + // Write in parallel + #pragma omp parallel for + for(int i=0; i<4; ++i) { + // Populate the thread data + void** buffers; + size_t* buffer_sizes; + const void* subarray; + if(i==0) { // First tile + buffers = buffers_1; + buffer_sizes = buffer_sizes_1; + subarray = subarray_1; + } else if(i==1) { // Second tile + buffers = buffers_2; + buffer_sizes = buffer_sizes_2; + subarray = subarray_2; + } else if(i==2) { // Third tile + buffers = buffers_3; + buffer_sizes = buffer_sizes_3; + subarray = subarray_3; + } else if(i==3) { // Fourth tile + buffers = buffers_4; + buffer_sizes = buffer_sizes_4; + subarray = subarray_4; + } + + // Parallel read + parallel_read( + tiledb_ctx, + array_name, + subarray, + buffers, + buffer_sizes, + &counts[i]); + } + + // Output result + int total_count = 0; + for(int i=0; i<4; ++i) + total_count += counts[i]; + printf("Number of a1 values greater than 10: %d \n", total_count); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void parallel_read( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void* subarray, + void** buffers, + size_t* buffer_sizes, + int* count) { + // Only attribute "a1" is needed + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + array_name, // Array name + TILEDB_ARRAY_READ, // Mode + subarray, // Subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Read from array + tiledb_array_read(tiledb_array, buffers, buffer_sizes); + + // Count number of a1 values greater than 10 + *count = 0; + int* a1 = (int*) buffers[0]; + int num = buffer_sizes[0] / sizeof(int); + for(int i=0; i 10) + ++(*count); + + // Finalize array + tiledb_array_finalize(tiledb_array); +} + diff --git a/examples/src/tiledb_array_parallel_read_sparse_1.cc b/examples/src/tiledb_array_parallel_read_sparse_1.cc new file mode 100644 index 00000000..50085c3e --- /dev/null +++ b/examples/src/tiledb_array_parallel_read_sparse_1.cc @@ -0,0 +1,146 @@ +/** + * @file tiledb_array_parallel_read_sparse_1.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 sparse array in parallel with pthreads. + */ + +#include "c_api.h" +#include +#include + + + + +// The function to be computed in parallel +void *parallel_read(void* args); + +// The arguments for each invocation of parallel_write +typedef struct _thread_data_t { + const TileDB_CTX* tiledb_ctx; + const char* array_name; + const void* subarray; + void** buffers; + size_t* buffer_sizes; + int count; +} thread_data_t; + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/sparse_arrays/my_array_B"; + + // Prepare cell buffers + // --- First read --- + const int64_t subarray_1[] = { 1, 2, 1, 4 }; + int buffer_a1_1[4]; + void* buffers_1[] = { buffer_a1_1 }; + size_t buffer_sizes_1[] = { sizeof(buffer_a1_1) }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 3, 4, 1, 4 }; + int buffer_a1_2[4]; + void* buffers_2[] = { buffer_a1_2 }; + size_t buffer_sizes_2[] = { sizeof(buffer_a1_2) }; + + // Initialize 2 pthreads and corresponding data + pthread_t threads[2]; + thread_data_t thread_data[2]; + + // Write in parallel + for(int i=0; i<2; ++i) { + // Populate the thread data + thread_data[i].tiledb_ctx = tiledb_ctx; + thread_data[i].array_name = array_name; + if(i==0) { // First read + thread_data[i].buffers = buffers_1; + thread_data[i].buffer_sizes = buffer_sizes_1; + thread_data[i].subarray = subarray_1; + } else if(i==1) { // Second read + thread_data[i].buffers = buffers_2; + thread_data[i].buffer_sizes = buffer_sizes_2; + thread_data[i].subarray = subarray_2; + } + + // Create thread + pthread_create(&threads[i], NULL, parallel_read, &thread_data[i]); + } + + // Wait till all threads finish + for(int i=0; i<2; ++i) + pthread_join(threads[i], NULL); + + // Output result + int total_count = 0; + for(int i=0; i<2; ++i) + total_count += thread_data[i].count; + printf("Number of a1 values greater than 5: %d \n", total_count); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void *parallel_read(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Only attribute "a1" is needed + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + data->tiledb_ctx, // Context + &tiledb_array, // Array object + data->array_name, // Array name + TILEDB_ARRAY_READ, // Mode + data->subarray, // Subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Read from array + tiledb_array_read(tiledb_array, data->buffers, data->buffer_sizes); + + // Count number of a1 values greater than 10 + data->count = 0; + int* a1 = (int*) data->buffers[0]; + int num = data->buffer_sizes[0] / sizeof(int); + for(int i=0; i 5) + ++data->count; + + // Finalize array + tiledb_array_finalize(tiledb_array); + + return 0; +} + diff --git a/examples/src/tiledb_array_parallel_read_sparse_2.cc b/examples/src/tiledb_array_parallel_read_sparse_2.cc new file mode 100644 index 00000000..4b209e50 --- /dev/null +++ b/examples/src/tiledb_array_parallel_read_sparse_2.cc @@ -0,0 +1,146 @@ +/** + * @file tiledb_array_parallel_read_sparse_2.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 sparse array in parallel with OpenMP. + */ + +#include "c_api.h" +#include +#include + + + + +// The function to be computed in parallel +void parallel_read( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void* subarray, + void** buffers, + size_t* buffer_sizes, + int* count); + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/sparse_arrays/my_array_B"; + + // Prepare cell buffers + // --- First read --- + const int64_t subarray_1[] = { 1, 2, 1, 4 }; + int buffer_a1_1[4]; + void* buffers_1[] = { buffer_a1_1 }; + size_t buffer_sizes_1[] = { sizeof(buffer_a1_1) }; + // --- Second read --- + const int64_t subarray_2[] = { 3, 4, 1, 4 }; + int buffer_a1_2[4]; + void* buffers_2[] = { buffer_a1_2 }; + size_t buffer_sizes_2[] = { sizeof(buffer_a1_2) }; + + // Buffer to store the individual thread counts + int counts[2]; + + // Write in parallel + #pragma omp parallel for + for(int i=0; i<2; ++i) { + // Populate the thread data + void** buffers; + size_t* buffer_sizes; + const void* subarray; + if(i==0) { // First read + buffers = buffers_1; + buffer_sizes = buffer_sizes_1; + subarray = subarray_1; + } else if(i==1) { // Second read + buffers = buffers_2; + buffer_sizes = buffer_sizes_2; + subarray = subarray_2; + } + + // Parallel read + parallel_read( + tiledb_ctx, + array_name, + subarray, + buffers, + buffer_sizes, + &counts[i]); + } + + // Output result + int total_count = 0; + for(int i=0; i<2; ++i) + total_count += counts[i]; + printf("Number of a1 values greater than 5: %d \n", total_count); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void parallel_read( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void* subarray, + void** buffers, + size_t* buffer_sizes, + int* count) { + // Only attribute "a1" is needed + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + array_name, // Array name + TILEDB_ARRAY_READ, // Mode + subarray, // Subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Read from array + tiledb_array_read(tiledb_array, buffers, buffer_sizes); + + // Count number of a1 values greater than 10 + *count = 0; + int* a1 = (int*) buffers[0]; + int num = buffer_sizes[0] / sizeof(int); + for(int i=0; i 5) + ++(*count); + + // Finalize array + tiledb_array_finalize(tiledb_array); +} + diff --git a/examples/src/tiledb_array_parallel_write_dense_1.cc b/examples/src/tiledb_array_parallel_write_dense_1.cc new file mode 100644 index 00000000..e95f7fc5 --- /dev/null +++ b/examples/src/tiledb_array_parallel_write_dense_1.cc @@ -0,0 +1,185 @@ +/** + * @file tiledb_array_parallel_write_dense_1.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 dense array in parallel with pthreads. + */ + +#include "c_api.h" +#include + + + + +// The function to be computed in parallel +void *parallel_write(void* args); + +// The arguments for each invocation of parallel_write +typedef struct _thread_data_t { + const TileDB_CTX* tiledb_ctx; + const char* array_name; + const void* subarray; + const void** buffers; + const size_t* buffer_sizes; +} thread_data_t; + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/dense_arrays/my_array_A"; + + // Prepare cell buffers + // --- Upper left tile --- + const int64_t subarray_1[] = { 1, 2, 1, 2 }; + int buffer_a1_1[] = { 0, 1, 2, 3 }; + size_t buffer_a2_1[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_1[] = "abbcccdddd"; + float buffer_a3_1[] = { 0.1, 0.2, 1.1, 1.2, 2.1, 2.2, 3.1, 3.2 }; + const void* buffers_1[] = { + buffer_a1_1, buffer_a2_1, buffer_var_a2_1, buffer_a3_1 }; + size_t buffer_sizes_1[] = + { + sizeof(buffer_a1_1), + sizeof(buffer_a2_1), + sizeof(buffer_var_a2_1)-1, // No need to store the last '\0' character + sizeof(buffer_a3_1) + }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 1, 2, 3, 4 }; + int buffer_a1_2[] = { 4, 5, 6, 7 }; + size_t buffer_a2_2[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_2[] = "effggghhhh"; + float buffer_a3_2[] = { 4.1, 4.2, 5.1, 5.2, 6.1, 6.2, 7.1, 7.2 }; + const void* buffers_2[] = { + buffer_a1_2, buffer_a2_2, buffer_var_a2_2, buffer_a3_2 }; + size_t buffer_sizes_2[] = + { + sizeof(buffer_a1_2), + sizeof(buffer_a2_2), + sizeof(buffer_var_a2_2)-1, // No need to store the last '\0' character + sizeof(buffer_a3_2) + }; + // --- Lower left tile --- + const int64_t subarray_3[] = { 3, 4, 1, 2 }; + int buffer_a1_3[] = { 8, 9, 10, 11 }; + size_t buffer_a2_3[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_3[] = "ijjkkkllll"; + float buffer_a3_3[] = { 8.1, 8.2, 9.1, 9.2, 10.1, 10.2, 11.1, 11.2 }; + const void* buffers_3[] = { + buffer_a1_3, buffer_a2_3, buffer_var_a2_3, buffer_a3_3 }; + size_t buffer_sizes_3[] = + { + sizeof(buffer_a1_3), + sizeof(buffer_a2_3), + sizeof(buffer_var_a2_3)-1, // No need to store the last '\0' character + sizeof(buffer_a3_3) + }; + // --- Lower right tile --- + const int64_t subarray_4[] = { 3, 4, 3, 4 }; + int buffer_a1_4[] = { 12, 13, 14, 15 }; + size_t buffer_a2_4[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_4[] = "mnnooopppp"; + float buffer_a3_4[] = { 12.1, 12.2, 13.1, 13.2, 14.1, 14.2, 15.1, 15.2 }; + const void* buffers_4[] = { + buffer_a1_4, buffer_a2_4, buffer_var_a2_4, buffer_a3_4 }; + size_t buffer_sizes_4[] = + { + sizeof(buffer_a1_4), + sizeof(buffer_a2_4), + sizeof(buffer_var_a2_4)-1, // No need to store the last '\0' character + sizeof(buffer_a3_4) + }; + + // Initialize 4 pthreads and corresponding data + pthread_t threads[4]; + thread_data_t thread_data[4]; + + // Write in parallel + for(int i=0; i<4; ++i) { + // Populate the thread data + thread_data[i].tiledb_ctx = tiledb_ctx; + thread_data[i].array_name = array_name; + if(i==0) { // First tile + thread_data[i].buffers = buffers_1; + thread_data[i].buffer_sizes = buffer_sizes_1; + thread_data[i].subarray = subarray_1; + } else if(i==1) { // Second tile + thread_data[i].buffers = buffers_2; + thread_data[i].buffer_sizes = buffer_sizes_2; + thread_data[i].subarray = subarray_2; + } else if(i==2) { // Third tile + thread_data[i].buffers = buffers_3; + thread_data[i].buffer_sizes = buffer_sizes_3; + thread_data[i].subarray = subarray_3; + } else if(i==3) { // Fourth tile + thread_data[i].buffers = buffers_4; + thread_data[i].buffer_sizes = buffer_sizes_4; + thread_data[i].subarray = subarray_4; + } + + // Create thread + pthread_create(&threads[i], NULL, parallel_write, &thread_data[i]); + } + + // Wait till all threads finish + for(int i=0; i<4; ++i) + pthread_join(threads[i], NULL); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void *parallel_write(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + data->tiledb_ctx, // Context + &tiledb_array, // Array object + data->array_name, // Array name + TILEDB_ARRAY_WRITE, // Mode + data->subarray, // Subarray + NULL, // All attributes + 0); // Number of attributes + + // Write to array + tiledb_array_write(tiledb_array, data->buffers, data->buffer_sizes); + + // Finalize array + tiledb_array_finalize(tiledb_array); + + return 0; +} + diff --git a/examples/src/tiledb_array_parallel_write_dense_2.cc b/examples/src/tiledb_array_parallel_write_dense_2.cc new file mode 100644 index 00000000..9a86d3ad --- /dev/null +++ b/examples/src/tiledb_array_parallel_write_dense_2.cc @@ -0,0 +1,180 @@ +/** + * @file tiledb_array_parallel_write_dense_2.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 dense array in parallel with OpenMP. + */ + +#include "c_api.h" +#include + + + + +// The function to be computed in parallel +void parallel_write( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void* subarray, + const void** buffers, + const size_t* buffer_sizes); + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/dense_arrays/my_array_A"; + + // Prepare cell buffers + // --- Upper left tile --- + const int64_t subarray_1[] = { 1, 2, 1, 2 }; + int buffer_a1_1[] = { 0, 1, 2, 3 }; + size_t buffer_a2_1[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_1[] = "abbcccdddd"; + float buffer_a3_1[] = { 0.1, 0.2, 1.1, 1.2, 2.1, 2.2, 3.1, 3.2 }; + const void* buffers_1[] = { + buffer_a1_1, buffer_a2_1, buffer_var_a2_1, buffer_a3_1 }; + size_t buffer_sizes_1[] = + { + sizeof(buffer_a1_1), + sizeof(buffer_a2_1), + sizeof(buffer_var_a2_1)-1, // No need to store the last '\0' character + sizeof(buffer_a3_1) + }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 1, 2, 3, 4 }; + int buffer_a1_2[] = { 4, 5, 6, 7 }; + size_t buffer_a2_2[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_2[] = "effggghhhh"; + float buffer_a3_2[] = { 4.1, 4.2, 5.1, 5.2, 6.1, 6.2, 7.1, 7.2 }; + const void* buffers_2[] = { + buffer_a1_2, buffer_a2_2, buffer_var_a2_2, buffer_a3_2 }; + size_t buffer_sizes_2[] = + { + sizeof(buffer_a1_2), + sizeof(buffer_a2_2), + sizeof(buffer_var_a2_2)-1, // No need to store the last '\0' character + sizeof(buffer_a3_2) + }; + // --- Lower left tile --- + const int64_t subarray_3[] = { 3, 4, 1, 2 }; + int buffer_a1_3[] = { 8, 9, 10, 11 }; + size_t buffer_a2_3[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_3[] = "ijjkkkllll"; + float buffer_a3_3[] = { 8.1, 8.2, 9.1, 9.2, 10.1, 10.2, 11.1, 11.2 }; + const void* buffers_3[] = { + buffer_a1_3, buffer_a2_3, buffer_var_a2_3, buffer_a3_3 }; + size_t buffer_sizes_3[] = + { + sizeof(buffer_a1_3), + sizeof(buffer_a2_3), + sizeof(buffer_var_a2_3)-1, // No need to store the last '\0' character + sizeof(buffer_a3_3) + }; + // --- Lower right tile --- + const int64_t subarray_4[] = { 3, 4, 3, 4 }; + int buffer_a1_4[] = { 12, 13, 14, 15 }; + size_t buffer_a2_4[] = { 0, 1, 3, 6 }; + const char buffer_var_a2_4[] = "mnnooopppp"; + float buffer_a3_4[] = { 12.1, 12.2, 13.1, 13.2, 14.1, 14.2, 15.1, 15.2 }; + const void* buffers_4[] = { + buffer_a1_4, buffer_a2_4, buffer_var_a2_4, buffer_a3_4 }; + size_t buffer_sizes_4[] = + { + sizeof(buffer_a1_4), + sizeof(buffer_a2_4), + sizeof(buffer_var_a2_4)-1, // No need to store the last '\0' character + sizeof(buffer_a3_4) + }; + + // Write in parallel + #pragma omp parallel for + for(int i=0; i<4; ++i) { + // Populate thread data + const void** buffers; + const size_t* buffer_sizes; + const void* subarray; + if(i==0) { // First tile + buffers = buffers_1; + buffer_sizes = buffer_sizes_1; + subarray = subarray_1; + } else if(i==1) { // Second tile + buffers = buffers_2; + buffer_sizes = buffer_sizes_2; + subarray = subarray_2; + } else if(i==2) { // Third tile + buffers = buffers_3; + buffer_sizes = buffer_sizes_3; + subarray = subarray_3; + } else if(i==3) { // Fourth tile + buffers = buffers_4; + buffer_sizes = buffer_sizes_4; + subarray = subarray_4; + } + + // Write + parallel_write( + tiledb_ctx, + array_name, + subarray, + buffers, + buffer_sizes); + } + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void parallel_write( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void* subarray, + const void** buffers, + const size_t* buffer_sizes) { + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + array_name, // Array name + TILEDB_ARRAY_WRITE, // Mode + subarray, // Subarray + NULL, // All attributes + 0); // Number of attributes + + // Write to array + tiledb_array_write(tiledb_array, buffers, buffer_sizes); + + // Finalize array + tiledb_array_finalize(tiledb_array); +} + diff --git a/examples/src/tiledb_array_parallel_write_sparse_1.cc b/examples/src/tiledb_array_parallel_write_sparse_1.cc new file mode 100644 index 00000000..c67ab894 --- /dev/null +++ b/examples/src/tiledb_array_parallel_write_sparse_1.cc @@ -0,0 +1,156 @@ +/** + * @file tiledb_array_parallel_write_sparse_1.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 sparse array in parallel with pthreads. + */ + +#include "c_api.h" +#include + +// The function to be computed in parallel +void *parallel_write(void* args); + +// The arguments for each invocation of parallel_write +typedef struct _thread_data_t { + const TileDB_CTX* tiledb_ctx; + const char* array_name; + const void** buffers; + const size_t* buffer_sizes; +} thread_data_t; + + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/sparse_arrays/my_array_B"; + + // Prepare cell buffers + // --- First write --- + int buffer_a1_1[] = { 7, 5, 0 }; + size_t buffer_a2_1[] = { 0, 4, 6 }; + const char buffer_var_a2_1[] = "hhhhffa"; + float buffer_a3_1[] = { 7.1, 7.2, 5.1, 5.2, 0.1, 0.2 }; + int64_t buffer_coords_1[] = { 3, 1, 3, 4, 1, 1 }; + const void* buffers_1[] = + { + buffer_a1_1, + buffer_a2_1, + buffer_var_a2_1, + buffer_a3_1, + buffer_coords_1 + }; + size_t buffer_sizes_1[] = + { + sizeof(buffer_a1_1), + sizeof(buffer_a2_1), + sizeof(buffer_var_a2_1)-1, // No need to store the last '\0' character + sizeof(buffer_a3_1), + sizeof(buffer_coords_1) + }; + // --- Second write --- + int buffer_a1_2[] = { 6, 4, 3, 1, 2 }; + size_t buffer_a2_2[] = { 0, 3, 4, 8, 10 }; + const char buffer_var_a2_2[] = "gggeddddbbccc"; + float buffer_a3_2[] = + { 6.1, 6.2, 4.1, 4.2, 3.1, 3.2, 1.1, 1.2, 2.1, 2.2 }; + int64_t buffer_coords_2[] = { 4, 2, 3, 3, 2, 3, 1, 2, 1, 4 }; + const void* buffers_2[] = + { + buffer_a1_2, + buffer_a2_2, + buffer_var_a2_2, + buffer_a3_2, + buffer_coords_2 + }; + size_t buffer_sizes_2[] = + { + sizeof(buffer_a1_2), + sizeof(buffer_a2_2), + sizeof(buffer_var_a2_2)-1, // No need to store the last '\0' character + sizeof(buffer_a3_2), + sizeof(buffer_coords_2) + }; + + // Initialize 2 pthreads and corresponding data + pthread_t threads[2]; + thread_data_t thread_data[2]; + + // Write in parallel + for(int i=0; i<2; ++i) { + // Populate the thread data + thread_data[i].tiledb_ctx = tiledb_ctx; + thread_data[i].array_name = array_name; + if(i==0) { // First tile + thread_data[i].buffers = buffers_1; + thread_data[i].buffer_sizes = buffer_sizes_1; + } else if(i==1) { // Second tile + thread_data[i].buffers = buffers_2; + thread_data[i].buffer_sizes = buffer_sizes_2; + } + + // Create thread + pthread_create(&threads[i], NULL, parallel_write, &thread_data[i]); + } + + // Wait till all threads finish + for(int i=0; i<2; ++i) + pthread_join(threads[i], NULL); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void *parallel_write(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + data->tiledb_ctx, // Context + &tiledb_array, // Array object + data->array_name, // Array name + TILEDB_ARRAY_WRITE_UNSORTED, // Mode + NULL, // Inapplicable + NULL, // All attributes + 0); // Number of attributes + + // Write to array + tiledb_array_write(tiledb_array, data->buffers, data->buffer_sizes); + + // Finalize array + tiledb_array_finalize(tiledb_array); + + return 0; +} diff --git a/examples/src/tiledb_array_parallel_write_sparse_2.cc b/examples/src/tiledb_array_parallel_write_sparse_2.cc new file mode 100644 index 00000000..c4af8955 --- /dev/null +++ b/examples/src/tiledb_array_parallel_write_sparse_2.cc @@ -0,0 +1,149 @@ +/** + * @file tiledb_array_parallel_write_sparse_2.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 sparse array in parallel with OpenMP. + */ + +#include "c_api.h" +#include + +// The function to be computed in parallel +void parallel_write( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void** buffers, + const size_t* buffer_sizes); + + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/sparse_arrays/my_array_B"; + + // Prepare cell buffers + // --- First write --- + int buffer_a1_1[] = { 7, 5, 0 }; + size_t buffer_a2_1[] = { 0, 4, 6 }; + const char buffer_var_a2_1[] = "hhhhffa"; + float buffer_a3_1[] = { 7.1, 7.2, 5.1, 5.2, 0.1, 0.2 }; + int64_t buffer_coords_1[] = { 3, 1, 3, 4, 1, 1 }; + const void* buffers_1[] = + { + buffer_a1_1, + buffer_a2_1, + buffer_var_a2_1, + buffer_a3_1, + buffer_coords_1 + }; + size_t buffer_sizes_1[] = + { + sizeof(buffer_a1_1), + sizeof(buffer_a2_1), + sizeof(buffer_var_a2_1)-1, // No need to store the last '\0' character + sizeof(buffer_a3_1), + sizeof(buffer_coords_1) + }; + // --- Second write --- + int buffer_a1_2[] = { 6, 4, 3, 1, 2 }; + size_t buffer_a2_2[] = { 0, 3, 4, 8, 10 }; + const char buffer_var_a2_2[] = "gggeddddbbccc"; + float buffer_a3_2[] = + { 6.1, 6.2, 4.1, 4.2, 3.1, 3.2, 1.1, 1.2, 2.1, 2.2 }; + int64_t buffer_coords_2[] = { 4, 2, 3, 3, 2, 3, 1, 2, 1, 4 }; + const void* buffers_2[] = + { + buffer_a1_2, + buffer_a2_2, + buffer_var_a2_2, + buffer_a3_2, + buffer_coords_2 + }; + size_t buffer_sizes_2[] = + { + sizeof(buffer_a1_2), + sizeof(buffer_a2_2), + sizeof(buffer_var_a2_2)-1, // No need to store the last '\0' character + sizeof(buffer_a3_2), + sizeof(buffer_coords_2) + }; + + + #pragma omp parallel for + // Write in parallel + for(int i=0; i<2; ++i) { + // Populate thread data + const void** buffers; + const size_t* buffer_sizes; + if(i==0) { // First tile + buffers = buffers_1; + buffer_sizes = buffer_sizes_1; + } else if(i==1) { // Second tile + buffers = buffers_2; + buffer_sizes = buffer_sizes_2; + } + + // Write + parallel_write( + tiledb_ctx, + array_name, + buffers, + buffer_sizes); + } + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void parallel_write( + const TileDB_CTX* tiledb_ctx, + const char* array_name, + const void** buffers, + const size_t* buffer_sizes) { + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + tiledb_ctx, // Context + &tiledb_array, // Array object + array_name, // Array name + TILEDB_ARRAY_WRITE_UNSORTED, // Mode + NULL, // Inapplicable + NULL, // All attributes + 0); // Number of attributes + + // Write to array + tiledb_array_write(tiledb_array, buffers, buffer_sizes); + + // Finalize array + tiledb_array_finalize(tiledb_array); +} diff --git a/examples/src/tiledb_array_primitive.cc b/examples/src/tiledb_array_primitive.cc index b8a77aab..8e7fa87b 100644 --- a/examples/src/tiledb_array_primitive.cc +++ b/examples/src/tiledb_array_primitive.cc @@ -37,7 +37,7 @@ void print_some_array_schema_info(const TileDB_ArraySchema* array_schema); int main() { - /* Intialize context with the default configuration parameters. */ + /* Initialize context with the default configuration parameters. */ TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_read_dense_1.cc b/examples/src/tiledb_array_read_dense_1.cc index 78d8d1c7..7685302f 100644 --- a/examples/src/tiledb_array_read_dense_1.cc +++ b/examples/src/tiledb_array_read_dense_1.cc @@ -34,7 +34,7 @@ #include int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); @@ -74,7 +74,7 @@ int main() { printf("%3d", buffer_a1[i]); size_t var_size = (i != result_num-1) ? buffer_a2[i+1] - buffer_a2[i] : buffer_sizes[2] - buffer_a2[i]; - printf("\t %4.*s", var_size, &buffer_var_a2[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]); } diff --git a/examples/src/tiledb_array_read_dense_2.cc b/examples/src/tiledb_array_read_dense_2.cc index 949deef8..38bfc216 100644 --- a/examples/src/tiledb_array_read_dense_2.cc +++ b/examples/src/tiledb_array_read_dense_2.cc @@ -36,7 +36,7 @@ #include int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_read_dense_3.cc b/examples/src/tiledb_array_read_dense_3.cc index 378a6c2e..89ea64ff 100644 --- a/examples/src/tiledb_array_read_dense_3.cc +++ b/examples/src/tiledb_array_read_dense_3.cc @@ -34,7 +34,7 @@ #include int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); @@ -74,7 +74,7 @@ int main() { // Read from array - #2 tiledb_array_read(tiledb_array, buffers_2, buffer_sizes_2); - printf("a2 for (4,3): %3.*s\n", buffer_sizes_2[1], buffer_var_a2); + printf("a2 for (4,3): %3.*s\n", int(buffer_sizes_2[1]), buffer_var_a2); // Finalize the array tiledb_array_finalize(tiledb_array); diff --git a/examples/src/tiledb_array_read_sparse_1.cc b/examples/src/tiledb_array_read_sparse_1.cc index 0811f6c1..99618b95 100644 --- a/examples/src/tiledb_array_read_sparse_1.cc +++ b/examples/src/tiledb_array_read_sparse_1.cc @@ -34,7 +34,7 @@ #include int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); @@ -78,7 +78,7 @@ int main() { printf("\t %3d", buffer_a1[i]); size_t var_size = (i != result_num-1) ? buffer_a2[i+1] - buffer_a2[i] : buffer_sizes[2] - buffer_a2[i]; - printf("\t %4.*s", var_size, &buffer_var_a2[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]); } diff --git a/examples/src/tiledb_array_read_sparse_2.cc b/examples/src/tiledb_array_read_sparse_2.cc index ed50357d..02702970 100644 --- a/examples/src/tiledb_array_read_sparse_2.cc +++ b/examples/src/tiledb_array_read_sparse_2.cc @@ -36,7 +36,7 @@ #include int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_update_dense_1.cc b/examples/src/tiledb_array_update_dense_1.cc index a82920fc..234e6d70 100644 --- a/examples/src/tiledb_array_update_dense_1.cc +++ b/examples/src/tiledb_array_update_dense_1.cc @@ -34,7 +34,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_update_dense_2.cc b/examples/src/tiledb_array_update_dense_2.cc index bb4bf97b..1a2b1992 100644 --- a/examples/src/tiledb_array_update_dense_2.cc +++ b/examples/src/tiledb_array_update_dense_2.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_update_sparse_1.cc b/examples/src/tiledb_array_update_sparse_1.cc index 7c10c901..d1a2f076 100644 --- a/examples/src/tiledb_array_update_sparse_1.cc +++ b/examples/src/tiledb_array_update_sparse_1.cc @@ -34,7 +34,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_update_sparse_2.cc b/examples/src/tiledb_array_update_sparse_2.cc index d1457664..d5a1ad7e 100644 --- a/examples/src/tiledb_array_update_sparse_2.cc +++ b/examples/src/tiledb_array_update_sparse_2.cc @@ -34,7 +34,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_write_dense_1.cc b/examples/src/tiledb_array_write_dense_1.cc index 357a1d4b..c32956d8 100644 --- a/examples/src/tiledb_array_write_dense_1.cc +++ b/examples/src/tiledb_array_write_dense_1.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_write_dense_2.cc b/examples/src/tiledb_array_write_dense_2.cc index 8b839294..aa59a37c 100644 --- a/examples/src/tiledb_array_write_dense_2.cc +++ b/examples/src/tiledb_array_write_dense_2.cc @@ -29,13 +29,13 @@ * * It shows how to write to a dense array invoking the write function * multiple times. This will have the same effect as program - * tiledb_array_write_1.cc. + * tiledb_array_write_dense_1.cc. */ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); @@ -54,7 +54,7 @@ int main() { int buffer_a1[] = { 0, 1, 2, 3, 4, 5 }; size_t buffer_a2[] = { 0, 1, 3, 6, 10, 11, 13, 16 }; const char buffer_var_a2[] = "abbcccddddeffggghhhh"; - float* buffer_a3; + float* buffer_a3 = NULL; const void* buffers[] = { buffer_a1, buffer_a2, buffer_var_a2, buffer_a3 }; size_t buffer_sizes[] = { diff --git a/examples/src/tiledb_array_write_sparse_1.cc b/examples/src/tiledb_array_write_sparse_1.cc index e46ac004..b4d6306c 100644 --- a/examples/src/tiledb_array_write_sparse_1.cc +++ b/examples/src/tiledb_array_write_sparse_1.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_write_sparse_2.cc b/examples/src/tiledb_array_write_sparse_2.cc index a9fcb6c5..f743188c 100644 --- a/examples/src/tiledb_array_write_sparse_2.cc +++ b/examples/src/tiledb_array_write_sparse_2.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); @@ -74,9 +74,9 @@ int main() { // Prepare cell buffers - #2 int buffer_a1_2[] = { 3, 4, 5, 6, 7 }; - size_t* buffer_a2_2; - const char* buffer_var_a2_2; - float* buffer_a3_2; + size_t* buffer_a2_2 = NULL; + const char* buffer_var_a2_2 = NULL; + float* buffer_a3_2 = NULL; int64_t buffer_coords_2[] = { 1, 4, 2, 3, 3, 3, 3, 4, 4, 2, 3, 1 }; const void* buffers_2[] = { diff --git a/examples/src/tiledb_array_write_sparse_3.cc b/examples/src/tiledb_array_write_sparse_3.cc index 1469ec4b..5c44bb58 100644 --- a/examples/src/tiledb_array_write_sparse_3.cc +++ b/examples/src/tiledb_array_write_sparse_3.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_array_write_sparse_4.cc b/examples/src/tiledb_array_write_sparse_4.cc index bb7922af..4719160e 100644 --- a/examples/src/tiledb_array_write_sparse_4.cc +++ b/examples/src/tiledb_array_write_sparse_4.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_clear_delete_move.cc b/examples/src/tiledb_clear_delete_move.cc index e4fabc2b..d0bec0cd 100644 --- a/examples/src/tiledb_clear_delete_move.cc +++ b/examples/src/tiledb_clear_delete_move.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_ls.cc b/examples/src/tiledb_ls.cc index 27997066..571dc9a0 100644 --- a/examples/src/tiledb_ls.cc +++ b/examples/src/tiledb_ls.cc @@ -41,12 +41,13 @@ int main(int argc, char** argv) { return -1; } - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); // Initialize variables char* dirs[10]; + int allocated_dir_num = 10; int dir_num = 10; int dir_types[10]; for(int i=0; i int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); // Initialize variables char* dirs[10]; + int allocated_dir_num = 10; int dir_num = 10; - int dir_types[10]; for(int i=0; i int main() { - /* Intialize context with the default configuration parameters. */ + /* Initialize context with the default configuration parameters. */ TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_metadata_primitive.cc b/examples/src/tiledb_metadata_primitive.cc index 05e703ba..d46c0483 100644 --- a/examples/src/tiledb_metadata_primitive.cc +++ b/examples/src/tiledb_metadata_primitive.cc @@ -38,7 +38,7 @@ void print_some_metadata_schema_info( const TileDB_MetadataSchema* metadata_schema); int main() { - /* Intialize context with the default configuration parameters. */ + /* Initialize context with the default configuration parameters. */ TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_metadata_read.cc b/examples/src/tiledb_metadata_read.cc index 2cc3fe43..c5305d85 100644 --- a/examples/src/tiledb_metadata_read.cc +++ b/examples/src/tiledb_metadata_read.cc @@ -40,7 +40,7 @@ int main(int argc, char** argv) { return -1; } - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); @@ -72,37 +72,30 @@ int main(int argc, char** argv) { sizeof(buffer_a2), sizeof(buffer_var_a2) // a2 }; - // Read from metadata tiledb_metadata_read(tiledb_metadata, argv[1], buffers, buffer_sizes); // Check existence if(buffer_sizes[0] == 0 && !tiledb_metadata_overflow(tiledb_metadata, 0)) { fprintf(stderr, "Key '%s' does not exist in the metadata!\n", argv[1]); - return -1; - } - - // Check overflow for a2 - if(buffer_sizes[2] == 0 && tiledb_metadata_overflow(tiledb_metadata, 1)) { + } else if(buffer_sizes[2] == 0 && + tiledb_metadata_overflow(tiledb_metadata, 1)) { + // Check overflow for a2 fprintf(stderr, "Reading value on attribute 'a2' for key '%s' resulted in " "a buffer overflow!\n", argv[1]); - return -1; - } - - // Check if deleted - if(static_cast(buffers[0])[0] == TILEDB_EMPTY_INT32) { + } else if(static_cast(buffers[0])[0] == TILEDB_EMPTY_INT32) { + // Check if deleted fprintf(stderr, "Key '%s' has been deleted!\n", argv[1]); - return -1; + } else { + // Print attribute values + printf( + "%s: a1=%d, a2=%.*s\n", + argv[1], + static_cast(buffers[0])[0], + int(buffer_sizes[2]), + static_cast(buffers[2])); } - // Print attribute values - printf( - "%s: a1=%d, a2=%.*s\n", - argv[1], - static_cast(buffers[0])[0], - buffer_sizes[2], - static_cast(buffers[2])); - /* Finalize the array. */ tiledb_metadata_finalize(tiledb_metadata); diff --git a/examples/src/tiledb_metadata_update.cc b/examples/src/tiledb_metadata_update.cc index 398cfc99..e1aedea5 100644 --- a/examples/src/tiledb_metadata_update.cc +++ b/examples/src/tiledb_metadata_update.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_metadata_write.cc b/examples/src/tiledb_metadata_write.cc index 0710854b..aebc99d4 100644 --- a/examples/src/tiledb_metadata_write.cc +++ b/examples/src/tiledb_metadata_write.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/examples/src/tiledb_workspace_group_create.cc b/examples/src/tiledb_workspace_group_create.cc index 22ef5359..59bec989 100644 --- a/examples/src/tiledb_workspace_group_create.cc +++ b/examples/src/tiledb_workspace_group_create.cc @@ -33,7 +33,7 @@ #include "c_api.h" int main() { - // Intialize context with the default configuration parameters + // Initialize context with the default configuration parameters TileDB_CTX* tiledb_ctx; tiledb_ctx_init(&tiledb_ctx, NULL); diff --git a/test/src/array/array_schema_spec.cc b/test/src/array/array_schema_spec.cc index ec8f5165..0a11f5fd 100644 --- a/test/src/array/array_schema_spec.cc +++ b/test/src/array/array_schema_spec.cc @@ -65,7 +65,8 @@ class ArraySchemaTest: public testing::Test { // Remove the temporary workspace std::string command = "rm -rf "; command.append(WORKSPACE); - int ret = system(command.c_str()); + int rc = system(command.c_str()); + ASSERT_EQ(rc, 0); } }; diff --git a/test/src/c_api/c_api_spec.cc b/test/src/c_api/c_api_spec.cc index 1c65c4d6..741654dd 100644 --- a/test/src/c_api/c_api_spec.cc +++ b/test/src/c_api/c_api_spec.cc @@ -97,7 +97,8 @@ class TileDBAPITest: public testing::Test { // Remove the temporary workspace std::string command = "rm -rf "; command.append(WORKSPACE); - int ret = system(command.c_str()); + int rc = system(command.c_str()); + ASSERT_EQ(rc, 0); } }; /** From 13fe72b25841cb2e673b335b436eebc5fe09255a Mon Sep 17 00:00:00 2001 From: spapadop Date: Thu, 21 Apr 2016 16:46:33 -0400 Subject: [PATCH 4/7] Implemented thread- and process-safety for consolidation. Now a user may consolidate an array or fragment in the background, while performing arbitrary concurrent reads/writes. Added examples as well. --- core/include/array/array.h | 9 +- core/include/metadata/metadata.h | 15 +- .../include/storage_manager/storage_manager.h | 87 +++++- core/src/array/array.cc | 27 +- core/src/metadata/metadata.cc | 6 +- core/src/storage_manager/storage_manager.cc | 275 +++++++++++++++--- ...tiledb_array_parallel_consolidate_dense.cc | 186 ++++++++++++ ...iledb_array_parallel_consolidate_sparse.cc | 167 +++++++++++ 8 files changed, 694 insertions(+), 78 deletions(-) create mode 100644 examples/src/tiledb_array_parallel_consolidate_dense.cc create mode 100644 examples/src/tiledb_array_parallel_consolidate_sparse.cc diff --git a/core/include/array/array.h b/core/include/array/array.h index b11884f9..069bb431 100644 --- a/core/include/array/array.h +++ b/core/include/array/array.h @@ -141,10 +141,17 @@ 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), + * along with the names of the old (consolidated) fragments (which also have + * to be deleted outside this function). * + * @param new_fragment The new fragment to be returned. + * @param old_fragment_names The names of the old fragments to be returned. * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. */ - int consolidate(); + int consolidate( + Fragment*& new_fragment, + std::vector& old_fragment_names); /** * Consolidates all fragment into a new single one, focusing on a specific diff --git a/core/include/metadata/metadata.h b/core/include/metadata/metadata.h index 4444842f..d4a2672b 100644 --- a/core/include/metadata/metadata.h +++ b/core/include/metadata/metadata.h @@ -117,11 +117,18 @@ class Metadata { /* ********************************* */ /** - * Consolidates the fragments of a metadata object into a single fragment. - * - * @return TILEDB_MT_OK on success, and TILEDB_MT_ERR on error. + * 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), + * along with the names of the old (consolidated) fragments (which also have + * to be deleted outside this function). + * + * @param new_fragment The new fragment to be returned. + * @param old_fragment_names The names of the old fragments to be returned. + * @return TILEDB_AR_OK for success and TILEDB_AR_ERR for error. */ - int consolidate(); + int consolidate( + Fragment*& new_fragment, + std::vector& old_fragment_names); /** * Finalizes the metadata, properly freeing up the memory space. diff --git a/core/include/storage_manager/storage_manager.h b/core/include/storage_manager/storage_manager.h index c3855944..20a70772 100755 --- a/core/include/storage_manager/storage_manager.h +++ b/core/include/storage_manager/storage_manager.h @@ -51,12 +51,21 @@ /**@{*/ /** Return code. */ -#define TILEDB_SM_OK 0 -#define TILEDB_SM_ERR -1 +#define TILEDB_SM_OK 0 +#define TILEDB_SM_ERR -1 /**@}*/ /** Name of the master catalog. */ -#define TILEDB_SM_MASTER_CATALOG "master_catalog" +#define TILEDB_SM_MASTER_CATALOG "master_catalog" + +/** Name of the consolidation file lock. */ +#define TILEDB_SM_CONSOLIDATION_FILELOCK_NAME ".__consolidation_lock" + +/**@{*/ +/** Lock types. */ +#define TILEDB_SM_SHARED_LOCK 0 +#define TILEDB_SM_EXCLUSIVE_LOCK 1 +/**@}*/ /** * The storage manager, which is repsonsible for creating, deleting, etc. of @@ -567,14 +576,13 @@ class StorageManager { * array is being initialized. The book-keeping structures are loaded only * if the input mode is TILEDB_ARRAY_READ. * - * @param array_schema The array schema. + * @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. * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ int array_open( - const ArraySchema* array_schema, - int mode, + const std::string& array_name, OpenArray*& open_array); /** @@ -594,6 +602,53 @@ class StorageManager { */ void config_set_default(); + /** + * Creates a special file that serves as lock needed for implementing + * thread- and process-safety during consolidation. The file is + * created inside an array or metadata directory. + * + * @param dir The array or metadata directory the filelock is created for. + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int consolidation_filelock_create(const std::string& dir) const; + + /** + * Locks the consolidation file lock. + * + * @param array_name The name of the array the lock is applied on. + * @param fd The file descriptor of the filelock. + * @param lock_type The lock type, which can be either TILEDB_SM_SHARED_LOCK + * or TILEDB_SM_EXCLUSIVE_LOCK. + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int consolidation_filelock_lock( + const std::string& array_name, + int& fd, + int lock_type) const; + + /** + * Unlocks the consolidation file lock. + * + * @param fd The file descriptor of the filelock. + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int consolidation_filelock_unlock(int fd) const; + + /** + * Finalizes the consolidation process, applying carefully the locks so that + * this can be done concurrently with other reads. The function finalizes the + * new consolidated fragment, and deletes the old fragments that created it. + * + * @param new_fragment The new consolidated fragment that the function will + * finalize. + * @param old_fragment_names The names of the old fragments that need to be + * deleted. + * @return TILEDB_SM_OK for success, and TILEDB_SM_ERR for error. + */ + int consolidation_finalize( + Fragment* new_fragment, + const std::vector& old_fragment_names); + /** * Creates a special group file inside the group directory. * @@ -697,32 +752,32 @@ class StorageManager { const std::string& new_metadata) const; /** - * Destroys all the mutexes. + * Destroys open array the mutexes. * * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int mutex_destroy(); + int open_array_mtx_destroy(); /** - * Initializes all the mutexes. + * Initializes open array mutexes. * * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int mutex_init(); + int open_array_mtx_init(); /** - * Locks all the mutexes. + * Locks open array mutexes. * * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int mutex_lock(); + int open_array_mtx_lock(); /** - * Unlocks all the mutexes. + * Unlocks open array mutexes. * * @return TILEDB_SM_OK for success and TILEDB_SM_ERR for error. */ - int mutex_unlock(); + int open_array_mtx_unlock(); /** * Appropriately sorts the fragment names based on their name timestamps. @@ -777,6 +832,8 @@ class StorageManager::OpenArray { public: // ATTRIBUTES + /** The array schema. */ + ArraySchema* array_schema_; /** The book-keeping structures for all the fragments of the array. */ std::vector book_keeping_; /** @@ -784,6 +841,8 @@ class StorageManager::OpenArray { * it was opened. */ int cnt_; + /** Descriptor for the consolidation filelock. */ + int consolidation_filelock_; /** The names of the fragments of the open array. */ std::vector fragment_names_; /** diff --git a/core/src/array/array.cc b/core/src/array/array.cc index 19acb660..d781563f 100644 --- a/core/src/array/array.cc +++ b/core/src/array/array.cc @@ -169,7 +169,9 @@ const void* Array::subarray() const { /* MUTATORS */ /* ****************************** */ -int Array::consolidate() { +int Array::consolidate( + Fragment*& new_fragment, + std::vector& old_fragment_names) { // Trivial case if(fragments_.size() == 1) return TILEDB_AS_OK; @@ -180,7 +182,7 @@ int Array::consolidate() { return TILEDB_AS_ERR; // Create new fragment - Fragment* new_fragment = new Fragment(this); + new_fragment = new Fragment(this); if(new_fragment->init(new_fragment_name, TILEDB_ARRAY_WRITE, subarray_) != TILEDB_FG_OK) return TILEDB_AR_ERR; @@ -194,25 +196,10 @@ int Array::consolidate() { } } - // Finalize new fragment - int rc = new_fragment->finalize(); - delete new_fragment; - if(rc != TILEDB_FG_OK) - return TILEDB_AR_ERR; - - // Delete old fragments + // Get old fragment names int fragment_num = fragments_.size(); - for(int i=0; ifinalize() != TILEDB_FG_OK) - return TILEDB_AR_ERR; - - std::string fragment_name = fragments_[i]->fragment_name(); - delete fragments_[i]; - - if(delete_dir(fragment_name) != TILEDB_UT_OK) - return TILEDB_AR_ERR; - } - fragments_.clear(); + for(int i=0; ifragment_name()); // Success return TILEDB_AR_OK; diff --git a/core/src/metadata/metadata.cc b/core/src/metadata/metadata.cc index 33b80ed2..5a7cc2aa 100644 --- a/core/src/metadata/metadata.cc +++ b/core/src/metadata/metadata.cc @@ -124,8 +124,10 @@ int Metadata::read(const char* key, void** buffers, size_t* buffer_sizes) { /* MUTATORS */ /* ****************************** */ -int Metadata::consolidate() { - if(array_->consolidate() != TILEDB_AR_OK) +int Metadata::consolidate( + Fragment*& new_fragment, + std::vector& old_fragment_names) { + if(array_->consolidate(new_fragment, old_fragment_names) != TILEDB_AR_OK) return TILEDB_MT_ERR; else return TILEDB_MT_OK; diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index 70548e1b..d40b6f3a 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -93,7 +93,7 @@ StorageManager::~StorageManager() { /* ****************************** */ int StorageManager::finalize() { - return mutex_destroy(); + return open_array_mtx_destroy(); } int StorageManager::init(const char* config_filename) { @@ -133,7 +133,7 @@ int StorageManager::init(const char* config_filename) { } // Initialize mutexes and return - return mutex_init(); + return open_array_mtx_init(); } @@ -281,13 +281,27 @@ int StorageManager::array_consolidate(const char* array_dir) { return TILEDB_SM_ERR; // Consolidate array - int rc_consolidate = array->consolidate(); + Fragment* new_fragment; + std::vector old_fragment_names; + int rc_array_consolidate = + array->consolidate(new_fragment, old_fragment_names); + // Close the array + int rc_array_close = array_close(array->array_schema()->array_name()); + + // Finalize consolidation + int rc_consolidation_finalize = + consolidation_finalize(new_fragment, old_fragment_names); + // Finalize array - int rc_finalize = array_finalize(array); + int rc_array_finalize = array->finalize(); + delete array; // Return - if(rc_consolidate != TILEDB_AR_OK || rc_finalize != TILEDB_SM_OK) + if(rc_array_consolidate != TILEDB_AR_OK || + rc_array_close != TILEDB_SM_OK || + rc_array_finalize != TILEDB_SM_OK || + rc_consolidation_finalize != TILEDB_SM_OK) return TILEDB_SM_ERR; else return TILEDB_SM_OK; @@ -368,6 +382,10 @@ int StorageManager::array_create(const ArraySchema* array_schema) const { return TILEDB_SM_ERR; } + // Create consolidation filelock + if(consolidation_filelock_create(dir) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + // Success return TILEDB_SM_OK; } @@ -500,8 +518,10 @@ int StorageManager::array_init( // Open the array OpenArray* open_array; - if(array_open(array_schema, mode, open_array) != TILEDB_SM_OK) - return TILEDB_SM_ERR; + if(mode == TILEDB_ARRAY_READ) { + if(array_open(real_dir(array_dir), open_array) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + } // Create Array object array = new Array(); @@ -529,8 +549,11 @@ 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 = array_close(array->array_schema()->array_name()); + int rc_close = TILEDB_SM_OK; + if(mode == TILEDB_ARRAY_READ) + rc_close = array_close(array->array_schema()->array_name()); // Clean up delete array; @@ -640,13 +663,28 @@ int StorageManager::metadata_consolidate(const char* metadata_dir) { return TILEDB_SM_ERR; // Consolidate metadata - int rc_consolidate = metadata->consolidate(); + Fragment* new_fragment; + std::vector old_fragment_names; + int rc_metadata_consolidate = + metadata->consolidate(new_fragment, old_fragment_names); + // Close the underlying array + std::string array_name = metadata->array_schema()->array_name(); + int rc_array_close = array_close(array_name); + + // Finalize consolidation + int rc_consolidation_finalize = + consolidation_finalize(new_fragment, old_fragment_names); + // Finalize metadata - int rc_finalize = metadata_finalize(metadata); + int rc_metadata_finalize = metadata->finalize(); + delete metadata; // Return - if(rc_consolidate != TILEDB_MT_OK || rc_finalize != TILEDB_SM_OK) + if(rc_metadata_consolidate != TILEDB_MT_OK || + rc_array_close != TILEDB_SM_OK || + rc_metadata_finalize != TILEDB_SM_OK || + rc_consolidation_finalize != TILEDB_SM_OK) return TILEDB_SM_ERR; else return TILEDB_SM_OK; @@ -729,6 +767,10 @@ int StorageManager::metadata_create(const ArraySchema* array_schema) const { return TILEDB_SM_ERR; } + // Create consolidation filelock + if(consolidation_filelock_create(dir) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + // Success return TILEDB_SM_OK; } @@ -812,8 +854,10 @@ int StorageManager::metadata_init( // Open the array that implements the metadata OpenArray* open_array; - if(array_open(array_schema, mode, open_array) != TILEDB_SM_OK) - return TILEDB_SM_ERR; + if(mode == TILEDB_METADATA_READ) { + if(array_open(real_dir(metadata_dir), open_array) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + } // Create metadata object metadata = new Metadata(); @@ -844,8 +888,11 @@ int StorageManager::metadata_finalize(Metadata* metadata) { // Finalize the metadata and close the underlying array std::string array_name = metadata->array_schema()->array_name(); + int mode = metadata->array()->mode(); int rc_finalize = metadata->finalize(); - int rc_close = array_close(array_name); + int rc_close = TILEDB_SM_OK; + if(mode == TILEDB_METADATA_READ) + rc_close = array_close(array_name); // Clean up delete metadata; @@ -1106,7 +1153,7 @@ int StorageManager::array_clear( int StorageManager::array_close(const std::string& array) { // Lock mutexes - if(mutex_lock() != TILEDB_SM_OK) + if(open_array_mtx_lock() != TILEDB_SM_OK) return TILEDB_SM_ERR; // Find the open array entry @@ -1128,7 +1175,8 @@ int StorageManager::array_close(const std::string& array) { // Delete open array entry if necessary int rc_mtx_destroy = TILEDB_SM_OK; - if(it->second != NULL && it->second->cnt_ == 0) { + int rc_filelock = TILEDB_SM_OK; + 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) @@ -1138,6 +1186,14 @@ int StorageManager::array_close(const std::string& array) { it->second->mutex_unlock(); rc_mtx_destroy = it->second->mutex_destroy(); + // 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_; + // Free open array delete it->second; @@ -1150,10 +1206,12 @@ int StorageManager::array_close(const std::string& array) { } // Unlock mutexes - int rc_mtx_unlock = mutex_unlock(); + int rc_mtx_unlock = open_array_mtx_unlock(); // Return - if(rc_mtx_destroy != TILEDB_SM_OK || rc_mtx_unlock != TILEDB_SM_OK) + if(rc_mtx_destroy != TILEDB_SM_OK || + rc_filelock != TILEDB_SM_OK || + rc_mtx_unlock != TILEDB_SM_OK) return TILEDB_SM_ERR; else return TILEDB_SM_OK; @@ -1177,7 +1235,7 @@ int StorageManager::array_get_open_array_entry( const std::string& array, OpenArray*& open_array) { // Lock mutexes - if(mutex_lock() != TILEDB_SM_OK) + if(open_array_mtx_lock() != TILEDB_SM_OK) return TILEDB_SM_ERR; // Find the open array entry @@ -1186,6 +1244,7 @@ int StorageManager::array_get_open_array_entry( if(it == open_arrays_.end()) { open_array = new OpenArray(); open_array->cnt_ = 0; + open_array->consolidation_filelock_ = -1; open_array->book_keeping_ = std::vector(); if(open_array->mutex_init() != TILEDB_SM_OK) { open_array->mutex_unlock(); @@ -1196,8 +1255,17 @@ int StorageManager::array_get_open_array_entry( open_array = it->second; } - // Unlock mutexes and return - return mutex_unlock(); + // Increment counter + ++(open_array->cnt_); + + // Unlock mutexes + if(open_array_mtx_unlock() != TILEDB_SM_OK) { + --open_array->cnt_; + return TILEDB_SM_ERR; + } + + // Success + return TILEDB_SM_OK; } int StorageManager::array_move( @@ -1242,12 +1310,8 @@ int StorageManager::array_move( } int StorageManager::array_open( - const ArraySchema* array_schema, - int mode, + const std::string& array_name, OpenArray*& open_array) { - // For easy reference - std::string array_name = array_schema->array_name(); - // Get the open array entry if(array_get_open_array_entry(array_name, open_array) != TILEDB_SM_OK) return TILEDB_SM_ERR; @@ -1256,24 +1320,45 @@ int StorageManager::array_open( if(open_array->mutex_lock() != TILEDB_SM_OK) return TILEDB_SM_ERR; - if(mode == TILEDB_ARRAY_READ && - open_array->fragment_names_.size() == 0) { + // First time the array is opened + if(open_array->fragment_names_.size() == 0) { + // Acquire shared lock on consolidation filelock + if(consolidation_filelock_lock( + array_name, + open_array->consolidation_filelock_, + TILEDB_SM_SHARED_LOCK)) { + open_array->mutex_unlock(); + return TILEDB_SM_ERR; + } + // Get the fragment names array_get_fragment_names(array_name, open_array->fragment_names_); + // Get array schema + if(is_array(array_name)) { // Array + if(array_load_schema( + array_name.c_str(), + open_array->array_schema_) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + } else { // Metadata + if(metadata_load_schema( + array_name.c_str(), + open_array->array_schema_) != TILEDB_SM_OK) + return TILEDB_SM_ERR; + } + // Load the book-keeping for each fragment if(array_load_book_keeping( - array_schema, + open_array->array_schema_, open_array->fragment_names_, open_array->book_keeping_) != TILEDB_SM_OK) { + delete open_array->array_schema_; + open_array->array_schema_ = NULL; open_array->mutex_unlock(); return TILEDB_SM_ERR; - } + } } - // Increment counter - ++(open_array->cnt_); - // Unlock the mutex of the array if(open_array->mutex_unlock() != TILEDB_UT_OK) return TILEDB_SM_ERR; @@ -1290,6 +1375,122 @@ int StorageManager::config_set(const char* config_filename) { void StorageManager::config_set_default() { } +int StorageManager::consolidation_filelock_create( + const std::string& dir) const { + std::string filename = dir + "/" + TILEDB_SM_CONSOLIDATION_FILELOCK_NAME; + int fd = ::open(filename.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRWXU); + if(fd == -1) { + PRINT_ERROR( + std::string("Cannot create consolidation filelock; ") + + strerror(errno)); + return TILEDB_SM_ERR; + } + + // Success + return TILEDB_SM_OK; +} + +int StorageManager::consolidation_filelock_lock( + const std::string& array_name, + int& fd, + int lock_type) const { + // Prepare the flock struct + struct flock fl; + if(lock_type == TILEDB_SM_SHARED_LOCK) { + fl.l_type = F_RDLCK; + } else if(lock_type == TILEDB_SM_EXCLUSIVE_LOCK) { + fl.l_type = F_WRLCK; + } else { + PRINT_ERROR("Cannot lock consolidation filelock; Invalid lock type"); + return TILEDB_SM_ERR; + } + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + + // Prepare the filelock name + std::string array_name_real = real_dir(array_name); + std::string filename = + array_name_real + "/" + + TILEDB_SM_CONSOLIDATION_FILELOCK_NAME; + + // Open the file + fd = ::open(filename.c_str(), O_RDWR); + if(fd == -1) { + PRINT_ERROR("Cannot lock consolidation filelock; Cannot open filelock"); + return TILEDB_SM_ERR; + } + + // Acquire the lock + if(fcntl(fd, F_SETLKW, &fl) == -1) { + PRINT_ERROR("Cannot lock consolidation filelock; Cannot lock"); + return TILEDB_SM_ERR; + } + + // Success + return TILEDB_SM_OK; +} + +int StorageManager::consolidation_filelock_unlock(int fd) const { + if(::close(fd) == -1) { + PRINT_ERROR("Cannot unlock consolidation filelock; Cannot close filelock"); + return TILEDB_SM_ERR; + } else { + return TILEDB_SM_OK; + } +} + +int StorageManager::consolidation_finalize( + Fragment* new_fragment, + const std::vector& old_fragment_names) { + // Trivial case - there was no consolidation + if(old_fragment_names.size() == 0) + return TILEDB_SM_OK; + + // Acquire exclusive lock on consolidation filelock + int fd; + if(consolidation_filelock_lock( + new_fragment->array()->array_schema()->array_name(), + fd, + TILEDB_SM_EXCLUSIVE_LOCK) != TILEDB_SM_OK) { + delete new_fragment; + return TILEDB_SM_ERR; + } + + // Finalize new fragment - makes the new fragment visible to new reads + int rc = new_fragment->finalize(); + delete new_fragment; + if(rc != TILEDB_FG_OK) + return TILEDB_SM_ERR; + + // Make old fragments invisible to new reads + int fragment_num = old_fragment_names.size(); + for(int i=0; i +#include + + + +// The consolidation function to be computed in parallel +void *parallel_consolidate(void* args); + +// The read function to be computed in parallel +void *parallel_read(void* args); + +// The arguments for each invocation of parallel_write +typedef struct _thread_data_t { + const TileDB_CTX* tiledb_ctx; + const char* array_name; + const void* subarray; + void** buffers; + size_t* buffer_sizes; + int count; +} thread_data_t; + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/dense_arrays/my_array_A"; + + // Prepare cell buffers + // --- Upper left tile --- + const int64_t subarray_1[] = { 1, 2, 1, 2 }; + int buffer_a1_1[4]; + void* buffers_1[] = { buffer_a1_1 }; + size_t buffer_sizes_1[] = { sizeof(buffer_a1_1) }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 1, 2, 3, 4 }; + int buffer_a1_2[4]; + void* buffers_2[] = { buffer_a1_2 }; + size_t buffer_sizes_2[] = { sizeof(buffer_a1_2) }; + // --- Lower left tile --- + const int64_t subarray_3[] = { 3, 4, 1, 2 }; + int buffer_a1_3[4]; + void* buffers_3[] = { buffer_a1_3 }; + size_t buffer_sizes_3[] = { sizeof(buffer_a1_3) }; + // --- Lower right tile --- + const int64_t subarray_4[] = { 3, 4, 3, 4 }; + int buffer_a1_4[4]; + void* buffers_4[] = { buffer_a1_4 }; + size_t buffer_sizes_4[] = { sizeof(buffer_a1_4) }; + + // Initialize 4 pthreads for reading, plus 1 for consolidation + pthread_t threads[5]; + thread_data_t thread_data[5]; + + // Write in parallel + for(int i=0; i<5; ++i) { + // Populate the thread data + thread_data[i].tiledb_ctx = tiledb_ctx; + thread_data[i].array_name = array_name; + if(i==0) { // First tile + thread_data[i].buffers = buffers_1; + thread_data[i].buffer_sizes = buffer_sizes_1; + thread_data[i].subarray = subarray_1; + } else if(i==1) { // Second tile + thread_data[i].buffers = buffers_2; + thread_data[i].buffer_sizes = buffer_sizes_2; + thread_data[i].subarray = subarray_2; + } else if(i==2) { // Third tile + thread_data[i].buffers = buffers_3; + thread_data[i].buffer_sizes = buffer_sizes_3; + thread_data[i].subarray = subarray_3; + } else if(i==3) { // Fourth tile + thread_data[i].buffers = buffers_4; + thread_data[i].buffer_sizes = buffer_sizes_4; + thread_data[i].subarray = subarray_4; + } + + // Create thread + if(i>=0 && i<4) + pthread_create(&threads[i], NULL, parallel_read, &thread_data[i]); + else // i == 4 + pthread_create(&threads[i], NULL, parallel_consolidate, &thread_data[i]); + } + + // Wait till all threads finish + for(int i=0; i<5; ++i) + pthread_join(threads[i], NULL); + + // Output result + int total_count = 0; + for(int i=0; i<4; ++i) + total_count += thread_data[i].count; + printf("Number of a1 values greater than 10: %d \n", total_count); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void *parallel_consolidate(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Consolidate array + printf("Started consolidation\n"); + tiledb_array_consolidate(data->tiledb_ctx, data->array_name); + printf("Finished consolidation\n"); + + return 0; +} + +void *parallel_read(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Only attribute "a1" is needed + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + data->tiledb_ctx, // Context + &tiledb_array, // Array object + data->array_name, // Array name + TILEDB_ARRAY_READ, // Mode + data->subarray, // Subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Read from array + printf("Started reading\n"); + tiledb_array_read(tiledb_array, data->buffers, data->buffer_sizes); + printf("Finished reading\n"); + + // Count number of a1 values greater than 10 + data->count = 0; + int* a1 = (int*) data->buffers[0]; + int num = data->buffer_sizes[0] / sizeof(int); + for(int i=0; i 10) + ++data->count; + } + + // Finalize array + tiledb_array_finalize(tiledb_array); + + return 0; +} + diff --git a/examples/src/tiledb_array_parallel_consolidate_sparse.cc b/examples/src/tiledb_array_parallel_consolidate_sparse.cc new file mode 100644 index 00000000..5b50b8da --- /dev/null +++ b/examples/src/tiledb_array_parallel_consolidate_sparse.cc @@ -0,0 +1,167 @@ +/** + * @file tiledb_array_parallel_consolidate_sparse.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 mix reading and consolidation on a sparse array in parallel. + * This program works with pthreads, but it is very easy to write a similar + * program for OpenMP. + */ + +#include "c_api.h" +#include +#include + + + +// The consolidation function to be computed in parallel +void *parallel_consolidate(void* args); + +// The function to be computed in parallel +void *parallel_read(void* args); + +// The arguments for each invocation of parallel_write +typedef struct _thread_data_t { + const TileDB_CTX* tiledb_ctx; + const char* array_name; + const void* subarray; + void** buffers; + size_t* buffer_sizes; + int count; +} thread_data_t; + +int main() { + // Initialize context with the default configuration parameters + TileDB_CTX* tiledb_ctx; + tiledb_ctx_init(&tiledb_ctx, NULL); + + // Array name + const char* array_name = "my_workspace/sparse_arrays/my_array_B"; + + // Prepare cell buffers + // --- First read --- + const int64_t subarray_1[] = { 1, 2, 1, 4 }; + int buffer_a1_1[4]; + void* buffers_1[] = { buffer_a1_1 }; + size_t buffer_sizes_1[] = { sizeof(buffer_a1_1) }; + // --- Upper right tile --- + const int64_t subarray_2[] = { 3, 4, 1, 4 }; + int buffer_a1_2[4]; + void* buffers_2[] = { buffer_a1_2 }; + size_t buffer_sizes_2[] = { sizeof(buffer_a1_2) }; + + // Initialize 2 pthreads for reading, plus 1 for consolidation + pthread_t threads[3]; + thread_data_t thread_data[2]; + + // Write in parallel + for(int i=0; i<3; ++i) { + // Populate the thread data + thread_data[i].tiledb_ctx = tiledb_ctx; + thread_data[i].array_name = array_name; + if(i==0) { // First read + thread_data[i].buffers = buffers_1; + thread_data[i].buffer_sizes = buffer_sizes_1; + thread_data[i].subarray = subarray_1; + } else if(i==1) { // Second read + thread_data[i].buffers = buffers_2; + thread_data[i].buffer_sizes = buffer_sizes_2; + thread_data[i].subarray = subarray_2; + } + + // Create thread + if(i>=0 && i<2) + pthread_create(&threads[i], NULL, parallel_read, &thread_data[i]); + else // i == 2 + pthread_create(&threads[i], NULL, parallel_consolidate, &thread_data[i]); + } + + // Wait till all threads finish + for(int i=0; i<3; ++i) + pthread_join(threads[i], NULL); + + // Output result + int total_count = 0; + for(int i=0; i<2; ++i) + total_count += thread_data[i].count; + printf("Number of a1 values greater than 5: %d \n", total_count); + + // Finalize context + tiledb_ctx_finalize(tiledb_ctx); + + return 0; +} + +void *parallel_consolidate(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Consolidate array + printf("Started consolidation\n"); + tiledb_array_consolidate(data->tiledb_ctx, data->array_name); + printf("Finished consolidation\n"); + + return 0; +} + +void *parallel_read(void* args) { + // Get arguments + thread_data_t* data = (thread_data_t*) args; + + // Only attribute "a1" is needed + const char* attributes[] = { "a1" }; + + // Initialize array + TileDB_Array* tiledb_array; + tiledb_array_init( + data->tiledb_ctx, // Context + &tiledb_array, // Array object + data->array_name, // Array name + TILEDB_ARRAY_READ, // Mode + data->subarray, // Subarray + attributes, // Subset on attributes + 1); // Number of attributes + + // Read from array + printf("Started reading\n"); + tiledb_array_read(tiledb_array, data->buffers, data->buffer_sizes); + printf("Finished reading\n"); + + // Count number of a1 values greater than 10 + data->count = 0; + int* a1 = (int*) data->buffers[0]; + int num = data->buffer_sizes[0] / sizeof(int); + for(int i=0; i 5) + ++data->count; + + // Finalize array + tiledb_array_finalize(tiledb_array); + + return 0; +} + From 6fdbdb4255c52c9f75d02acfe184896e38fb6d2c Mon Sep 17 00:00:00 2001 From: Andreas Noack Date: Tue, 10 May 2016 17:13:45 -0400 Subject: [PATCH 5/7] Substitute repeated INT64 with missing FLOAT64 --- core/src/array/array_schema.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/array/array_schema.cc b/core/src/array/array_schema.cc index 82d5b2a7..71be49df 100644 --- a/core/src/array/array_schema.cc +++ b/core/src/array/array_schema.cc @@ -1304,7 +1304,7 @@ int ArraySchema::set_types(const int* types) { if(types[i] != TILEDB_INT32 && types[i] != TILEDB_INT64 && types[i] != TILEDB_FLOAT32 && - types[i] != TILEDB_INT64 && + types[i] != TILEDB_FLOAT64 && types[i] != TILEDB_CHAR) { PRINT_ERROR("Cannot set types; Invalid type"); return TILEDB_AS_ERR; @@ -1316,7 +1316,7 @@ int ArraySchema::set_types(const int* types) { if(types[attribute_num_] != TILEDB_INT32 && types[attribute_num_] != TILEDB_INT64 && types[attribute_num_] != TILEDB_FLOAT32 && - types[attribute_num_] != TILEDB_INT64) { + types[attribute_num_] != TILEDB_FLOAT64) { PRINT_ERROR("Cannot set types; Invalid type"); return TILEDB_AS_ERR; } From 4f2b9ad2e16ede43998b443766a1159f2e162b62 Mon Sep 17 00:00:00 2001 From: Karthik Gururaj Date: Tue, 3 May 2016 09:07:44 -0700 Subject: [PATCH 6/7] getenv() may return NULL if a variable isn't defined - this happens for batch job submissions. --- core/src/misc/utils.cc | 3 ++- core/src/storage_manager/storage_manager.cc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/misc/utils.cc b/core/src/misc/utils.cc index f19a9330..63562c13 100644 --- a/core/src/misc/utils.cc +++ b/core/src/misc/utils.cc @@ -801,7 +801,8 @@ int read_from_file_with_mmap( std::string real_dir(const std::string& dir) { // Initialize current, home and root std::string current = current_dir(); - std::string home = getenv("HOME"); + auto env_home_ptr = getenv("HOME"); + std::string home = env_home_ptr ? env_home_ptr : current; std::string root = "/"; // Easy cases diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index d40b6f3a..e49507cc 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -106,7 +106,8 @@ int StorageManager::init(const char* config_filename) { // Set the TileDB home directory tiledb_home_ = TILEDB_HOME; if(tiledb_home_ == "") { - tiledb_home_ = getenv("HOME"); + auto env_home_ptr = getenv("HOME"); + tiledb_home_ = env_home_ptr ? env_home_ptr : ""; if(tiledb_home_ == "") { char cwd[1024]; if(getcwd(cwd, sizeof(cwd)) != NULL) { From 919c54f53633ccb0e6b62c82b31be6dd89966a63 Mon Sep 17 00:00:00 2001 From: spapadop Date: Thu, 12 May 2016 14:32:19 -0400 Subject: [PATCH 7/7] Fixing minor bug when deleting an array/metadata. --- core/src/storage_manager/storage_manager.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/storage_manager/storage_manager.cc b/core/src/storage_manager/storage_manager.cc index e49507cc..9717eefd 100755 --- a/core/src/storage_manager/storage_manager.cc +++ b/core/src/storage_manager/storage_manager.cc @@ -1126,7 +1126,8 @@ int StorageManager::array_clear( while((next_file = readdir(dir))) { if(!strcmp(next_file->d_name, ".") || !strcmp(next_file->d_name, "..") || - !strcmp(next_file->d_name, TILEDB_ARRAY_SCHEMA_FILENAME)) + !strcmp(next_file->d_name, TILEDB_ARRAY_SCHEMA_FILENAME) || + !strcmp(next_file->d_name, TILEDB_SM_CONSOLIDATION_FILELOCK_NAME)) continue; filename = array_real + "/" + next_file->d_name; if(is_metadata(filename)) { // Metadata @@ -1742,7 +1743,8 @@ int StorageManager::metadata_clear( while((next_file = readdir(dir))) { if(!strcmp(next_file->d_name, ".") || !strcmp(next_file->d_name, "..") || - !strcmp(next_file->d_name, TILEDB_METADATA_SCHEMA_FILENAME)) + !strcmp(next_file->d_name, TILEDB_METADATA_SCHEMA_FILENAME) || + !strcmp(next_file->d_name, TILEDB_SM_CONSOLIDATION_FILELOCK_NAME)) continue; filename = metadata_real + "/" + next_file->d_name; if(is_fragment(filename)) { // Fragment