~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/*
17
  Cashing of files with only does (sequential) read or writes of fixed-
18
  length records. A read isn't allowed to go over file-length. A read is ok
19
  if it ends at file-length and next read can try to read after file-length
20
  (and get a EOF-error).
21
  Possibly use of asyncronic io.
22
  macros for read and writes for faster io.
23
  Used instead of FILE when reading or writing whole files.
24
  This code makes mf_rec_cache obsolete (currently only used by ISAM)
25
  One can change info->pos_in_file to a higher value to skip bytes in file if
26
  also info->read_pos is set to info->read_end.
27
  If called through open_cached_file(), then the temporary file will
28
  only be created if a write exeeds the file buffer or if one calls
29
  my_b_flush_io_cache().
30
31
  If one uses SEQ_READ_APPEND, then two buffers are allocated, one for
32
  reading and another for writing.  Reads are first done from disk and
33
  then done from the write buffer.  This is an efficient way to read
34
  from a log file when one is writing to it at the same time.
35
  For this to work, the file has to be opened in append mode!
36
  Note that when one uses SEQ_READ_APPEND, one MUST write using
37
  my_b_append !  This is needed because we need to lock the mutex
38
  every time we access the write buffer.
39
40
TODO:
41
  When one SEQ_READ_APPEND and we are reading and writing at the same time,
42
  each time the write buffer gets full and it's written to disk, we will
43
  always do a disk read to read a part of the buffer from disk to the
44
  read buffer.
45
  This should be fixed so that when we do a my_b_flush_io_cache() and
46
  we have been reading the write buffer, we should transfer the rest of the
47
  write buffer to the read buffer before we start to reuse it.
48
*/
49
994.2.4 by Monty Taylor
Blast. Fixed some make distcheck issues.
50
#include "mysys/mysys_priv.h"
212.5.18 by Monty Taylor
Moved m_ctype, m_string and my_bitmap. Removed t_ctype.
51
#include <mystrings/m_string.h>
1 by brian
clean slate
52
#ifdef HAVE_AIOWAIT
994.2.4 by Monty Taylor
Blast. Fixed some make distcheck issues.
53
#include "mysys/mysys_err.h"
481.1.16 by Monty Taylor
Merged iocache.h addition.
54
#include <mysys/aio_result.h>
1 by brian
clean slate
55
static void my_aiowait(my_aio_result *result);
56
#endif
481.1.16 by Monty Taylor
Merged iocache.h addition.
57
#include <mysys/iocache.h>
1 by brian
clean slate
58
#include <errno.h>
492.1.7 by Monty Taylor
Moved test() to its own file.
59
#include <drizzled/util/test.h>
629.1.1 by Monty Taylor
More solaris fixes.
60
#include <stdlib.h>
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
61
#include <algorithm>
62
63
using namespace std;
629.1.1 by Monty Taylor
More solaris fixes.
64
1165.1.162 by Stewart Smith
SunStudio extern C fixes for mf_iocache.cc
65
extern "C" {
1165.1.147 by Stewart Smith
make _my_b_read() static to mysys/mf_iocache.cc
66
static int _my_b_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count);
1165.1.148 by Stewart Smith
make _my_b_read_r() static to mysys/mf_iocache.cc
67
static int _my_b_read_r(register IO_CACHE *cache, unsigned char *Buffer, size_t Count);
1165.1.149 by Stewart Smith
make static int _my_b_seq_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)() static to mysys/mf_iocache.cc
68
static int _my_b_seq_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count);
1165.1.150 by Stewart Smith
make _my_b_write() static to mysys/mf_iocache.cc
69
static int _my_b_write(register IO_CACHE *info, const unsigned char *Buffer, size_t Count);
1165.1.162 by Stewart Smith
SunStudio extern C fixes for mf_iocache.cc
70
}
1165.1.147 by Stewart Smith
make _my_b_read() static to mysys/mf_iocache.cc
71
1 by brian
clean slate
72
#define lock_append_buffer(info) \
73
 pthread_mutex_lock(&(info)->append_buffer_lock)
74
#define unlock_append_buffer(info) \
75
 pthread_mutex_unlock(&(info)->append_buffer_lock)
76
77
#define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1))
78
#define IO_ROUND_DN(X) ( (X)            & ~(IO_SIZE-1))
79
80
/*
81
  Setup internal pointers inside IO_CACHE
82
83
  SYNOPSIS
84
    setup_io_cache()
85
    info		IO_CACHE handler
86
87
  NOTES
88
    This is called on automaticly on init or reinit of IO_CACHE
89
    It must be called externally if one moves or copies an IO_CACHE
90
    object.
91
*/
92
93
void setup_io_cache(IO_CACHE* info)
94
{
95
  /* Ensure that my_b_tell() and my_b_bytes_in_cache works */
96
  if (info->type == WRITE_CACHE)
97
  {
98
    info->current_pos= &info->write_pos;
99
    info->current_end= &info->write_end;
100
  }
101
  else
102
  {
103
    info->current_pos= &info->read_pos;
104
    info->current_end= &info->read_end;
105
  }
106
}
107
108
109
static void
110
init_functions(IO_CACHE* info)
111
{
112
  enum cache_type type= info->type;
113
  switch (type) {
114
  case READ_NET:
115
    /*
116
      Must be initialized by the caller. The problem is that
117
      _my_b_net_read has to be defined in sql directory because of
118
      the dependency on THD, and therefore cannot be visible to
119
      programs that link against mysys but know nothing about THD, such
120
      as myisamchk
121
    */
122
    break;
123
  case SEQ_READ_APPEND:
124
    info->read_function = _my_b_seq_read;
125
    info->write_function = 0;			/* Force a core if used */
126
    break;
127
  default:
128
    info->read_function =
129
                          info->share ? _my_b_read_r :
130
                                        _my_b_read;
131
    info->write_function = _my_b_write;
132
  }
133
134
  setup_io_cache(info);
135
}
136
137
138
/*
139
  Initialize an IO_CACHE object
140
141
  SYNOPSOS
142
    init_io_cache()
143
    info		cache handler to initialize
144
    file		File that should be associated to to the handler
145
			If == -1 then real_open_cached_file()
146
			will be called when it's time to open file.
147
    cachesize		Size of buffer to allocate for read/write
148
			If == 0 then use my_default_record_cache_size
149
    type		Type of cache
150
    seek_offset		Where cache should start reading/writing
151
    use_async_io	Set to 1 of we should use async_io (if avaiable)
152
    cache_myflags	Bitmap of differnt flags
153
			MY_WME | MY_FAE | MY_NABP | MY_FNABP |
154
			MY_DONT_CHECK_FILESIZE
155
156
  RETURN
157
    0  ok
158
    #  error
159
*/
160
161
int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
162
		  enum cache_type type, my_off_t seek_offset,
154 by Brian Aker
Removed oddball types in my_global.h
163
		  bool use_async_io, myf cache_myflags)
1 by brian
clean slate
164
{
165
  size_t min_cache;
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
166
  off_t pos;
1 by brian
clean slate
167
  my_off_t end_of_file= ~(my_off_t) 0;
168
169
  info->file= file;
170
  info->type= TYPE_NOT_SET;	    /* Don't set it until mutex are created */
171
  info->pos_in_file= seek_offset;
172
  info->pre_close = info->pre_read = info->post_read = 0;
173
  info->arg = 0;
174
  info->alloced_buffer = 0;
175
  info->buffer=0;
176
  info->seek_not_done= 0;
177
178
  if (file >= 0)
179
  {
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
180
    pos= lseek(file, 0, SEEK_CUR);
181
    if ((pos == MY_FILEPOS_ERROR) && (my_errno == ESPIPE))
1 by brian
clean slate
182
    {
183
      /*
184
         This kind of object doesn't support seek() or tell(). Don't set a
185
         flag that will make us again try to seek() later and fail.
186
      */
187
      info->seek_not_done= 0;
188
      /*
189
        Additionally, if we're supposed to start somewhere other than the
190
        the beginning of whatever this file is, then somebody made a bad
191
        assumption.
192
      */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
193
      assert(seek_offset == 0);
1 by brian
clean slate
194
    }
195
    else
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
196
      info->seek_not_done= test(seek_offset != (my_off_t)pos);
1 by brian
clean slate
197
  }
198
199
  info->share=0;
200
201
  if (!cachesize && !(cachesize= my_default_record_cache_size))
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
202
    return(1);				/* No cache requested */
1 by brian
clean slate
203
  min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
204
  if (type == READ_CACHE || type == SEQ_READ_APPEND)
205
  {						/* Assume file isn't growing */
206
    if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
207
    {
208
      /* Calculate end of file to avoid allocating oversized buffers */
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
209
      end_of_file=lseek(file,0L,SEEK_END);
1 by brian
clean slate
210
      /* Need to reset seek_not_done now that we just did a seek. */
211
      info->seek_not_done= end_of_file == seek_offset ? 0 : 1;
212
      if (end_of_file < seek_offset)
213
	end_of_file=seek_offset;
214
      /* Trim cache size if the file is very small */
215
      if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1)
216
      {
217
	cachesize= (size_t) (end_of_file-seek_offset)+IO_SIZE*2-1;
218
	use_async_io=0;				/* No need to use async */
219
      }
220
    }
221
  }
