~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/schema_engine/schema.cc

  • Committer: Monty Taylor
  • Date: 2009-08-17 18:46:08 UTC
  • mto: (1182.1.1 staging)
  • mto: This revision was merged to the branch mainline in revision 1183.
  • Revision ID: mordred@inaugust.com-20090817184608-0b2emowpjr9m6le7
"Fixed" the deadlock test. I'd still like someone to look at what's going on here.

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