~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/internal/mf_iocache.cc

  • Committer: Stewart Smith
  • Date: 2010-08-12 16:48:46 UTC
  • mto: This revision was merged to the branch mainline in revision 1707.
  • Revision ID: stewart@flamingspork.com-20100812164846-s9bhy47g60bvqs41
bug lp:611379 Equivalent queries with Impossible where return different results

The following two equivalent queries return different results in maria 5.2 and 5.3 (and identical results in mysql 5.5.5) :

SELECT SUM( DISTINCT table1 .`pk` ) FROM B table1 STRAIGHT_JOIN ( BB table2 JOIN CC ON table2 .`col_varchar_key` ) ON table2 .`pk` ;

SELECT * FROM ( SELECT SUM( DISTINCT table1 .`pk` ) FROM B table1 STRAIGHT_JOIN ( BB table2 JOIN CC ON table2 .`col_varchar_key` ) ON table2 .`pk` );

MariaDB returns 0 on the second query and NULL on the first, whereas MySQL returns NULL on both. In MariaDB, both EXPLAIN plans agree that "Impossible WHERE noticed after reading const tables"



We have some slightly different output in drizzle:

main.bug_lp611379 [ fail ]
drizzletest: At line 9: query 'explain select * from (select sum(distinct t1.a) from t1,t2 where t1.a=t2.a)
as t' failed: 1048: Column 'sum(distinct t1.a)' cannot be null

but the fix gets us the correct query results, although with slightly different execution plans.



This fix is directly ported from MariaDB.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Cashing of files with only does (sequential) read or writes of fixed-
47
47
  write buffer to the read buffer before we start to reuse it.
48
48
*/
49
49
 
50
 
#include <config.h>
 
50
#include "config.h"
51
51
 
52
 
#include <drizzled/internal/my_sys.h>
53
 
#include <drizzled/internal/m_string.h>
54
 
#include <drizzled/drizzled.h>
 
52
#include "drizzled/internal/my_sys.h"
 
53
#include "drizzled/internal/m_string.h"
55
54
#ifdef HAVE_AIOWAIT
56
 
#include <drizzled/error.h>
57
 
#include <drizzled/internal/aio_result.h>
 
55
#include "drizzled/error.h"
 
56
#include "drizzled/internal/aio_result.h"
58
57
static void my_aiowait(my_aio_result *result);
59
58
#endif
60
 
#include <drizzled/internal/iocache.h>
 
59
#include "drizzled/internal/iocache.h"
61
60
#include <errno.h>
62
61
#include <drizzled/util/test.h>
63
62
#include <stdlib.h>
70
69
namespace internal
71
70
{
72
71
 
73
 
static int _my_b_read(st_io_cache *info, unsigned char *Buffer, size_t Count);
74
 
static int _my_b_write(st_io_cache *info, const unsigned char *Buffer, size_t Count);
 
72
static int _my_b_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count);
 
73
static int _my_b_write(register IO_CACHE *info, const unsigned char *Buffer, size_t Count);
75
74
 
76
75
/**
77
76
 * @brief
78
 
 *   Lock appends for the st_io_cache if required (need_append_buffer_lock)   
 
77
 *   Lock appends for the IO_CACHE if required (need_append_buffer_lock)   
79
78
 */
80
79
inline
81
 
static void lock_append_buffer(st_io_cache *, int )
 
80
static void lock_append_buffer(register IO_CACHE *, int )
82
81
{
83
82
}
84
83
 
85
84
/**
86
85
 * @brief
87
 
 *   Unlock appends for the st_io_cache if required (need_append_buffer_lock)   
 
86
 *   Unlock appends for the IO_CACHE if required (need_append_buffer_lock)   
88
87
 */
89
88
inline
90
 
static void unlock_append_buffer(st_io_cache *, int )
 
89
static void unlock_append_buffer(register IO_CACHE *, int )
91
90
{
92
91
}
93
92
 
114
113
 
115
114
/**
116
115
 * @brief 
117
 
 *   Setup internal pointers inside st_io_cache
 
116
 *   Setup internal pointers inside IO_CACHE
118
117
 * 
119
118
 * @details
120
 
 *   This is called on automatically on init or reinit of st_io_cache
121
 
 *   It must be called externally if one moves or copies an st_io_cache object.
 
119
 *   This is called on automatically on init or reinit of IO_CACHE
 
120
 *   It must be called externally if one moves or copies an IO_CACHE object.
122
121
 * 
123
122
 * @param info Cache handler to setup
124
123
 */
125
 
void st_io_cache::setup_io_cache()
 