222
  cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
223
  if (type != READ_NET && type != WRITE_NET)
224
  {
225
    /* Retry allocating memory in smaller blocks until we get one */
226
    cachesize= ((cachesize + min_cache-1) & ~(min_cache-1));
227
    for (;;)
228
    {
229
      size_t buffer_block;
230
      if (cachesize < min_cache)
231
	cachesize = min_cache;
232
      buffer_block= cachesize;
233
      if (type == SEQ_READ_APPEND)
234
	buffer_block *= 2;
235
      if ((info->buffer=
656.1.26 by Monty Taylor
Finally removed all of the my_malloc stuff.
236
	   (unsigned char*) malloc(buffer_block)) != 0)
1 by brian
clean slate
237
      {
238
	info->write_buffer=info->buffer;
239
	if (type == SEQ_READ_APPEND)
240
	  info->write_buffer = info->buffer + cachesize;
241
	info->alloced_buffer=1;
242
	break;					/* Enough memory found */
243
      }
244
      if (cachesize == min_cache)
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
245
	return(2);				/* Can't alloc cache */
1 by brian
clean slate
246
      /* Try with less memory */
247
      cachesize= (cachesize*3/4 & ~(min_cache-1));
248
    }
249
  }
250
251
  info->read_length=info->buffer_length=cachesize;
252
  info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
253
  info->request_pos= info->read_pos= info->write_pos = info->buffer;
254
  if (type == SEQ_READ_APPEND)
255
  {
256
    info->append_read_pos = info->write_pos = info->write_buffer;
257
    info->write_end = info->write_buffer + info->buffer_length;
258
    pthread_mutex_init(&info->append_buffer_lock,MY_MUTEX_INIT_FAST);
259
  }
260
261
  if (type == WRITE_CACHE)
262
    info->write_end=
263
      info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
264
  else
265
    info->read_end=info->buffer;		/* Nothing in cache */
266
267
  /* End_of_file may be changed by user later */
268
  info->end_of_file= end_of_file;
269
  info->error=0;
270
  info->type= type;
271
  init_functions(info);
272
#ifdef HAVE_AIOWAIT
273
  if (use_async_io && ! my_disable_async_io)
274
  {
275
    info->read_length/=2;
276
    info->read_function=_my_b_async_read;
277
  }
278
  info->inited=info->aio_result.pending=0;
279
#endif
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
280
  return(0);
1 by brian
clean slate
281
}						/* init_io_cache */
282
283
	/* Wait until current request is ready */
284
285
#ifdef HAVE_AIOWAIT
286
static void my_aiowait(my_aio_result *result)
287
{
288
  if (result->pending)
289
  {
290
    struct aio_result_t *tmp;
291
    for (;;)
292
    {
293
      if ((int) (tmp=aiowait((struct timeval *) 0)) == -1)
294
      {
295
	if (errno == EINTR)
296
	  continue;
297
	result->pending=0;			/* Assume everythings is ok */
298
	break;
299
      }
300
      ((my_aio_result*) tmp)->pending=0;
301
      if ((my_aio_result*) tmp == result)
302
	break;
303
    }
304
  }
305
  return;
306
}
307
#endif
308
309
310
/*
311
  Use this to reset cache to re-start reading or to change the type
312
  between READ_CACHE <-> WRITE_CACHE
313
  If we are doing a reinit of a cache where we have the start of the file
314
  in the cache, we are reusing this memory without flushing it to disk.
315
*/
316
146 by Brian Aker
my_bool cleanup.
317
bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
1 by brian
clean slate
318
			my_off_t seek_offset,
595 by Brian Aker
Fix, partial, for Sun Studio.
319
			bool use_async_io,
154 by Brian Aker
Removed oddball types in my_global.h
320
			bool clear_cache)
