~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/blitzdb/blitzdata.cc

  • Committer: Olaf van der Spek
  • Date: 2011-02-12 18:24:24 UTC
  • mto: (2167.1.2 build) (2172.1.4 build)
  • mto: This revision was merged to the branch mainline in revision 2168.
  • Revision ID: olafvdspek@gmail.com-20110212182424-kgnm9osi7qo97at2
casts

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) 2009 - 2010 Toru Maesaka
 
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; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
#include "ha_blitz.h"
 
22
 
 
23
using namespace std;
 
24
using namespace drizzled;
 
25
 
 
26
int BlitzData::startup(const char *path) {
 
27
  int rv = 0;
 
28
 
 
29
  if ((rv = open_data_table(path, HDBOWRITER)) != 0)
 
30
    return rv;
 
31
 
 
32
  current_hidden_row_id = read_meta_row_id();
 
33
  return rv;
 
34
}
 
35
 
 
36
int BlitzData::shutdown() {
 
37
  int rv = 0;
 
38
 
 
39
  /* Copy the latest autogenerated ID back to TC's metadata buffer.
 
40
     This data will be sync'd by TC. */
 
41
  write_meta_row_id(current_hidden_row_id);
 
42
 
 
43
  if ((rv = close_data_table()) != 0)
 
44
    return rv;
 
45
 
 
46
  return rv;
 
47
}
 
48
 
 
49
/* Similar to UNIX touch(1) but generates a tuned TCHDB file. */
 
50
int BlitzData::create_data_table(drizzled::message::Table &proto,
 
51
                                 drizzled::Table &table_info,
 
52
                                 const drizzled::identifier::Table &identifier) {
 
53
 
 
54
  std::string path = identifier.getPath() + BLITZ_DATA_EXT;
 
55
 
 
56
  uint64_t autoinc = (proto.options().has_auto_increment_value())
 
57
                     ? proto.options().auto_increment_value() - 1 : 0;
 
58
 
 
59
  uint64_t hash_buckets = (blitz_estimated_rows == 0) ? BLITZ_TC_BUCKETS
 
60
                                                      : blitz_estimated_rows;
 
61
  int n_options = proto.engine().options_size();
 
62
 
 
63
  for (int i = 0; i < n_options; i++) {
 
64
    if (proto.engine().options(i).name() == "estimated_rows" ||
 
65
        proto.engine().options(i).name() == "ESTIMATED_ROWS") {
 
66
      std::istringstream stream(proto.engine().options(i).state());
 
67
      stream >> hash_buckets;
 
68
 
 
69
      if (hash_buckets <= 0)
 
70
        hash_buckets = BLITZ_TC_BUCKETS;
 
71
    }
 
72
  }
 
73
 
 
74
  if (data_table != NULL)
 
75
    return HA_ERR_GENERIC;
 
76
 
 
77
  if ((data_table = tchdbnew()) == NULL)
 
78
    return HA_ERR_OUT_OF_MEM;
 
79
 
 
80
  if (!tchdbtune(data_table, hash_buckets, -1, -1, 0)) {
 
81
    tchdbdel(data_table);
 
82
    return HA_ERR_CRASHED_ON_USAGE;
 
83
  }
 
84
 
 
85
  if (!tchdbopen(data_table, path.c_str(), (HDBOWRITER | HDBOCREAT))) {
 
86
    tchdbdel(data_table);
 
87
    return HA_ERR_CRASHED_ON_USAGE;
 
88
  }
 
89
 
 
90
  /* Write the Meta Data for this Table. */
 
91
  tc_meta_buffer = tchdbopaque(data_table);
 
92
  write_meta_autoinc(autoinc);
 
93
  write_meta_keycount(table_info.getShare()->keys);
 
94
 
 
95
  /* We're Done. */
 
96
  if (close_data_table() != 0)
 
97
    return HA_ERR_CRASHED_ON_USAGE;
 
98
 
 
99
  return 0;
 
100
}
 
101
 
 
102
int BlitzData::open_data_table(const char *path, const int mode) {
 
103
  char buf[FN_REFLEN];
 
104
 
 
105
  if ((data_table = tchdbnew()) == NULL)
 
106
    return HA_ERR_OUT_OF_MEM;
 
107
 
 
108
  if (!tchdbsetmutex(data_table)) {
 
109
    tchdbdel(data_table);
 
110
    return HA_ERR_CRASHED_ON_USAGE;
 
111
  }
 
112
 
 
113
  if (!tchdbsetxmsiz(data_table, BLITZ_TC_EXTRA_MMAP_SIZE)) {
 
114
    tchdbdel(data_table);
 
115
    return HA_ERR_CRASHED_ON_USAGE;
 
116
  }
 
117
 
 
118
  snprintf(buf, FN_REFLEN, "%s%s", path, BLITZ_DATA_EXT);
 
119
 
 
120
  if (!tchdbopen(data_table, buf, mode)) {
 
121
    tchdbdel(data_table);
 
122
    return HA_ERR_CRASHED_ON_USAGE;
 
123
  }
 
124
 
 
125
  tc_meta_buffer = tchdbopaque(data_table);
 
126
  return 0;
 
127
}
 
