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