124
void setup_io_cache(IO_CACHE* info)
126
125
{
127
126
  /* Ensure that my_b_tell() and my_b_bytes_in_cache works */
128
 
  if (type == WRITE_CACHE)
 
127
  if (info->type == WRITE_CACHE)
129
128
  {
130
 
    current_pos= &write_pos;
131
 
    current_end= &write_end;
 
129
    info->current_pos= &info->write_pos;
 
130
    info->current_end= &info->write_end;
132
131
  }
133
132
  else
134
133
  {
135
 
    current_pos= &read_pos;
136
 
    current_end= &read_end;
 
134
    info->current_pos= &info->read_pos;
 
135
    info->current_end= &info->read_end;
137
136
  }
138
137
}
139
138
 
140
139
 
141
 
void st_io_cache::init_functions()
 
140
static void
 
141
init_functions(IO_CACHE* info)
142
142
{
 
143
  enum cache_type type= info->type;
143
144
  switch (type) {
144
145
  case READ_NET:
145
146
    /*
151
152
    */
152
153
    break;
153
154
  default:
154
 
    read_function = _my_b_read;
155
 
    write_function = _my_b_write;
 
155
    info->read_function = _my_b_read;
 
156
    info->write_function = _my_b_write;
156
157
  }
157
158
 
158
 
  setup_io_cache();
 
159
  setup_io_cache(info);
159
160
}
160
161
 
161
162
/**
162
163
 * @brief
163
 
 *   Initialize an st_io_cache object
 
164
 *   Initialize an IO_CACHE object
164
165
 *
 
166
 * @param info Cache handler to initialize
165
167
 * @param file File that should be associated with the handler
166
168
 *                 If == -1 then real_open_cached_file() will be called when it's time to open file.
167
169
 * @param cachesize Size of buffer to allocate for read/write
175
177
 * @retval 0 success
176
178
 * @retval # error
177
179
 */
178
 
int st_io_cache::init_io_cache(int file_arg, size_t cachesize,
179
 
                               enum cache_type type_arg, my_off_t seek_offset,
180
 
                               bool use_async_io, myf cache_myflags)
 
180
int init_io_cache(IO_CACHE *info, int file, size_t cachesize,
 
181
                  enum cache_type type, my_off_t seek_offset,
 
182
                  bool use_async_io, myf cache_myflags)
