~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to innobase/fil/fil0fil.c

  • Committer: monty at mysql
  • Date: 2001-02-17 12:19:19 UTC
  • mto: (554.1.1)
  • mto: This revision was merged to the branch mainline in revision 556.
  • Revision ID: sp1r-monty@donna.mysql.com-20010217121919-07904
Added Innobase to source distribution

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The low-level file system
 
3
 
 
4
(c) 1995 Innobase Oy
 
5
 
 
6
Created 10/25/1995 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "fil0fil.h"
 
10
 
 
11
#include "mem0mem.h"
 
12
#include "sync0sync.h"
 
13
#include "hash0hash.h"
 
14
#include "os0file.h"
 
15
#include "os0sync.h"
 
16
#include "mach0data.h"
 
17
#include "ibuf0ibuf.h"
 
18
#include "buf0buf.h"
 
19
#include "log0log.h"
 
20
#include "log0recv.h"
 
21
#include "fsp0fsp.h"
 
22
 
 
23
/*
 
24
                IMPLEMENTATION OF THE LOW-LEVEL FILE SYSTEM
 
25
                ===========================================
 
26
 
 
27
The file system is responsible for providing fast read/write access to
 
28
tablespaces and logs of the database. File creation and deletion is done
 
29
in other modules which know more of the logic of the operation, however.
 
30
 
 
31
A tablespace consists of a chain of files. The size of the files does not
 
32
have to be divisible by the database block size, because we may just leave
 
33
the last incomplete block unused. When a new file is appended to the
 
34
tablespace, the maximum size of the file is also specified. At the moment,
 
35
we think that it is best to extend the file to its maximum size already at
 
36
the creation of the file, because then we can avoid dynamically extending
 
37
the file when more space is needed for the tablespace.
 
38
 
 
39
A block's position in the tablespace is specified with a 32-bit unsigned
 
40
integer. The files in the chain are thought to be catenated, and the block
 
41
corresponding to an address n is the nth block in the catenated file (where
 
42
the first block is named the 0th block, and the incomplete block fragments
 
43
at the end of files are not taken into account). A tablespace can be extended
 
44
by appending a new file at the end of the chain.
 
45
 
 
46
Our tablespace concept is similar to the one of Oracle.
 
47
 
 
48
To acquire more speed in disk transfers, a technique called disk striping is
 
49
sometimes used. This means that logical block addresses are divided in a
 
50
round-robin fashion across several disks. Windows NT supports disk striping,
 
51
so there we do not need to support it in the database. Disk striping is
 
52
implemented in hardware in RAID disks. We conclude that it is not necessary
 
53
to implement it in the database. Oracle 7 does not support disk striping,
 
54
either.
 
55
 
 
56
Another trick used at some database sites is replacing tablespace files by
 
57
raw disks, that is, the whole physical disk drive, or a partition of it, is
 
58
opened as a single file, and it is accessed through byte offsets calculated
 
59
from the start of the disk or the partition. This is recommended in some
 
60
books on database tuning to achieve more speed in i/o. Using raw disk
 
61
certainly prevents the OS from fragmenting disk space, but it is not clear
 
62
if it really adds speed. We measured on the Pentium 100 MHz + NT + NTFS file
 
63
system + EIDE Conner disk only a negligible difference in speed when reading
 
64
from a file, versus reading from a raw disk. 
 
65
 
 
66
To have fast access to a tablespace or a log file, we put the data structures
 
67
to a hash table. Each tablespace and log file is given an unique 32-bit
 
68
identifier.
 
69
 
 
70
Some operating systems do not support many open files at the same time,
 
71
though NT seems to tolerate at least 900 open files. Therefore, we put the
 
72
open files in an LRU-list. If we need to open another file, we may close the
 
73
file at the end of the LRU-list. When an i/o-operation is pending on a file,
 
74
the file cannot be closed. We take the file nodes with pending i/o-operations
 
75
out of the LRU-list and keep a count of pending operations. When an operation
 
76
completes, we decrement the count and return the file node to the LRU-list if
 
77
the count drops to zero. */
 
78
 
 
79
/* Null file address */
 
80
fil_addr_t      fil_addr_null = {FIL_NULL, 0};
 
81
 
 
82
/* File system file node data structure */
 
83
typedef struct fil_node_struct  fil_node_t;
 
84
struct fil_node_struct {
 
85
        char*           name;   /* the file name or path */
 
86
        ibool           open;   /* TRUE if file open */
 
87
        os_file_t       handle; /* OS handle to the file, if file open */
 
88
        ulint           size;   /* size of the file in database blocks
 
89
                                (where the possible last incomplete block
 
90
                                is ignored) */
 
91
        ulint           n_pending;
 
92
                                /* count of pending i/o-ops on this file */
 
93
        UT_LIST_NODE_T(fil_node_t) chain;
 
94
                                /* link field for the file chain */
 
95
        UT_LIST_NODE_T(fil_node_t) LRU;
 
96
                                /* link field for the LRU list */
 
97
        ulint           magic_n;
 
98
};
 
99
 
 
100
#define FIL_NODE_MAGIC_N        89389
 
101
 
 
102
/* File system tablespace or log data structure: let us call them by a common
 
103
name space */
 
104
struct fil_space_struct {
 
105
        char*           name;   /* space name */
 
106
        ulint           id;     /* space id */
 
107
        ulint           purpose;/* FIL_TABLESPACE, FIL_LOG, or FIL_ARCH_LOG */
 
108
        UT_LIST_BASE_NODE_T(fil_node_t) chain;
 
109
                                /* base node for the file chain */
 
110
        ulint           size;   /* space size in pages */
 
111
        ulint           n_reserved_extents;
 
112
                                /* number of reserved free extents for
 
113
                                ongoing operations like B-tree page split */
 
114
        hash_node_t     hash;   /* hash chain node */
 
115
        rw_lock_t       latch;  /* latch protecting the file space storage
 
116
                                allocation */
 
117
        UT_LIST_NODE_T(fil_space_t) space_list;
 
118
                                /* list of all spaces */
 
119
        ibuf_data_t*    ibuf_data;
 
120
                                /* insert buffer data */
 
121
        ulint           magic_n;
 
122
};
 
123
 
 
124
#define FIL_SPACE_MAGIC_N       89472
 
125
 
 
126
/* The file system data structure */
 
127
 
 
128
typedef struct fil_system_struct        fil_system_t;
 
