/** * @file filter_buffer.h * * @section LICENSE * * The MIT License * * @copyright Copyright (c) 2017-2020 TileDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * @section DESCRIPTION * * This file declares class FilterBuffer. */ #ifndef TILEDB_FILTER_BUFFER_H #define TILEDB_FILTER_BUFFER_H #include #include #include #include "tiledb/common/status.h" #include "tiledb/sm/buffer/buffer.h" #include "tiledb/sm/buffer/const_buffer.h" using namespace tiledb::common; namespace tiledb { namespace sm { class Buffer; class FilterStorage; /** * Class that manages an ordered list of multiple separate buffers and offers as * a single contiguous view on the underlying bytes. */ class FilterBuffer { public: /** Constructor. */ FilterBuffer(); /** * Constructor. * * @param storage FilterStorage instance to use for buffer * allocation/management. */ explicit FilterBuffer(FilterStorage* storage); /** * Advance the offset (global across buffers) by the given number of bytes. */ void advance_offset(uint64_t nbytes); /** * Append a new buffer "view" to the end of the ordered list of buffers and * reset the offset. * * A buffer "view" is just a pointer into an existing buffer and associated * length. No bytes are copied by this function, but the underlying bytes * behind the view are treated as a part of this FilterBuffer for reads and * writes. * * @param other Buffer to "view" into * @param offset Offset into other * @param nbytes Length of the view, starting at offset. * @return Status */ Status append_view( const FilterBuffer* other, uint64_t offset, uint64_t nbytes); /** * Append a new buffer "view" to the end of the ordered list of buffers and * reset the offset. * * A buffer "view" is just a pointer into an existing buffer and associated * length. No bytes are copied by this function, but the underlying bytes * behind the view are treated as a part of this FilterBuffer for reads and * writes. * * @param other Buffer to "view" into * @return Status */ Status append_view(const FilterBuffer* other); /** * Return a list of ConstBuffers representing the multiple separate buffers * making up this FilterBuffer. */ std::vector buffers() const; /** * Return a pointer to the underlying buffer at the given index. It is allowed * to modify the contents, and offset of the returned buffer. * * Note the returned buffer is not guaranteed to "own" its data. If the * returned buffer does own its data, it is allowed to realloc and resize it. * * @param index Index into the underlying list of buffers. * @return Pointer to buffer (or nullptr for invalid index). */ Buffer* buffer_ptr(unsigned index) const; /** * Reset the global offset and removes all underlying buffers. * @return Status */ Status clear(); /** * Copy the underlying bytes contiguously to the given buffer. * * @param dest Buffer to copy to * @return Status */ Status copy_to(Buffer* dest) const; /** * Copy the underlying bytes contiguously to the given memory region. * * @param dest Memory region to copy to * @return Status */ Status copy_to(void* dest) const; /** * Returns a ConstBuffer wrapping data at the current offset of the given * length. Returns an error if this is not possible (e.g. the region would * span multiple discontiguous regions of memory). * * @param nbytes Size of ConstBuffer * @param buffer Set to the resulting ConstBuffer * @return Status */ Status get_const_buffer(uint64_t nbytes, ConstBuffer* buffer) const; /** * Initialize this FilterBuffer with a preallocated buffer view. * * @param data Allocation to view into * @param nbytes Length of the view * @return Status */ Status init(void* data, uint64_t nbytes); /** Return the number of underlying buffers. */ uint64_t num_buffers() const; /** Return the current offset, global across all buffers. */ uint64_t offset() const; /** * Prepend a new buffer to the front of the list of underlying buffers, and * reset the offset. * * The new buffer is guaranteed to have at least nbytes allocated, but note * the buffer is not guaranteed to own its data (i.e. you may not be able to * realloc buffers prepended with this function). * * @param nbytes Allocation size of the new buffer. * @return Status */ Status prepend_buffer(uint64_t nbytes); /** * Read a number of bytes from the current global offset into the given * buffer. * * @param buffer Buffer to read into * @param nbytes Number of bytes to read * @return Status */ Status read(void* buffer, uint64_t nbytes); /** Return whether this buffer is read-only. */ bool read_only() const; /** Reset the global offset to 0. */ void reset_offset(); /** * Sets this buffer to a "fixed allocation." This can only happen when there * are no buffers already being managed. * * If a FilterBuffer is a fixed allocation, only a single prepend or * append_view operation is allowed on it. Prepending will return a buffer * encapsulating the fixed allocation. Appending a view will copy the viewed * data into the fixed allocation. * * Reset to the normal state by calling clear(). * * @param buffer Pointer to fixed allocation * @param nbytes Size of fixed allocation * @return Status */ Status set_fixed_allocation(void* buffer, uint64_t nbytes); /** Set the global offset to the given value. */ void set_offset(uint64_t offset); /** Set the read-only state to the given value. */ void set_read_only(bool read_only); /** Return the total size of all underlying buffers. */ uint64_t size() const; /** * Swap (no copying) the contents of this FilterBuffer with the other. * * @param other Buffer to swap with * @return Status */ Status swap(FilterBuffer& other); /** * Return a typed pointer to the value at the current global offset. * * @tparam T Type of value to point to * @return Pointer to value */ template T* value_ptr() const { return (T*)current_buffer_->buffer()->value_ptr(current_relative_offset_); } /** * Write a number of bytes from the given buffer at the current global offset. * * @param buffer Buffer to copy from * @param nbytes Number of bytes to copy * @return Status */ Status write(const void* buffer, uint64_t nbytes); /** * Write a number of bytes from the given buffer at the current global offset. * * The given buffer's offset is not modified. * * @param buffer Buffer to copy from * @param nbytes Number of bytes to copy * @return Status */ Status write(FilterBuffer* buffer, uint64_t nbytes); private: /** * Helper class that represents a Buffer or a "view" on an underlying Buffer. * In either case a shared_ptr to the underlying Buffer is maintained, which * prevents FilterStorage from marking a buffer as available as long as there * is still an active view on it. */ class BufferOrView { public: /** * Constructor. Initializes a non-view on the given Buffer. */ explicit BufferOrView(const std::shared_ptr& buffer); /** * Constructor. Initializes a view on the given Buffer. * * @param buffer Buffer to view * @param offset Offset in buffer where view will start * @param nbytes Length of view in bytes. */ BufferOrView( const std::shared_ptr& buffer, uint64_t offset, uint64_t nbytes); /** Move constructor. */ BufferOrView(BufferOrView&& other); /** Deleted copy constructor (due to the unique_ptr). */ BufferOrView(const BufferOrView& other) = delete; /** * Return a Buffer instance used to access the underlying data, which will * either be the underlying buffer itself, or a view on it. */ Buffer* buffer() const; /** * Constructs and returns a new view on this instance. * * @param offset Offset in this buffer where view will start * @param nbytes Length of view * @return The new view */ BufferOrView get_view(uint64_t offset, uint64_t nbytes) const; /** Return true if this instance is a view. */ bool is_view() const; /** Return a pointer to the underlying buffer. */ std::shared_ptr underlying_buffer() const; private: /** * Pointer to the underlying buffer, regardless of whether this instance is * a view or not. */ std::shared_ptr underlying_buffer_; /** True if this instance is a view on the underlying buffer. */ bool is_view_; /** * If this instance is a view, the view Buffer (which does not own its * data). Otherwise nullptr. */ std::unique_ptr view_; }; /** * Ordered list of underlying Buffers (not all of which may own their * allocations). */ std::list buffers_; /** * Linked list node (from buffers_) of the buffer containing the current * global offset. */ std::list::const_iterator current_buffer_; /** * Relative offset into the current buffer, corresponding to the current * global offset. */ uint64_t current_relative_offset_; /** Pointer to the fixed allocation, if any. */ void* fixed_allocation_data_; /** * If true, a prepend or append operation is allowed when a fixed allocation * is set. */ bool fixed_allocation_op_allowed_; /** Current global offset. */ uint64_t offset_; /** * If true, the buffer can be read from, and the offset can be modified, but * not otherwise modified. */ bool read_only_; /** Buffer pool used for prepend operations. */ FilterStorage* storage_; /** * Convert a global offset into a buffer, relative offset pair. * * @param offset Global offset * @param list_node Set to the list node of the buffer containing the given * global offset. * @param relative_offset Set to the relative offset in the buffer containing * the given global offset. * @return Status */ Status get_relative_offset( uint64_t offset, std::list::const_iterator* list_node, uint64_t* relative_offset) const; }; } // namespace sm } // namespace tiledb #endif // TILEDB_FILTER_BUFFER_H