1 by brian
clean slate
321
{
322
  /* One can't do reinit with the following types */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
323
  assert(type != READ_NET && info->type != READ_NET &&
1 by brian
clean slate
324
	      type != WRITE_NET && info->type != WRITE_NET &&
325
	      type != SEQ_READ_APPEND && info->type != SEQ_READ_APPEND);
326
327
  /* If the whole file is in memory, avoid flushing to disk */
328
  if (! clear_cache &&
329
      seek_offset >= info->pos_in_file &&
330
      seek_offset <= my_b_tell(info))
331
  {
332
    /* Reuse current buffer without flushing it to disk */
481 by Brian Aker
Remove all of uchar.
333
    unsigned char *pos;
1 by brian
clean slate
334
    if (info->type == WRITE_CACHE && type == READ_CACHE)
335
    {
336
      info->read_end=info->write_pos;
337
      info->end_of_file=my_b_tell(info);
338
      /*
339
        Trigger a new seek only if we have a valid
340
        file handle.
341
      */
342
      info->seek_not_done= (info->file != -1);
343
    }
344
    else if (type == WRITE_CACHE)
345
    {
346
      if (info->type == READ_CACHE)
347
      {
348
	info->write_end=info->write_buffer+info->buffer_length;
349
	info->seek_not_done=1;
350
      }
351
      info->end_of_file = ~(my_off_t) 0;
352
    }
353
    pos=info->request_pos+(seek_offset-info->pos_in_file);
354
    if (type == WRITE_CACHE)
355
      info->write_pos=pos;
356
    else
357
      info->read_pos= pos;
358
#ifdef HAVE_AIOWAIT
359
    my_aiowait(&info->aio_result);		/* Wait for outstanding req */
360
#endif
361
  }
362
  else
363
  {
364
    /*
365
      If we change from WRITE_CACHE to READ_CACHE, assume that everything
366
      after the current positions should be ignored
367
    */
368
    if (info->type == WRITE_CACHE && type == READ_CACHE)
369
      info->end_of_file=my_b_tell(info);
370
    /* flush cache if we want to reuse it */
371
    if (!clear_cache && my_b_flush_io_cache(info,1))
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
372
      return(1);
1 by brian
clean slate
373
    info->pos_in_file=seek_offset;
374
    /* Better to do always do a seek */
375
    info->seek_not_done=1;
376
    info->request_pos=info->read_pos=info->write_pos=info->buffer;
377
    if (type == READ_CACHE)
378
    {
379
      info->read_end=info->buffer;		/* Nothing in cache */
380
    }
381
    else
382
    {
383
      info->write_end=(info->buffer + info->buffer_length -
384
		       (seek_offset & (IO_SIZE-1)));
385
      info->end_of_file= ~(my_off_t) 0;
386
    }
387
  }
388
  info->type=type;
389
  info->error=0;
390
  init_functions(info);
391
392
#ifdef HAVE_AIOWAIT
393
  if (use_async_io && ! my_disable_async_io &&
298 by Brian Aker
ulong conversion.
394
      ((uint32_t) info->buffer_length <
395
       (uint32_t) (info->end_of_file - seek_offset)))
1 by brian
clean slate
396
  {
397
    info->read_length=info->buffer_length/2;
398
    info->read_function=_my_b_async_read;
399
  }
400
  info->inited=0;
595 by Brian Aker
Fix, partial, for Sun Studio.
401
#else
402
  (void)use_async_io;
1 by brian
clean slate
403
#endif
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
404
  return(0);
1 by brian
clean slate
405
} /* reinit_io_cache */
406
407
408
409
/*
410
  Read buffered.
411
412
  SYNOPSIS
413
    _my_b_read()
414
      info                      IO_CACHE pointer
415
      Buffer                    Buffer to retrieve count bytes from file
416
      Count                     Number of bytes to read into Buffer
417
418
  NOTE
419
    This function is only called from the my_b_read() macro when there
420
    isn't enough characters in the buffer to satisfy the request.
421
422
  WARNING
423
424
    When changing this function, be careful with handling file offsets
425
    (end-of_file, pos_in_file). Do not cast them to possibly smaller
426
    types than my_off_t unless you can be sure that their value fits.
427
    Same applies to differences of file offsets.
428
429
    When changing this function, check _my_b_read_r(). It might need the
430
    same change.
431
432
  RETURN
433
    0      we succeeded in reading all data
434
    1      Error: can't read requested characters
435
*/
436
1165.1.147 by Stewart Smith
make _my_b_read() static to mysys/mf_iocache.cc
437
static int _my_b_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
1 by brian
clean slate
438
{
439
  size_t length,diff_length,left_length, max_length;
440
  my_off_t pos_in_file;
441
442
  if ((left_length= (size_t) (info->read_end-info->read_pos)))
443
  {
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
444
    assert(Count >= left_length);	/* User is not using my_b_read() */
1 by brian
clean slate
445
    memcpy(Buffer,info->read_pos, left_length);
446
    Buffer+=left_length;
447
    Count-=left_length;
448
  }
449
450
  /* pos_in_file always point on where info->buffer was read */
451
  pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
452
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
453
  /*
1 by brian
clean slate
454
    Whenever a function which operates on IO_CACHE flushes/writes
455
    some part of the IO_CACHE to disk it will set the property
456
    "seek_not_done" to indicate this to other functions operating
457
    on the IO_CACHE.
458
  */
459
  if (info->seek_not_done)
460
  {
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
461
    if ((lseek(info->file,pos_in_file,SEEK_SET) != MY_FILEPOS_ERROR))
1 by brian
clean slate
462
    {
463
      /* No error, reset seek_not_done flag. */
464
      info->seek_not_done= 0;
465
    }
466
    else
467
    {
468
      /*
469
        If the seek failed and the error number is ESPIPE, it is because
470
        info->file is a pipe or socket or FIFO.  We never should have tried
471
        to seek on that.  See Bugs#25807 and #22828 for more info.
472
      */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
473
      assert(my_errno != ESPIPE);
1 by brian
clean slate
474
      info->error= -1;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
475
      return(1);
1 by brian
clean slate
476
    }
477
  }
478
479
  diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
480
  if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
481
  {					/* Fill first intern buffer */
482
    size_t read_length;
483
    if (info->end_of_file <= pos_in_file)
484
    {					/* End of file */
485
      info->error= (int) left_length;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
486
      return(1);
1 by brian
clean slate
487
    }
488
    length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
489
    if ((read_length= my_read(info->file,Buffer, length, info->myflags))
490
	!= length)
491
    {
492
      info->error= (read_length == (size_t) -1 ? -1 :
493
		    (int) (read_length+left_length));
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
494
      return(1);
1 by brian
clean slate
495
    }
496
    Count-=length;
497
    Buffer+=length;
498
    pos_in_file+=length;
499
    left_length+=length;
500
    diff_length=0;
501
  }
502
503
  max_length= info->read_length-diff_length;
504
  if (info->type != READ_FIFO &&
505
      max_length > (info->end_of_file - pos_in_file))
506
    max_length= (size_t) (info->end_of_file - pos_in_file);
507
  if (!max_length)
508
  {
509
    if (Count)
510
    {
1126.13.8 by Joe Daly
Fix up spacing in various files, also had new style casts in several places
511
      info->error= static_cast<int>(left_length);	/* We only got this many char */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
512
      return(1);
1 by brian
clean slate
513
    }
514
    length=0;				/* Didn't read any chars */
515
  }
516
  else if ((length= my_read(info->file,info->buffer, max_length,
517
                            info->myflags)) < Count ||
518
	   length == (size_t) -1)
519
  {
520
    if (length != (size_t) -1)
521
      memcpy(Buffer, info->buffer, length);
522
    info->pos_in_file= pos_in_file;
523
    info->error= length == (size_t) -1 ? -1 : (int) (length+left_length);
524
    info->read_pos=info->read_end=info->buffer;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
525
    return(1);
1 by brian
clean slate
526
  }
527
  info->read_pos=info->buffer+Count;
528
  info->read_end=info->buffer+length;
529
  info->pos_in_file=pos_in_file;
530
  memcpy(Buffer, info->buffer, Count);
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
531
  return(0);
1 by brian
clean slate
532
}
533
534
535
/*
536
  Prepare IO_CACHE for shared use.
537
538
  SYNOPSIS
539
    init_io_cache_share()
540
      read_cache                A read cache. This will be copied for
541
                                every thread after setup.
542
      cshare                    The share.
543
      write_cache               If non-NULL a write cache that is to be
544
                                synchronized with the read caches.
545
      num_threads               Number of threads sharing the cache
546
                                including the write thread if any.
547
548
  DESCRIPTION
549
550
    The shared cache is used so: One IO_CACHE is initialized with
551
    init_io_cache(). This includes the allocation of a buffer. Then a
552
    share is allocated and init_io_cache_share() is called with the io
553
    cache and the share. Then the io cache is copied for each thread. So
554
    every thread has its own copy of IO_CACHE. But the allocated buffer
555
    is shared because cache->buffer is the same for all caches.
556
557
    One thread reads data from the file into the buffer. All threads
558
    read from the buffer, but every thread maintains its own set of
559
    pointers into the buffer. When all threads have used up the buffer
560
    contents, one of the threads reads the next block of data into the
561
    buffer. To accomplish this, each thread enters the cache lock before
562
    accessing the buffer. They wait in lock_io_cache() until all threads
563
    joined the lock. The last thread entering the lock is in charge of
564
    reading from file to buffer. It wakes all threads when done.
565
566
    Synchronizing a write cache to the read caches works so: Whenever
567
    the write buffer needs a flush, the write thread enters the lock and
568
    waits for all other threads to enter the lock too. They do this when
569
    they have used up the read buffer. When all threads are in the lock,
570
    the write thread copies the write buffer to the read buffer and
571
    wakes all threads.
572
573
    share->running_threads is the number of threads not being in the
574
    cache lock. When entering lock_io_cache() the number is decreased.
575
    When the thread that fills the buffer enters unlock_io_cache() the
576
    number is reset to the number of threads. The condition
577
    running_threads == 0 means that all threads are in the lock. Bumping
578
    up the number to the full count is non-intuitive. But increasing the
579
    number by one for each thread that leaves the lock could lead to a
580
    solo run of one thread. The last thread to join a lock reads from
581
    file to buffer, wakes the other threads, processes the data in the
582
    cache and enters the lock again. If no other thread left the lock
583
    meanwhile, it would think it's the last one again and read the next
584
    block...
585
586
    The share has copies of 'error', 'buffer', 'read_end', and
587
    'pos_in_file' from the thread that filled the buffer. We may not be
588
    able to access this information directly from its cache because the
589
    thread may be removed from the share before the variables could be
590
    copied by all other threads. Or, if a write buffer is synchronized,
591
    it would change its 'pos_in_file' after waking the other threads,
592
    possibly before they could copy its value.
593
594
    However, the 'buffer' variable in the share is for a synchronized
595
    write cache. It needs to know where to put the data. Otherwise it
596
    would need access to the read cache of one of the threads that is
597
    not yet removed from the share.
598
599
  RETURN
600
    void
601
*/
602
603
void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
482 by Brian Aker
Remove uint.
604
                         IO_CACHE *write_cache, uint32_t num_threads)