129
struct fil_system_struct {
 
130
        mutex_t         mutex;          /* The mutex protecting the system */
 
131
        hash_table_t*   spaces;         /* The hash table of spaces in the
 
132
                                        system */       
 
133
        UT_LIST_BASE_NODE_T(fil_node_t) LRU;
 
134
                                        /* base node for the LRU list of the
 
135
                                        most recently used open files */
 
136
        ulint           n_open_pending; /* current number of open files with
 
137
                                        pending i/o-ops on them */
 
138
        ulint           max_n_open;     /* maximum allowed open files */
 
139
        os_event_t      can_open;       /* this event is set to the signaled
 
140
                                        state when the system is capable of
 
141
                                        opening a new file, i.e.,
 
142
                                        n_open_pending < max_n_open */
 
143
        UT_LIST_BASE_NODE_T(fil_space_t) space_list;
 
144
                                        /* list of all file spaces */
 
145
};
 
146
 
 
147
/* The file system. This variable is NULL before the module is initialized. */
 
148
fil_system_t*   fil_system      = NULL;
 
149
 
 
150
/* The file system hash table size */
 
151
#define FIL_SYSTEM_HASH_SIZE    500
 
152
 
 
153
 
 
154
/***********************************************************************
 
155
Reserves a right to open a single file. The right must be released with
 
156
fil_release_right_to_open. */
 
157
 
 
158
void
 
159
fil_reserve_right_to_open(void)
 
160
/*===========================*/
 
161
{
 
162
loop:
 
163
        mutex_enter(&(fil_system->mutex));
 
164
        
 
165
        if (fil_system->n_open_pending == fil_system->max_n_open) {
 
166
 
 
167
                /* It is not sure we can open the file if it is closed: wait */
 
168
 
 
169
                os_event_reset(fil_system->can_open);
 
170
 
 
171
                mutex_exit(&(fil_system->mutex));
 
172
 
 
173
                os_event_wait(fil_system->can_open);
 
174
 
 
175
                goto loop;
 
176
        }
 
177
 
 
178
        fil_system->max_n_open--;
 
179
 
 
180
        mutex_exit(&(fil_system->mutex));
 
181
}
 
182
 
 
183
/***********************************************************************
 
184
Releases a right to open a single file. */
 
185
 
 
186
void
 
187
fil_release_right_to_open(void)
 
188
/*===========================*/
 
189
{
 
190
        mutex_enter(&(fil_system->mutex));
 
191
        
 
192
        if (fil_system->n_open_pending == fil_system->max_n_open) {
 
193
 
 
194
                os_event_set(fil_system->can_open);
 
195
        }
 
196
 
 
197
        fil_system->max_n_open++;
 
198
 
 
199
        mutex_exit(&(fil_system->mutex));
 
200
}
 
201
 
 
202
/***********************************************************************
 
203
Returns the latch of a file space. */
 
204
 
 
205
rw_lock_t*
 
206
fil_space_get_latch(
 
207
/*================*/
 
208
                        /* out: latch protecting storage allocation */
 
209
        ulint   id)     /* in: space id */
 
210
{
 
211
        fil_space_t*    space;
 
212
        fil_system_t*   system          = fil_system;
 
213
 
 
214
        ut_ad(system);
 
215
 
 
216
        mutex_enter(&(system->mutex));
 
217
 
 
218
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
219
 
 
220
        mutex_exit(&(system->mutex));
 
221
 
 
222
        return(&(space->latch));
 
223
}
 
224
 
 
225
/***********************************************************************
 
226
Returns the type of a file space. */
 
227
 
 
228
ulint
 
229
fil_space_get_type(
 
230
/*===============*/
 
231
                        /* out: FIL_TABLESPACE or FIL_LOG */
 
232
        ulint   id)     /* in: space id */
 
233
{
 
234
        fil_space_t*    space;
 
235
        fil_system_t*   system          = fil_system;
 
236
 
 
237
        ut_ad(system);
 
238
 
 
239
        mutex_enter(&(system->mutex));
 
240
 
 
241
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
242
 
 
243
        mutex_exit(&(system->mutex));
 
244
 
 
245
        return(space->purpose);
 
246
}
 
247
 
 
248
/***********************************************************************
 
249
Returns the ibuf data of a file space. */
 
250
 
 
251
ibuf_data_t*
 
252
fil_space_get_ibuf_data(
 
253
/*====================*/
 
254
                        /* out: ibuf data for this space */
 
255
        ulint   id)     /* in: space id */
 
256
{
 
257
        fil_space_t*    space;
 
258
        fil_system_t*   system  = fil_system;
 
259
 
 
260
        ut_ad(system);
 
261
 
 
262
        mutex_enter(&(system->mutex));
 
263
 
 
264
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
265
 
 
266
        mutex_exit(&(system->mutex));
 
267
 
 
268
        return(space->ibuf_data);
 
269
}
 
270
 
 
271
/***********************************************************************
 
272
Appends a new file to the chain of files of a space. File must be closed. */
 
273
 
 
274
void
 
275
fil_node_create(
 
276
/*============*/
 
277
        char*   name,   /* in: file name (file must be closed) */
 
278
        ulint   size,   /* in: file size in database blocks, rounded downwards
 
279
                        to an integer */
 
280
        ulint   id)     /* in: space id where to append */
 
281
{
 
282
        fil_node_t*     node;
 
283
        fil_space_t*    space;
 
284
        char*           name2;
 
285
        fil_system_t*   system          = fil_system;
 
286
 
 
287
        ut_a(system);
 
288
        ut_a(name);
 
289
        ut_a(size > 0);
 
290
 
 
291
        mutex_enter(&(system->mutex));
 
292
 
 
293
        node = mem_alloc(sizeof(fil_node_t));
 
294
 
 
295
        name2 = mem_alloc(ut_strlen(name) + 1);
 
296
 
 
297
        ut_strcpy(name2, name);
 
298
 
 
299
        node->name = name2;
 
300
        node->open = FALSE;
 
301
        node->size = size;
 
302
        node->magic_n = FIL_NODE_MAGIC_N;
 
303
        node->n_pending = 0;
 
304
        
 
305
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
306
 
 
307
        space->size += size;
 
308
 
 
309
        UT_LIST_ADD_LAST(chain, space->chain, node);
 
310
                                
 
311
        mutex_exit(&(system->mutex));
 
312
}
 
313
 
 
314
/**************************************************************************
 
315
Closes a file. */
 
316
static
 
317
void
 
318
fil_node_close(
 
319
/*===========*/
 
320
        fil_node_t*     node,   /* in: file node */
 
321
        fil_system_t*   system) /* in: file system */
 