181
183
{
182
184
  size_t min_cache;
183
185
  off_t pos;
184
 
  my_off_t end_of_file_local= ~(my_off_t) 0;
 
186
  my_off_t end_of_file= ~(my_off_t) 0;
185
187
 
186
 
  file= file_arg;
187
 
  type= TYPE_NOT_SET;       /* Don't set it until mutex are created */
188
 
  pos_in_file= seek_offset;
189
 
  pre_close = pre_read = post_read = 0;
190
 
  arg = 0;
191
 
  alloced_buffer = 0;
192
 
  buffer=0;
193
 
  seek_not_done= 0;
 
188
  info->file= file;
 
189
  info->type= TYPE_NOT_SET;         /* Don't set it until mutex are created */
 
190
  info->pos_in_file= seek_offset;
 
191
  info->pre_close = info->pre_read = info->post_read = 0;
 
192
  info->arg = 0;
 
193
  info->alloced_buffer = 0;
 
194
  info->buffer=0;
 
195
  info->seek_not_done= 0;
194
196
 
195
197
  if (file >= 0)
196
198
  {
201
203
         This kind of object doesn't support seek() or tell(). Don't set a
202
204
         flag that will make us again try to seek() later and fail.
203
205
      */
204
 
      seek_not_done= 0;
 
206
      info->seek_not_done= 0;
205
207
      /*
206
208
        Additionally, if we're supposed to start somewhere other than the
207
209
        the beginning of whatever this file is, then somebody made a bad
210
212
      assert(seek_offset == 0);
211
213
    }
212
214
    else
213
 
      seek_not_done= test(seek_offset != (my_off_t)pos);
 
215
      info->seek_not_done= test(seek_offset != (my_off_t)pos);
214
216
  }
215
217
 
216
218
  if (!cachesize && !(cachesize= my_default_record_cache_size))
217
 
    return 1;                           /* No cache requested */
 
219
    return(1);                          /* No cache requested */
218
220
  min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
219
 
  if (type_arg == READ_CACHE)
 
221
  if (type == READ_CACHE)
220
222
  {                                             /* Assume file isn't growing */
221
223
    if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
222
224
    {
223
225
      /* Calculate end of file to avoid allocating oversized buffers */
224
 
      end_of_file_local=lseek(file,0L,SEEK_END);
 
226
      end_of_file=lseek(file,0L,SEEK_END);
225
227
      /* Need to reset seek_not_done now that we just did a seek. */
226
 
      seek_not_done= end_of_file_local == seek_offset ? 0 : 1;
227
 
      if (end_of_file_local < seek_offset)
228
 
        end_of_file_local=seek_offset;
 
228
      info->seek_not_done= end_of_file == seek_offset ? 0 : 1;
 
229
      if (end_of_file < seek_offset)
 
230
        end_of_file=seek_offset;
229
231
      /* Trim cache size if the file is very small */
230
 
      if ((my_off_t) cachesize > end_of_file_local-seek_offset+IO_SIZE*2-1)
 
232
      if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1)
231
233
      {
232
 
        cachesize= (size_t) (end_of_file_local-seek_offset)+IO_SIZE*2-1;
 
234
        cachesize= (size_t) (end_of_file-seek_offset)+IO_SIZE*2-1;
233
235
        use_async_io=0;                         /* No need to use async */
234
236
      }
235
237
    }
236
238
  }
237
239
  cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
238
 
  if (type_arg != READ_NET && type_arg != WRITE_NET)
 
240
  if (type != READ_NET && type != WRITE_NET)
239
241
  {
240
242
    /* Retry allocating memory in smaller blocks until we get one */
241
243
    cachesize= ((cachesize + min_cache-1) & ~(min_cache-1));
245
247
      if (cachesize < min_cache)
246
248
        cachesize = min_cache;
247
249
      buffer_block= cachesize;
248
 
      if ((type_arg == READ_CACHE) and (not global_read_buffer.add(buffer_block)))
249
 
      {
250
 
        my_error(ER_OUT_OF_GLOBAL_READMEMORY, MYF(ME_ERROR+ME_WAITTANG));
251
 
        return 2;
252
 
      }
253
 
 
254
 
      if ((buffer=
 
250
      if ((info->buffer=
255
251
           (unsigned char*) malloc(buffer_block)) != 0)
256
252
      {
257
 
        write_buffer=buffer;
258
 
        alloced_buffer= true;
 
253
        info->write_buffer=info->buffer;
 
254
        info->alloced_buffer= true;
259
255
        break;                                  /* Enough memory found */
260
256
      }
261
257
      if (cachesize == min_cache)
262
 
      {
263
 
        if (type_arg == READ_CACHE)
264
 
          global_read_buffer.sub(buffer_block);
265
 
        return 2;                               /* Can't alloc cache */
266
 
      }
 
258
        return(2);                              /* Can't alloc cache */
267
259
      /* Try with less memory */
268
 
      if (type_arg == READ_CACHE)
269
 
        global_read_buffer.sub(buffer_block);
270
260
      cachesize= (cachesize*3/4 & ~(min_cache-1));
271
261
    }
272
262
  }
273
263
 
274
 
  read_length=buffer_length=cachesize;
275
 
  myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
276
 
  request_pos= read_pos= write_pos = buffer;
 
264
  info->read_length=info->buffer_length=cachesize;
 
265
  info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
 
266
  info->request_pos= info->read_pos= info->write_pos = info->buffer;
277
267
 
278
 
  if (type_arg == WRITE_CACHE)
279
 
    write_end=
280
 
      buffer+buffer_length- (seek_offset & (IO_SIZE-1));
 
268
  if (type == WRITE_CACHE)
 
269
    info->write_end=
 
270
      info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
281
271
  else
282
 
    read_end=buffer;            /* Nothing in cache */
 
272
    info->read_end=info->buffer;                /* Nothing in cache */
283
273
 
284
274
  /* End_of_file may be changed by user later */
285
 
  end_of_file= end_of_file_local;
286
 
  error= 0;
287
 
  type= type_arg;
288
 
  init_functions();
 
275
  info->end_of_file= end_of_file;
 
276
  info->error=0;
 
277
  info->type= type;
 
278
  init_functions(info);
289
279
#ifdef HAVE_AIOWAIT
290
280
  if (use_async_io && ! my_disable_async_io)
291
281
  {
292
 
    read_length/=2;
293
 
    read_function=_my_b_async_read;
 
282
    info->read_length/=2;
 
283
    info->read_function=_my_b_async_read;
294
284
  }
295
 
  inited= aio_result.pending= 0;
 
285
  info->inited=info->aio_result.pending=0;
296
286
#endif
297
 
  return 0;
 
287
  return(0);
298
288
}                                               /* init_io_cache */
299
289
 
300
290
        /* Wait until current request is ready */
319
309
        break;
320
310
    }
321
311
  }
 
312
  return;
322
313
}
323
314
#endif
324
315
 
332
323
 *   If we are doing a reinit of a cache where we have the start of the file
333
324
 *   in the cache, we are reusing this memory without flushing it to disk.
334
325
 */
335
 
bool st_io_cache::reinit_io_cache(enum cache_type type_arg,
336
 
                                  my_off_t seek_offset,
337
 
                                  bool use_async_io,
338
 
                                  bool clear_cache)
 
