| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include "P_CacheDoc.h" |
| |
| #include "iocore/eventsystem/Continuation.h" |
| |
| #include "tscore/ink_memory.h" |
| #include "tscore/List.h" |
| |
| #include <cstring> |
| |
| #define AGG_SIZE (4 * 1024 * 1024) // 4MB |
| #define AGG_HIGH_WATER (AGG_SIZE / 2) // 2MB |
| |
| struct CacheVC; |
| |
| class AggregateWriteBuffer |
| { |
| public: |
| AggregateWriteBuffer() |
| { |
| this->_buffer = static_cast<char *>(ats_memalign(ats_pagesize(), AGG_SIZE)); |
| memset(this->_buffer, 0, AGG_SIZE); |
| } |
| |
| ~AggregateWriteBuffer() { ats_free(this->_buffer); } |
| |
| AggregateWriteBuffer(AggregateWriteBuffer const &) = delete; |
| AggregateWriteBuffer &operator=(AggregateWriteBuffer const &) = delete; |
| |
| // move semantics not supported yet to keep things simple |
| AggregateWriteBuffer(AggregateWriteBuffer &&other) = delete; |
| AggregateWriteBuffer &operator=(AggregateWriteBuffer &&other) = delete; |
| |
| /** |
| * Check whether the internal buffer is empty. |
| * |
| * @return Returns true if the buffer is empty, otherwise false. |
| */ |
| bool is_empty() const; |
| |
| /** |
| * Add a new document to the buffer. |
| * |
| * This method copies the provided document into the buffer. |
| * |
| * This method may only be called if there is space at the current |
| * buffer position for the document, and the document has a correct len |
| * field. Use reset_buffer_pos to reset to the beginning of the buffer |
| * when it gets full. If this condition is not met, the new document may |
| * overrun the buffer. |
| * |
| * The buffer position will be updated to the end of the document's data |
| * and approx_size will be subtracted from the bytes pending aggregation. |
| * |
| * @param document: A pointer to the document to add to the buffer. It must |
| * have a correct len field, and its headers and data must follow it. This |
| * requires a pointer to a full document buffer - not just the Doc struct. |
| * @param approx_size The approximate size of all headers and data as |
| * determined by Stripe::round_to_approx_size. The document may not need |
| * this much space. |
| * |
| */ |
| void add(Doc const *document, int approx_size); |
| |
| /** |
| * Create a new document in the buffer. |
| * |
| * This method may only be called if there is space at the current |
| * buffer position for the document. Use reset_buffer_pos to reset |
| * to the beginning of the buffer when it gets full. If this |
| * condition is not met, the new document may overrun the buffer. |
| * |
| * The buffer position will be updated to the end of the document's data |
| * and approx_size will be subtracted from the bytes pending aggregation. |
| * |
| * The new document will be uninitialized. |
| * |
| * @param approx_size The approximate size of all headers and data as |
| * determined by Stripe::round_to_approx_size. The document may not need |
| * this much space. |
| * @return Returns a non-owning pointer to the new document. |
| */ |
| Doc *emplace(int approx_size); |
| |
| /** |
| * Flush the internal buffer to disk. |
| * |
| * This method should be called during shutdown. It must not be called |
| * during regular operation. |
| * |
| * Flushing the buffer only writes the buffer to disk; it does not |
| * modify the contents of the buffer. To reset the buffer, call |
| * reset_buffer_pos(). |
| * |
| * @param fd File descriptor to write to. |
| * @param write_pos The offset at which to write the buffer data. |
| * @return Returns true if all bytes were flushed, otherwise false. |
| */ |
| bool flush(int fd, off_t write_pos) const; |
| |
| /** |
| * Copy part of the buffer. |
| * |
| * The range of bytes to copy must fit within the written buffer. |
| * |
| * @param dest: The destination buffer. |
| * @param offset: Byte offset to begin copying at. |
| * @param nbytes: Number of bytes to copy. |
| */ |
| void copy_from(char *dest, int offset, size_t nbytes) const; |
| |
| Queue<CacheVC, Continuation::Link_link> &get_pending_writers(); |
| char *get_buffer(); |
| int get_buffer_pos() const; |
| void seek(int offset); |
| void reset_buffer_pos(); |
| int get_bytes_pending_aggregation() const; |
| void add_bytes_pending_aggregation(int size); |
| |
| private: |
| Queue<CacheVC, Continuation::Link_link> _pending_writers; |
| char *_buffer = nullptr; |
| int _bytes_pending_aggregation = 0; |
| int _buffer_pos = 0; |
| }; |
| |
| inline Queue<CacheVC, Continuation::Link_link> & |
| AggregateWriteBuffer::get_pending_writers() |
| { |
| return this->_pending_writers; |
| } |
| |
| inline char * |
| AggregateWriteBuffer::get_buffer() |
| { |
| return this->_buffer; |
| } |
| |
| inline int |
| AggregateWriteBuffer::get_buffer_pos() const |
| { |
| return this->_buffer_pos; |
| } |
| |
| inline void |
| AggregateWriteBuffer::seek(int offset) |
| { |
| this->_buffer_pos = offset; |
| } |
| |
| inline void |
| AggregateWriteBuffer::reset_buffer_pos() |
| { |
| this->seek(0); |
| } |
| |
| inline int |
| AggregateWriteBuffer::get_bytes_pending_aggregation() const |
| { |
| return this->_bytes_pending_aggregation; |
| } |
| |
| inline void |
| AggregateWriteBuffer::add_bytes_pending_aggregation(int size) |
| { |
| this->_bytes_pending_aggregation += size; |
| } |
| |
| inline bool |
| AggregateWriteBuffer::is_empty() const |
| { |
| return this->_buffer_pos == 0; |
| } |