322
{
 
323
        ibool   ret;
 
324
 
 
325
        ut_ad(node && system);
 
326
        ut_ad(mutex_own(&(system->mutex)));
 
327
        ut_a(node->open);
 
328
        ut_a(node->n_pending == 0);
 
329
 
 
330
        ret = os_file_close(node->handle);
 
331
        ut_a(ret);
 
332
 
 
333
        node->open = FALSE;
 
334
 
 
335
        /* The node is in the LRU list, remove it */
 
336
        UT_LIST_REMOVE(LRU, system->LRU, node);
 
337
}
 
338
 
 
339
/***********************************************************************
 
340
Frees a file node object from a file system. */
 
341
static
 
342
void
 
343
fil_node_free(
 
344
/*==========*/
 
345
        fil_node_t*     node,   /* in, own: file node */
 
346
        fil_system_t*   system, /* in: file system */
 
347
        fil_space_t*    space)  /* in: space where the file node is chained */
 
348
{
 
349
        ut_ad(node && system && space);
 
350
        ut_ad(mutex_own(&(system->mutex)));
 
351
        ut_a(node->magic_n == FIL_NODE_MAGIC_N);
 
352
 
 
353
        if (node->open) {
 
354
                fil_node_close(node, system);
 
355
        }
 
356
 
 
357
        space->size -= node->size;
 
358
        
 
359
        UT_LIST_REMOVE(chain, space->chain, node);
 
360
 
 
361
        mem_free(node->name);
 
362
        mem_free(node);
 
363
}
 
364
 
 
365
/********************************************************************
 
366
Drops files from the start of a file space, so that its size is cut by
 
367
the amount given. */
 
368
 
 
369
void
 
370
fil_space_truncate_start(
 
371
/*=====================*/
 
372
        ulint   id,             /* in: space id */
 
373
        ulint   trunc_len)      /* in: truncate by this much; it is an error
 
374
                                if this does not equal to the combined size of
 
375
                                some initial files in the space */
 
376
{
 
377
        fil_node_t*     node;
 
378
        fil_space_t*    space;
 
379
        fil_system_t*   system          = fil_system;
 
380
 
 
381
        mutex_enter(&(system->mutex));
 
382
 
 
383
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
384
 
 
385
        ut_a(space);
 
386
        
 
387
        while (trunc_len > 0) {
 
388
 
 
389
                node = UT_LIST_GET_FIRST(space->chain);
 
390
 
 
391
                ut_a(node->size * UNIV_PAGE_SIZE >= trunc_len);
 
392
 
 
393
                trunc_len -= node->size * UNIV_PAGE_SIZE;
 
394
 
 
395
                fil_node_free(node, system, space);
 
396
        }       
 
397
                                
 
398
        mutex_exit(&(system->mutex));
 
399
}                               
 
400
 
 
401
/********************************************************************
 
402
Creates a file system object. */
 
403
static
 
404
fil_system_t*
 
405
fil_system_create(
 
406
/*==============*/
 
407
                                /* out, own: file system object */
 
408
        ulint   hash_size,      /* in: hash table size */
 
409
        ulint   max_n_open)     /* in: maximum number of open files */
 
410
{
 
411
        fil_system_t*   system;
 
412
 
 
413
        ut_a(hash_size > 0);
 
414
        ut_a(max_n_open > 0);
 
415
 
 
416
        system = mem_alloc(sizeof(fil_system_t));
 
417
 
 
418
        mutex_create(&(system->mutex));
 
419
 
 
420
        mutex_set_level(&(system->mutex), SYNC_ANY_LATCH);
 
421
 
 
422
        system->spaces = hash_create(hash_size);
 
423
 
 
424
        UT_LIST_INIT(system->LRU);
 
425
 
 
426
        system->n_open_pending = 0;
 
427
        system->max_n_open = max_n_open;
 
428
        system->can_open = os_event_create(NULL);
 
429
 
 
430
        UT_LIST_INIT(system->space_list);
 
431
 
 
432
        return(system);
 
433
}
 
434
 
 
435
/********************************************************************
 
436
Initializes the file system of this module. */
 
437
 
 
438
void
 
439
fil_init(
 
440
/*=====*/
 
441
        ulint   max_n_open)     /* in: max number of open files */
 
442
{
 
443
        ut_a(fil_system == NULL);
 
444
 
 
445
        fil_system = fil_system_create(FIL_SYSTEM_HASH_SIZE, max_n_open);
 
446
}
 
447
 
 
448
/********************************************************************
 
449
Writes the flushed lsn to the header of each file space. */
 
450
 
 
451
void
 
452
fil_ibuf_init_at_db_start(void)
 
453
/*===========================*/
 
454
{
 
455
        fil_space_t*    space;
 
456
 
 
457
        space = UT_LIST_GET_FIRST(fil_system->space_list);
 
458
        
 
459
        while (space) {
 
460
                if (space->purpose == FIL_TABLESPACE) {
 
461
                        space->ibuf_data = ibuf_data_init_for_space(space->id);
 
462
                }
 
463
 
 
464
                space = UT_LIST_GET_NEXT(space_list, space);
 
465
        }
 
466
}
 
467
 
 
468
/********************************************************************
 
469
Writes the flushed lsn and the latest archived log number to the page
 
470
header of the first page of a data file. */
 
471
static
 
472
ulint
 
473
fil_write_lsn_and_arch_no_to_file(
 
474
/*==============================*/
 
475
        ulint   space_id,       /* in: space number */
 
476
        ulint   sum_of_sizes,   /* in: combined size of previous files in space,
 
477
                                in database pages */
 
478
        dulint  lsn,            /* in: lsn to write */
 
479
        ulint   arch_log_no)    /* in: archived log number to write */
 
