/** * @file buffer_list.cc * * @section LICENSE * * The MIT License * * @copyright Copyright (c) 2019-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 implements class BufferList. */ #include "tiledb/sm/buffer/buffer_list.h" #include "tiledb/common/logger.h" #include "tiledb/sm/buffer/buffer.h" using namespace tiledb::common; namespace tiledb { namespace sm { BufferList::BufferList() : current_buffer_index_(0) , current_relative_offset_(0) , offset_(0) { } Status BufferList::add_buffer(Buffer&& buffer) { buffers_.emplace_back(std::move(buffer)); return Status::Ok(); } Status BufferList::get_buffer(uint64_t index, Buffer** buffer) { if (index >= buffers_.size()) return LOG_STATUS(Status::BufferError( "Cannot get buffer " + std::to_string(index) + " from buffer list; index out of bounds.")); *buffer = &buffers_[index]; return Status::Ok(); } uint64_t BufferList::num_buffers() const { return buffers_.size(); } Status BufferList::read(void* dest, uint64_t nbytes) { uint64_t bytes_read = 0; RETURN_NOT_OK(read(dest, nbytes, &bytes_read)); if (bytes_read != nbytes) return LOG_STATUS(Status::BufferError( "BufferList error; could not read requested byte count.")); return Status::Ok(); } Status BufferList::read_at_most( void* dest, uint64_t nbytes, uint64_t* bytes_read) { return read(dest, nbytes, bytes_read); } Status BufferList::read(void* dest, uint64_t nbytes, uint64_t* bytes_read) { uint64_t bytes_left = nbytes; uint64_t dest_offset = 0; auto dest_ptr = static_cast(dest); // Starting from current buffer, read bytes until finished. for (size_t idx = current_buffer_index_; idx < buffers_.size() && bytes_left > 0; ++idx) { Buffer& src = buffers_[idx]; src.set_offset(current_relative_offset_); // Read from buffer const uint64_t bytes_in_src = src.size() - current_relative_offset_; const uint64_t bytes_from_src = std::min(bytes_in_src, bytes_left); // If the destination pointer is not null, then read into it // if it is null then we are just seeking if (dest_ptr != nullptr) RETURN_NOT_OK(src.read(dest_ptr + dest_offset, bytes_from_src)); bytes_left -= bytes_from_src; dest_offset += bytes_from_src; // Always keep current buffer and offset in sync. current_buffer_index_ = idx; current_relative_offset_ += bytes_from_src; if (bytes_left > 0) { // Moving to next buffer; set relative offset to 0. current_relative_offset_ = 0; } } if (bytes_read != nullptr) *bytes_read = nbytes - bytes_left; return Status::Ok(); } Status BufferList::seek(off_t offset, int whence) { switch (whence) { case SEEK_SET: // We just reset the offsets to 0/start, then fall through to seek_current reset_offset(); // fall through case SEEK_CUR: return read(nullptr, offset); case SEEK_END: return Status::BufferError( "SEEK_END operation not supported for BufferList"); default: return Status::BufferError("Invalid seek operation for BufferList"); } return Status::Ok(); } void BufferList::reset_offset() { offset_ = 0; current_buffer_index_ = 0; current_relative_offset_ = 0; } uint64_t BufferList::total_size() const { uint64_t size = 0; for (const auto& b : buffers_) size += b.size(); return size; } } // namespace sm } // namespace tiledb