diff options
author | Sergey Petrunya <psergey@askmonty.org> | 2010-09-28 12:20:16 +0400 |
---|---|---|
committer | Sergey Petrunya <psergey@askmonty.org> | 2010-09-28 12:20:16 +0400 |
commit | 8e59978b08569395a5ae24bd46c8db8548d18dd9 (patch) | |
tree | ca27034c30d99f480c27673e02fa70401f8dbdea /sql/sql_lifo_buffer.h | |
parent | 4f56acb676f273b3e7f92311fd557d4fb7c4068c (diff) | |
download | mariadb-git-8e59978b08569395a5ae24bd46c8db8548d18dd9.tar.gz |
Move Lifo_buffer to separate file.
Diffstat (limited to 'sql/sql_lifo_buffer.h')
-rw-r--r-- | sql/sql_lifo_buffer.h | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/sql/sql_lifo_buffer.h b/sql/sql_lifo_buffer.h new file mode 100644 index 00000000000..dc0ed30ab43 --- /dev/null +++ b/sql/sql_lifo_buffer.h @@ -0,0 +1,412 @@ +/** + @defgroup Bi-directional LIFO buffers used by DS-MRR implementation + @{ +*/ + +class Forward_lifo_buffer; +class Backward_lifo_buffer; + + +/* + A base class for in-memory buffer used by DS-MRR implementation. Common + properties: + - The buffer is last-in-first-out, i.e. elements that are written last are + read first. + - The buffer contains fixed-size elements. The elements are either atomic + byte sequences or pairs of them. + - The buffer resides in the memory provided by the user. It is possible to + = dynamically (ie. between write operations) add ajacent memory space to + the buffer + = dynamically remove unused space from the buffer. + The intent of this is to allow to have two buffers on adjacent memory + space, one is being read from (and so its space shrinks), while the other + is being written to (and so it needs more and more space). + + There are two concrete classes, Forward_lifo_buffer and Backward_lifo_buffer. +*/ + +class Lifo_buffer +{ +protected: + /** + Pointers to data to be written. write() call will assume that + (*write_ptr1) points to size1 bytes of data to be written. + If write_ptr2 != NULL then the buffer stores pairs, and (*write_ptr2) + points to size2 bytes of data that form the second component. + */ + uchar **write_ptr1; + size_t size1; + uchar **write_ptr2; + size_t size2; + + /** + read() will do reading by storing pointer to read data into *read_ptr1 (if + the buffer stores atomic elements), or into {*read_ptr1, *read_ptr2} (if + the buffer stores pairs). + */ + uchar **read_ptr1; + uchar **read_ptr2; + + uchar *start; /**< points to start of buffer space */ + uchar *end; /**< points to just beyond the end of buffer space */ +public: + + enum enum_direction { + BACKWARD=-1, /**< buffer is filled/read from bigger to smaller memory addresses */ + FORWARD=1 /**< buffer is filled/read from smaller to bigger memory addresses */ + }; + + virtual enum_direction type() = 0; + + /* Buffer space control functions */ + + /** Let the buffer store data in the given space. */ + void set_buffer_space(uchar *start_arg, uchar *end_arg) + { + start= start_arg; + end= end_arg; + TRASH(start, end - start); + reset(); + } + + /** + Specify where write() should get the source data from, as well as source + data size. + */ + void setup_writing(uchar **data1, size_t len1, uchar **data2, size_t len2) + { + write_ptr1= data1; + size1= len1; + write_ptr2= data2; + size2= len2; + } + + /** + Specify where read() should store pointers to read data, as well as read + data size. The sizes must match those passed to setup_writing(). + */ + void setup_reading(uchar **data1, size_t len1, uchar **data2, size_t len2) + { + read_ptr1= data1; + DBUG_ASSERT(len1 == size1); + read_ptr2= data2; + DBUG_ASSERT(len2 == size2); + } + + bool can_write() + { + return have_space_for(size1 + (write_ptr2 ? size2 : 0)); + } + virtual void write() = 0; + + bool is_empty() { return used_size() == 0; } + virtual bool read() = 0; + + void sort(qsort2_cmp cmp_func, void *cmp_func_arg) + { + uint elem_size= size1 + (write_ptr2 ? size2 : 0); + uint n_elements= used_size() / elem_size; + my_qsort2(used_area(), n_elements, elem_size, cmp_func, cmp_func_arg); + } + + virtual void reset() = 0; + virtual uchar *end_of_space() = 0; +protected: + bool have_data(size_t bytes) + { + return (used_size() >= bytes); + } + virtual bool have_space_for(size_t bytes) = 0; + virtual size_t used_size() = 0; + +public: + + virtual void remove_unused_space(uchar **unused_start, uchar **unused_end)=0; + virtual uchar *used_area() = 0; + + /** Iterator to walk over contents of the buffer without reading it. */ + class Iterator + { + public: + virtual void init(Lifo_buffer *buf) = 0; + /* + Read the next value. The calling convention is the same as buf->read() + has. + + @retval FALSE - ok + @retval TRUE - EOF, reached the end of the buffer + */ + virtual bool read_next()= 0; + virtual ~Iterator() {} + protected: + Lifo_buffer *buf; + virtual uchar *get_next(size_t nbytes)=0; + }; + virtual ~Lifo_buffer() {}; + + friend class Forward_iterator; + friend class Backward_iterator; +}; + + +/** + Forward LIFO buffer + + The buffer that is being written to from start to end and read in the + reverse. 'pos' points to just beyond the end of used space. + + It is possible to grow/shink the buffer at the end bound + + used space unused space + *==============*-----------------* + ^ ^ ^ + | | +--- end + | +---- pos + +--- start +*/ + +class Forward_lifo_buffer: public Lifo_buffer +{ + uchar *pos; +public: + enum_direction type() { return FORWARD; } + size_t used_size() + { + return pos - start; + } + void reset() + { + pos= start; + } + uchar *end_of_space() { return pos; } + bool have_space_for(size_t bytes) + { + return (pos + bytes < end); + } + + void write() + { + write_bytes(*write_ptr1, size1); + if (write_ptr2) + write_bytes(*write_ptr2, size2); + } + void write_bytes(const uchar *data, size_t bytes) + { + DBUG_ASSERT(have_space_for(bytes)); + memcpy(pos, data, bytes); + pos += bytes; + } + uchar *read_bytes(size_t bytes) + { + DBUG_ASSERT(have_data(bytes)); + pos= pos - bytes; + return pos; + } + bool read() + { + if (!have_data(size1 + (read_ptr2 ? size2 : 0))) + return TRUE; + if (read_ptr2) + *read_ptr2= read_bytes(size2); + *read_ptr1= read_bytes(size1); + return FALSE; + } + void remove_unused_space(uchar **unused_start, uchar **unused_end) + { + DBUG_ASSERT(0); /* Don't need this yet */ + } + /** + Add more space to the buffer. The caller is responsible that the space + being added is adjacent to the end of the buffer. + + @param unused_start Start of space + @param unused_end End of space + */ + void grow(uchar *unused_start, uchar *unused_end) + { + DBUG_ASSERT(unused_end >= unused_start); + DBUG_ASSERT(end == unused_start); + TRASH(unused_start, unused_end - unused_start); + end= unused_end; + } + /* Return pointer to start of the memory area that is occupied by the data */ + uchar *used_area() { return start; } + friend class Forward_iterator; +}; + + +/** + Iterator for Forward_lifo_buffer +*/ + +class Forward_iterator : public Lifo_buffer::Iterator +{ + uchar *pos; + + /** Return pointer to next chunk of nbytes bytes and avance over it */ + uchar *get_next(size_t nbytes) + { + if (pos - nbytes < ((Forward_lifo_buffer*)buf)->start) + return NULL; + pos -= nbytes; + return pos; + } +public: + bool read_next() + { + uchar *res; + if (buf->read_ptr2) + { + if ((res= get_next(buf->size2))) + { + *(buf->read_ptr2)= res; + *buf->read_ptr1= get_next(buf->size1); + return FALSE; + } + } + else + { + if ((res= get_next(buf->size1))) + { + *(buf->read_ptr1)= res; + return FALSE; + } + } + return TRUE; /* EOF */ + } + + void init(Lifo_buffer *buf_arg) + { + DBUG_ASSERT(buf_arg->type() == Lifo_buffer::FORWARD); + buf= buf_arg; + pos= ((Forward_lifo_buffer*)buf)->pos; + } +}; + + +/** + Backward LIFO buffer + + The buffer that is being written to from start to end and read in the + reverse. 'pos' points to the start of used space. + + It is possible to grow/shink the buffer at the start. + + unused space used space + *--------------*=================* + ^ ^ ^ + | | +--- end + | +---- pos + +--- start +*/ +class Backward_lifo_buffer: public Lifo_buffer +{ + uchar *pos; +public: + enum_direction type() { return BACKWARD; } + + size_t used_size() + { + return end - pos; + } + void reset() + { + pos= end; + } + uchar *end_of_space() { return end; } + bool have_space_for(size_t bytes) + { + return (pos - bytes >= start); + } + void write() + { + if (write_ptr2) + write_bytes(*write_ptr2, size2); + write_bytes(*write_ptr1, size1); + } + void write_bytes(const uchar *data, size_t bytes) + { + DBUG_ASSERT(have_space_for(bytes)); + pos -= bytes; + memcpy(pos, data, bytes); + } + bool read() + { + if (!have_data(size1 + (read_ptr2 ? size2 : 0))) + return TRUE; + *read_ptr1= read_bytes(size1); + if (read_ptr2) + *read_ptr2= read_bytes(size2); + return FALSE; + } + uchar *read_bytes(size_t bytes) + { + DBUG_ASSERT(have_data(bytes)); + uchar *ret= pos; + pos= pos + bytes; + return ret; + } + /** + Stop using/return the unused part of the space + @param unused_start OUT Start of the unused space + @param unused_end OUT End of the unused space + */ + void remove_unused_space(uchar **unused_start, uchar **unused_end) + { + *unused_start= start; + *unused_end= pos; + start= pos; + } + void grow(uchar *unused_start, uchar *unused_end) + { + DBUG_ASSERT(0); /* Not used for backward buffers */ + } + /* Return pointer to start of the memory area that is occupied by the data */ + uchar *used_area() { return pos; } + friend class Backward_iterator; +}; + + +/** + Iterator for Backward_lifo_buffer +*/ + +class Backward_iterator : public Lifo_buffer::Iterator +{ + uchar *pos; + /* Return pointer to next chunk of nbytes bytes and advance over it */ + uchar *get_next(size_t nbytes) + { + if (pos + nbytes > ((Backward_lifo_buffer*)buf)->end) + return NULL; + uchar *res= pos; + pos += nbytes; + return res; + } +public: + bool read_next() + { + /* + Always read the first component first (if the buffer is backwards, we + have written the second component first). + */ + uchar *res; + if ((res= get_next(buf->size1))) + { + *(buf->read_ptr1)= res; + if (buf->read_ptr2) + *buf->read_ptr2= get_next(buf->size2); + return FALSE; + } + return TRUE; /* EOF */ + } + void init(Lifo_buffer *buf_arg) + { + DBUG_ASSERT(buf_arg->type() == Lifo_buffer::BACKWARD); + buf= buf_arg; + pos= ((Backward_lifo_buffer*)buf)->pos; + } +}; + + + |