480
{
 
481
        byte*   buf1;
 
482
        byte*   buf;
 
483
 
 
484
        buf1 = mem_alloc(2 * UNIV_PAGE_SIZE);
 
485
        buf = ut_align(buf1, UNIV_PAGE_SIZE);
 
486
 
 
487
        fil_read(TRUE, space_id, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
 
488
 
 
489
        mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);
 
490
        mach_write_to_4(buf + FIL_PAGE_ARCH_LOG_NO, arch_log_no);
 
491
 
 
492
        fil_write(TRUE, space_id, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
 
493
 
 
494
        return(DB_SUCCESS);     
 
495
}
 
496
 
 
497
/********************************************************************
 
498
Writes the flushed lsn and the latest archived log number to the page
 
499
header of the first page of each data file. */
 
500
 
 
501
ulint
 
502
fil_write_flushed_lsn_to_data_files(
 
503
/*================================*/
 
504
                                /* out: DB_SUCCESS or error number */
 
505
        dulint  lsn,            /* in: lsn to write */
 
506
        ulint   arch_log_no)    /* in: latest archived log file number */
 
507
{
 
508
        fil_space_t*    space;
 
509
        fil_node_t*     node;
 
510
        ulint           sum_of_sizes;
 
511
        ulint           err;
 
512
 
 
513
        mutex_enter(&(fil_system->mutex));
 
514
        
 
515
        space = UT_LIST_GET_FIRST(fil_system->space_list);
 
516
        
 
517
        while (space) {
 
518
                if (space->purpose == FIL_TABLESPACE) {
 
519
                        sum_of_sizes = 0;
 
520
 
 
521
                        node = UT_LIST_GET_FIRST(space->chain);
 
522
 
 
523
                        while (node) {
 
524
                                mutex_exit(&(fil_system->mutex));
 
525
 
 
526
                                err = fil_write_lsn_and_arch_no_to_file(
 
527
                                                        space->id,
 
528
                                                        sum_of_sizes,
 
529
                                                        lsn, arch_log_no);
 
530
                                if (err != DB_SUCCESS) {
 
531
 
 
532
                                        return(err);
 
533
                                }
 
534
 
 
535
                                mutex_enter(&(fil_system->mutex));
 
536
 
 
537
                                sum_of_sizes += node->size;
 
538
 
 
539
                                node = UT_LIST_GET_NEXT(chain, node);
 
540
                        }
 
541
                }
 
542
 
 
543
                space = UT_LIST_GET_NEXT(space_list, space);
 
544
        }
 
545
 
 
546
        mutex_exit(&(fil_system->mutex));
 
547
}
 
548
 
 
549
/***********************************************************************
 
550
Reads the flushed lsn and arch no fields from a data file at database
 
551
startup. */
 
552
 
 
553
void
 
554
fil_read_flushed_lsn_and_arch_log_no(
 
555
/*=================================*/
 
556
        os_file_t data_file,            /* in: open data file */
 
557
        ibool   one_read_already,       /* in: TRUE if min and max parameters
 
558
                                        below already contain sensible data */
 
559
        dulint* min_flushed_lsn,        /* in/out: */
 
560
        ulint*  min_arch_log_no,        /* in/out: */
 
561
        dulint* max_flushed_lsn,        /* in/out: */
 
562
        ulint*  max_arch_log_no)        /* in/out: */
 
563
{
 
564
        byte*   buf;
 
565
        dulint  flushed_lsn;
 
566
        ulint   arch_log_no;
 
567
 
 
568
        buf = ut_malloc(UNIV_PAGE_SIZE);
 
569
 
 
570
        os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE);
 
571
 
 
572
        flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN);
 
573
        arch_log_no = mach_read_from_4(buf + FIL_PAGE_ARCH_LOG_NO);
 
574
 
 
575
        ut_free(buf);
 
576
 
 
577
        if (!one_read_already) {
 
578
                *min_flushed_lsn = flushed_lsn;
 
579
                *max_flushed_lsn = flushed_lsn;
 
580
                *min_arch_log_no = arch_log_no;
 
581
                *max_arch_log_no = arch_log_no;
 
582
 
 
583
                return;
 
584
        }
 
585
 
 
586
        if (ut_dulint_cmp(*min_flushed_lsn, flushed_lsn) > 0) {
 
587
                *min_flushed_lsn = flushed_lsn;
 
588
        }
 
589
        if (ut_dulint_cmp(*max_flushed_lsn, flushed_lsn) < 0) {
 
590
                *max_flushed_lsn = flushed_lsn;
 
591
        }
 
592
        if (*min_arch_log_no > arch_log_no) {
 
593
                *min_arch_log_no = arch_log_no;
 
594
        }
 
595
        if (*max_arch_log_no < arch_log_no) {
 
596
                *max_arch_log_no = arch_log_no;
 
597
        }
 
598
}
 
599
 
 
600
/***********************************************************************
 
601
Creates a space object and puts it to the file system. */
 
602
 
 
603
void
 
604
fil_space_create(
 
605
/*=============*/
 
606
        char*   name,   /* in: space name */
 
607
        ulint   id,     /* in: space id */
 
608
        ulint   purpose)/* in: FIL_TABLESPACE, or FIL_LOG if log */
 
609
{
 
610
        fil_space_t*    space;  
 
611
        char*           name2;
 
612
        fil_system_t*   system = fil_system;
 
613
        
 
614
        ut_a(system);
 
615
        ut_a(name);
 
616
 
 
617
#ifndef UNIV_BASIC_LOG_DEBUG
 
618
        /* Spaces with an odd id number are reserved to replicate spaces
 
619
        used in log debugging */
 
620
        
 
621
        ut_a((purpose == FIL_LOG) || (id % 2 == 0));
 
622
#endif
 
623
        mutex_enter(&(system->mutex));
 
624
 
 
625
        space = mem_alloc(sizeof(fil_space_t));
 
626
 
 
627
        name2 = mem_alloc(ut_strlen(name) + 1);
 
628
 
 
629
        ut_strcpy(name2, name);
 
630
 
 
631
        space->name = name2;
 
632
        space->id = id;
 
633
        space->purpose = purpose;
 
634
        space->size = 0;
 
635
 
 
636
        space->n_reserved_extents = 0;
 
637
        
 
638
        UT_LIST_INIT(space->chain);
 
639
        space->magic_n = FIL_SPACE_MAGIC_N;
 
640
 
 
641
        space->ibuf_data = NULL;
 
642
        
 
643
        rw_lock_create(&(space->latch));
 
644
        rw_lock_set_level(&(space->latch), SYNC_FSP);
 
645
        
 
646
        HASH_INSERT(fil_space_t, hash, system->spaces, id, space);
 
647
 
 
648
        UT_LIST_ADD_LAST(space_list, system->space_list, space);
 
649
                                
 
650
        mutex_exit(&(system->mutex));
 
651
}
 
652
 
 
653
/***********************************************************************
 
654
Frees a space object from a file system. Closes the files in the chain
 
655
but does not delete them. */
 
656
 
 
657
void
 
658
fil_space_free(
 
659
/*===========*/
 
660
        ulint   id)     /* in: space id */
 