326
bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
 
327
                        my_off_t seek_offset,
 
328
                        bool use_async_io,
 
329
                        bool clear_cache)
339
330
{
340
331
  /* One can't do reinit with the following types */
341
 
  assert(type_arg != READ_NET && type != READ_NET &&
342
 
              type_arg != WRITE_NET && type != WRITE_NET);
 
332
  assert(type != READ_NET && info->type != READ_NET &&
 
333
              type != WRITE_NET && info->type != WRITE_NET);
343
334
 
344
335
  /* If the whole file is in memory, avoid flushing to disk */
345
336
  if (! clear_cache &&
346
 
      seek_offset >= pos_in_file &&
347
 
      seek_offset <= my_b_tell(this))
 
337
      seek_offset >= info->pos_in_file &&
 
338
      seek_offset <= my_b_tell(info))
348
339
  {
349
340
    /* Reuse current buffer without flushing it to disk */
350
341
    unsigned char *pos;
351
 
    if (type == WRITE_CACHE && type_arg == READ_CACHE)
 
342
    if (info->type == WRITE_CACHE && type == READ_CACHE)
352
343
    {
353
 
      read_end=write_pos;
354
 
      end_of_file=my_b_tell(this);
 
344
      info->read_end=info->write_pos;
 
345
      info->end_of_file=my_b_tell(info);
355
346
      /*
356
347
        Trigger a new seek only if we have a valid
357
348
        file handle.
358
349
      */
359
 
      seek_not_done= (file != -1);
 
350
      info->seek_not_done= (info->file != -1);
360
351
    }
361
 
    else if (type_arg == WRITE_CACHE)
 
352
    else if (type == WRITE_CACHE)
362
353
    {
363
 
      if (type == READ_CACHE)
 
354
      if (info->type == READ_CACHE)
364
355
      {
365
 
        write_end=write_buffer+buffer_length;
366
 
        seek_not_done=1;
 
356
        info->write_end=info->write_buffer+info->buffer_length;
 
357
        info->seek_not_done=1;
367
358
      }
368
 
      end_of_file = ~(my_off_t) 0;
 
359
      info->end_of_file = ~(my_off_t) 0;
369
360
    }
370
 
    pos=request_pos+(seek_offset-pos_in_file);
371
 
    if (type_arg == WRITE_CACHE)
372
 
      write_pos=pos;
 
361
    pos=info->request_pos+(seek_offset-info->pos_in_file);
 
362
    if (type == WRITE_CACHE)
 
363
      info->write_pos=pos;
373
364
    else
374
 
      read_pos= pos;
 
365
      info->read_pos= pos;
375
366
#ifdef HAVE_AIOWAIT
376
 
    my_aiowait(&aio_result);            /* Wait for outstanding req */
 
367
    my_aiowait(&info->aio_result);              /* Wait for outstanding req */
377
368
#endif
378
369
  }
379
370
  else
382
373
      If we change from WRITE_CACHE to READ_CACHE, assume that everything
383
374
      after the current positions should be ignored
384
375
    */
385
 
    if (type == WRITE_CACHE && type_arg == READ_CACHE)
386
 
      end_of_file=my_b_tell(this);
 
376
    if (info->type == WRITE_CACHE && type == READ_CACHE)
 
377
      info->end_of_file=my_b_tell(info);
387
378
    /* flush cache if we want to reuse it */
388
 
    if (!clear_cache && my_b_flush_io_cache(this, 1))
389
 
      return 1;
390
 
    pos_in_file=seek_offset;
 
379
    if (!clear_cache && my_b_flush_io_cache(info,1))
 
380
      return(1);
 
381
    info->pos_in_file=seek_offset;
391
382
    /* Better to do always do a seek */
392
 
    seek_not_done=1;
393
 
    request_pos=read_pos=write_pos=buffer;
394
 
    if (type_arg == READ_CACHE)
 
383
    info->seek_not_done=1;
 
384
    info->request_pos=info->read_pos=info->write_pos=info->buffer;
 
385
    if (type == READ_CACHE)
395
386
    {
396
 
      read_end=buffer;          /* Nothing in cache */
 
387
      info->read_end=info->buffer;              /* Nothing in cache */
397
388
    }
398
389
    else
399
390
    {
400
 
      write_end=(buffer + buffer_length -
 
391
      info->write_end=(info->buffer + info->buffer_length -
401
392
                       (seek_offset & (IO_SIZE-1)));
402
 
      end_of_file= ~(my_off_t) 0;
 
393
      info->end_of_file= ~(my_off_t) 0;
403
394
    }
404
395
  }
405
 
  type= type_arg;
406
 
  error=0;
407
 
  init_functions();
 
396
  info->type=type;
 