1 by brian
clean slate
605
{
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
606
  assert(num_threads > 1);
607
  assert(read_cache->type == READ_CACHE);
608
  assert(!write_cache || (write_cache->type == WRITE_CACHE));
1 by brian
clean slate
609
610
  pthread_mutex_init(&cshare->mutex, MY_MUTEX_INIT_FAST);
611
  pthread_cond_init(&cshare->cond, 0);
612
  pthread_cond_init(&cshare->cond_writer, 0);
613
614
  cshare->running_threads= num_threads;
615
  cshare->total_threads=   num_threads;
616
  cshare->error=           0;    /* Initialize. */
617
  cshare->buffer=          read_cache->buffer;
618
  cshare->read_end=        NULL; /* See function comment of lock_io_cache(). */
619
  cshare->pos_in_file=     0;    /* See function comment of lock_io_cache(). */
620
  cshare->source_cache=    write_cache; /* Can be NULL. */
621
622
  read_cache->share=         cshare;
623
  read_cache->read_function= _my_b_read_r;
624
  read_cache->current_pos=   NULL;
625
  read_cache->current_end=   NULL;
626
627
  if (write_cache)
628
    write_cache->share= cshare;
629
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
630
  return;
1 by brian
clean slate
631
}
632
633
634
/*
635
  Remove a thread from shared access to IO_CACHE.
636
637
  SYNOPSIS
638
    remove_io_thread()
639
      cache                     The IO_CACHE to be removed from the share.
640
641
  NOTE
642
643
    Every thread must do that on exit for not to deadlock other threads.
644
645
    The last thread destroys the pthread resources.
646
647
    A writer flushes its cache first.
648
649
  RETURN
650
    void
651
*/
652
653
void remove_io_thread(IO_CACHE *cache)
654
{
655
  IO_CACHE_SHARE *cshare= cache->share;
482 by Brian Aker
Remove uint.
656
  uint32_t total;
1 by brian
clean slate
657
658
  /* If the writer goes, it needs to flush the write cache. */
659
  if (cache == cshare->source_cache)
660
    flush_io_cache(cache);
661
662
  pthread_mutex_lock(&cshare->mutex);
663
664
  /* Remove from share. */
665
  total= --cshare->total_threads;
666
667
  /* Detach from share. */
668
  cache->share= NULL;
669
670
  /* If the writer goes, let the readers know. */
671
  if (cache == cshare->source_cache)
672
  {
673
    cshare->source_cache= NULL;
674
  }
675
676
  /* If all threads are waiting for me to join the lock, wake them. */
677
  if (!--cshare->running_threads)
678
  {
679
    pthread_cond_signal(&cshare->cond_writer);
680
    pthread_cond_broadcast(&cshare->cond);
681
  }
682
683
  pthread_mutex_unlock(&cshare->mutex);
684
685
  if (!total)
686
  {
687
    pthread_cond_destroy (&cshare->cond_writer);
688
    pthread_cond_destroy (&cshare->cond);
689
    pthread_mutex_destroy(&cshare->mutex);
690
  }
691
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
692
  return;
1 by brian
clean slate
693
}
694
695
696
/*
697
  Lock IO cache and wait for all other threads to join.
698
699
  SYNOPSIS
700
    lock_io_cache()
701
      cache                     The cache of the thread entering the lock.
702
      pos                       File position of the block to read.
703
                                Unused for the write thread.
704
705
  DESCRIPTION
706
707
    Wait for all threads to finish with the current buffer. We want
708
    all threads to proceed in concert. The last thread to join
709
    lock_io_cache() will read the block from file and all threads start
710
    to use it. Then they will join again for reading the next block.
711
712
    The waiting threads detect a fresh buffer by comparing
713
    cshare->pos_in_file with the position they want to process next.
714
    Since the first block may start at position 0, we take
715
    cshare->read_end as an additional condition. This variable is
716
    initialized to NULL and will be set after a block of data is written
717
    to the buffer.
718
719
  RETURN
720
    1           OK, lock in place, go ahead and read.
721
    0           OK, unlocked, another thread did the read.
722
*/
723
724
static int lock_io_cache(IO_CACHE *cache, my_off_t pos)
725
{
726
  IO_CACHE_SHARE *cshare= cache->share;
727
728
  /* Enter the lock. */
729
  pthread_mutex_lock(&cshare->mutex);
730
  cshare->running_threads--;
731
732
  if (cshare->source_cache)
733
  {
734
    /* A write cache is synchronized to the read caches. */
735
736
    if (cache == cshare->source_cache)
737
    {
738
      /* The writer waits until all readers are here. */
739
      while (cshare->running_threads)
740
      {
741
        pthread_cond_wait(&cshare->cond_writer, &cshare->mutex);
742
      }
743
      /* Stay locked. Leave the lock later by unlock_io_cache(). */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
744
      return(1);
1 by brian
clean slate
745
    }
746
747
    /* The last thread wakes the writer. */
748
    if (!cshare->running_threads)
749
    {
750
      pthread_cond_signal(&cshare->cond_writer);
751
    }
752
753
    /*
754
      Readers wait until the data is copied from the writer. Another
755
      reason to stop waiting is the removal of the write thread. If this
756
      happens, we leave the lock with old data in the buffer.
757
    */
758
    while ((!cshare->read_end || (cshare->pos_in_file < pos)) &&
759
           cshare->source_cache)
760
    {
761
      pthread_cond_wait(&cshare->cond, &cshare->mutex);
762
    }
763
764
    /*
765
      If the writer was removed from the share while this thread was
766
      asleep, we need to simulate an EOF condition. The writer cannot
767
      reset the share variables as they might still be in use by readers
768
      of the last block. When we awake here then because the last
769
      joining thread signalled us. If the writer is not the last, it
770
      will not signal. So it is safe to clear the buffer here.
771
    */
772
    if (!cshare->read_end || (cshare->pos_in_file < pos))
773
    {
774
      cshare->read_end= cshare->buffer; /* Empty buffer. */
775
      cshare->error= 0; /* EOF is not an error. */
776
    }
777
  }
778
  else
779
  {
780
    /*
781
      There are read caches only. The last thread arriving in
782
      lock_io_cache() continues with a locked cache and reads the block.
783
    */
784
    if (!cshare->running_threads)
785
    {
786
      /* Stay locked. Leave the lock later by unlock_io_cache(). */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
787
      return(1);
1 by brian
clean slate
788
    }
789
790
    /*
791
      All other threads wait until the requested block is read by the
792
      last thread arriving. Another reason to stop waiting is the
793
      removal of a thread. If this leads to all threads being in the
794
      lock, we have to continue also. The first of the awaken threads
795
      will then do the read.
796
    */
797
    while ((!cshare->read_end || (cshare->pos_in_file < pos)) &&
798
           cshare->running_threads)
799
    {
800
      pthread_cond_wait(&cshare->cond, &cshare->mutex);
801
    }
802
803
    /* If the block is not yet read, continue with a locked cache and read. */
804
    if (!cshare->read_end || (cshare->pos_in_file < pos))
805
    {
806
      /* Stay locked. Leave the lock later by unlock_io_cache(). */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
807
      return(1);
1 by brian
clean slate
808
    }
809
810
    /* Another thread did read the block already. */
811
  }
812
813
  /*
814
    Leave the lock. Do not call unlock_io_cache() later. The thread that
815
    filled the buffer did this and marked all threads as running.
816
  */
817
  pthread_mutex_unlock(&cshare->mutex);
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
818
  return(0);
1 by brian
clean slate
819
}
820
821
822
/*
823
  Unlock IO cache.
824
825
  SYNOPSIS
826
    unlock_io_cache()
827
      cache                     The cache of the thread leaving the lock.
828
829
  NOTE
830
    This is called by the thread that filled the buffer. It marks all
831
    threads as running and awakes them. This must not be done by any
832
    other thread.
833
834
    Do not signal cond_writer. Either there is no writer or the writer
835
    is the only one who can call this function.
836
837
    The reason for resetting running_threads to total_threads before
838
    waking all other threads is that it could be possible that this
839
    thread is so fast with processing the buffer that it enters the lock
840
    before even one other thread has left it. If every awoken thread
841
    would increase running_threads by one, this thread could think that
842
    he is again the last to join and would not wait for the other
843
    threads to process the data.
844
845
  RETURN
846
    void
847
*/
848
849
static void unlock_io_cache(IO_CACHE *cache)
850
{
851
  IO_CACHE_SHARE *cshare= cache->share;
852
853
  cshare->running_threads= cshare->total_threads;
854
  pthread_cond_broadcast(&cshare->cond);
855
  pthread_mutex_unlock(&cshare->mutex);
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
856
  return;
1 by brian
clean slate
857
}
858
859
860
/*
861
  Read from IO_CACHE when it is shared between several threads.
862
863
  SYNOPSIS
864
    _my_b_read_r()
865
      cache                     IO_CACHE pointer
866
      Buffer                    Buffer to retrieve count bytes from file
867
      Count                     Number of bytes to read into Buffer
868
869
  NOTE
870
    This function is only called from the my_b_read() macro when there
871
    isn't enough characters in the buffer to satisfy the request.
872
873
  IMPLEMENTATION
874
875
    It works as follows: when a thread tries to read from a file (that
876
    is, after using all the data from the (shared) buffer), it just
877
    hangs on lock_io_cache(), waiting for other threads. When the very
878
    last thread attempts a read, lock_io_cache() returns 1, the thread
879
    does actual IO and unlock_io_cache(), which signals all the waiting
880
    threads that data is in the buffer.
881
882
  WARNING
883
884
    When changing this function, be careful with handling file offsets
885
    (end-of_file, pos_in_file). Do not cast them to possibly smaller
886
    types than my_off_t unless you can be sure that their value fits.
887
    Same applies to differences of file offsets. (Bug #11527)
888
889
    When changing this function, check _my_b_read(). It might need the
890
    same change.
891
892
  RETURN
893
    0      we succeeded in reading all data
894
    1      Error: can't read requested characters
895
*/
896
1165.1.162 by Stewart Smith
SunStudio extern C fixes for mf_iocache.cc
897
extern "C" int _my_b_read_r(register IO_CACHE *cache, unsigned char *Buffer, size_t Count)
1 by brian
clean slate
898
{
899
  my_off_t pos_in_file;
900
  size_t length, diff_length, left_length;
901
  IO_CACHE_SHARE *cshare= cache->share;
902
903
  if ((left_length= (size_t) (cache->read_end - cache->read_pos)))
904
  {
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
905
    assert(Count >= left_length);	/* User is not using my_b_read() */
1 by brian
clean slate
906
    memcpy(Buffer, cache->read_pos, left_length);
907
    Buffer+= left_length;
908
    Count-= left_length;
909
  }
910
  while (Count)
911
  {
912
    size_t cnt, len;
913
914
    pos_in_file= cache->pos_in_file + (cache->read_end - cache->buffer);
915
    diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
916
    length=IO_ROUND_UP(Count+diff_length)-diff_length;
917
    length= ((length <= cache->read_length) ?
918
             length + IO_ROUND_DN(cache->read_length - length) :
919
             length - IO_ROUND_UP(length - cache->read_length));
920
    if (cache->type != READ_FIFO &&
921
	(length > (cache->end_of_file - pos_in_file)))
922
      length= (size_t) (cache->end_of_file - pos_in_file);
923
    if (length == 0)
924
    {
925
      cache->error= (int) left_length;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
926
      return(1);
1 by brian
clean slate
927
    }
928
    if (lock_io_cache(cache, pos_in_file))
929
    {
930
      /* With a synchronized write/read cache we won't come here... */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
931
      assert(!cshare->source_cache);
1 by brian
clean slate
932
      /*
933
        ... unless the writer has gone before this thread entered the
934
        lock. Simulate EOF in this case. It can be distinguished by
935
        cache->file.
936
      */
937
      if (cache->file < 0)
938
        len= 0;
939
      else
940
      {
941
        /*
942
          Whenever a function which operates on IO_CACHE flushes/writes
943
          some part of the IO_CACHE to disk it will set the property
944
          "seek_not_done" to indicate this to other functions operating
945
          on the IO_CACHE.
946
        */
947
        if (cache->seek_not_done)
948
        {
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
949
          if (lseek(cache->file, pos_in_file, SEEK_SET) == MY_FILEPOS_ERROR)
1 by brian
clean slate
950
          {
951
            cache->error= -1;
952
            unlock_io_cache(cache);
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
953
            return(1);
1 by brian
clean slate
954
          }
955
        }
956
        len= my_read(cache->file, cache->buffer, length, cache->myflags);
957
      }
958
      cache->read_end=    cache->buffer + (len == (size_t) -1 ? 0 : len);
959
      cache->error=       (len == length ? 0 : (int) len);
960
      cache->pos_in_file= pos_in_file;
961
962
      /* Copy important values to the share. */
963
      cshare->error=       cache->error;
964
      cshare->read_end=    cache->read_end;
965
      cshare->pos_in_file= pos_in_file;
966
967
      /* Mark all threads as running and wake them. */
968
      unlock_io_cache(cache);
969
    }
970
    else
971
    {
972
      /*
973
        With a synchronized write/read cache readers always come here.
974
        Copy important values from the share.
975
      */
976
      cache->error=       cshare->error;
977
      cache->read_end=    cshare->read_end;
978
      cache->pos_in_file= cshare->pos_in_file;
979
980
      len= ((cache->error == -1) ? (size_t) -1 :
981
            (size_t) (cache->read_end - cache->buffer));
982
    }
983
    cache->read_pos=      cache->buffer;
984
    cache->seek_not_done= 0;
985
    if (len == 0 || len == (size_t) -1)
986
    {
987
      cache->error= (int) left_length;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
988
      return(1);
1 by brian
clean slate
989
    }
990
    cnt= (len > Count) ? Count : len;
991
    memcpy(Buffer, cache->read_pos, cnt);
992
    Count -= cnt;
993
    Buffer+= cnt;
994
    left_length+= cnt;
995
    cache->read_pos+= cnt;
996
  }
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
997
  return(0);
1 by brian
clean slate
998
}
999
1000
1001
/*
1002
  Copy data from write cache to read cache.
1003
1004
  SYNOPSIS
1005
    copy_to_read_buffer()
1006
      write_cache               The write cache.
1007
      write_buffer              The source of data, mostly the cache buffer.
1008
      write_length              The number of bytes to copy.
1009
1010
  NOTE
1011
    The write thread will wait for all read threads to join the cache
1012
    lock. Then it copies the data over and wakes the read threads.
1013
1014
  RETURN
1015
    void
1016
*/
1017
1018
static void copy_to_read_buffer(IO_CACHE *write_cache,
481 by Brian Aker
Remove all of uchar.
1019
                                const unsigned char *write_buffer, size_t write_length)