661
{
 
662
        fil_space_t*    space;
 
663
        fil_node_t*     fil_node;
 
664
        fil_system_t*   system          = fil_system;
 
665
        
 
666
        mutex_enter(&(system->mutex));
 
667
 
 
668
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
669
 
 
670
        HASH_DELETE(fil_space_t, hash, system->spaces, id, space);
 
671
 
 
672
        UT_LIST_REMOVE(space_list, system->space_list, space);
 
673
 
 
674
        ut_a(space->magic_n == FIL_SPACE_MAGIC_N);
 
675
 
 
676
        fil_node = UT_LIST_GET_FIRST(space->chain);
 
677
 
 
678
        ut_d(UT_LIST_VALIDATE(chain, fil_node_t, space->chain));
 
679
 
 
680
        while (fil_node != NULL) {
 
681
                fil_node_free(fil_node, system, space);
 
682
 
 
683
                fil_node = UT_LIST_GET_FIRST(space->chain);
 
684
        }       
 
685
        
 
686
        ut_d(UT_LIST_VALIDATE(chain, fil_node_t, space->chain));
 
687
        ut_ad(0 == UT_LIST_GET_LEN(space->chain));
 
688
 
 
689
        mutex_exit(&(system->mutex));
 
690
 
 
691
        mem_free(space->name);
 
692
        mem_free(space);
 
693
}
 
694
 
 
695
/***********************************************************************
 
696
Returns the size of the space in pages. */
 
697
 
 
698
ulint
 
699
fil_space_get_size(
 
700
/*===============*/
 
701
                        /* out: space size */
 
702
        ulint   id)     /* in: space id */
 
703
{
 
704
        fil_space_t*    space;
 
705
        fil_system_t*   system          = fil_system;
 
706
        ulint           size;
 
707
 
 
708
        ut_ad(system);
 
709
 
 
710
        mutex_enter(&(system->mutex));
 
711
 
 
712
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
713
 
 
714
        size = space->size;
 
715
        
 
716
        mutex_exit(&(system->mutex));
 
717
 
 
718
        return(size);
 
719
}
 
720
 
 
721
/***********************************************************************
 
722
Tries to reserve free extents in a file space. */
 
723
 
 
724
ibool
 
725
fil_space_reserve_free_extents(
 
726
/*===========================*/
 
727
                                /* out: TRUE if succeed */
 
728
        ulint   id,             /* in: space id */
 
729
        ulint   n_free_now,     /* in: number of free extents now */
 
730
        ulint   n_to_reserve)   /* in: how many one wants to reserve */
 
731
{
 
732
        fil_space_t*    space;
 
733
        fil_system_t*   system          = fil_system;
 
734
        ibool           success;
 
735
 
 
736
        ut_ad(system);
 
737
 
 
738
        mutex_enter(&(system->mutex));
 
739
 
 
740
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
741
 
 
742
        if (space->n_reserved_extents + n_to_reserve > n_free_now) {
 
743
                success = FALSE;
 
744
        } else {
 
745
                space->n_reserved_extents += n_to_reserve;
 
746
                success = TRUE;
 
747
        }
 
748
        
 
749
        mutex_exit(&(system->mutex));
 
750
 
 
751
        return(success);
 
752
}
 
753
 
 
754
/***********************************************************************
 
755
Releases free extents in a file space. */
 
756
 
 
757
void
 
758
fil_space_release_free_extents(
 
759
/*===========================*/
 
760
        ulint   id,             /* in: space id */
 
761
        ulint   n_reserved)     /* in: how many one reserved */
 
762
{
 
763
        fil_space_t*    space;
 
764
        fil_system_t*   system          = fil_system;
 
765
 
 
766
        ut_ad(system);
 
767
 
 
768
        mutex_enter(&(system->mutex));
 
769
 
 
770
        HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
 
771
 
 
772
        ut_a(space->n_reserved_extents >= n_reserved);
 
773
        
 
774
        space->n_reserved_extents -= n_reserved;
 
775
        
 
776
        mutex_exit(&(system->mutex));
 
777
}
 
778
 
 
779
/************************************************************************
 
780
Prepares a file node for i/o. Opens the file if it is closed. Updates the
 
781
pending i/o's field in the node and the system appropriately. Takes the node
 
782
off the LRU list if it is in the LRU list. */
 
783
static
 
784
void
 
785
fil_node_prepare_for_io(
 
786
/*====================*/
 
787
        fil_node_t*     node,   /* in: file node */
 
788
        fil_system_t*   system, /* in: file system */
 
789
        fil_space_t*    space)  /* in: space */
 
790
{
 
791
        ibool           ret;
 
792
        fil_node_t*     last_node;
 
793
 
 
794
        ut_ad(node && system && space);
 
795
        ut_ad(mutex_own(&(system->mutex)));
 
796
        
 
797
        if (node->open == FALSE) {
 
798
                /* File is closed */
 
799
                ut_a(node->n_pending == 0);
 
800
 
 
801
                /* If too many files are open, close one */
 
802
 
 
803
                if (system->n_open_pending + UT_LIST_GET_LEN(system->LRU)
 
804
                                                == system->max_n_open) {
 
805
 
 
806
                        ut_a(UT_LIST_GET_LEN(system->LRU) > 0);
 
807
 
 
808
                        last_node = UT_LIST_GET_LAST(system->LRU);
 
809
 
 
810
                        fil_node_close(last_node, system);
 
811
                }
 
812
 
 
813
                node->handle = os_file_create(node->name, OS_FILE_OPEN,
 
814
                                                        OS_FILE_AIO, &ret);
 
815
                ut_a(ret);
 
816
                
 
817
                node->open = TRUE;
 
818
 
 
819
                system->n_open_pending++;
 
820
                node->n_pending = 1;
 
821
 
 
822
                /* File was closed: the node was not in the LRU list */
 
823
 
 
824
                return;
 
825
        }
 
826
 
 
827
        /* File is open */
 
828
        if (node->n_pending == 0) {
 
829
                /* The node is in the LRU list, remove it */
 
830
 
 
831
                UT_LIST_REMOVE(LRU, system->LRU, node);
 
832
 
 
833
                system->n_open_pending++;
 
834
                node->n_pending = 1;
 
835
        } else {
 
836
                /* There is already a pending i/o-op on the file: the node is
 
837
                not in the LRU list */
 
838
 
 
839
                node->n_pending++;
 
840
        }
 
841
}
 
842
 
 
843
/************************************************************************
 
844
Updates the data structures when an i/o operation finishes. Updates the
 
845
pending i/os field in the node and the system appropriately. Puts the node
 
846
in the LRU list if there are no other pending i/os. */
 
