1 : /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 : /* close a isam-database */
17 : /*
18 : TODO:
19 : We need to have a separate mutex on the closed file to allow other threads
20 : to open other files during the time we flush the cache and close this file
21 : */
22 :
23 : #include "maria_def.h"
24 :
25 : int maria_close(register MARIA_HA *info)
26 130 : {
27 130 : int error=0,flag;
28 130 : my_bool share_can_be_freed= FALSE;
29 130 : MARIA_SHARE *share= info->s;
30 130 : DBUG_ENTER("maria_close");
31 130 : DBUG_PRINT("enter",("base: 0x%lx reopen: %u locks: %u",
32 : (long) info, (uint) share->reopen,
33 : (uint) share->tot_locks));
34 :
35 : /* Check that we have unlocked key delete-links properly */
36 130 : DBUG_ASSERT(info->key_del_used == 0);
37 :
38 130 : pthread_mutex_lock(&THR_LOCK_maria);
39 130 : if (info->lock_type == F_EXTRA_LCK)
40 0 : info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
41 :
42 130 : if (share->reopen == 1 && share->kfile.file >= 0)
43 130 : _ma_decrement_open_count(info);
44 :
45 130 : if (info->lock_type != F_UNLCK)
46 : {
47 130 : if (maria_lock_database(info,F_UNLCK))
48 0 : error=my_errno;
49 : }
50 130 : pthread_mutex_lock(&share->close_lock);
51 130 : pthread_mutex_lock(&share->intern_lock);
52 :
53 130 : if (share->options & HA_OPTION_READ_ONLY_DATA)
54 : {
55 121 : share->r_locks--;
56 121 : share->tot_locks--;
57 : }
58 130 : if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
59 : {
60 0 : if (end_io_cache(&info->rec_cache))
61 0 : error=my_errno;
62 0 : info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
63 : }
64 130 : flag= !--share->reopen;
65 130 : maria_open_list=list_delete(maria_open_list,&info->open_list);
66 :
67 130 : my_free(info->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
68 130 : (*share->end)(info);
69 :
70 130 : if (flag)
71 : {
72 : /* Last close of file; Flush everything */
73 :
74 : /* Check that we don't have any dangling pointers from the transaction */
75 130 : DBUG_ASSERT(share->in_trans == 0);
76 :
77 130 : if (share->kfile.file >= 0)
78 : {
79 130 : if ((*share->once_end)(share))
80 0 : error= my_errno;
81 130 : if (flush_pagecache_blocks(share->pagecache, &share->kfile,
82 : (share->temporary ?
83 : FLUSH_IGNORE_CHANGED :
84 : FLUSH_RELEASE)))
85 0 : error= my_errno;
86 : #ifdef HAVE_MMAP
87 130 : if (share->file_map)
88 0 : _ma_unmap_file(info);
89 : #endif
90 : /*
91 : If we are crashed, we can safely flush the current state as it will
92 : not change the crashed state.
93 : We can NOT write the state in other cases as other threads
94 : may be using the file at this point
95 : IF using --external-locking, which does not apply to Maria.
96 : */
97 130 : if (((share->changed && share->base.born_transactional) ||
98 : maria_is_crashed(info)))
99 : {
100 : /*
101 : State must be written to file as it was not done at table's
102 : unlocking.
103 : */
104 0 : if (_ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET))
105 0 : error= my_errno;
106 : }
107 : /*
108 : File must be synced as it is going out of the maria_open_list and so
109 : becoming unknown to future Checkpoints.
110 : */
111 130 : if (share->now_transactional && my_sync(share->kfile.file, MYF(MY_WME)))
112 0 : error= my_errno;
113 130 : if (my_close(share->kfile.file, MYF(0)))
114 0 : error= my_errno;
115 : }
116 : #ifdef THREAD
117 130 : thr_lock_delete(&share->lock);
118 130 : (void) pthread_mutex_destroy(&share->key_del_lock);
119 : {
120 : int i,keys;
121 130 : keys = share->state.header.keys;
122 130 : VOID(rwlock_destroy(&share->mmap_lock));
123 132 : for(i=0; i<keys; i++) {
124 2 : VOID(rwlock_destroy(&share->keyinfo[i].root_lock));
125 : }
126 : }
127 : #endif
128 130 : DBUG_ASSERT(share->now_transactional == share->base.born_transactional);
129 : /*
130 : We assign -1 because checkpoint does not need to flush (in case we
131 : have concurrent checkpoint if no then we do not need it here also)
132 : */
133 130 : share->kfile.file= -1;
134 :
135 : /*
136 : Remember share->history for future opens
137 :
138 : We have to unlock share->intern_lock then lock it after
139 : LOCK_trn_list (trnman_lock()) to avoid dead locks.
140 : */
141 130 : pthread_mutex_unlock(&share->intern_lock);
142 130 : _ma_remove_not_visible_states_with_lock(share, TRUE);
143 130 : pthread_mutex_lock(&share->intern_lock);
144 :
145 130 : if (share->in_checkpoint & MARIA_CHECKPOINT_LOOKS_AT_ME)
146 : {
147 : /* we cannot my_free() the share, Checkpoint would see a bad pointer */
148 0 : share->in_checkpoint|= MARIA_CHECKPOINT_SHOULD_FREE_ME;
149 : }
150 : else
151 130 : share_can_be_freed= TRUE;
152 :
153 130 : if (share->state_history)
154 : {
155 : MARIA_STATE_HISTORY_CLOSED *history;
156 : /*
157 : Here we ignore the unlikely case that we don't have memory to
158 : store the state. In the worst case what happens is that any transaction
159 : that tries to access this table will get a wrong status information.
160 : */
161 0 : if ((history= (MARIA_STATE_HISTORY_CLOSED *)
162 : my_malloc(sizeof(*history), MYF(MY_WME))))
163 : {
164 0 : history->create_rename_lsn= share->state.create_rename_lsn;
165 0 : history->state_history= share->state_history;
166 0 : if (my_hash_insert(&maria_stored_state, (uchar*) history))
167 0 : my_free(history, MYF(0));
168 : }
169 : /* Marker for concurrent checkpoint */
170 0 : share->state_history= 0;
171 : }
172 : }
173 130 : pthread_mutex_unlock(&THR_LOCK_maria);
174 130 : pthread_mutex_unlock(&share->intern_lock);
175 130 : pthread_mutex_unlock(&share->close_lock);
176 130 : if (share_can_be_freed)
177 : {
178 130 : (void) pthread_mutex_destroy(&share->intern_lock);
179 130 : (void) pthread_mutex_destroy(&share->close_lock);
180 130 : my_free((uchar *)share, MYF(0));
181 : /*
182 : If share cannot be freed, it's because checkpoint has previously
183 : recorded to include this share in the checkpoint and so is soon going to
184 : look at some of its content (share->in_checkpoint/id/last_version).
185 : */
186 : }
187 130 : my_free(info->ftparser_param, MYF(MY_ALLOW_ZERO_PTR));
188 130 : if (info->dfile.file >= 0)
189 : {
190 : /*
191 : This is outside of mutex so would confuse a concurrent
192 : Checkpoint. Fortunately in BLOCK_RECORD we close earlier under mutex.
193 : */
194 0 : if (my_close(info->dfile.file, MYF(0)))
195 0 : error= my_errno;
196 : }
197 :
198 130 : delete_dynamic(&info->pinned_pages);
199 130 : my_free(info, MYF(0));
200 :
201 130 : if (error)
202 : {
203 0 : DBUG_PRINT("error", ("Got error on close: %d", my_errno));
204 0 : DBUG_RETURN(my_errno= error);
205 : }
206 130 : DBUG_RETURN(0);
207 : } /* maria_close */
|