~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/schema_engine/schema.cc

This patch completes the first step in the splitting of
the XA resource manager API from the storage engine API,
as outlined in the specification here:

http://drizzle.org/wiki/XaStorageEngine

* Splits plugin::StorageEngine into a base StorageEngine
  class and two derived classes, TransactionalStorageEngine
  and XaStorageEngine.  XaStorageEngine derives from
  TransactionalStorageEngine and creates the XA Resource
  Manager API for storage engines.

  - The methods moved from StorageEngine to TransactionalStorageEngine
    include releaseTemporaryLatches(), startConsistentSnapshot(), 
    commit(), rollback(), setSavepoint(), releaseSavepoint(),
    rollbackToSavepoint() and hasTwoPhaseCommit()
  - The methods moved from StorageEngine to XaStorageEngine
    include recover(), commitXid(), rollbackXid(), and prepare()

* Places all static "EngineVector"s into their proper
  namespaces (typedefs belong in header files, not implementation files)
  and places all static methods corresponding
  to either only transactional engines or only XA engines
  into their respective files in /drizzled/plugin/

* Modifies the InnoDB "handler" files to extend plugin::XaStorageEngine
  and not plugin::StorageEngine

The next step, as outlined in the wiki spec page above, is to isolate
the XA Resource Manager API into its own plugin class and modify
plugin::XaStorageEngine to implement plugin::XaResourceManager via
composition.  This is necessary to enable building plugins which can
participate in an XA transaction *without having to have that plugin
implement the entire storage engine API*

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 <plugin/schema_engine/schema.h>
24
 
#include <drizzled/schema.h>
25
 
#include <drizzled/sql_table.h>
26
 
#include <drizzled/global_charset_info.h>
27
 
#include <drizzled/charset.h>
28
 
#include <drizzled/charset_info.h>
29
 
#include <drizzled/cursor.h>
30
 
#include <drizzled/data_home.h>
31
 
 
32
 
#include <drizzled/pthread_globals.h>
33
 
 
34
 
#include <drizzled/execute.h>
35
 
 
36
 
#include <drizzled/internal/my_sys.h>
37
 
 
38
 
#include <fcntl.h>
39
 
#include <sys/stat.h>
40
 
#include <sys/types.h>
41
 
 
42
 
#include <google/protobuf/io/zero_copy_stream.h>
43
 
#include <google/protobuf/io/zero_copy_stream_impl.h>
44
 
 
45
 
#include <iostream>
46
 
#include <fstream>
47
 
#include <string>
48
 
 
49
 
using namespace std;
50
 
using namespace drizzled;
51
 
 
52
 
 
53
 
#define MY_DB_OPT_FILE "db.opt"
54
 
#define DEFAULT_FILE_EXTENSION ".dfe" // Deep Fried Elephant
55
 
 
56
 
Schema::Schema():
57
 
  drizzled::plugin::StorageEngine("schema",
58
 
                                  HTON_ALTER_NOT_SUPPORTED |
59
 
                                  HTON_HAS_SCHEMA_DICTIONARY |
60
 
                                  HTON_SKIP_STORE_LOCK |
61
 
                                  HTON_TEMPORARY_NOT_SUPPORTED),
62
 
  schema_cache_filled(false)
63
 
{
64
 
  table_definition_ext= DEFAULT_FILE_EXTENSION;
65
 
}
66
 
 
67
 
Schema::~Schema()
68
 
{
69
 
}
70
 
 
71
 
void Schema::prime()
72
 
{
73
 
  CachedDirectory directory(getDataHomeCatalog().file_string(), CachedDirectory::DIRECTORY);
74
 
  CachedDirectory::Entries files= directory.getEntries();
75
 
  boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
76
 
 
77
 
  for (CachedDirectory::Entries::iterator fileIter= files.begin();
78
 
       fileIter != files.end(); fileIter++)
79
 
  {
80
 
    CachedDirectory::Entry *entry= *fileIter;
81
 
    message::Schema schema_message;
82
 
 
83
 
    if (not entry->filename.compare(GLOBAL_TEMPORARY_EXT))
84
 
      continue;
85
 
 
86
 
    if (readSchemaFile(entry->filename, schema_message))
87
 
    {
88
 
      identifier::Schema schema_identifier(schema_message.name());
89
 
 
90
 
      pair<SchemaCache::iterator, bool> ret=
91
 
        schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
92
 
 
93
 
      if (ret.second == false)
94
 
      {
95
 
        abort(); // If this has happened, something really bad is going down.
96
 
      }
97
 
    }
98
 
  }
99
 
}
100
 
 
101
 
