Drizzled Public API Documentation

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