847
static
 
848
void
 
849
fil_node_complete_io(
 
850
/*=================*/
 
851
        fil_node_t*     node,   /* in: file node */
 
852
        fil_system_t*   system) /* in: file system */
 
853
{
 
854
        ut_ad(node);
 
855
        ut_ad(system);
 
856
        ut_ad(mutex_own(&(system->mutex)));
 
857
        ut_a(node->n_pending > 0);
 
858
        
 
859
        node->n_pending--;
 
860
 
 
861
        if (node->n_pending == 0) {
 
862
                /* The node must be put back to the LRU list */
 
863
                UT_LIST_ADD_FIRST(LRU, system->LRU, node);
 
864
 
 
865
                ut_a(system->n_open_pending > 0);
 
866
 
 
867
                system->n_open_pending--;
 
868
 
 
869
                if (system->n_open_pending == system->max_n_open - 1) {
 
870
 
 
871
                        os_event_set(system->can_open);
 
872
                }
 
873
        }
 
874
}
 
875
                
 
876
/************************************************************************
 
877
Reads or writes data. This operation is asynchronous (aio). */
 
878
 
 
879
void
 
880
fil_io(
 
881
/*===*/
 
882
        ulint   type,           /* in: OS_FILE_READ or OS_FILE_WRITE,
 
883
                                ORed to OS_FILE_LOG, if a log i/o
 
884
                                and ORed to OS_AIO_SIMULATED_WAKE_LATER
 
885
                                if simulated aio and we want to post a
 
886
                                batch of i/os; NOTE that a simulated batch
 
887
                                may introduce hidden chances of deadlocks,
 
888
                                because i/os are not actually handled until
 
889
                                all have been posted: use with great
 
890
                                caution! */
 
891
        ibool   sync,           /* in: TRUE if synchronous aio is desired */
 
892
        ulint   space_id,       /* in: space id */
 
893
        ulint   block_offset,   /* in: offset in number of blocks */
 
894
        ulint   byte_offset,    /* in: remainder of offset in bytes; in
 
895
                                aio this must be divisible by the OS block
 
896
                                size */
 
897
        ulint   len,            /* in: how many bytes to read; this must
 
898
                                not cross a file boundary; in aio this must
 
899
                                be a block size multiple */
 
900
        void*   buf,            /* in/out: buffer where to store read data
 
901
                                or from where to write; in aio this must be
 
902
                                appropriately aligned */
 
903
        void*   message)        /* in: message for aio handler if non-sync
 
904
                                aio used, else ignored */
 
905
{
 
906
        ulint           mode;
 
907
        fil_space_t*    space;
 
908
        fil_node_t*     node;
 
909
        ulint           offset_high;
 
910
        ulint           offset_low;
 
911
        fil_system_t*   system;
 
912
        os_event_t      event;
 
913
        ibool           ret;
 
914
        ulint           is_log;
 
915
        ulint           wake_later;
 
916
 
 
917
        is_log = type & OS_FILE_LOG;
 
918
        type = type & ~OS_FILE_LOG;
 
919
 
 
920
        wake_later = type & OS_AIO_SIMULATED_WAKE_LATER;
 
921
        type = type & ~OS_AIO_SIMULATED_WAKE_LATER;
 
922
        
 
923
        ut_ad(byte_offset < UNIV_PAGE_SIZE);
 
924
        ut_ad(buf);
 
925
        ut_ad(len > 0);
 
926
        ut_ad((1 << UNIV_PAGE_SIZE_SHIFT) == UNIV_PAGE_SIZE);
 
927
        ut_ad(fil_validate());
 
928
#ifndef UNIV_LOG_DEBUG
 
929
        /* ibuf bitmap pages must be read in the sync aio mode: */
 
930
        ut_ad(recv_no_ibuf_operations || (type == OS_FILE_WRITE)
 
931
                || !ibuf_bitmap_page(block_offset) || sync || is_log);
 
932
#ifdef UNIV_SYNC_DEBUG
 
933
        ut_ad(!ibuf_inside() || is_log || (type == OS_FILE_WRITE)
 
934
                                        || ibuf_page(space_id, block_offset));
 
935
#endif
 
936
#endif
 
937
        if (sync) {
 
938
                mode = OS_AIO_SYNC;
 
939
        } else if ((type == OS_FILE_READ) && !is_log
 
940
                                && ibuf_page(space_id, block_offset)) {
 
941
                mode = OS_AIO_IBUF;
 
942
        } else if (is_log) {
 
943
                mode = OS_AIO_LOG;
 
944
        } else {
 
945
                mode = OS_AIO_NORMAL;
 
946
        }
 
947
 
 
948
        system = fil_system;
 
949
loop:
 
950
        mutex_enter(&(system->mutex));
 
951
        
 
952
        if (system->n_open_pending == system->max_n_open) {
 
953
 
 
954
                /* It is not sure we can open the file if it is closed: wait */
 
955
 
 
956
                event = system->can_open;
 
957
                os_event_reset(event);
 
958
 
 
959
                mutex_exit(&(system->mutex));
 
960
 
 
961
                os_event_wait(event);
 
962
 
 
963
                goto loop;
 
964
        }        
 
965
        
 
966
        HASH_SEARCH(hash, system->spaces, space_id, space,
 
967
                                                space->id == space_id);
 
968
        ut_a(space);
 
969
 
 
970
        ut_ad((mode != OS_AIO_IBUF) || (space->purpose == FIL_TABLESPACE));
 
971
 
 
972
        node = UT_LIST_GET_FIRST(space->chain);
 
973
 
 
974
        for (;;) {
 
975
                ut_a(node);
 
976
 
 
977
                if (node->size > block_offset) {
 
978
                        /* Found! */
 
979
                        break;
 
980
                } else {
 
981
                        block_offset -= node->size;
 
982
                        node = UT_LIST_GET_NEXT(chain, node);
 
983
                }
 
984
        }               
 
985
        
 
986
        /* Open file if closed */
 
987
        fil_node_prepare_for_io(node, system, space);
 
988
 
 
989
        /* Now we have made the changes in the data structures of system */
 
990
        mutex_exit(&(system->mutex));
 
991
 
 
992
        /* Calculate the low 32 bits and the high 32 bits of the file offset */
 
993
 
 
994
        offset_high = (block_offset >> (32 - UNIV_PAGE_SIZE_SHIFT));
 
995
        offset_low  = ((block_offset << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFF)
 
996
                        + byte_offset;
 
997
 
 
998
        ut_a(node->size - block_offset >=
 
999
                (byte_offset + len + (UNIV_PAGE_SIZE - 1)) / UNIV_PAGE_SIZE);
 
1000
 
 
1001
        /* Do aio */
 
1002
 
 
1003
        ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
 
1004
        ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
 
1005
 
 
1006
        /* Queue the aio request */
 
1007
        ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
 
1008
                                offset_low, offset_high, len, node, message);
 
1009
        ut_a(ret);
 
1010
 
 
1011
        if (mode == OS_AIO_SYNC) {
 
1012
                /* The i/o operation is already completed when we return from
 
1013
                os_aio: */
 
1014
                
 
1015
                mutex_enter(&(system->mutex));
 
1016
 
 
1017
                fil_node_complete_io(node, system);
 
1018
 
 
1019
                mutex_exit(&(system->mutex));
 
1020
 
 
1021
                ut_ad(fil_validate());
 
1022
        }
 
1023
}
 
