1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
*
* Copyright (C) 2010 Brian Aker
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "drizzled/session.h"
#include "plugin/myisam/myisam.h"
#include "drizzled/plugin/transactional_storage_engine.h"
#include "drizzled/table.h"
namespace drizzled
{
namespace table
{
/*
Open table which is already name-locked by this thread.
SYNOPSIS
reopen_name_locked_table()
session Thread handle
table_list TableList object for table to be open, TableList::table
member should point to Table object which was used for
name-locking.
link_in true - if Table object for table to be opened should be
linked into Session::open_tables list.
false - placeholder used for name-locking is already in
this list so we only need to preserve Table::next
pointer.
NOTE
This function assumes that its caller already acquired table::Cache::singleton().mutex() mutex.
RETURN VALUE
false - Success
true - Error
*/
bool Concurrent::reopen_name_locked_table(TableList* table_list, Session *session)
{
safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
if (session->getKilled())
return true;
TableIdentifier identifier(table_list->getSchemaName(), table_list->getTableName());
if (open_unireg_entry(session, table_list->getTableName(), identifier))
{
intern_close_table();
return true;
}
/*
We want to prevent other connections from opening this table until end
of statement as it is likely that modifications of table's metadata are
not yet finished (for example CREATE TRIGGER have to change .TRG cursor,
or we might want to drop table if CREATE TABLE ... SELECT fails).
This also allows us to assume that no other connection will sneak in
before we will get table-level lock on this table.
*/
getMutableShare()->resetVersion();
in_use = session;
tablenr= session->current_tablenr++;
used_fields= 0;
const_table= 0;
null_row= false;
maybe_null= false;
force_index= false;
status= STATUS_NO_RECORD;
return false;
}
/*
Load a table definition from cursor and open unireg table
SYNOPSIS
open_unireg_entry()
session Thread handle
entry Store open table definition here
table_list TableList with db, table_name
alias Alias name
cache_key Key for share_cache
cache_key_length length of cache_key
NOTES
Extra argument for open is taken from session->open_options
One must have a lock on table::Cache::singleton().mutex() when calling this function
RETURN
0 ok
# Error
*/
int table::Concurrent::open_unireg_entry(Session *session,
const char *alias,
TableIdentifier &identifier)
{
int error;
TableShare::shared_ptr share;
uint32_t discover_retry_count= 0;
safe_mutex_assert_owner(table::Cache::singleton().mutex().native_handle());
retry:
if (not (share= TableShare::getShareCreate(session,
identifier,
error)))
{
return 1;
}
while ((error= share->open_table_from_share(session,
identifier,
alias,
(uint32_t) (HA_OPEN_KEYFILE |
HA_OPEN_RNDFILE |
HA_GET_INDEX |
HA_TRY_READ_ONLY),
session->open_options, *this)))
{
if (error == 7) // Table def changed
{
share->resetVersion(); // Mark share as old
if (discover_retry_count++) // Retry once
{
TableShare::release(share);
return 1;
}
/*
TODO->
Here we should wait until all threads has released the table.
For now we do one retry. This may cause a deadlock if there
is other threads waiting for other tables used by this thread.
Proper fix would be to if the second retry failed:
- Mark that table def changed
- Return from open table
- Close all tables used by this thread
- Start waiting that the share is released
- Retry by opening all tables again
*/
/*
TO BE FIXED
To avoid deadlock, only wait for release if no one else is
using the share.
*/
if (share->getTableCount() != 1)
{
TableShare::release(share);
return 1;
}
/* Free share and wait until it's released by all threads */
TableShare::release(share);
if (not session->getKilled())
{
drizzle_reset_errors(session, 1); // Clear warnings
session->clear_error(); // Clear error message
goto retry;
}
return 1;
}
TableShare::release(share);
return 1;
}
return 0;
}
void table::Concurrent::release(void)
{
// During an ALTER TABLE we could see the proto go away when the
// definition is pushed out of this table object. In this case we would
// not release from the cache because we were not in the cache. We just
// delete if this happens.
if (getShare()->getType() == message::Table::STANDARD)
{
TableShare::release(getMutableShare());
}
else
{
delete _share;
}
_share= NULL;
}
} /* namespace table */
} /* namespace drizzled */
|