1 by brian
clean slate
1020
{
1021
  IO_CACHE_SHARE *cshare= write_cache->share;
1022
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1023
  assert(cshare->source_cache == write_cache);
1 by brian
clean slate
1024
  /*
1025
    write_length is usually less or equal to buffer_length.
1026
    It can be bigger if _my_b_write() is called with a big length.
1027
  */
1028
  while (write_length)
1029
  {
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
1030
    size_t copy_length= min(write_length, write_cache->buffer_length);
595 by Brian Aker
Fix, partial, for Sun Studio.
1031
    int  rc;
1 by brian
clean slate
1032
1033
    rc= lock_io_cache(write_cache, write_cache->pos_in_file);
1034
    /* The writing thread does always have the lock when it awakes. */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1035
    assert(rc);
1 by brian
clean slate
1036
1037
    memcpy(cshare->buffer, write_buffer, copy_length);
1038
1039
    cshare->error=       0;
1040
    cshare->read_end=    cshare->buffer + copy_length;
1041
    cshare->pos_in_file= write_cache->pos_in_file;
1042
1043
    /* Mark all threads as running and wake them. */
1044
    unlock_io_cache(write_cache);
1045
1046
    write_buffer+= copy_length;
1047
    write_length-= copy_length;
1048
  }
1049
}
1050
1051
1052
/*
1053
  Do sequential read from the SEQ_READ_APPEND cache.
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
1054
1 by brian
clean slate
1055
  We do this in three stages:
1056
   - first read from info->buffer
1057
   - then if there are still data to read, try the file descriptor
1058
   - afterwards, if there are still data to read, try append buffer
1059
1060
  RETURNS
1061
    0  Success
1062
    1  Failed to read
1063
*/
1064
1165.1.162 by Stewart Smith
SunStudio extern C fixes for mf_iocache.cc
1065
extern "C" int _my_b_seq_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
1 by brian
clean slate
1066
{
1067
  size_t length, diff_length, left_length, save_count, max_length;
1068
  my_off_t pos_in_file;
1069
  save_count=Count;
1070
1071
  /* first, read the regular buffer */
1072
  if ((left_length=(size_t) (info->read_end-info->read_pos)))
1073
  {
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1074
    assert(Count > left_length);	/* User is not using my_b_read() */
1 by brian
clean slate
1075
    memcpy(Buffer,info->read_pos, left_length);
1076
    Buffer+=left_length;
1077
    Count-=left_length;
1078
  }
1079
  lock_append_buffer(info);
1080
1081
  /* pos_in_file always point on where info->buffer was read */
1082
  if ((pos_in_file=info->pos_in_file +
1083
       (size_t) (info->read_end - info->buffer)) >= info->end_of_file)
1084
    goto read_append_buffer;
1085
1086
  /*
1087
    With read-append cache we must always do a seek before we read,
1088
    because the write could have moved the file pointer astray
1089
  */
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
1090
  if (lseek(info->file,pos_in_file,SEEK_SET) == MY_FILEPOS_ERROR)
1 by brian
clean slate
1091
  {
1092
   info->error= -1;
1093
   unlock_append_buffer(info);
1094
   return (1);
1095
  }
1096
  info->seek_not_done=0;
1097
1098
  diff_length= (size_t) (pos_in_file & (IO_SIZE-1));
1099
1100
  /* now the second stage begins - read from file descriptor */
1101
  if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length)))
1102
  {
1103
    /* Fill first intern buffer */
1104
    size_t read_length;
1105
1106
    length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
1107
    if ((read_length= my_read(info->file,Buffer, length,
1108
                              info->myflags)) == (size_t) -1)
1109
    {
1110
      info->error= -1;
1111
      unlock_append_buffer(info);
1112
      return 1;
1113
    }
1114
    Count-=read_length;
1115
    Buffer+=read_length;
1116
    pos_in_file+=read_length;
1117
1118
    if (read_length != length)
1119
    {
1120
      /*
1121
	We only got part of data;  Read the rest of the data from the
1122
	write buffer
1123
      */
1124
      goto read_append_buffer;
1125
    }
1126
    left_length+=length;
1127
    diff_length=0;
1128
  }
1129
1130
  max_length= info->read_length-diff_length;
1131
  if (max_length > (info->end_of_file - pos_in_file))