128
 
 
129
bool BlitzData::rename_table(const char *from, const char *to) {
 
130
  char from_buf[FN_REFLEN];
 
131
  char to_buf[FN_REFLEN];
 
132
 
 
133
  snprintf(from_buf, FN_REFLEN, "%s%s", from, BLITZ_DATA_EXT);
 
134
  snprintf(to_buf, FN_REFLEN, "%s%s", to, BLITZ_DATA_EXT);
 
135
 
 
136
  if (rename(from_buf, to_buf) != 0)
 
137
    return false;
 
138
 
 
139
  snprintf(from_buf, FN_REFLEN, "%s%s", from, BLITZ_SYSTEM_EXT);
 
140
  snprintf(to_buf, FN_REFLEN, "%s%s", to, BLITZ_SYSTEM_EXT);
 
141
 
 
142
  if (rename(from_buf, to_buf) != 0)
 
143
    return false;
 
144
 
 
145
  return true;
 
146
}
 
147
 
 
148
int BlitzData::close_data_table(void) {
 
149
  assert(data_table);
 
150
 
 
151
  if (!tchdbclose(data_table)) {
 
152
    tchdbdel(data_table);
 
153
    return HA_ERR_CRASHED_ON_USAGE;
 
154
  }
 
155
 
 
156
  tchdbdel(data_table);
 
157
  data_table = NULL;
 
158
  tc_meta_buffer = NULL;
 
159
  return 0;
 
160
}
 
161
 
 
162
uint64_t BlitzData::nrecords(void) {
 
163
  return tchdbrnum(data_table);
 
164
}
 
165
 
 
166
uint64_t BlitzData::table_size(void) {
 
167
  return tchdbfsiz(data_table);
 
168
}
 
169
 
 
170
uint64_t BlitzData::read_meta_row_id(void) {
 
171
  assert(tc_meta_buffer);
 
172
  return (uint64_t)uint8korr(tc_meta_buffer);
 
173
}
 
174
 
 
175
uint64_t BlitzData::read_meta_autoinc(void) {
 
176
  assert(tc_meta_buffer);
 
177
  char *pos = tc_meta_buffer + sizeof (current_hidden_row_id);
 
178
  return (uint64_t)uint8korr(pos);
 
179
}
 
180
 
 
181
uint32_t BlitzData::read_meta_keycount(void) {
 
182
  assert(tc_meta_buffer);
 
183
  char *pos = tc_meta_buffer;
 
184
  pos += sizeof(current_hidden_row_id) + sizeof(uint64_t);
 
185
  return (uint32_t)uint4korr(pos);
 
186
}
 
187
 
 
188
void BlitzData::write_meta_row_id(uint64_t row_id) {
 
189
  assert(tc_meta_buffer);
 
190
  int8store(tc_meta_buffer, row_id);
 
191
}
 
192
 
 
193
void BlitzData::write_meta_autoinc(uint64_t num) {
 
194
  assert(tc_meta_buffer);
 
195
  char *pos = tc_meta_buffer + sizeof(current_hidden_row_id);
 
196
  int8store(pos, num);
 
197
}
 
198
 
 
199
void BlitzData::write_meta_keycount(uint32_t nkeys) {
 
200
  assert(tc_meta_buffer);
 
201
  char *pos = tc_meta_buffer;
 
202
  pos += sizeof(current_hidden_row_id) + sizeof(uint64_t);
 
203
  int4store(pos, nkeys);
 
204
}
 
205
 
 
206
char *BlitzData::get_row(const char *key, const size_t klen, int *vlen) {
 
207
  return (char *)tchdbget(data_table, key, klen, vlen);
 
208
}
 
209
 
 
210
/* Fastest way to fetch both key and value from TCHDB since it only
 
211
   involves one allocation. That is, both key and value are living
 
212
   on the same block of memory. The return value is a pointer to the
 
213
   next key. Technically it is a pointer to the region of memory that
 
214
   holds both key and value. */
 
215
char *BlitzData::next_key_and_row(const char *key, const size_t klen,
 
216
                                  int *next_key_len, const char **value,
 
217
                                  int *value_len) {
 
218
  return tchdbgetnext3(data_table, key, klen, next_key_len, value, value_len);
 
219
}
 
220
 
 
221
char *BlitzData::first_row(int *row_len) {
 
222
  return (char *)tchdbgetnext(data_table, NULL, 0, row_len);
 
223
}
 
224
 
 
225
uint64_t BlitzData::next_hidden_row_id(void) {
 
226
  /* current_hidden_row_id is an atomic type */
 
227
  uint64_t rv = current_hidden_row_id.increment();
 
228
  return rv;
 
229
}
 
230
 
 
231
int BlitzData::write_row(const char *key, const size_t klen,
 
232
                         const unsigned char *row, const size_t rlen) {
 
233
  return (tchdbput(data_table, key, klen, row, rlen)) ? 0 : 1;
 
234
}
 