void Schema::startup(drizzled::Session &)
102
 
{
103
 
}
104
 
 
105
 
void Schema::doGetSchemaIdentifiers(identifier::Schema::vector &set_of_names)
106
 
{
107
 
  mutex.lock_shared();
108
 
  {
109
 
    for (SchemaCache::iterator iter= schema_cache.begin();
110
 
         iter != schema_cache.end();
111
 
         iter++)
112
 
    {
113
 
      set_of_names.push_back(identifier::Schema((*iter).second->name()));
114
 
    }
115
 
  }
116
 
  mutex.unlock_shared();
117
 
}
118
 
 
119
 
drizzled::message::schema::shared_ptr Schema::doGetSchemaDefinition(const identifier::Schema &schema_identifier)
120
 
{
121
 
  mutex.lock_shared();
122
 
  SchemaCache::iterator iter= schema_cache.find(schema_identifier.getPath());
123
 
 
124
 
  if (iter != schema_cache.end())
125
 
  {
126
 
    drizzled::message::schema::shared_ptr schema_message;
127
 
    schema_message= (*iter).second;
128
 
    mutex.unlock_shared();
129
 
 
130
 
    return schema_message;
131
 
  }
132
 
  mutex.unlock_shared();
133
 
 
134
 
  return drizzled::message::schema::shared_ptr();
135
 
}
136
 
 
137
 
 
138
 
bool Schema::doCreateSchema(const drizzled::message::Schema &schema_message)
139
 
{
140
 
  identifier::Schema schema_identifier(schema_message.name());
141
 
 
142
 
  if (mkdir(schema_identifier.getPath().c_str(), 0777) == -1)
143
 
  {
144
 
    sql_perror(schema_identifier.getPath().c_str());
145
 
    return false;
146
 
  }
147
 
 
148
 
  if (not writeSchemaFile(schema_identifier, schema_message))
149
 
  {
150
 
    rmdir(schema_identifier.getPath().c_str());
151
 
 
152
 
    return false;
153
 
  }
154
 
 
155
 
  {
156
 
    boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
157
 
    pair<SchemaCache::iterator, bool> ret=
158
 
      schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
159
 
 
160
 
 
161
 
    if (ret.second == false)
162
 
    {
163
 
      abort(); // If this has happened, something really bad is going down.
164
 
    }
165
 
  }
166
 
 
167
 
  return true;
168
 
}
169
 
 
170
 
bool Schema::doDropSchema(const identifier::Schema &schema_identifier)
171
 
{
172
 
  string schema_file(schema_identifier.getPath());
173
 
  schema_file.append(1, FN_LIBCHAR);
174
 
  schema_file.append(MY_DB_OPT_FILE);
175
 
 
176
 
  if (not doGetSchemaDefinition(schema_identifier))
177
 
    return false;
178
 
 
179
 
  // No db.opt file, no love from us.
180
 
  if (access(schema_file.c_str(), F_OK))
181
 
  {
182
 
    sql_perror(schema_file.c_str());
183
 
    return false;
184
 
  }
185
 
 
186
 
  if (unlink(schema_file.c_str()))
187
 
  {
188
 
    sql_perror(schema_file.c_str());
189
 
    return false;
190
 
  }
191
 
 
192
 
  if (rmdir(schema_identifier.getPath().c_str()))
193
 
  {
194
 
    sql_perror(schema_identifier.getPath().c_str());
195
 
    //@todo If this happens, we want a report of it. For the moment I dump
196
 
    //to stderr so I can catch it in Hudson.
197
 
    CachedDirectory dir(schema_identifier.getPath());
198
 
    cerr << dir;
199
 
  }
200
 
 
201
 
  boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
202
 
  schema_cache.erase(schema_identifier.getPath());
203
 
 
204
 
  return true;
205
 
}
206
 
 
207
 
bool Schema::doAlterSchema(const drizzled::message::Schema &schema_message)
208
 
{
209
 
  identifier::Schema schema_identifier(schema_message.name());
210
 
 
211
 
  if (access(schema_identifier.getPath().c_str(), F_OK))
212
 
    return false;
213
 
 
214
 
  if (writeSchemaFile(schema_identifier, schema_message))
215
 
  {
216
 
    boost::unique_lock<boost::shared_mutex> scopedLock(mutex);
217
 
    schema_cache.erase(schema_identifier.getPath());
218
 
 
219
 
    pair<SchemaCache::iterator, bool> ret=
220
 
      schema_cache.insert(make_pair(schema_identifier.getPath(), new message::Schema(schema_message)));
221
 
 
222
 
    if (ret.second == false)
223
 
    {
224
 
      abort(); // If this has happened, something really bad is going down.
225
 
    }
226
 
  }
227
 
 
228
 
  return true;
229
 
}
230
 
 
231
 