1132
    max_length= (size_t) (info->end_of_file - pos_in_file);
1133
  if (!max_length)
1134
  {
1135
    if (Count)
1136
      goto read_append_buffer;
1137
    length=0;				/* Didn't read any more chars */
1138
  }
1139
  else
1140
  {
1141
    length= my_read(info->file,info->buffer, max_length, info->myflags);
1142
    if (length == (size_t) -1)
1143
    {
1144
      info->error= -1;
1145
      unlock_append_buffer(info);
1146
      return 1;
1147
    }
1148
    if (length < Count)
1149
    {
1150
      memcpy(Buffer, info->buffer, length);
1151
      Count -= length;
1152
      Buffer += length;
1153
1154
      /*
1155
	 added the line below to make
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1156
	 assert(pos_in_file==info->end_of_file) pass.
1 by brian
clean slate
1157
	 otherwise this does not appear to be needed
1158
      */
1159
      pos_in_file += length;
1160
      goto read_append_buffer;
1161
    }
1162
  }
1163
  unlock_append_buffer(info);
1164
  info->read_pos=info->buffer+Count;
1165
  info->read_end=info->buffer+length;
1166
  info->pos_in_file=pos_in_file;
1167
  memcpy(Buffer,info->buffer,(size_t) Count);
1168
  return 0;
1169
1170
read_append_buffer:
1171
1172
  /*
1173
     Read data from the current write buffer.
1174
     Count should never be == 0 here (The code will work even if count is 0)
1175
  */
1176
1177
  {
1178
    /* First copy the data to Count */
1179
    size_t len_in_buff = (size_t) (info->write_pos - info->append_read_pos);
1180
    size_t copy_len;
1181
    size_t transfer_len;
1182
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1183
    assert(info->append_read_pos <= info->write_pos);
1 by brian
clean slate
1184
    /*
1185
      TODO: figure out if the assert below is needed or correct.
1186
    */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1187
    assert(pos_in_file == info->end_of_file);
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
1188
    copy_len=min(Count, len_in_buff);
1 by brian
clean slate
1189
    memcpy(Buffer, info->append_read_pos, copy_len);
1190
    info->append_read_pos += copy_len;
1191
    Count -= copy_len;
1192
    if (Count)
1126.13.8 by Joe Daly
Fix up spacing in various files, also had new style casts in several places
1193
      info->error = static_cast<int>(save_count - Count);
1 by brian
clean slate
1194
1195
    /* Fill read buffer with data from write buffer */
1196
    memcpy(info->buffer, info->append_read_pos,
1197
	   (size_t) (transfer_len=len_in_buff - copy_len));
1198
    info->read_pos= info->buffer;
1199
    info->read_end= info->buffer+transfer_len;
1200
    info->append_read_pos=info->write_pos;
1201
    info->pos_in_file=pos_in_file+copy_len;
1202
    info->end_of_file+=len_in_buff;
1203
  }
1204
  unlock_append_buffer(info);
1205
  return Count ? 1 : 0;
1206
}
1207
1208
1209
#ifdef HAVE_AIOWAIT
1210
1211
/*
1212
  Read from the IO_CACHE into a buffer and feed asynchronously
1213
  from disk when needed.
1214
1215
  SYNOPSIS
1216
    _my_b_async_read()
1217
      info                      IO_CACHE pointer
1218
      Buffer                    Buffer to retrieve count bytes from file
1219
      Count                     Number of bytes to read into Buffer
1220
1221
  RETURN VALUE
1222
    -1          An error has occurred; my_errno is set.
1223
     0          Success
1224
     1          An error has occurred; IO_CACHE to error state.
1225
*/
1226
481 by Brian Aker
Remove all of uchar.
1227
int _my_b_async_read(register IO_CACHE *info, unsigned char *Buffer, size_t Count)
1 by brian
clean slate
1228
{
1229
  size_t length,read_length,diff_length,left_length,use_length,org_Count;
1230
  size_t max_length;
1231
  my_off_t next_pos_in_file;
481 by Brian Aker
Remove all of uchar.
1232
  unsigned char *read_buffer;
1 by brian
clean slate
1233
1234
  memcpy(Buffer,info->read_pos,
1235
	 (left_length= (size_t) (info->read_end-info->read_pos)));
1236
  Buffer+=left_length;
1237
  org_Count=Count;
1238
  Count-=left_length;
1239
1240
  if (info->inited)
1241
  {						/* wait for read block */
1242
    info->inited=0;				/* No more block to read */
1243
    my_aiowait(&info->aio_result);		/* Wait for outstanding req */
1244
    if (info->aio_result.result.aio_errno)
1245
    {
1246
      if (info->myflags & MY_WME)
1247
	my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
1248
		 my_filename(info->file),
1249
		 info->aio_result.result.aio_errno);
1250
      my_errno=info->aio_result.result.aio_errno;
1251
      info->error= -1;
1252
      return(1);
1253
    }
1254
    if (! (read_length= (size_t) info->aio_result.result.aio_return) ||
1255
	read_length == (size_t) -1)
1256
    {
1257
      my_errno=0;				/* For testing */
1258
      info->error= (read_length == (size_t) -1 ? -1 :
1259
		    (int) (read_length+left_length));
1260
      return(1);
1261
    }
1262
    info->pos_in_file+= (size_t) (info->read_end - info->request_pos);
1263
1264
    if (info->request_pos != info->buffer)
1265
      info->request_pos=info->buffer;
1266
    else
1267
      info->request_pos=info->buffer+info->read_length;
1268
    info->read_pos=info->request_pos;
1269
    next_pos_in_file=info->aio_read_pos+read_length;
1270
1271
	/* Check if pos_in_file is changed
1272
	   (_ni_read_cache may have skipped some bytes) */
1273
1274
    if (info->aio_read_pos < info->pos_in_file)
1275
    {						/* Fix if skipped bytes */
1276
      if (info->aio_read_pos + read_length < info->pos_in_file)
1277
      {
1278
	read_length=0;				/* Skip block */
1279
	next_pos_in_file=info->pos_in_file;
1280
      }
1281
      else
1282
      {
1283
	my_off_t offset= (info->pos_in_file - info->aio_read_pos);
1284
	info->pos_in_file=info->aio_read_pos; /* Whe are here */
1285
	info->read_pos=info->request_pos+offset;
1286
	read_length-=offset;			/* Bytes left from read_pos */
1287
      }
1288
    }
1289
	/* Copy found bytes to buffer */
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
1290
    length=min(Count,read_length);
1 by brian
clean slate
1291
    memcpy(Buffer,info->read_pos,(size_t) length);
1292
    Buffer+=length;
1293
    Count-=length;
1294
    left_length+=length;
1295
    info->read_end=info->rc_pos+read_length;
1296
    info->read_pos+=length;
1297
  }
1298
  else
1299
    next_pos_in_file=(info->pos_in_file+ (size_t)
1300
		      (info->read_end - info->request_pos));
1301
1302
	/* If reading large blocks, or first read or read with skip */
1303
  if (Count)
1304
  {
1305
    if (next_pos_in_file == info->end_of_file)
1306
    {
1307
      info->error=(int) (read_length+left_length);
1308
      return 1;
1309
    }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
1310
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
1311
    if (lseek(info->file,next_pos_in_file,SEEK_SET) == MY_FILEPOS_ERROR)
1 by brian
clean slate
1312
    {
1313
      info->error= -1;
1314
      return (1);
1315
    }
1316
1317
    read_length=IO_SIZE*2- (size_t) (next_pos_in_file & (IO_SIZE-1));
1318
    if (Count < read_length)
1319
    {					/* Small block, read to cache */
1320
      if ((read_length=my_read(info->file,info->request_pos,
1321
			       read_length, info->myflags)) == (size_t) -1)
1322
        return info->error= -1;
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
1323
      use_length=min(Count,read_length);
1 by brian
clean slate
1324
      memcpy(Buffer,info->request_pos,(size_t) use_length);
1325
      info->read_pos=info->request_pos+Count;
1326
      info->read_end=info->request_pos+read_length;
1327
      info->pos_in_file=next_pos_in_file;	/* Start of block in cache */
1328
      next_pos_in_file+=read_length;
1329
1330
      if (Count != use_length)
1331
      {					/* Didn't find hole block */
1332
	if (info->myflags & (MY_WME | MY_FAE | MY_FNABP) && Count != org_Count)
1333
	  my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
1334
		   my_filename(info->file),my_errno);
1335
	info->error=(int) (read_length+left_length);
1336
	return 1;
1337
      }
1338
    }
1339
    else
