~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/mf_iocache2.cc

  • Committer: Brian Aker
  • Date: 2009-07-16 22:37:01 UTC
  • mto: This revision was merged to the branch mainline in revision 1100.
  • Revision ID: brian@gaz-20090716223701-vbbbo8dmgd2ljqqo
Refactor TableShare has to be behind class.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
  More functions to be used with IO_CACHE files
 
18
*/
 
19
 
 
20
#include "mysys/mysys_priv.h"
 
21
#include <mystrings/m_string.h>
 
22
#include <stdarg.h>
 
23
#include <mystrings/m_ctype.h>
 
24
#include <mysys/iocache.h>
 
25
#include <string>
 
26
 
 
27
using namespace std;
 
28
 
 
29
/*
 
30
  Copy contents of an IO_CACHE to a file.
 
31
 
 
32
  SYNOPSIS
 
33
    my_b_copy_to_file()
 
34
    cache  IO_CACHE to copy from
 
35
    file   File to copy to
 
36
 
 
37
  DESCRIPTION
 
38
    Copy the contents of the cache to the file. The cache will be
 
39
    re-inited to a read cache and will read from the beginning of the
 
40
    cache.
 
41
 
 
42
    If a failure to write fully occurs, the cache is only copied
 
43
    partially.
 
44
 
 
45
  TODO
 
46
    Make this function solid by handling partial reads from the cache
 
47
    in a correct manner: it should be atomic.
 
48
 
 
49
  RETURN VALUE
 
50
    0  All OK
 
51
    1  An error occured
 
52
*/
 
53
int
 
54
my_b_copy_to_file(IO_CACHE *cache, FILE *file)
 
55
{
 
56
  size_t bytes_in_cache;
 
57
 
 
58
  /* Reinit the cache to read from the beginning of the cache */
 
59
  if (reinit_io_cache(cache, READ_CACHE, 0L, false, false))
 
60
    return(1);
 
61
  bytes_in_cache= my_b_bytes_in_cache(cache);
 
62
  do
 
63
  {
 
64
    if (fwrite(cache->read_pos, 1, bytes_in_cache, file)
 
65
               != bytes_in_cache)
 
66
      return(1);
 
67
    cache->read_pos= cache->read_end;
 
68
  } while ((bytes_in_cache= my_b_fill(cache)));
 
69
  return(0);
 
70
}
 
71
 
 
72
 
 
73
my_off_t my_b_append_tell(IO_CACHE* info)
 
74
{
 
75
  /*
 
76
    Prevent optimizer from putting res in a register when debugging
 
77
    we need this to be able to see the value of res when the assert fails
 
78
  */
 
79
  volatile my_off_t res;
 
80
 
 
81
  /*
 
82
    We need to lock the append buffer mutex to keep flush_io_cache()
 
83
    from messing with the variables that we need in order to provide the
 
84
    answer to the question.
 
85
  */
 
86
  pthread_mutex_lock(&info->append_buffer_lock);
 
87
  res = info->end_of_file + (info->write_pos-info->append_read_pos);
 
88
  pthread_mutex_unlock(&info->append_buffer_lock);
 
89
  return res;
 
90
}
 
91
 
 
92
my_off_t my_b_safe_tell(IO_CACHE *info)
 
93
{
 
94
  if (unlikely(info->type == SEQ_READ_APPEND))
 
95
    return my_b_append_tell(info);
 
96
  return my_b_tell(info);
 
97
}
 
98
 
 
99
/*
 
100
  Make next read happen at the given position
 
101
  For write cache, make next write happen at the given position
 
102
*/
 
103
 
 
104
void my_b_seek(IO_CACHE *info,my_off_t pos)
 