397
  info->error=0;
 
398
  init_functions(info);
408
399
 
409
400
#ifdef HAVE_AIOWAIT
410
401
  if (use_async_io && ! my_disable_async_io &&
411
 
      ((uint32_t) buffer_length <
412
 
       (uint32_t) (end_of_file - seek_offset)))
 
402
      ((uint32_t) info->buffer_length <
 
403
       (uint32_t) (info->end_of_file - seek_offset)))
413
404
  {
414
 
    read_length=buffer_length/2;
415
 
    read_function=_my_b_async_read;
 
405
    info->read_length=info->buffer_length/2;
 
406
    info->read_function=_my_b_async_read;
416
407
  }
417
 
  inited= 0;
 
408
  info->inited=0;
418
409
#else
419
410
  (void)use_async_io;
420
411
#endif
421
 
  return 0;
 
412
  return(0);
422
413
} /* reinit_io_cache */
423
414
 
424
415
/**
435
426
 *   types than my_off_t unless you can be sure that their value fits.
436
427
 *   Same applies to differences of file offsets.
437
428
 *
438
 
 * @param info st_io_cache pointer @param Buffer Buffer to retrieve count bytes
 
429
 * @param info IO_CACHE pointer @param Buffer Buffer to retrieve count bytes
439
430
 * from file @param Count Number of bytes to read into Buffer
440
431
 * 
441
432
 * @retval 0 We succeeded in reading all data
442
433
 * @retval 1 Error: can't read requested characters
443
434
 */
444
 
static int _my_b_read(st_io_cache *info, unsigned char *Buffer, size_t Count)
 
435
static int _my_b_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
445
436
{
446
 
  size_t length_local,diff_length,left_length, max_length;
447
 
  my_off_t pos_in_file_local;
 
437
  size_t length,diff_length,left_length, max_length;
 
438
  my_off_t pos_in_file;
448
439
 
449
440
  if ((left_length= (size_t) (info->read_end-info->read_pos)))
450
441
  {
455
446
  }
456
447
 
457
448
  /* pos_in_file always point on where info->buffer was read */
458
 
  pos_in_file_local=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
 
449
  pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
459
450
 
460
451
  /*
461
 
    Whenever a function which operates on st_io_cache flushes/writes
462
 
    some part of the st_io_cache to disk it will set the property
 
452
    Whenever a function which operates on IO_CACHE flushes/writes
 
453
    some part of the IO_CACHE to disk it will set the property
463
454
    "seek_not_done" to indicate this to other functions operating
464
 
    on the st_io_cache.
 
455
    on the IO_CACHE.
465
456
  */
466
457
  if (info->seek_not_done)
467
458
  {
468
 
    if ((lseek(info->file,pos_in_file_local,SEEK_SET) != MY_FILEPOS_ERROR))
 
459
    if ((lseek(info->file,pos_in_file,SEEK_SET) != MY_FILEPOS_ERROR))
469
460
    {
470
461
      /* No error, reset seek_not_done flag. */
471
462
      info->seek_not_done= 0;
483
474
    }
484
475
  }
485
476
 
486
 
  diff_length= (size_t) (pos_in_file_local & (IO_SIZE-1));
 
477
  diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
487
478
  if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
488
479
  {                                     /* Fill first intern buffer */
489
480
    size_t read_length;
490
 
    if (info->end_of_file <= pos_in_file_local)
 
481
    if (info->end_of_file <= pos_in_file)
491
482
    {                                   /* End of file */
492
483
      info->error= (int) left_length;
493
484
      return(1);
494
485
    }
495
 
    length_local=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
496
 
    if ((read_length= my_read(info->file,Buffer, length_local, info->myflags)) != length_local)
 
486
    length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
 
487
    if ((read_length= my_read(info->file,Buffer, length, info->myflags))
 
488
        != length)
497
489
    {
498
490
      info->error= (read_length == (size_t) -1 ? -1 :
499
491
                    (int) (read_length+left_length));
500
492
      return(1);
501
493
    }
502
 
    Count-= length_local;
503
 
    Buffer+= length_local;
504
 
    pos_in_file_local+= length_local;
505
 
    left_length+= length_local;
 
494
    Count-=length;
 
495
    Buffer+=length;
 
496
    pos_in_file+=length;
 
497
    left_length+=length;
506
498
    diff_length=0;
507
499
  }
508
500
 
509
501
  max_length= info->read_length-diff_length;
510
502
  if (info->type != READ_FIFO &&
511
 
      max_length > (info->end_of_file - pos_in_file_local))
512
 
    max_length= (size_t) (info->end_of_file - pos_in_file_local);
 
503
      max_length > (info->end_of_file - pos_in_file))
 
504
    max_length= (size_t) (info->end_of_file - pos_in_file);
