summaryrefslogtreecommitdiff
path: root/mysys/mf_iocache.c
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2016-09-23 14:18:29 +0300
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2016-09-24 15:12:34 +0200
commit047963922c0c89c76f82cd14eb05ec56c19a91e9 (patch)
treeb16d867934146b3c38961830f4e43ca08d890982 /mysys/mf_iocache.c
parent6e4015727a60c5b98bdc9c4590adc687dacc4876 (diff)
downloadmariadb-git-047963922c0c89c76f82cd14eb05ec56c19a91e9.tar.gz
MDEV-9736: Window functions: multiple cursors to read filesort result
Add support for having multiple IO_CACHEs with type=READ_CACHE to share the file they are reading from. Each IO_CACHE keeps its own in-memory buffer. When doing a read or seek operation on the file, it notifies other IO_CACHEs that the file position has been changed. Make Rowid_seq_cursor use cloned IO_CACHE when reading filesort result.
Diffstat (limited to 'mysys/mf_iocache.c')
-rw-r--r--mysys/mf_iocache.c148
1 files changed, 134 insertions, 14 deletions
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index 635e544d367..77581a51d75 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -193,6 +193,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
info->alloced_buffer = 0;
info->buffer=0;
info->seek_not_done= 0;
+ info->next_file_user= NULL;
if (file >= 0)
{
@@ -328,6 +329,101 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
DBUG_RETURN(0);
} /* init_io_cache */
+
+
+/*
+ Initialize the slave IO_CACHE to read the same file (and data)
+ as master does.
+
+ One can create multiple slaves from a single master. Every slave and master
+ will have independent file positions.
+
+ The master must be a non-shared READ_CACHE.
+ It is assumed that no more reads are done after a master and/or a slave
+ has been freed (this limitation can be easily lifted).
+*/
+
+int init_slave_io_cache(IO_CACHE *master, IO_CACHE *slave)
+{
+ uchar *slave_buf;
+ DBUG_ASSERT(master->type == READ_CACHE);
+ DBUG_ASSERT(!master->share);
+ DBUG_ASSERT(master->alloced_buffer);
+
+ if (!(slave_buf= (uchar*)my_malloc(master->buffer_length, MYF(0))))
+ {
+ return 1;
+ }
+ memcpy(slave, master, sizeof(IO_CACHE));
+ slave->buffer= slave_buf;
+
+ memcpy(slave->buffer, master->buffer, master->buffer_length);
+ slave->read_pos= slave->buffer + (master->read_pos - master->buffer);
+ slave->read_end= slave->buffer + (master->read_end - master->buffer);
+
+ DBUG_ASSERT(master->current_pos == &master->read_pos);
+ slave->current_pos= &slave->read_pos;
+ DBUG_ASSERT(master->current_end == &master->read_end);
+ slave->current_end= &slave->read_end;
+
+ if (master->next_file_user)
+ {
+ IO_CACHE *p;
+ for (p= master->next_file_user;
+ p->next_file_user !=master;
+ p= p->next_file_user)
+ {}
+
+ p->next_file_user= slave;
+ slave->next_file_user= master;
+ }
+ else
+ {
+ slave->next_file_user= master;
+ master->next_file_user= slave;
+ }
+ return 0;
+}
+
+
+void end_slave_io_cache(IO_CACHE *cache)
+{
+ my_free(cache->buffer);
+}
+
+/*
+ Seek a read io cache to a given offset
+*/
+void seek_io_cache(IO_CACHE *cache, my_off_t needed_offset)
+{
+ my_off_t cached_data_start= cache->pos_in_file;
+ my_off_t cached_data_end= cache->pos_in_file + (cache->read_pos -
+ cache->buffer);
+ if (needed_offset >= cached_data_start &&
+ needed_offset < cached_data_end)
+ {
+ /*
+ The offset we're seeking to is in the buffer.
+ Move buffer's read position accordingly
+ */
+ cache->read_pos= cache->buffer + (needed_offset - cached_data_start);
+ }
+ else
+ {
+ if (needed_offset > cache->end_of_file)
+ needed_offset= cache->end_of_file;
+ /*
+ The offset we're seeking to is not in the buffer.
+ - Set the buffer to be exhausted.
+ - Make the next read to a mysql_file_seek() call to the required
+ offset (but still use aligned reads).
+ */
+ cache->read_pos= cache->read_end;
+ cache->seek_not_done= 1;
+ cache->pos_in_file= (needed_offset / IO_SIZE) * IO_SIZE;
+ }
+}
+
/* Wait until current request is ready */
#ifdef HAVE_AIOWAIT
@@ -583,6 +679,17 @@ int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count)
{
/* No error, reset seek_not_done flag. */
info->seek_not_done= 0;
+
+ if (info->next_file_user)
+ {
+ IO_CACHE *c;
+ for (c= info->next_file_user;
+ c!= info;
+ c= c->next_file_user)
+ {
+ c->seek_not_done= 1;
+ }
+ }
}
else
{
@@ -671,22 +778,35 @@ int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count)
DBUG_RETURN(0); /* EOF */
}
}
- else if ((length= mysql_file_read(info->file,info->buffer, max_length,
+ else
+ {
+ if (info->next_file_user)
+ {
+ IO_CACHE *c;
+ for (c= info->next_file_user;
+ c!= info;
+ c= c->next_file_user)
+ {
+ c->seek_not_done= 1;
+ }
+ }
+ if ((length= mysql_file_read(info->file,info->buffer, max_length,
info->myflags)) < Count ||
length == (size_t) -1)
- {
- /*
- We got an read error, or less than requested (end of file).
- If not a read error, copy, what we got.
- */
- if (length != (size_t) -1)
- memcpy(Buffer, info->buffer, length);
- info->pos_in_file= pos_in_file;
- /* For a read error, return -1, otherwise, what we got in total. */
- info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
- info->read_pos=info->read_end=info->buffer;
- info->seek_not_done=1;
- DBUG_RETURN(1);
+ {
+ /*
+ We got an read error, or less than requested (end of file).
+ If not a read error, copy, what we got.
+ */
+ if (length != (size_t) -1)
+ memcpy(Buffer, info->buffer, length);
+ info->pos_in_file= pos_in_file;
+ /* For a read error, return -1, otherwise, what we got in total. */
+ info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
+ info->read_pos=info->read_end=info->buffer;
+ info->seek_not_done=1;
+ DBUG_RETURN(1);
+ }
}
/*
Count is the remaining number of bytes requested.