105
{
 
106
  my_off_t offset;
 
107
 
 
108
  /*
 
109
    TODO:
 
110
       Verify that it is OK to do seek in the non-append
 
111
       area in SEQ_READ_APPEND cache
 
112
     a) see if this always works
 
113
     b) see if there is a better way to make it work
 
114
  */
 
115
  if (info->type == SEQ_READ_APPEND)
 
116
    flush_io_cache(info);
 
117
 
 
118
  offset=(pos - info->pos_in_file);
 
119
 
 
120
  if (info->type == READ_CACHE || info->type == SEQ_READ_APPEND)
 
121
  {
 
122
    /* TODO: explain why this works if pos < info->pos_in_file */
 
123
    if ((uint64_t) offset < (uint64_t) (info->read_end - info->buffer))
 
124
    {
 
125
      /* The read is in the current buffer; Reuse it */
 
126
      info->read_pos = info->buffer + offset;
 
127
      return;
 
128
    }
 
129
    else
 
130
    {
 
131
      /* Force a new read on next my_b_read */
 
132
      info->read_pos=info->read_end=info->buffer;
 
133
    }
 
134
  }
 
135
  else if (info->type == WRITE_CACHE)
 
136
  {
 
137
    /* If write is in current buffer, reuse it */
 
138
    if ((uint64_t) offset <
 
139
        (uint64_t) (info->write_end - info->write_buffer))
 
140
    {
 
141
      info->write_pos = info->write_buffer + offset;
 
142
      return;
 
143
    }
 
144
    flush_io_cache(info);
 
145
    /* Correct buffer end so that we write in increments of IO_SIZE */
 
146
    info->write_end=(info->write_buffer+info->buffer_length-
 
147
                     (pos & (IO_SIZE-1)));
 
148
  }
 
149
  info->pos_in_file=pos;
 
150
  info->seek_not_done=1;
 
151
  return;
 
152
}
 
153
 
 
154
 
 
155
/*
 
156
  Fill buffer of the cache.
 
157
 
 
158
  NOTES
 
159
    This assumes that you have already used all characters in the CACHE,
 
160
    independent of the read_pos value!
 
161
 
 
162
  RETURN
 
163
  0  On error or EOF (info->error = -1 on error)
 
164
  #  Number of characters
 
165
*/
 
166
 
 
167
 
 
168
size_t my_b_fill(IO_CACHE *info)
 
169
{
 
170
  my_off_t pos_in_file=(info->pos_in_file+
 
171
                        (size_t) (info->read_end - info->buffer));
 
172
  size_t diff_length, length, max_length;
 
173
 
 
174
  if (info->seek_not_done)
 
175
  {                                     /* File touched, do seek */
 
176
    if (lseek(info->file,pos_in_file,SEEK_SET) ==
 
177
        MY_FILEPOS_ERROR)
 
178
    {
 
179
      info->error= 0;
 
180
      return 0;
 
181
    }
 
182
    info->seek_not_done=0;
 
183
  }
 
184
  diff_length=(size_t) (pos_in_file & (IO_SIZE-1));
 
185
  max_length=(info->read_length-diff_length);
 
186
  if (max_length >= (info->end_of_file - pos_in_file))
 
187
    max_length= (size_t) (info->end_of_file - pos_in_file);
 
188
 
 
189
  if (!max_length)
 
190
  {
 
191
    info->error= 0;
 
192
    return 0;                                   /* EOF */
 
193
  }
 
194
  if ((length= my_read(info->file,info->buffer,max_length,
 
195
                       info->myflags)) == (size_t) -1)
 
196
  {
 
197
    info->error= -1;
 
198
    return 0;
 
199
  }
 
200
  info->read_pos=info->buffer;
 
201
  info->read_end=info->buffer+length;
 
202
  info->pos_in_file=pos_in_file;
 
203
  return length;
 
204
}
 
205
 
 
206
 
 
207
/*
 
208
  Read a string ended by '\n' into a buffer of 'max_length' size.
 
209
  Returns number of characters read, 0 on error.
 
210
  last byte is set to '\0'
 
211
  If buffer is full then to[max_length-1] will be set to \0.
 
212
*/
 
213
 
 
214
size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length)
 