1024
 
 
1025
/************************************************************************
 
1026
Reads data from a space to a buffer. Remember that the possible incomplete
 
1027
blocks at the end of file are ignored: they are not taken into account when
 
1028
calculating the byte offset within a space. */
 
1029
 
 
1030
void
 
1031
fil_read(
 
1032
/*=====*/
 
1033
        ibool   sync,           /* in: TRUE if synchronous aio is desired */
 
1034
        ulint   space_id,       /* in: space id */
 
1035
        ulint   block_offset,   /* in: offset in number of blocks */
 
1036
        ulint   byte_offset,    /* in: remainder of offset in bytes; in aio
 
1037
                                this must be divisible by the OS block size */
 
1038
        ulint   len,            /* in: how many bytes to read; this must not
 
1039
                                cross a file boundary; in aio this must be a
 
1040
                                block size multiple */
 
1041
        void*   buf,            /* in/out: buffer where to store data read;
 
1042
                                in aio this must be appropriately aligned */
 
1043
        void*   message)        /* in: message for aio handler if non-sync
 
1044
                                aio used, else ignored */
 
1045
{
 
1046
        fil_io(OS_FILE_READ, sync, space_id, block_offset, byte_offset, len,
 
1047
                                                                buf, message);
 
1048
}
 
1049
 
 
1050
/************************************************************************
 
1051
Writes data to a space from a buffer. Remember that the possible incomplete
 
1052
blocks at the end of file are ignored: they are not taken into account when
 
1053
calculating the byte offset within a space. */
 
1054
 
 
1055
void
 
1056
fil_write(
 
1057
/*======*/
 
1058
        ibool   sync,           /* in: TRUE if synchronous aio is desired */
 
1059
        ulint   space_id,       /* in: space id */
 
1060
        ulint   block_offset,   /* in: offset in number of blocks */
 
1061
        ulint   byte_offset,    /* in: remainder of offset in bytes; in aio
 
1062
                                this must be divisible by the OS block size */
 
1063
        ulint   len,            /* in: how many bytes to write; this must
 
1064
                                not cross a file boundary; in aio this must
 
1065
                                be a block size multiple */
 
1066
        void*   buf,            /* in: buffer from which to write; in aio
 
1067
                                this must be appropriately aligned */
 
1068
        void*   message)        /* in: message for aio handler if non-sync
 
1069
                                aio used, else ignored */
 
1070
{
 
1071
        fil_io(OS_FILE_WRITE, sync, space_id, block_offset, byte_offset, len,
 
1072
                                                                buf, message);
 
1073
}
 
1074
 
 
1075
/**************************************************************************
 
1076
Waits for an aio operation to complete. This function is used to write the
 
1077
handler for completed requests. The aio array of pending requests is divided
 
1078
into segments (see os0file.c for more info). The thread specifies which
 
1079
segment it wants to wait for. */
 
1080
 
 
1081
void
 
1082
fil_aio_wait(
 
1083
/*=========*/
 
1084
        ulint   segment)        /* in: the number of the segment in the aio
 
1085
                                array to wait for */ 
 
1086
{
 
1087
        ibool           ret;            
 
1088
        fil_node_t*     fil_node;
 
1089
        fil_system_t*   system          = fil_system;
 
1090
        void*           message;
 
1091
        
 
1092
        ut_ad(fil_validate());
 
1093
 
 
1094
        if (os_aio_use_native_aio) {
 
1095
#ifdef WIN_ASYNC_IO
 
1096
                ret = os_aio_windows_handle(segment, 0, &fil_node, &message);
 
1097
#elif defined(POSIX_ASYNC_IO)
 
1098
                ret = os_aio_posix_handle(segment, &fil_node, &message);
 
1099
#else
 
1100
                ut_a(0);
 
1101
#endif
 
1102
        } else {
 
1103
                ret = os_aio_simulated_handle(segment, (void**) &fil_node,
 
1104
                                                            &message);
 
1105
        }
 
1106
        
 
1107
        ut_a(ret);
 
1108
        
 
1109
        mutex_enter(&(system->mutex));
 
1110
 
 
1111
        fil_node_complete_io(fil_node, fil_system);
 
1112
 
 
1113
        mutex_exit(&(system->mutex));
 
1114
 
 
1115
        ut_ad(fil_validate());
 
1116
 
 
1117
        /* Do the i/o handling */
 
1118
 
 
1119
        if (buf_pool_is_block(message)) {
 
1120
        
 
1121
                buf_page_io_complete(message);
 
1122
        } else {
 
1123
                log_io_complete(message);
 
1124
        }
 
1125
}
 
1126
 
 
1127
/**************************************************************************
 
1128
Flushes to disk possible writes cached by the OS. */
 
1129
 
 
1130
void
 
1131
fil_flush(
 
1132
/*======*/
 
1133
        ulint   space_id)       /* in: file space id (this can be a group of
 
1134
                                log files or a tablespace of the database) */
 