1340
    {						/* Big block, don't cache it */
1341
      if ((read_length= my_read(info->file,Buffer, Count,info->myflags))
1342
	  != Count)
1343
      {
1344
	info->error= read_length == (size_t) -1 ? -1 : read_length+left_length;
1345
	return 1;
1346
      }
1347
      info->read_pos=info->read_end=info->request_pos;
1348
      info->pos_in_file=(next_pos_in_file+=Count);
1349
    }
1350
  }
1351
1352
  /* Read next block with asyncronic io */
1353
  diff_length=(next_pos_in_file & (IO_SIZE-1));
1354
  max_length= info->read_length - diff_length;
1355
  if (max_length > info->end_of_file - next_pos_in_file)
1356
    max_length= (size_t) (info->end_of_file - next_pos_in_file);
1357
1358
  if (info->request_pos != info->buffer)
1359
    read_buffer=info->buffer;
1360
  else
1361
    read_buffer=info->buffer+info->read_length;
1362
  info->aio_read_pos=next_pos_in_file;
1363
  if (max_length)
1364
  {
1365
    info->aio_result.result.aio_errno=AIO_INPROGRESS;	/* Marker for test */
1366
    if (aioread(info->file,read_buffer, max_length,
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
1367
		(my_off_t) next_pos_in_file,SEEK_SET,
1 by brian
clean slate
1368
		&info->aio_result.result))
1369
    {						/* Skip async io */
1370
      my_errno=errno;
1371
      if (info->request_pos != info->buffer)
1372
      {
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
1373
        memmove(info->buffer, info->request_pos,
1374
                (size_t) (info->read_end - info->read_pos));
1 by brian
clean slate
1375
	info->request_pos=info->buffer;
1376
	info->read_pos-=info->read_length;
1377
	info->read_end-=info->read_length;
1378
      }
1379
      info->read_length=info->buffer_length;	/* Use hole buffer */
1380
      info->read_function=_my_b_read;		/* Use normal IO_READ next */
1381
    }
1382
    else
1383
      info->inited=info->aio_result.pending=1;
1384
  }
1385
  return 0;					/* Block read, async in use */
1386
} /* _my_b_async_read */
1387
#endif
1388
1389
1390
/* Read one byte when buffer is empty */
1391
1392
int _my_b_get(IO_CACHE *info)
1393
{
481 by Brian Aker
Remove all of uchar.
1394
  unsigned char buff;
1 by brian
clean slate
1395
  IO_CACHE_CALLBACK pre_read,post_read;
1396
  if ((pre_read = info->pre_read))
1397
    (*pre_read)(info);
1398
  if ((*(info)->read_function)(info,&buff,1))
1399
    return my_b_EOF;
1400
  if ((post_read = info->post_read))
1401
    (*post_read)(info);
481 by Brian Aker
Remove all of uchar.
1402
  return (int) (unsigned char) buff;
1 by brian
clean slate
1403
}
1404
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
1405
/*
1 by brian
clean slate
1406
   Write a byte buffer to IO_CACHE and flush to disk
1407
   if IO_CACHE is full.
1408
1409
   RETURN VALUE
1410
    1 On error on write
1411
    0 On success
1412
   -1 On error; my_errno contains error code.
1413
*/
1414
1165.1.162 by Stewart Smith
SunStudio extern C fixes for mf_iocache.cc
1415
extern "C" int _my_b_write(register IO_CACHE *info, const unsigned char *Buffer, size_t Count)
1 by brian
clean slate
1416
{
1417
  size_t rest_length,length;
1418
1419
  if (info->pos_in_file+info->buffer_length > info->end_of_file)
1420
  {
1421
    my_errno=errno=EFBIG;
1422
    return info->error = -1;
1423
  }
1424
1425
  rest_length= (size_t) (info->write_end - info->write_pos);
1426
  memcpy(info->write_pos,Buffer,(size_t) rest_length);
1427
  Buffer+=rest_length;
1428
  Count-=rest_length;
1429
  info->write_pos+=rest_length;
1430
1431
  if (my_b_flush_io_cache(info,1))
1432
    return 1;
1433
  if (Count >= IO_SIZE)
1434
  {					/* Fill first intern buffer */
1435
    length=Count & (size_t) ~(IO_SIZE-1);
1436
    if (info->seek_not_done)
1437
    {
1438
      /*
1439
        Whenever a function which operates on IO_CACHE flushes/writes
1440
        some part of the IO_CACHE to disk it will set the property
1441
        "seek_not_done" to indicate this to other functions operating
1442
        on the IO_CACHE.
1443
      */
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
1444
      if (lseek(info->file,info->pos_in_file,SEEK_SET))
1 by brian
clean slate
1445
      {
1446
        info->error= -1;
1447
        return (1);
1448
      }
1449
      info->seek_not_done=0;
1450
    }
1451
    if (my_write(info->file, Buffer, length, info->myflags | MY_NABP))
1452
      return info->error= -1;
1453
1454
    /*
1455
      In case of a shared I/O cache with a writer we normally do direct
1456
      write cache to read cache copy. Simulate this here by direct
1457
      caller buffer to read cache copy. Do it after the write so that
1458
      the cache readers actions on the flushed part can go in parallel
1459
      with the write of the extra stuff. copy_to_read_buffer()
1460
      synchronizes writer and readers so that after this call the
1461
      readers can act on the extra stuff while the writer can go ahead
1462
      and prepare the next output. copy_to_read_buffer() relies on
1463
      info->pos_in_file.
1464
    */
1465
    if (info->share)
1466
      copy_to_read_buffer(info, Buffer, length);
1467
1468
    Count-=length;
1469
    Buffer+=length;
1470
    info->pos_in_file+=length;
1471
  }
1472
  memcpy(info->write_pos,Buffer,(size_t) Count);
1473
  info->write_pos+=Count;
1474
  return 0;
1475
}
1476
1477
/*
1478
  Write a block to disk where part of the data may be inside the record
1479
  buffer.  As all write calls to the data goes through the cache,
1480
  we will never get a seek over the end of the buffer
1481
*/
1482
481 by Brian Aker
Remove all of uchar.
1483
int my_block_write(register IO_CACHE *info, const unsigned char *Buffer, size_t Count,
1 by brian
clean slate
1484
		   my_off_t pos)
1485
{
1486
  size_t length;
1487
  int error=0;
1488
1489
  /*
1490
    Assert that we cannot come here with a shared cache. If we do one
1491
    day, we might need to add a call to copy_to_read_buffer().
1492
  */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1493
  assert(!info->share);
1 by brian
clean slate
1494
1495
  if (pos < info->pos_in_file)
1496
  {
1497
    /* Of no overlap, write everything without buffering */
1498
    if (pos + Count <= info->pos_in_file)
32 by Brian Aker
More cleanup on pread()
1499
      return (pwrite(info->file, Buffer, Count, pos) == 0);
1 by brian
clean slate
1500
    /* Write the part of the block that is before buffer */
895 by Brian Aker
Completion (?) of uint conversion.
1501
    length= (uint32_t) (info->pos_in_file - pos);
32 by Brian Aker
More cleanup on pread()
1502
    if (pwrite(info->file, Buffer, length, pos) == 0)
1 by brian
clean slate
1503
      info->error= error= -1;
1504
    Buffer+=length;
1505
    pos+=  length;
1506
    Count-= length;
1507
#ifndef HAVE_PREAD
1508
    info->seek_not_done=1;
1509
#endif
1510
  }
1511
1512
  /* Check if we want to write inside the used part of the buffer.*/
1513
  length= (size_t) (info->write_end - info->buffer);
1514
  if (pos < info->pos_in_file + length)
1515
  {
1516
    size_t offset= (size_t) (pos - info->pos_in_file);
1517
    length-=offset;
1518
    if (length > Count)
1519
      length=Count;
1520
    memcpy(info->buffer+offset, Buffer, length);
1521
    Buffer+=length;
1522
    Count-= length;
1523
    /* Fix length of buffer if the new data was larger */
1524
    if (info->buffer+length > info->write_pos)
1525
      info->write_pos=info->buffer+length;
1526
    if (!Count)
1527
      return (error);
1528
  }
1529
  /* Write at the end of the current buffer; This is the normal case */
1530
  if (_my_b_write(info, Buffer, Count))
1531
    error= -1;
1532
  return error;
1533
}
1534
1535
1536
	/* Flush write cache */
1537
1538
#define LOCK_APPEND_BUFFER if (need_append_buffer_lock) \
1539
  lock_append_buffer(info);
1540
#define UNLOCK_APPEND_BUFFER if (need_append_buffer_lock) \
1541
  unlock_append_buffer(info);