215
{
 
216
  char *start = to;
 
217
  size_t length;
 
218
  max_length--;                                 /* Save place for end \0 */
 
219
 
 
220
  /* Calculate number of characters in buffer */
 
221
  if (!(length= my_b_bytes_in_cache(info)) &&
 
222
      !(length= my_b_fill(info)))
 
223
    return 0;
 
224
 
 
225
  for (;;)
 
226
  {
 
227
    unsigned char *pos, *end;
 
228
    if (length > max_length)
 
229
      length=max_length;
 
230
    for (pos=info->read_pos,end=pos+length ; pos < end ;)
 
231
    {
 
232
      if ((*to++ = *pos++) == '\n')
 
233
      {
 
234
        info->read_pos=pos;
 
235
        *to='\0';
 
236
        return (size_t) (to-start);
 
237
      }
 
238
    }
 
239
    if (!(max_length-=length))
 
240
    {
 
241
     /* Found enough charcters;  Return found string */
 
242
      info->read_pos=pos;
 
243
      *to='\0';
 
244
      return (size_t) (to-start);
 
245
    }
 
246
    if (!(length=my_b_fill(info)))
 
247
      return 0;
 
248
  }
 
249
}
 
250
 
 
251
 
 
252
my_off_t my_b_filelength(IO_CACHE *info)
 
253
{
 
254
  if (info->type == WRITE_CACHE)
 
255
    return my_b_tell(info);
 
256
 
 
257
  info->seek_not_done= 1;
 
258
  return lseek(info->file, 0L, SEEK_END);
 
259
}
 
260
 
 
261
 
 
262
/*
 
263
  Simple printf version.  Supports '%s', '%d', '%u', "%ld" and "%lu"
 
264
  Used for logging in MySQL
 
265
  returns number of written character, or (size_t) -1 on error
 
266
*/
 
267
 
 
268
size_t my_b_printf(IO_CACHE *info, const char* fmt, ...)
 
269
{
 
270
  size_t result;
 
271
  va_list args;
 
272
  va_start(args,fmt);
 
273
  result=my_b_vprintf(info, fmt, args);
 
274
  va_end(args);
 
275
  return result;
 
276
}
 
277
 
 
278
 
 
279
size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list args)
 