513
505
  if (!max_length)
514
506
  {
515
507
    if (Count)
517
509
      info->error= static_cast<int>(left_length);       /* We only got this many char */
518
510
      return(1);
519
511
    }
520
 
     length_local=0;                            /* Didn't read any chars */
 
512
    length=0;                           /* Didn't read any chars */
521
513
  }
522
 
  else if (( length_local= my_read(info->file,info->buffer, max_length,
 
514
  else if ((length= my_read(info->file,info->buffer, max_length,
523
515
                            info->myflags)) < Count ||
524
 
            length_local == (size_t) -1)
 
516
           length == (size_t) -1)
525
517
  {
526
 
    if ( length_local != (size_t) -1)
527
 
      memcpy(Buffer, info->buffer,  length_local);
528
 
    info->pos_in_file= pos_in_file_local;
529
 
    info->error=  length_local == (size_t) -1 ? -1 : (int) ( length_local+left_length);
 
518
    if (length != (size_t) -1)
 
519
      memcpy(Buffer, info->buffer, length);
 
520
    info->pos_in_file= pos_in_file;
 
521
    info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
530
522
    info->read_pos=info->read_end=info->buffer;
531
523
    return(1);
532
524
  }
533
525
  info->read_pos=info->buffer+Count;
534
 
  info->read_end=info->buffer+ length_local;
535
 
  info->pos_in_file=pos_in_file_local;
 
526
  info->read_end=info->buffer+length;
 
527
  info->pos_in_file=pos_in_file;
536
528
  memcpy(Buffer, info->buffer, Count);
537
529
  return(0);
538
530
}
542
534
 
543
535
/**
544
536
 * @brief
545
 
 *   Read from the st_io_cache into a buffer and feed asynchronously from disk when needed.
 
537
 *   Read from the IO_CACHE into a buffer and feed asynchronously from disk when needed.
546
538
 *
547
 
 * @param info st_io_cache pointer
 
539
 * @param info IO_CACHE pointer
548
540
 * @param Buffer Buffer to retrieve count bytes from file
549
541
 * @param Count Number of bytes to read into Buffer
550
542
 * 
551
543
 * @retval -1 An error has occurred; errno is set.
552
544
 * @retval 0 Success
553
 
 * @retval 1 An error has occurred; st_io_cache to error state.
 
545
 * @retval 1 An error has occurred; IO_CACHE to error state.
554
546
 */
555
 
int _my_b_async_read(st_io_cache *info, unsigned char *Buffer, size_t Count)
 
547
int _my_b_async_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
556
548
{
557
 
  size_t length_local,read_length,diff_length,left_length,use_length,org_Count;
 
549
  size_t length,read_length,diff_length,left_length,use_length,org_Count;
558
550
  size_t max_length;
559
551
  my_off_t next_pos_in_file;
560
552
  unsigned char *read_buffer;
615
607
      }
616
608
    }
617
609
        /* Copy found bytes to buffer */
618
 
    length_local=min(Count,read_length);
619
 
    memcpy(Buffer,info->read_pos,(size_t) length_local);
620
 
    Buffer+=length_local;
621
 
    Count-=length_local;
622
 
    left_length+=length_local;
 
610
    length=min(Count,read_length);
 
611
    memcpy(Buffer,info->read_pos,(size_t) length);
 
612
    Buffer+=length;
 
613
    Count-=length;
 
614
    left_length+=length;
623
615
    info->read_end=info->rc_pos+read_length;
624
 
    info->read_pos+=length_local;
 
616
    info->read_pos+=length;
625
617
  }
626
618
  else