/**
232
 
  path is path to database, not schema file 
233
 
 
234
 
  @note we do the rename to make it crash safe.
235
 
*/
236
 
bool Schema::writeSchemaFile(const identifier::Schema &schema_identifier, const message::Schema &db)
237
 
{
238
 
  char schema_file_tmp[FN_REFLEN];
239
 
  string schema_file(schema_identifier.getPath());
240
 
 
241
 
 
242
 
  schema_file.append(1, FN_LIBCHAR);
243
 
  schema_file.append(MY_DB_OPT_FILE);
244
 
 
245
 
  snprintf(schema_file_tmp, FN_REFLEN, "%sXXXXXX", schema_file.c_str());
246
 
 
247
 
  int fd= mkstemp(schema_file_tmp);
248
 
 
249
 
  if (fd == -1)
250
 
  {
251
 
    sql_perror(schema_file_tmp);
252
 
 
253
 
    return false;
254
 
  }
255
 
 
256
 
  bool success;
257
 
 
258
 
  try {
259
 
    success= db.SerializeToFileDescriptor(fd);
260
 
  }
261
 
  catch (...)
262
 
  {
263
 
    success= false;
264
 
  }
265
 
 
266
 
  if (not success)
267
 
  {
268
 
    my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), schema_file.c_str(),
269
 
             db.InitializationErrorString().empty() ? "unknown" :  db.InitializationErrorString().c_str());
270
 
 
271
 
    if (close(fd) == -1)
272
 
      sql_perror(schema_file_tmp);
273
 
 
274
 
    if (unlink(schema_file_tmp))
275
 
      sql_perror(schema_file_tmp);
276
 
 
277
 
    return false;
278
 
  }
279
 
 
280
 
  if (close(fd) == -1)
281
 
  {
282
 
    sql_perror(schema_file_tmp);
283
 
 
284
 
    if (unlink(schema_file_tmp))
285
 
      sql_perror(schema_file_tmp);
286
 
 
287
 
    return false;
288
 
  }
289
 
 
290
 
  if (rename(schema_file_tmp, schema_file.c_str()) == -1)
291
 
  {
292
 
    if (unlink(schema_file_tmp))
293
 
      sql_perror(schema_file_tmp);
294
 
 
295
 
    return false;
296
 
  }
297
 
 
298
 
  return true;
299
 
}
300
 
 
301
 
 
302
 
bool Schema::readSchemaFile(const drizzled::identifier::Schema &schema_identifier, drizzled::message::Schema &schema)
303
 
{
304
 
  return readSchemaFile(schema_identifier.getPath(), schema); 
305
 
}
306
 
 
307
 
bool Schema::readSchemaFile(std::string db_opt_path, drizzled::message::Schema &schema)
308
 
{
309
 
  /*
310
 
    Pass an empty file name, and the database options file name as extension
311
 
    to avoid table name to file name encoding.
312
 
  */
313
 
  db_opt_path.append(1, FN_LIBCHAR);
314
 
  db_opt_path.append(MY_DB_OPT_FILE);
315
 
 
316
 
  fstream input(db_opt_path.c_str(), ios::in | ios::binary);
317
 
 
318
 
  /**
319
 
    @note If parsing fails, either someone has done a "mkdir" or has deleted their opt file.
320
 
    So what do we do? We muddle through the adventure by generating 
321
 
    one with a name in it, and the charset set to the default.
322
 
  */
323
 
  if (input.good())
324
 
  {
325
 
    if (schema.ParseFromIstream(&input))
326
 
    {
327
 
      return true;
328
 
    }
329
 
 
330
 
    my_error(ER_CORRUPT_SCHEMA_DEFINITION, MYF(0), db_opt_path.c_str(),
331
 
             schema.InitializationErrorString().empty() ? "unknown" :  schema.InitializationErrorString().c_str());
332
 
  }
333
 
  else
334
 
  {
335
 
    sql_perror(db_opt_path.c_str());
336
 
  }
337
 
 
338
 
  return false;
339
 
}
340
 
 
341
 
void Schema::doGetTableIdentifiers(drizzled::CachedDirectory&,
342
 
                                   const drizzled::identifier::Schema&,
343
 
                                   drizzled::identifier::Table::vector&)
344
 
{
345
 
}