280
{
 
281
  size_t out_length= 0;
 
282
  int32_t minimum_width; /* as yet unimplemented */
 
283
  int32_t minimum_width_sign;
 
284
  uint32_t precision; /* as yet unimplemented for anything but %b */
 
285
  bool is_zero_padded;
 
286
  basic_string<unsigned char> buffz;
 
287
 
 
288
  /*
 
289
    Store the location of the beginning of a format directive, for the
 
290
    case where we learn we shouldn't have been parsing a format string
 
291
    at all, and we don't want to lose the flag/precision/width/size
 
292
    information.
 
293
   */
 
294
  const char* backtrack;
 
295
 
 
296
  for (; *fmt != '\0'; fmt++)
 
297
  {
 
298
    /* Copy everything until '%' or end of string */
 
299
    const char *start=fmt;
 
300
    size_t length;
 
301
 
 
302
    for (; (*fmt != '\0') && (*fmt != '%'); fmt++) ;
 
303
 
 
304
    length= (size_t) (fmt - start);
 
305
    out_length+=length;
 
306
    if (my_b_write(info, (const unsigned char*) start, length))
 
307
      goto err;
 
308
 
 
309
    if (*fmt == '\0')                           /* End of format */
 
310
      return out_length;
 
311
 
 
312
    /*
 
313
      By this point, *fmt must be a percent;  Keep track of this location and
 
314
      skip over the percent character.
 
315
    */
 
316
    assert(*fmt == '%');
 
317
    backtrack= fmt;
 
318
    fmt++;
 
319
 
 
320
    is_zero_padded= false;
 
321
    minimum_width_sign= 1;
 
322
    minimum_width= 0;
 
323
    precision= 0;
 
324
    /* Skip if max size is used (to be compatible with printf) */
 
325
 
 
326
process_flags:
 
327
    switch (*fmt)
 
328
    {
 
329
      case '-':
 
330
        minimum_width_sign= -1; fmt++; goto process_flags;
 
331
      case '0':
 
332
        is_zero_padded= true; fmt++; goto process_flags;
 
333
      case '#':
 
334
        /** @todo Implement "#" conversion flag. */  fmt++; goto process_flags;
 
335
      case ' ':
 
336
        /** @todo Implement " " conversion flag. */  fmt++; goto process_flags;
 
337
      case '+':
 
338
        /** @todo Implement "+" conversion flag. */  fmt++; goto process_flags;
 
339
    }
 
340
 
 
341
    if (*fmt == '*')
 
342
    {
 
343
      precision= (int) va_arg(args, int);
 
344
      fmt++;
 
345
    }
 
346
    else
 
347
    {
 
348
      while (my_isdigit(&my_charset_utf8_general_ci, *fmt)) {
 
349
        minimum_width=(minimum_width * 10) + (*fmt - '0');
 
350
        fmt++;
 
351
      }
 
352
    }
 
353
    minimum_width*= minimum_width_sign;
 
354
 
 
355
    if (*fmt == '.')
 
356
    {
 
357
      fmt++;
 
358
      if (*fmt == '*') {
 
359
        precision= (int) va_arg(args, int);
 
360
        fmt++;
 
361
      }
 
362
      else
 
363
      {
 
364
        while (my_isdigit(&my_charset_utf8_general_ci, *fmt)) {
 
365
          precision=(precision * 10) + (*fmt - '0');
 
366
          fmt++;
 
367
        }
 
368
      }
 
369
    }
 
370
 
 
371
    if (*fmt == 's')                            /* String parameter */
 
372
    {
 
373
      register char *par = va_arg(args, char *);
 
374
      size_t length2 = strlen(par);
 
375
      /* TODO: implement precision */
 
376
      out_length+= length2;
 
377
      if (my_b_write(info, (const unsigned char*) par, length2))
 
378
        goto err;
 
379
    }
 
380
    else if (*fmt == 'b')                       /* Sized buffer parameter, only precision makes sense */
 
381
    {
 
382
      char *par = va_arg(args, char *);
 
383
      out_length+= precision;
 
384
      if (my_b_write(info, (const unsigned char*) par, precision))
 
385
        goto err;
 
386
    }
 
387
    else if (*fmt == 'd' || *fmt == 'u')        /* Integer parameter */
 
388
    {
 
389
      register int iarg;
 
390
      ssize_t length2;
 
391
      char buff[17];
 
392
 
 
393
      iarg = va_arg(args, int);
 
394
      if (*fmt == 'd')
 
395
        length2= (size_t) (int10_to_str((long) iarg,buff, -10) - buff);
 
396
      else
 
397
        length2= (uint32_t) (int10_to_str((long) (uint32_t) iarg,buff,10)- buff);
 
398
 
 
399
      /* minimum width padding */
 
400
      if (minimum_width > length2)
 
401
      {
 
402
        const size_t buflen = minimum_width - length2;
 
403
        buffz.clear();
 
404
        buffz.reserve(buflen);
 
405
        buffz.append(buflen, is_zero_padded ? '0' : ' ');
 
406
        my_b_write(info, buffz.data(), buflen);
 
407
      }
 
408
 
 
409
      out_length+= length2;
 
410
      if (my_b_write(info, (const unsigned char *)buff, length2))
 
411
        goto err;
 
412
    }
 
413
    else if ((*fmt == 'l' && fmt[1] == 'd') || fmt[1] == 'u')
 
414
      /* long parameter */
 
415
    {
 
416
      register long iarg;
 
417
      size_t length2;
 
418
      char buff[17];
 
419
 
 
420
      iarg = va_arg(args, long);
 
421
      if (*++fmt == 'd')
 
422
        length2= (size_t) (int10_to_str(iarg,buff, -10) - buff);
 
423
      else
 
424
        length2= (size_t) (int10_to_str(iarg,buff,10)- buff);
 
425
      out_length+= length2;
 
426
      if (my_b_write(info, (unsigned char*) buff, length2))
 
427
        goto err;
 
428
    }
 
429
    else
 
430
    {
 
431
      /* %% or unknown code */
 
432
      if (my_b_write(info, (const unsigned char*) backtrack, (size_t) (fmt-backtrack)))
 
433
        goto err;
 
434
      out_length+= fmt-backtrack;
 
435
    }
 
436
  }
 
437
  return out_length;
 
438
 
 
439
err:
 
440
  return (size_t) -1;
 
441
}