1135
{
 
1136
        fil_system_t*   system  = fil_system;
 
1137
        fil_space_t*    space;
 
1138
        fil_node_t*     node;
 
1139
        os_file_t       file;
 
1140
 
 
1141
        mutex_enter(&(system->mutex));
 
1142
        
 
1143
        HASH_SEARCH(hash, system->spaces, space_id, space,
 
1144
                                                space->id == space_id);
 
1145
        ut_a(space);
 
1146
 
 
1147
        node = UT_LIST_GET_FIRST(space->chain);
 
1148
 
 
1149
        while (node) {
 
1150
                if (node->open) {
 
1151
                        file = node->handle;
 
1152
                        
 
1153
                        mutex_exit(&(system->mutex));
 
1154
 
 
1155
                        /* Note that it is not certain, when we have
 
1156
                        released the mutex above, that the file of the
 
1157
                        handle is still open: we assume that the OS
 
1158
                        will not crash or trap even if we pass a handle
 
1159
                        to a closed file below in os_file_flush! */
 
1160
                        
 
1161
                        os_file_flush(file);
 
1162
 
 
1163
                        mutex_enter(&(system->mutex));
 
1164
                }
 
1165
 
 
1166
                node = UT_LIST_GET_NEXT(chain, node);
 
1167
        }               
 
1168
 
 
1169
        mutex_exit(&(system->mutex));
 
1170
}
 
1171
 
 
1172
/**************************************************************************
 
1173
Flushes to disk writes in file spaces of the given type possibly cached by
 
1174
the OS. */
 
1175
 
 
1176
void
 
1177
fil_flush_file_spaces(
 
1178
/*==================*/
 
1179
        ulint   purpose)        /* in: FIL_TABLESPACE, FIL_LOG */
 
1180
{
 
1181
        fil_system_t*   system  = fil_system;
 
1182
        fil_space_t*    space;
 
1183
 
 
1184
        mutex_enter(&(system->mutex));
 
1185
 
 
1186
        space = UT_LIST_GET_FIRST(system->space_list);
 
1187
 
 
1188
        while (space) {
 
1189
                if (space->purpose == purpose) {
 
1190
                        mutex_exit(&(system->mutex));
 
1191
 
 
1192
                        fil_flush(space->id);
 
1193
 
 
1194
                        mutex_enter(&(system->mutex));
 
1195
                }
 
1196
 
 
1197
                space = UT_LIST_GET_NEXT(space_list, space);
 
1198
        }
 
1199
        
 
1200
        mutex_exit(&(system->mutex));
 
1201
}
 
1202
 
 
1203
/**********************************************************************
 
1204
Checks the consistency of the file system. */
 
1205
 
 
1206
ibool
 
1207
fil_validate(void)
 
1208
/*==============*/
 
1209
                        /* out: TRUE if ok */
 
1210
{       
 
1211
        fil_space_t*    space;
 
1212
        fil_node_t*     fil_node;
 
1213
        ulint           pending_count   = 0;
 
1214
        fil_system_t*   system;
 
1215
        ulint           i;
 
1216
 
 
1217
        system = fil_system;
 
1218
        
 
1219
        mutex_enter(&(system->mutex));
 
1220
 
 
1221
        /* Look for spaces in the hash table */
 
1222
 
 
1223
        for (i = 0; i < hash_get_n_cells(system->spaces); i++) {
 
1224
 
 
1225
                space = HASH_GET_FIRST(system->spaces, i);
 
1226
        
 
1227
                while (space != NULL) {
 
1228
 
 
1229
                        UT_LIST_VALIDATE(chain, fil_node_t, space->chain); 
 
1230
 
 
1231
                        fil_node = UT_LIST_GET_FIRST(space->chain);
 
1232
 
 
1233
                        while (fil_node != NULL) {
 
1234
 
 
1235
                                if (fil_node->n_pending > 0) {
 
1236
 
 
1237
                                        pending_count++;
 
1238
                                        ut_a(fil_node->open);
 
1239
                                }
 
1240
 
 
1241
                                fil_node = UT_LIST_GET_NEXT(chain, fil_node);
 
1242
                        }
 
1243
 
 
1244
                        space = HASH_GET_NEXT(hash, space);
 
1245
                }
 
1246
        }
 
1247
 
 
1248
        ut_a(pending_count == system->n_open_pending);
 
1249
 
 
1250
        UT_LIST_VALIDATE(LRU, fil_node_t, system->LRU);
 
1251
 
 
1252
        fil_node = UT_LIST_GET_FIRST(system->LRU);
 
1253
 
 
1254
        while (fil_node != NULL) {
 
1255
 
 
1256
                ut_a(fil_node->n_pending == 0);
 
1257
                ut_a(fil_node->open);
 
1258
 
 
1259
                fil_node = UT_LIST_GET_NEXT(LRU, fil_node);
 
1260
        }
 
1261
        
 
1262
        mutex_exit(&(system->mutex));
 
1263
 
 
1264
        return(TRUE);
 
1265
}
 
1266
 
 
1267
/************************************************************************
 
1268
Returns TRUE if file address is undefined. */
 
1269
ibool
 
1270
fil_addr_is_null(
 
1271
/*=============*/
 
1272
                                /* out: TRUE if undefined */
 
1273
        fil_addr_t      addr)   /* in: address */
 
1274
{
 
1275
        if (addr.page == FIL_NULL) {
 
1276
 
 
1277
                return(TRUE);
 
1278
        }
 
1279
 
 
1280
        return(FALSE);
 
1281
}
 
1282
 
 
1283
/************************************************************************
 
1284
Accessor functions for a file page */
 
1285
 
 
1286
ulint
 
1287
fil_page_get_prev(byte* page)
 
1288
{
 
1289
        return(mach_read_from_4(page + FIL_PAGE_PREV));
 
1290
}
 
1291
 
 
1292
ulint
 
1293
fil_page_get_next(byte* page)
 
1294
{
 
1295
        return(mach_read_from_4(page + FIL_PAGE_NEXT));
 
1296
}
 
1297
 
 
1298
/*************************************************************************
 
1299
Sets the file page type. */
 
1300
 
 
1301
void
 
1302
fil_page_set_type(
 
1303
/*==============*/
 
1304
        byte*   page,   /* in: file page */
 
1305
        ulint   type)   /* in: type */
 
1306
{
 
1307
        ut_ad(page);
 
1308
        ut_ad((type == FIL_PAGE_INDEX) || (type == FIL_PAGE_INDEX));
 
1309
 
 
1310
        mach_write_to_2(page + FIL_PAGE_TYPE, type);
 
1311
}       
 
1312
 
 
1313
/*************************************************************************
 
1314
Gets the file page type. */
 
1315
 
 
1316
ulint
 
1317
fil_page_get_type(
 
1318
/*==============*/
 
1319
                        /* out: type; NOTE that if the type has not been
 
1320
                        written to page, the return value not defined */
 
1321
        byte*   page)   /* in: file page */
 
1322
{
 
1323
        ut_ad(page);
 
1324
 
 
1325
        return(mach_read_from_2(page + FIL_PAGE_TYPE));
 
1326
}