235
 
 
236
int BlitzData::write_unique_row(const char *key, const size_t klen,
 
237
                                const unsigned char *row, const size_t rlen) {
 
238
  int rv = 0;
 
239
 
 
240
  if (!tchdbputkeep(data_table, key, klen, row, rlen)) {
 
241
    if (tchdbecode(data_table) == TCEKEEP) {
 
242
      errno = HA_ERR_FOUND_DUPP_KEY;
 
243
      rv = HA_ERR_FOUND_DUPP_KEY;
 
244
    }
 
245
  }
 
246
  return rv;
 
247
}
 
248
 
 
249
int BlitzData::delete_row(const char *key, const size_t klen) {
 
250
  return (tchdbout(data_table, key, klen)) ? 0 : -1;
 
251
}
 
252
 
 
253
bool BlitzData::delete_all_rows() {
 
254
  char buf[BLITZ_MAX_META_LEN];
 
255
 
 
256
  /* Evacuate the meta data buffer since this will be wiped out. */
 
257
  memcpy(buf, tc_meta_buffer, BLITZ_MAX_META_LEN);
 
258
 
 
259
  /* Now it's safe to wipe everything. */
 
260
  if (!tchdbvanish(data_table))
 
261
    return false;
 
262
 
 
263
  /* Copy the evacuated meta buffer back to the fresh TCHDB file. */
 
264
  tc_meta_buffer = tchdbopaque(data_table);
 
265
  memcpy(tc_meta_buffer, buf, BLITZ_MAX_META_LEN);
 
266
  
 
267
  return true;
 
268
}
 
269
 
 
270
/* Code from here on is for BlitzDB's internal system information management.
 
271
   It is deliberately separated from the data dictionary code because we
 
272
   might move to a simple flat file structure in the future. For now we
 
273
   use a micro Tokyo Cabinet database for this. */
 
274
int BlitzData::create_system_table(const std::string &path) {
 
275
  int rv = 0;
 
276
  int mode = (HDBOWRITER | HDBOCREAT);
 
277
 
 
278
  if ((rv = open_system_table(path.c_str(), mode)) != 0)
 
279
    return rv;
 
280
 
 
281
  return close_system_table();
 
282
}
 
283
 
 
284
int BlitzData::open_system_table(const std::string &path, const int mode) {
 
285
  char buf[FN_REFLEN];
 
286
  const int BUCKETS = 7;
 
287
 
 
288
  if ((system_table = tchdbnew()) == NULL)
 
289
    return HA_ERR_OUT_OF_MEM;
 
290
 
 
291
  if (!tchdbsetmutex(system_table)) {
 
292
    tchdbdel(system_table);
 
293
    return HA_ERR_CRASHED_ON_USAGE;
 
294
  }
 
295
 
 
296
  if (!tchdbtune(system_table, BUCKETS, -1, -1, 0)) {
 
297
    tchdbdel(system_table);
 
298
    return HA_ERR_CRASHED_ON_USAGE;
 
299
  }
 
300
 
 
301
  snprintf(buf, FN_REFLEN, "%s%s", path.c_str(), BLITZ_SYSTEM_EXT);
 
302
 
 
303
  if (!tchdbopen(system_table, buf, mode)) {
 
304
    tchdbdel(system_table);
 
305
    return HA_ERR_CRASHED_ON_USAGE;
 
306
  }
 
307
 
 
308
  return 0;
 
309
}
 
310
 
 
311
int BlitzData::close_system_table(void) {
 
312
  assert(system_table);
 
313
 
 
314
  if (!tchdbclose(system_table)) {
 
315
    tchdbdel(system_table);
 
316
    return HA_ERR_CRASHED_ON_USAGE;
 
317
  }
 
318
  tchdbdel(system_table);
 
319
  return 0;
 
320
}
 
321
 
 
322
bool BlitzData::write_table_definition(drizzled::message::Table &proto) {
 
323
  assert(system_table);
 
324
 
 
325
  std::string serialized_proto;
 
326
  proto.SerializeToString(&serialized_proto);
 
327
 
 
328
  if (!tchdbput(system_table, BLITZ_TABLE_PROTO_KEY.c_str(),
 
329
                BLITZ_TABLE_PROTO_KEY.length(), serialized_proto.c_str(),
 
330
                serialized_proto.length())) {
 
331
    return false;
 
332
  }
 
333
 
 
334
  if (proto.options().has_comment()) {
 
335
    if (!tchdbput(system_table, BLITZ_TABLE_PROTO_COMMENT_KEY.c_str(),
 
336
                  BLITZ_TABLE_PROTO_COMMENT_KEY.length(),
 
337
                  proto.options().comment().c_str(),
 
338
                  proto.options().comment().length())) {
 
339
      return false;
 
340
    }
 
341
  }
 
342
  return true;
 
343
}
 
344
 
 
345
char *BlitzData::get_system_entry(const char *key, const size_t klen,
 
346
                                  int *vlen) {
 
347
  assert(system_table);
 
348
  return (char *)tchdbget(system_table, key, klen, vlen);
 
349
}