1542
1543
int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
1544
{
1545
  size_t length;
146 by Brian Aker
my_bool cleanup.
1546
  bool append_cache;
1 by brian
clean slate
1547
  my_off_t pos_in_file;
1548
1549
  if (!(append_cache = (info->type == SEQ_READ_APPEND)))
1550
    need_append_buffer_lock=0;
1551
1552
  if (info->type == WRITE_CACHE || append_cache)
1553
  {
1554
    if (info->file == -1)
1555
    {
1556
      if (real_open_cached_file(info))
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1557
	return((info->error= -1));
1 by brian
clean slate
1558
    }
1559
    LOCK_APPEND_BUFFER;
1560
1561
    if ((length=(size_t) (info->write_pos - info->write_buffer)))
1562
    {
1563
      /*
1564
        In case of a shared I/O cache with a writer we do direct write
1565
        cache to read cache copy. Do it before the write here so that
1566
        the readers can work in parallel with the write.
1567
        copy_to_read_buffer() relies on info->pos_in_file.
1568
      */
1569
      if (info->share)
1570
        copy_to_read_buffer(info, info->write_buffer, length);
1571
1572
      pos_in_file=info->pos_in_file;
1573
      /*
1574
	If we have append cache, we always open the file with
1575
	O_APPEND which moves the pos to EOF automatically on every write
1576
      */
1577
      if (!append_cache && info->seek_not_done)
1578
      {					/* File touched, do seek */
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
1579
	if (lseek(info->file,pos_in_file,SEEK_SET) == MY_FILEPOS_ERROR)
1 by brian
clean slate
1580
	{
1581
	  UNLOCK_APPEND_BUFFER;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1582
	  return((info->error= -1));
1 by brian
clean slate
1583
	}
1584
	if (!append_cache)
1585
	  info->seek_not_done=0;
1586
      }
1587
      if (!append_cache)
1588
	info->pos_in_file+=length;
1589
      info->write_end= (info->write_buffer+info->buffer_length-
1590
			((pos_in_file+length) & (IO_SIZE-1)));
1591
1592
      if (my_write(info->file,info->write_buffer,length,
1593
		   info->myflags | MY_NABP))
1594
	info->error= -1;
1595
      else
1596
	info->error= 0;
1597
      if (!append_cache)
1598
      {
1599
        set_if_bigger(info->end_of_file,(pos_in_file+length));
1600
      }
1601
      else
1602
      {
1603
	info->end_of_file+=(info->write_pos-info->append_read_pos);
656.1.39 by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek.
1604
	my_off_t tell_ret= lseek(info->file, 0, SEEK_CUR);
632.1.15 by Monty
Finished fixing my_tell.
1605
	assert(info->end_of_file == tell_ret);
1 by brian
clean slate
1606
      }
1607
1608
      info->append_read_pos=info->write_pos=info->write_buffer;
1609
      UNLOCK_APPEND_BUFFER;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1610
      return(info->error);
1 by brian
clean slate
1611
    }
1612
  }
1613
#ifdef HAVE_AIOWAIT
1614
  else if (info->type != READ_NET)
1615
  {
1616
    my_aiowait(&info->aio_result);		/* Wait for outstanding req */
1617
    info->inited=0;
1618
  }
1619
#endif
1620
  UNLOCK_APPEND_BUFFER;
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1621
  return(0);
1 by brian
clean slate
1622
}
1623
1624
/*
1625
  Free an IO_CACHE object
1626
1627
  SYNOPSOS
1628
    end_io_cache()
1629
    info		IO_CACHE Handle to free
1630
1631
  NOTES
1632
    It's currently safe to call this if one has called init_io_cache()
1633
    on the 'info' object, even if init_io_cache() failed.
1634
    This function is also safe to call twice with the same handle.
1635
1636
  RETURN
1637
   0  ok
1638
   #  Error
1639
*/
1640
1641
int end_io_cache(IO_CACHE *info)
1642
{
1643
  int error=0;
1644
  IO_CACHE_CALLBACK pre_close;
1645
1646
  /*
1647
    Every thread must call remove_io_thread(). The last one destroys
1648
    the share elements.
1649
  */
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1650
  assert(!info->share || !info->share->total_threads);
1 by brian
clean slate
1651
1652
  if ((pre_close=info->pre_close))
1653
  {
1654
    (*pre_close)(info);
1655
    info->pre_close= 0;
1656
  }
1657
  if (info->alloced_buffer)
1658
  {
1659
    info->alloced_buffer=0;
1660
    if (info->file != -1)			/* File doesn't exist */
1661
      error= my_b_flush_io_cache(info,1);
481 by Brian Aker
Remove all of uchar.
1662
    free((unsigned char*) info->buffer);
1663
    info->buffer=info->read_pos=(unsigned char*) 0;
1 by brian
clean slate
1664
  }
1665
  if (info->type == SEQ_READ_APPEND)
1666
  {
1667
    /* Destroy allocated mutex */
1668
    info->type= TYPE_NOT_SET;
1669
    pthread_mutex_destroy(&info->append_buffer_lock);
1670
  }
51.3.22 by Jay Pipes
Final round of removal of DBUG in mysys/, including Makefile
1671
  return(error);
1 by brian
clean slate
1672
} /* end_io_cache */
1673
1674
1675
/**********************************************************************
1676
 Testing of MF_IOCACHE
1677
**********************************************************************/
1678
1679
#ifdef MAIN
1680
1681
#include <my_dir.h>
1682
1683
void die(const char* fmt, ...)
1684
{
1685
  va_list va_args;
1686
  va_start(va_args,fmt);
1687
  fprintf(stderr,"Error:");
1688
  vfprintf(stderr, fmt,va_args);
1689
  fprintf(stderr,", errno=%d\n", errno);
1690
  exit(1);
1691
}
1692
1693
int open_file(const char* fname, IO_CACHE* info, int cache_size)
1694
{
1695
  int fd;
1696
  if ((fd=my_open(fname,O_CREAT | O_RDWR,MYF(MY_WME))) < 0)
1697
    die("Could not open %s", fname);
1698
  if (init_io_cache(info, fd, cache_size, SEQ_READ_APPEND, 0,0,MYF(MY_WME)))
1699
    die("failed in init_io_cache()");
1700
  return fd;
1701
}
1702
1703
void close_file(IO_CACHE* info)
1704
{
1705
  end_io_cache(info);
1706
  my_close(info->file, MYF(MY_WME));
1707
}
1708
1709
int main(int argc, char** argv)
1710
{
1711
  IO_CACHE sra_cache; /* SEQ_READ_APPEND */
1712
  MY_STAT status;
1713
  const char* fname="/tmp/iocache.test";
1714
  int cache_size=16384;
1715
  char llstr_buf[22];
1716
  int max_block,total_bytes=0;
1717
  int i,num_loops=100,error=0;
1718
  char *p;
1719
  char* block, *block_end;
1720
  MY_INIT(argv[0]);
1721
  max_block = cache_size*3;
656.1.26 by Monty Taylor
Finally removed all of the my_malloc stuff.
1722
  if (!(block=(char*)malloc(max_block)))
1 by brian
clean slate
1723
    die("Not enough memory to allocate test block");
1724
  block_end = block + max_block;
1725
  for (p = block,i=0; p < block_end;i++)
1726
  {
1727
    *p++ = (char)i;
1728
  }
1729
  if (my_stat(fname,&status, MYF(0)) &&
1730
      my_delete(fname,MYF(MY_WME)))
1731
    {
1732
      die("Delete of %s failed, aborting", fname);
1733
    }
1734
  open_file(fname,&sra_cache, cache_size);
1735
  for (i = 0; i < num_loops; i++)
1736
  {
1737
    char buf[4];
1738
    int block_size = abs(rand() % max_block);
1739
    int4store(buf, block_size);
1740
    if (my_b_append(&sra_cache,buf,4) ||
1741
	my_b_append(&sra_cache, block, block_size))
1742
      die("write failed");
1743
    total_bytes += 4+block_size;
1744
  }
1745
  close_file(&sra_cache);
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
1746
  free(block);
1 by brian
clean slate
1747
  if (!my_stat(fname,&status,MYF(MY_WME)))
1748
    die("%s failed to stat, but I had just closed it,\
1749
 wonder how that happened");
1750
  printf("Final size of %s is %s, wrote %d bytes\n",fname,
1751
	 llstr(status.st_size,llstr_buf),
1752
	 total_bytes);
1753
  my_delete(fname, MYF(MY_WME));
1754
  /* check correctness of tests */
1755
  if (total_bytes != status.st_size)
1756
  {
1757
    fprintf(stderr,"Not the same number of bytes acutally  in file as bytes \
1758
supposedly written\n");
1759
    error=1;
1760
  }
1761
  exit(error);
1762
  return 0;
1763
}
1764
#endif