627
619
    next_pos_in_file=(info->pos_in_file+ (size_t)
719
711
 * @brief
720
712
 *   Read one byte when buffer is empty
721
713
 */
722
 
int _my_b_get(st_io_cache *info)
 
714
int _my_b_get(IO_CACHE *info)
723
715
{
724
716
  unsigned char buff;
725
717
  IO_CACHE_CALLBACK pre_read,post_read;
734
726
 
735
727
/**
736
728
 * @brief
737
 
 *   Write a byte buffer to st_io_cache and flush to disk if st_io_cache is full.
 
729
 *   Write a byte buffer to IO_CACHE and flush to disk if IO_CACHE is full.
738
730
 *
739
731
 * @retval -1 On error; errno contains error code.
740
732
 * @retval 0 On success
741
733
 * @retval 1 On error on write
742
734
 */
743
 
int _my_b_write(st_io_cache *info, const unsigned char *Buffer, size_t Count)
 
735
int _my_b_write(register IO_CACHE *info, const unsigned char *Buffer, size_t Count)
744
736
{
745
 
  size_t rest_length,length_local;
 
737
  size_t rest_length,length;
746
738
 
747
739
  if (info->pos_in_file+info->buffer_length > info->end_of_file)
748
740
  {
749
 
    errno=EFBIG;
 
741
    errno=errno=EFBIG;
750
742
    return info->error = -1;
751
743
  }
752
744
 
760
752
    return 1;
761
753
  if (Count >= IO_SIZE)
762
754
  {                                     /* Fill first intern buffer */
763
 
    length_local=Count & (size_t) ~(IO_SIZE-1);
 
755
    length=Count & (size_t) ~(IO_SIZE-1);
764
756
    if (info->seek_not_done)
765
757
    {
766
758
      /*
767
 
        Whenever a function which operates on st_io_cache flushes/writes
768
 
        some part of the st_io_cache to disk it will set the property
 
759
        Whenever a function which operates on IO_CACHE flushes/writes
 
760
        some part of the IO_CACHE to disk it will set the property
769
761
        "seek_not_done" to indicate this to other functions operating
770
 
        on the st_io_cache.
 
762
        on the IO_CACHE.
771
763
      */
772
764
      if (lseek(info->file,info->pos_in_file,SEEK_SET))
773
765
      {
776
768
      }
777
769
      info->seek_not_done=0;
778
770
    }
779
 
    if (my_write(info->file, Buffer, length_local, info->myflags | MY_NABP))
 
771
    if (my_write(info->file, Buffer, length, info->myflags | MY_NABP))
780
772
      return info->error= -1;
781
773
 
782
 
    Count-=length_local;
783
 
    Buffer+=length_local;
784
 
    info->pos_in_file+=length_local;
 
774
    Count-=length;
 
775
    Buffer+=length;
 
776
    info->pos_in_file+=length;
785
777
  }
786
778
  memcpy(info->write_pos,Buffer,(size_t) Count);
787
779
  info->write_pos+=Count;
794
786
 *   As all write calls to the data goes through the cache,
795
787
 *   we will never get a seek over the end of the buffer.
796
788
 */
797
 
int my_block_write(st_io_cache *info, const unsigned char *Buffer, size_t Count,
 
789
int my_block_write(register IO_CACHE *info, const unsigned char *Buffer, size_t Count,
798
790
                   my_off_t pos)
799
791
{
800
 
  size_t length_local;
 
792
  size_t length;
801
793
  int error=0;
802
794
 
803
795
  if (pos < info->pos_in_file)
806
798
    if (pos + Count <= info->pos_in_file)
807
799
      return (pwrite(info->file, Buffer, Count, pos) == 0);
808
800
    /* Write the part of the block that is before buffer */
809
 
    length_local= (uint32_t) (info->pos_in_file - pos);
810
 
    if (pwrite(info->file, Buffer, length_local, pos) == 0)
 
801
    length= (uint32_t) (info->pos_in_file - pos);
 
802
    if (pwrite(info->file, Buffer, length, pos) == 0)
811
803
      info->error= error= -1;
812
 
    Buffer+=length_local;
813
 
    pos+=  length_local;
814
 
    Count-= length_local;
 
804
    Buffer+=length;
 
805
    pos+=  length;
 
806
    Count-= length;
815
807
  }
816
808
 
817
809
  /* Check if we want to write inside the used part of the buffer.*/
818
 
  length_local= (size_t) (info->write_end - info->buffer);
819
 
  if (pos < info->pos_in_file + length_local)
 
810
  length= (size_t) (info->write_end - info->buffer);
 
811
  if (pos < info->pos_in_file + length)
820
812
  {
821
813
    size_t offset= (size_t) (pos - info->pos_in_file);
822
 
    length_local-=offset;
823
 
    if (length_local > Count)
824
 
      length_local=Count;
825
 
    memcpy(info->buffer+offset, Buffer, length_local);
826
 
    Buffer+=length_local;
827
 
    Count-= length_local;
828
 
    /* Fix length_local of buffer if the new data was larger */
829
 
    if (info->buffer+length_local > info->write_pos)
830
 
      info->write_pos=info->buffer+length_local;
 
814
    length-=offset;
 
815
    if (length > Count)
 
816
      length=Count;
 
817
    memcpy(info->buffer+offset, Buffer, length);
 
818
    Buffer+=length;
 
819
    Count-= length;
 
820
    /* Fix length of buffer if the new data was larger */
 
821
    if (info->buffer+length > info->write_pos)
 
822
      info->write_pos=info->buffer+length;
831
823
    if (!Count)
832
824
      return (error);
833
825
  }
841
833
 * @brief
842
834
 *   Flush write cache 
843
835
 */
844
 
int my_b_flush_io_cache(st_io_cache *info, int need_append_buffer_lock)
 
836
int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
845
837
{
846
 
  size_t length_local;
 
838
  size_t length;
847
839
  bool append_cache= false;
848
 
  my_off_t pos_in_file_local;
 
840
  my_off_t pos_in_file;
849
841
 
850
842
  if (info->type == WRITE_CACHE || append_cache)
851
843
  {
852
844
    if (info->file == -1)
853
845
    {
854
 
      if (info->real_open_cached_file())
 
846
      if (real_open_cached_file(info))
855
847
        return((info->error= -1));
856
848
    }
857
849
    lock_append_buffer(info, need_append_buffer_lock);
858
850
 
859
 
    if ((length_local=(size_t) (info->write_pos - info->write_buffer)))
 
851
    if ((length=(size_t) (info->write_pos - info->write_buffer)))
860
852
    {
861
 
      pos_in_file_local=info->pos_in_file;
 
853
      pos_in_file=info->pos_in_file;
862
854
      /*
863
855
        If we have append cache, we always open the file with
864
856
        O_APPEND which moves the pos to EOF automatically on every write
865
857
      */
866
858
      if (!append_cache && info->seek_not_done)
867
859
      {                                 /* File touched, do seek */
868
 
        if (lseek(info->file,pos_in_file_local,SEEK_SET) == MY_FILEPOS_ERROR)
 
860
        if (lseek(info->file,pos_in_file,SEEK_SET) == MY_FILEPOS_ERROR)
869
861
        {
870
862
          unlock_append_buffer(info, need_append_buffer_lock);
871
863
          return((info->error= -1));
874
866
          info->seek_not_done=0;
875
867
      }
876
868
      if (!append_cache)
877
 
        info->pos_in_file+=length_local;
 
869
        info->pos_in_file+=length;
878
870
      info->write_end= (info->write_buffer+info->buffer_length-
879
 
                        ((pos_in_file_local+length_local) & (IO_SIZE-1)));
 
871
                        ((pos_in_file+length) & (IO_SIZE-1)));
880
872
 
881
 
      if (my_write(info->file,info->write_buffer,length_local,
 
873
      if (my_write(info->file,info->write_buffer,length,
882
874
                   info->myflags | MY_NABP))
883
875
        info->error= -1;
884
876
      else
885
877
        info->error= 0;
886
878
      if (!append_cache)
887
879
      {
888
 
        set_if_bigger(info->end_of_file,(pos_in_file_local+length_local));
 
880
        set_if_bigger(info->end_of_file,(pos_in_file+length));
889
881
      }
890
882
      else
891
883
      {
912
904
 
913
905
/**
914
906
 * @brief
915
 
 *   Free an st_io_cache object
 
907
 *   Free an IO_CACHE object
916
908
 * 
917
909
 * @detail
918
910
 *   It's currently safe to call this if one has called init_io_cache()
919
911
 *   on the 'info' object, even if init_io_cache() failed.
920
912
 *   This function is also safe to call twice with the same handle.
921
913
 * 
922
 
 * @param info st_io_cache Handle to free
 
914
 * @param info IO_CACHE Handle to free
923
915
 * 
924
916
 * @retval 0 ok
925
917
 * @retval # Error
926
918
 */
927
 
int st_io_cache::end_io_cache()
 
919
int end_io_cache(IO_CACHE *info)
928
920
{
929
 
  int _error=0;
930
 
 
931
 
  if (pre_close)
932
 
  {
933
 
    (*pre_close)(this);
934
 
    pre_close= 0;
935
 
  }
936
 
  if (alloced_buffer)
937
 
  {
938
 
    if (type == READ_CACHE)
939
 
      global_read_buffer.sub(buffer_length);
940
 
    alloced_buffer=0;
941
 
    if (file != -1)                     /* File doesn't exist */
942
 
      _error= my_b_flush_io_cache(this, 1);
943
 
    free((unsigned char*) buffer);
944
 
    buffer=read_pos=(unsigned char*) 0;
945
 
  }
946
 
 
947
 
  return _error;
 
921
  int error=0;
 
922
  IO_CACHE_CALLBACK pre_close;
 
923
 
 
924
  if ((pre_close=info->pre_close))
 
925
  {
 
926
    (*pre_close)(info);
 
927
    info->pre_close= 0;
 
928
  }
 
929
  if (info->alloced_buffer)
 
930
  {
 
931
    info->alloced_buffer=0;
 
932
    if (info->file != -1)                       /* File doesn't exist */
 
933
      error= my_b_flush_io_cache(info,1);
 
934
    free((unsigned char*) info->buffer);
 
935
    info->buffer=info->read_pos=(unsigned char*) 0;
 
936
  }
 
937
 
 
938
  return(error);
948
939
} /* end_io_cache */
949
940
 
950
941
} /* namespace internal */