~ubuntu-branches/ubuntu/vivid/mariadb-5.5/vivid

« back to all changes in this revision

Viewing changes to storage/tokudb/ft-index/ft/logformat.cc

  • Committer: Package Import Robot
  • Author(s): Otto Kekäläinen
  • Date: 2014-11-14 21:04:24 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20141114210424-xlyna0ozl11647o5
Tags: 5.5.40-0ubuntu0.14.10.1
* SECURITY UPDATE: Update to 5.5.40 to fix security issues (LP: #1391676)
  - CVE-2014-6507
  - CVE-2014-6491
  - CVE-2014-6500
  - CVE-2014-6469
  - CVE-2014-6555
  - CVE-2014-6559
  - CVE-2014-6494
  - CVE-2014-6496
  - CVE-2014-6464
* Add bsdutils as mariadb-server dependency like upstream does in 5.5.40.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
 
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3
 
#ident "$Id$"
4
 
/*
5
 
COPYING CONDITIONS NOTICE:
6
 
 
7
 
  This program is free software; you can redistribute it and/or modify
8
 
  it under the terms of version 2 of the GNU General Public License as
9
 
  published by the Free Software Foundation, and provided that the
10
 
  following conditions are met:
11
 
 
12
 
      * Redistributions of source code must retain this COPYING
13
 
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
14
 
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
15
 
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
16
 
        GRANT (below).
17
 
 
18
 
      * Redistributions in binary form must reproduce this COPYING
19
 
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
20
 
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
21
 
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
22
 
        GRANT (below) in the documentation and/or other materials
23
 
        provided with the distribution.
24
 
 
25
 
  You should have received a copy of the GNU General Public License
26
 
  along with this program; if not, write to the Free Software
27
 
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28
 
  02110-1301, USA.
29
 
 
30
 
COPYRIGHT NOTICE:
31
 
 
32
 
  TokuDB, Tokutek Fractal Tree Indexing Library.
33
 
  Copyright (C) 2007-2013 Tokutek, Inc.
34
 
 
35
 
DISCLAIMER:
36
 
 
37
 
  This program is distributed in the hope that it will be useful, but
38
 
  WITHOUT ANY WARRANTY; without even the implied warranty of
39
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
40
 
  General Public License for more details.
41
 
 
42
 
UNIVERSITY PATENT NOTICE:
43
 
 
44
 
  The technology is licensed by the Massachusetts Institute of
45
 
  Technology, Rutgers State University of New Jersey, and the Research
46
 
  Foundation of State University of New York at Stony Brook under
47
 
  United States of America Serial No. 11/760379 and to the patents
48
 
  and/or patent applications resulting from it.
49
 
 
50
 
PATENT MARKING NOTICE:
51
 
 
52
 
  This software is covered by US Patent No. 8,185,551.
53
 
  This software is covered by US Patent No. 8,489,638.
54
 
 
55
 
PATENT RIGHTS GRANT:
56
 
 
57
 
  "THIS IMPLEMENTATION" means the copyrightable works distributed by
58
 
  Tokutek as part of the Fractal Tree project.
59
 
 
60
 
  "PATENT CLAIMS" means the claims of patents that are owned or
61
 
  licensable by Tokutek, both currently or in the future; and that in
62
 
  the absence of this license would be infringed by THIS
63
 
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
64
 
 
65
 
  "PATENT CHALLENGE" shall mean a challenge to the validity,
66
 
  patentability, enforceability and/or non-infringement of any of the
67
 
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
68
 
 
69
 
  Tokutek hereby grants to you, for the term and geographical scope of
70
 
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
71
 
  irrevocable (except as stated in this section) patent license to
72
 
  make, have made, use, offer to sell, sell, import, transfer, and
73
 
  otherwise run, modify, and propagate the contents of THIS
74
 
  IMPLEMENTATION, where such license applies only to the PATENT
75
 
  CLAIMS.  This grant does not include claims that would be infringed
76
 
  only as a consequence of further modifications of THIS
77
 
  IMPLEMENTATION.  If you or your agent or licensee institute or order
78
 
  or agree to the institution of patent litigation against any entity
79
 
  (including a cross-claim or counterclaim in a lawsuit) alleging that
80
 
  THIS IMPLEMENTATION constitutes direct or contributory patent
81
 
  infringement, or inducement of patent infringement, then any rights
82
 
  granted to you under this License shall terminate as of the date
83
 
  such litigation is filed.  If you or your agent or exclusive
84
 
  licensee institute or order or agree to the institution of a PATENT
85
 
  CHALLENGE, then Tokutek may terminate any rights granted to you
86
 
  under this License.
87
 
*/
88
 
 
89
 
#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."
90
 
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
91
 
 
92
 
/* This file defines the logformat in an executable fashion.
93
 
 * This code is used to generate
94
 
 *   The code that writes into the log.
95
 
 *   The code that reads the log and prints it to stdout (the log_print utility)
96
 
 *   The code that reads the log for recovery.
97
 
 *   The struct definitions.
98
 
 *   The Latex documentation.
99
 
 */
100
 
#include <ctype.h>
101
 
#include <errno.h>
102
 
#include <stdarg.h>
103
 
#include <stdio.h>
104
 
#include <stdlib.h>
105
 
#include <string.h>
106
 
#include <sys/stat.h>
107
 
#include <sys/types.h>
108
 
#include <unistd.h>
109
 
#include <toku_portability.h>
110
 
#include <toku_assert.h>
111
 
 
112
 
 
113
 
typedef struct field {
114
 
    const char *type;
115
 
    const char *name;
116
 
    const char *format; // optional format string
117
 
} F;
118
 
 
119
 
#define NULLFIELD {0,0,0}
120
 
#define FA (F[])
121
 
 
122
 
enum log_begin_action {
123
 
    IGNORE_LOG_BEGIN,
124
 
    SHOULD_LOG_BEGIN,
125
 
    ASSERT_BEGIN_WAS_LOGGED,
126
 
    LOG_BEGIN_ACTION_NA = IGNORE_LOG_BEGIN
127
 
};
128
 
 
129
 
struct logtype {
130
 
    const char *name;
131
 
    unsigned int command_and_flags;
132
 
    struct field *fields;
133
 
    enum log_begin_action log_begin_action;
134
 
};
135
 
 
136
 
// In the fields, don't mention the command, the LSN, the CRC or the trailing LEN.
137
 
 
138
 
const struct logtype rollbacks[] = {
139
 
    //TODO: #2037 Add dname
140
 
    {"fdelete", 'U', FA{{"FILENUM",    "filenum", 0},
141
 
                        NULLFIELD}, LOG_BEGIN_ACTION_NA},
142
 
    //TODO: #2037 Add dname
143
 
    {"fcreate", 'F', FA{{"FILENUM", "filenum", 0},
144
 
                        {"BYTESTRING", "iname", 0},
145
 
                        NULLFIELD}, LOG_BEGIN_ACTION_NA},
146
 
    // cmdinsert is used to insert a key-value pair into a DB.  For rollback we don't need the data.
147
 
    {"cmdinsert", 'i', FA{
148
 
                          {"FILENUM", "filenum", 0},
149
 
                          {"BYTESTRING", "key", 0},
150
 
                          NULLFIELD}, LOG_BEGIN_ACTION_NA},
151
 
    {"cmddelete", 'd', FA{
152
 
                          {"FILENUM", "filenum", 0},
153
 
                          {"BYTESTRING", "key", 0},
154
 
                          NULLFIELD}, LOG_BEGIN_ACTION_NA},
155
 
    {"rollinclude", 'r', FA{{"TXNID_PAIR",     "xid", 0},
156
 
                            {"uint64_t", "num_nodes", 0},
157
 
                            {"BLOCKNUM",  "spilled_head", 0},
158
 
                            {"BLOCKNUM",  "spilled_tail", 0},
159
 
                            NULLFIELD}, LOG_BEGIN_ACTION_NA},
160
 
    {"load", 'l', FA{{"FILENUM",    "old_filenum", 0},
161
 
                     {"BYTESTRING", "new_iname", 0},
162
 
                     NULLFIELD}, LOG_BEGIN_ACTION_NA},
163
 
    // #2954
164
 
    {"hot_index", 'h', FA{{"FILENUMS",  "hot_index_filenums", 0},
165
 
                          NULLFIELD}, LOG_BEGIN_ACTION_NA},
166
 
    {"dictionary_redirect", 'R', FA{{"FILENUM", "old_filenum", 0},
167
 
                                    {"FILENUM", "new_filenum", 0},
168
 
                                    NULLFIELD}, LOG_BEGIN_ACTION_NA},
169
 
    {"cmdupdate", 'u', FA{{"FILENUM", "filenum", 0},
170
 
                          {"BYTESTRING", "key", 0},
171
 
                          NULLFIELD}, LOG_BEGIN_ACTION_NA},
172
 
    {"cmdupdatebroadcast", 'B', FA{{"FILENUM", "filenum", 0},
173
 
                                   {"bool",    "is_resetting_op", 0},
174
 
                                   NULLFIELD}, LOG_BEGIN_ACTION_NA},
175
 
    {"change_fdescriptor", 'D', FA{{"FILENUM",    "filenum", 0},
176
 
                            {"BYTESTRING", "old_descriptor", 0},
177
 
                            NULLFIELD}, LOG_BEGIN_ACTION_NA},
178
 
    {0,0,FA{NULLFIELD}, LOG_BEGIN_ACTION_NA}
179
 
};
180
 
 
181
 
const struct logtype logtypes[] = {
182
 
    // Records produced by checkpoints
183
 
#if 0 // no longer used, but reserve the type
184
 
    {"local_txn_checkpoint", 'c', FA{{"TXNID",      "xid", 0}, NULLFIELD}},
185
 
#endif
186
 
    {"begin_checkpoint", 'x', FA{{"uint64_t", "timestamp", 0}, {"TXNID", "last_xid", 0}, NULLFIELD}, IGNORE_LOG_BEGIN},
187
 
    {"end_checkpoint",   'X', FA{{"LSN", "lsn_begin_checkpoint", 0},
188
 
                                 {"uint64_t", "timestamp", 0},
189
 
                                 {"uint32_t", "num_fassociate_entries", 0}, // how many files were checkpointed
190
 
                                 {"uint32_t", "num_xstillopen_entries", 0},  // how many txns  were checkpointed
191
 
                                 NULLFIELD}, IGNORE_LOG_BEGIN},
192
 
    //TODO: #2037 Add dname
193
 
    {"fassociate",  'f', FA{{"FILENUM", "filenum", 0},
194
 
                            {"uint32_t",  "treeflags", 0},
195
 
                            {"BYTESTRING", "iname", 0},   // pathname of file
196
 
                            {"uint8_t", "unlink_on_close", 0},
197
 
                            NULLFIELD}, IGNORE_LOG_BEGIN},
198
 
    //We do not use a TXNINFO struct since recovery log has
199
 
    //FILENUMS and TOKUTXN has FTs (for open_fts)
200
 
    {"xstillopen", 's', FA{{"TXNID_PAIR", "xid", 0}, 
201
 
                           {"TXNID_PAIR", "parentxid", 0}, 
202
 
                           {"uint64_t", "rollentry_raw_count", 0}, 
203
 
                           {"FILENUMS",  "open_filenums", 0},
204
 
                           {"uint8_t",  "force_fsync_on_commit", 0}, 
205
 
                           {"uint64_t", "num_rollback_nodes", 0}, 
206
 
                           {"uint64_t", "num_rollentries", 0}, 
207
 
                           {"BLOCKNUM",  "spilled_rollback_head", 0}, 
208
 
                           {"BLOCKNUM",  "spilled_rollback_tail", 0}, 
209
 
                           {"BLOCKNUM",  "current_rollback", 0}, 
210
 
                           NULLFIELD}, ASSERT_BEGIN_WAS_LOGGED}, // record all transactions
211
 
    // prepared txns need a gid
212
 
    {"xstillopenprepared", 'p', FA{{"TXNID_PAIR", "xid", 0},
213
 
                                   {"XIDP",  "xa_xid", 0}, // prepared transactions need a gid, and have no parentxid.
214
 
                                   {"uint64_t", "rollentry_raw_count", 0}, 
215
 
                                   {"FILENUMS",  "open_filenums", 0},
216
 
                                   {"uint8_t",  "force_fsync_on_commit", 0}, 
217
 
                                   {"uint64_t", "num_rollback_nodes", 0},
218
 
                                   {"uint64_t", "num_rollentries", 0},
219
 
                                   {"BLOCKNUM",  "spilled_rollback_head", 0},
220
 
                                   {"BLOCKNUM",  "spilled_rollback_tail", 0},
221
 
                                   {"BLOCKNUM",  "current_rollback", 0},
222
 
                                   NULLFIELD}, ASSERT_BEGIN_WAS_LOGGED}, // record all transactions
223
 
    // Records produced by transactions
224
 
    {"xbegin", 'b', FA{{"TXNID_PAIR", "xid", 0},{"TXNID_PAIR", "parentxid", 0},NULLFIELD}, IGNORE_LOG_BEGIN},
225
 
    {"xcommit",'C', FA{{"TXNID_PAIR", "xid", 0},NULLFIELD}, ASSERT_BEGIN_WAS_LOGGED},
226
 
    {"xprepare",'P', FA{{"TXNID_PAIR", "xid", 0}, {"XIDP", "xa_xid", 0}, NULLFIELD}, ASSERT_BEGIN_WAS_LOGGED},
227
 
    {"xabort", 'q', FA{{"TXNID_PAIR", "xid", 0},NULLFIELD}, ASSERT_BEGIN_WAS_LOGGED},
228
 
    //TODO: #2037 Add dname
229
 
    {"fcreate", 'F', FA{{"TXNID_PAIR",      "xid", 0},
230
 
                        {"FILENUM",    "filenum", 0},
231
 
                        {"BYTESTRING", "iname", 0},
232
 
                        {"uint32_t",  "mode",  "0%o"},
233
 
                        {"uint32_t",  "treeflags", 0},
234
 
                        {"uint32_t", "nodesize", 0},
235
 
                        {"uint32_t", "basementnodesize", 0},
236
 
                        {"uint32_t", "compression_method", 0},
237
 
                        NULLFIELD}, SHOULD_LOG_BEGIN},
238
 
    //TODO: #2037 Add dname
239
 
    {"fopen",   'O', FA{{"BYTESTRING", "iname", 0},
240
 
                        {"FILENUM",    "filenum", 0},
241
 
                        {"uint32_t",  "treeflags", 0},
242
 
                        NULLFIELD}, IGNORE_LOG_BEGIN},
243
 
    //TODO: #2037 Add dname
244
 
    {"fclose",   'e', FA{{"BYTESTRING", "iname", 0},
245
 
                         {"FILENUM",    "filenum", 0},
246
 
                         NULLFIELD}, IGNORE_LOG_BEGIN},
247
 
    //TODO: #2037 Add dname
248
 
    {"fdelete", 'U', FA{{"TXNID_PAIR",      "xid", 0},
249
 
                        {"FILENUM", "filenum", 0},
250
 
                        NULLFIELD}, SHOULD_LOG_BEGIN},
251
 
    {"enq_insert", 'I', FA{{"FILENUM",    "filenum", 0},
252
 
                           {"TXNID_PAIR",      "xid", 0},
253
 
                           {"BYTESTRING", "key", 0},
254
 
                           {"BYTESTRING", "value", 0},
255
 
                           NULLFIELD}, SHOULD_LOG_BEGIN},
256
 
    {"enq_insert_no_overwrite", 'i', FA{{"FILENUM",    "filenum", 0},
257
 
                                        {"TXNID_PAIR",      "xid", 0},
258
 
                                        {"BYTESTRING", "key", 0},
259
 
                                        {"BYTESTRING", "value", 0},
260
 
                                        NULLFIELD}, SHOULD_LOG_BEGIN},
261
 
    {"enq_delete_any", 'E', FA{{"FILENUM",    "filenum", 0},
262
 
                               {"TXNID_PAIR",      "xid", 0},
263
 
                               {"BYTESTRING", "key", 0},
264
 
                               NULLFIELD}, SHOULD_LOG_BEGIN},
265
 
    {"enq_insert_multiple", 'm', FA{{"FILENUM",    "src_filenum", 0},
266
 
                                    {"FILENUMS",   "dest_filenums", 0},
267
 
                                    {"TXNID_PAIR",      "xid", 0},
268
 
                                    {"BYTESTRING", "src_key", 0},
269
 
                                    {"BYTESTRING", "src_val", 0},
270
 
                                    NULLFIELD}, SHOULD_LOG_BEGIN},
271
 
    {"enq_delete_multiple", 'M', FA{{"FILENUM",    "src_filenum", 0},
272
 
                                    {"FILENUMS",   "dest_filenums", 0},
273
 
                                    {"TXNID_PAIR",      "xid", 0},
274
 
                                    {"BYTESTRING", "src_key", 0},
275
 
                                    {"BYTESTRING", "src_val", 0},
276
 
                                    NULLFIELD}, SHOULD_LOG_BEGIN},
277
 
    {"comment", 'T', FA{{"uint64_t", "timestamp", 0},
278
 
                        {"BYTESTRING", "comment", 0},
279
 
                        NULLFIELD}, IGNORE_LOG_BEGIN},
280
 
    // Note: shutdown_up_to_19 log entry is NOT ALLOWED TO BE CHANGED.
281
 
    // Do not change the letter ('Q'), do not add fields,
282
 
    // do not remove fields.
283
 
    // TODO: Kill this logentry entirely once we no longer support version 19.
284
 
    {"shutdown_up_to_19", 'Q', FA{{"uint64_t", "timestamp", 0},
285
 
                         NULLFIELD}, IGNORE_LOG_BEGIN},
286
 
    // Note: Shutdown log entry is NOT ALLOWED TO BE CHANGED.
287
 
    // Do not change the letter ('0'), do not add fields,
288
 
    // do not remove fields.
289
 
    // You CAN leave this alone and add a new one, but then you have
290
 
    // to deal with the upgrade mechanism again.
291
 
    // This is how we detect clean shutdowns from OLDER VERSIONS.
292
 
    // This log entry must always be readable for future versions.
293
 
    // If you DO change it, you need to write a separate log upgrade mechanism.
294
 
    {"shutdown", '0', FA{{"uint64_t", "timestamp", 0},
295
 
                         {"TXNID", "last_xid", 0},
296
 
                         NULLFIELD}, IGNORE_LOG_BEGIN},
297
 
    {"load", 'l', FA{{"TXNID_PAIR",      "xid", 0},
298
 
                     {"FILENUM",    "old_filenum", 0},
299
 
                     {"BYTESTRING", "new_iname", 0},
300
 
                     NULLFIELD}, SHOULD_LOG_BEGIN},
301
 
    // #2954
302
 
    {"hot_index", 'h', FA{{"TXNID_PAIR",     "xid", 0},
303
 
                          {"FILENUMS",  "hot_index_filenums", 0},
304
 
                          NULLFIELD}, SHOULD_LOG_BEGIN},
305
 
    {"enq_update", 'u', FA{{"FILENUM",    "filenum", 0},
306
 
                           {"TXNID_PAIR",      "xid", 0},
307
 
                           {"BYTESTRING", "key", 0},
308
 
                           {"BYTESTRING", "extra", 0},
309
 
                           NULLFIELD}, SHOULD_LOG_BEGIN},
310
 
    {"enq_updatebroadcast", 'B', FA{{"FILENUM",    "filenum", 0},
311
 
                                    {"TXNID_PAIR",      "xid", 0},
312
 
                                    {"BYTESTRING", "extra", 0},
313
 
                                    {"bool",       "is_resetting_op", 0},
314
 
                                    NULLFIELD}, SHOULD_LOG_BEGIN},
315
 
    {"change_fdescriptor", 'D', FA{{"FILENUM",    "filenum", 0},
316
 
                            {"TXNID_PAIR",      "xid", 0},
317
 
                            {"BYTESTRING", "old_descriptor", 0},
318
 
                            {"BYTESTRING", "new_descriptor", 0},
319
 
                            {"bool",       "update_cmp_descriptor", 0},
320
 
                            NULLFIELD}, SHOULD_LOG_BEGIN},
321
 
    {0,0,FA{NULLFIELD}, (enum log_begin_action) 0}
322
 
};
323
 
 
324
 
 
325
 
#define DO_STRUCTS(lt, array, body) do {        \
326
 
    const struct logtype *lt;    \
327
 
    for (lt=&array[0]; lt->name; lt++) {        \
328
 
        body; \
329
 
    } } while (0)
330
 
 
331
 
#define DO_ROLLBACKS(lt, body) DO_STRUCTS(lt, rollbacks, body)
332
 
 
333
 
#define DO_LOGTYPES(lt, body) DO_STRUCTS(lt, logtypes, body)
334
 
 
335
 
#define DO_LOGTYPES_AND_ROLLBACKS(lt, body) (DO_ROLLBACKS(lt,body), DO_LOGTYPES(lt, body))
336
 
 
337
 
#define DO_FIELDS(fld, lt, body) do { \
338
 
    struct field *fld; \
339
 
    for (fld=lt->fields; fld->type; fld++) { \
340
 
        body; \
341
 
    } } while (0)
342
 
 
343
 
 
344
 
static void __attribute__((format (printf, 3, 4))) fprintf2 (FILE *f1, FILE *f2, const char *format, ...) {
345
 
    va_list ap;
346
 
    int r;
347
 
    va_start(ap, format);
348
 
    r=vfprintf(f1, format, ap); assert(r>=0);
349
 
    va_end(ap);
350
 
    va_start(ap, format);
351
 
    r=vfprintf(f2, format, ap); assert(r>=0);
352
 
    va_end(ap);
353
 
}
354
 
 
355
 
FILE *hf=0, *cf=0, *pf=0;
356
 
 
357
 
static void
358
 
generate_enum_internal (const char *enum_name, const char *enum_prefix, const struct logtype *lts) {
359
 
    char used_cmds[256];
360
 
    int count=0;
361
 
    memset(used_cmds, 0, 256);
362
 
    fprintf(hf, "enum %s {", enum_name);
363
 
    DO_STRUCTS(lt, lts,
364
 
                {
365
 
                    unsigned char cmd = (unsigned char)(lt->command_and_flags&0xff);
366
 
                    if (count!=0) fprintf(hf, ",");
367
 
                    count++;
368
 
                    fprintf(hf, "\n");
369
 
                    fprintf(hf,"    %s_%-16s = '%c'", enum_prefix, lt->name, cmd);
370
 
                    if (used_cmds[cmd]!=0) { fprintf(stderr, "%s:%d: error: Command %d (%c) was used twice (second time for %s)\n", __FILE__, __LINE__, cmd, cmd, lt->name); abort(); }
371
 
                    used_cmds[cmd]=1;
372
 
                });
373
 
    fprintf(hf, "\n};\n\n");
374
 
 
375
 
}
376
 
 
377
 
static void
378
 
generate_enum (void) {
379
 
    generate_enum_internal("lt_cmd", "LT", logtypes);
380
 
    generate_enum_internal("rt_cmd", "RT", rollbacks);
381
 
}
382
 
 
383
 
static void
384
 
generate_log_struct (void) {
385
 
    DO_LOGTYPES(lt,
386
 
                {  fprintf(hf, "struct logtype_%s {\n", lt->name);
387
 
                    fprintf(hf, "  %-16s lsn;\n", "LSN");
388
 
                    DO_FIELDS(field_type, lt,
389
 
                              fprintf(hf, "  %-16s %s;\n", field_type->type, field_type->name));
390
 
                    fprintf(hf, "  %-16s crc;\n", "uint32_t");
391
 
                    fprintf(hf, "  %-16s len;\n", "uint32_t");
392
 
                    fprintf(hf, "};\n");
393
 
                    //fprintf(hf, "void toku_recover_%s (LSN lsn", lt->name);
394
 
                    //DO_FIELDS(field_type, lt, fprintf(hf, ", %s %s", field_type->type, field_type->name));
395
 
                    //fprintf(hf, ");\n");
396
 
                });
397
 
    DO_ROLLBACKS(lt,
398
 
                 {  fprintf(hf, "struct rolltype_%s {\n", lt->name);
399
 
                     DO_FIELDS(field_type, lt,
400
 
                               fprintf(hf, "  %-16s %s;\n", field_type->type, field_type->name));
401
 
                     fprintf(hf, "};\n");
402
 
                     fprintf(hf, "int toku_rollback_%s (", lt->name);
403
 
                     DO_FIELDS(field_type, lt, fprintf(hf, "%s %s,", field_type->type, field_type->name));
404
 
                     fprintf(hf, "TOKUTXN txn, LSN oplsn);\n");
405
 
                     fprintf(hf, "int toku_commit_%s (", lt->name);
406
 
                     DO_FIELDS(field_type, lt, fprintf(hf, "%s %s,", field_type->type, field_type->name));
407
 
                     fprintf(hf, "TOKUTXN txn, LSN oplsn);\n");
408
 
                 });
409
 
    fprintf(hf, "struct log_entry {\n");
410
 
    fprintf(hf, "  enum lt_cmd cmd;\n");
411
 
    fprintf(hf, "  union {\n");
412
 
    DO_LOGTYPES(lt, fprintf(hf,"    struct logtype_%s %s;\n", lt->name, lt->name));
413
 
    fprintf(hf, "  } u;\n");
414
 
    fprintf(hf, "};\n");
415
 
 
416
 
    fprintf(hf, "struct roll_entry {\n");
417
 
    fprintf(hf, "  enum rt_cmd cmd;\n");
418
 
    fprintf(hf, "  struct roll_entry *prev; /* for in-memory list of log entries.  Threads from newest to oldest. */\n");
419
 
    fprintf(hf, "  union {\n");
420
 
    DO_ROLLBACKS(lt, fprintf(hf,"    struct rolltype_%s %s;\n", lt->name, lt->name));
421
 
    fprintf(hf, "  } u;\n");
422
 
    fprintf(hf, "};\n");
423
 
 
424
 
}
425
 
 
426
 
static void
427
 
generate_dispatch (void) {
428
 
    fprintf(hf, "#define rolltype_dispatch(s, funprefix) ({ switch((s)->cmd) {\\\n");
429
 
    DO_ROLLBACKS(lt, fprintf(hf, "  case RT_%s: funprefix ## %s (&(s)->u.%s); break;\\\n", lt->name, lt->name, lt->name));
430
 
    fprintf(hf, " }})\n");
431
 
 
432
 
    fprintf(hf, "#define logtype_dispatch_assign(s, funprefix, var, ...) do { switch((s)->cmd) {\\\n");
433
 
    DO_LOGTYPES(lt, fprintf(hf, "  case LT_%s: var = funprefix ## %s (&(s)->u.%s, __VA_ARGS__); break;\\\n", lt->name, lt->name, lt->name));
434
 
    fprintf(hf, " }} while (0)\n");
435
 
 
436
 
    fprintf(hf, "#define rolltype_dispatch_assign(s, funprefix, var, ...) do { \\\n");
437
 
    fprintf(hf, "  switch((s)->cmd) {\\\n");
438
 
    DO_ROLLBACKS(lt, {
439
 
                    fprintf(hf, "  case RT_%s: var = funprefix ## %s (", lt->name, lt->name);
440
 
                    int fieldcount=0;
441
 
                    DO_FIELDS(field_type, lt, {
442
 
                                if (fieldcount>0) fprintf(hf, ",");
443
 
                                fprintf(hf, "(s)->u.%s.%s", lt->name, field_type->name);
444
 
                                fieldcount++;
445
 
                            });
446
 
                    fprintf(hf, ", __VA_ARGS__); break;\\\n");
447
 
                });
448
 
    fprintf(hf, "  default: assert(0);} } while (0)\n");
449
 
 
450
 
    fprintf(hf, "#define logtype_dispatch_args(s, funprefix, ...) do { switch((s)->cmd) {\\\n");
451
 
    DO_LOGTYPES(lt,
452
 
                {
453
 
                    fprintf(hf, "  case LT_%s: funprefix ## %s ((s)->u.%s.lsn", lt->name, lt->name, lt->name);
454
 
                    DO_FIELDS(field_type, lt, fprintf(hf, ",(s)->u.%s.%s", lt->name, field_type->name));
455
 
                    fprintf(hf, ", __VA_ARGS__); break;\\\n");
456
 
                });
457
 
    fprintf(hf, " }} while (0)\n");
458
 
}
459
 
 
460
 
static void
461
 
generate_get_timestamp(void) {
462
 
    fprintf(cf, "static uint64_t toku_get_timestamp(void) {\n");
463
 
    fprintf(cf, "  struct timeval tv; int r = gettimeofday(&tv, NULL);\n");
464
 
    fprintf(cf, "  assert(r==0);\n");
465
 
    fprintf(cf, "  return tv.tv_sec * 1000000ULL + tv.tv_usec;\n");
466
 
    fprintf(cf, "}\n");
467
 
}
468
 
 
469
 
static void
470
 
generate_log_writer (void) {
471
 
    generate_get_timestamp();
472
 
    DO_LOGTYPES(lt, {
473
 
            //TODO(yoni): The overhead variables are NOT correct for BYTESTRING, FILENUMS (or any other variable length type)
474
 
            //            We should switch to something like using toku_logsizeof_*.
475
 
            fprintf(hf, "static const size_t toku_log_%s_overhead = (+4+1+8", lt->name);
476
 
            DO_FIELDS(field_type, lt, fprintf(hf, "+sizeof(%s)", field_type->type));
477
 
            fprintf(hf, "+8);\n");
478
 
                        fprintf2(cf, hf, "void toku_log_%s (TOKULOGGER logger, LSN *lsnp, int do_fsync", lt->name);
479
 
                        switch (lt->log_begin_action) {
480
 
                        case SHOULD_LOG_BEGIN:
481
 
                        case ASSERT_BEGIN_WAS_LOGGED: {
482
 
                            fprintf2(cf, hf, ", TOKUTXN txn");
483
 
                            break;
484
 
                        }
485
 
                        case IGNORE_LOG_BEGIN: break;
486
 
                        }
487
 
                        DO_FIELDS(field_type, lt, fprintf2(cf, hf, ", %s %s", field_type->type, field_type->name));
488
 
                        fprintf(hf, ");\n");
489
 
                        fprintf(cf, ") {\n");
490
 
                        fprintf(cf, "  if (logger == NULL) {\n");
491
 
                        fprintf(cf, "     return;\n");
492
 
                        fprintf(cf, "  }\n");
493
 
                        switch (lt->log_begin_action) {
494
 
                        case SHOULD_LOG_BEGIN: {
495
 
                            fprintf(cf, "  //txn can be NULL during tests\n");
496
 
                            fprintf(cf, "  //never null when not checkpoint.\n");
497
 
                            fprintf(cf, "  if (txn && !txn->begin_was_logged) {\n");
498
 
                            fprintf(cf, "    invariant(!txn_declared_read_only(txn));\n");
499
 
                            fprintf(cf, "    toku_maybe_log_begin_txn_for_write_operation(txn);\n");
500
 
                            fprintf(cf, "  }\n");
501
 
                            break;
502
 
                        }
503
 
                        case ASSERT_BEGIN_WAS_LOGGED: {
504
 
                            fprintf(cf, "  //txn can be NULL during tests\n");
505
 
                            fprintf(cf, "  invariant(!txn || txn->begin_was_logged);\n");
506
 
                            fprintf(cf, "  invariant(!txn || !txn_declared_read_only(txn));\n");
507
 
                            break;
508
 
                        }
509
 
                        case IGNORE_LOG_BEGIN: break;
510
 
                        }
511
 
                        fprintf(cf, "  if (!logger->write_log_files) {\n");
512
 
                        fprintf(cf, "    ml_lock(&logger->input_lock);\n");
513
 
                        fprintf(cf, "    logger->lsn.lsn++;\n");
514
 
                        fprintf(cf, "    if (lsnp) *lsnp=logger->lsn;\n");
515
 
                        fprintf(cf, "    ml_unlock(&logger->input_lock);\n");
516
 
                        fprintf(cf, "    return;\n");
517
 
                        fprintf(cf, "  }\n");
518
 
                        fprintf(cf, "  const unsigned int buflen= (+4 // len at the beginning\n");
519
 
                        fprintf(cf, "                              +1 // log command\n");
520
 
                        fprintf(cf, "                              +8 // lsn\n");
521
 
                        DO_FIELDS(field_type, lt,
522
 
                                  fprintf(cf, "                              +toku_logsizeof_%s(%s)\n", field_type->type, field_type->name));
523
 
                        fprintf(cf, "                              +8 // crc + len\n");
524
 
                        fprintf(cf, "                     );\n");
525
 
                        fprintf(cf, "  struct wbuf wbuf;\n");
526
 
                        fprintf(cf, "  ml_lock(&logger->input_lock);\n");
527
 
                        fprintf(cf, "  toku_logger_make_space_in_inbuf(logger, buflen);\n");
528
 
                        fprintf(cf, "  wbuf_nocrc_init(&wbuf, logger->inbuf.buf+logger->inbuf.n_in_buf, buflen);\n");
529
 
                        fprintf(cf, "  wbuf_nocrc_int(&wbuf, buflen);\n");
530
 
                        fprintf(cf, "  wbuf_nocrc_char(&wbuf, '%c');\n", (char)(0xff&lt->command_and_flags));
531
 
                        fprintf(cf, "  logger->lsn.lsn++;\n");
532
 
                        fprintf(cf, "  logger->inbuf.max_lsn_in_buf = logger->lsn;\n");
533
 
                        fprintf(cf, "  wbuf_nocrc_LSN(&wbuf, logger->lsn);\n");
534
 
                        fprintf(cf, "  if (lsnp) *lsnp=logger->lsn;\n");
535
 
                        DO_FIELDS(field_type, lt,
536
 
                                  if (strcmp(field_type->name, "timestamp") == 0)
537
 
                                      fprintf(cf, "  if (timestamp == 0) timestamp = toku_get_timestamp();\n");
538
 
                                  fprintf(cf, "  wbuf_nocrc_%s(&wbuf, %s);\n", field_type->type, field_type->name));
539
 
                        fprintf(cf, "  wbuf_nocrc_int(&wbuf, toku_x1764_memory(wbuf.buf, wbuf.ndone));\n");
540
 
                        fprintf(cf, "  wbuf_nocrc_int(&wbuf, buflen);\n");
541
 
                        fprintf(cf, "  assert(wbuf.ndone==buflen);\n");
542
 
                        fprintf(cf, "  logger->inbuf.n_in_buf += buflen;\n");
543
 
                        fprintf(cf, "  toku_logger_maybe_fsync(logger, logger->lsn, do_fsync, true);\n");
544
 
                        fprintf(cf, "}\n\n");
545
 
                    });
546
 
}
547
 
 
548
 
static void
549
 
generate_log_reader (void) {
550
 
    DO_LOGTYPES(lt, {
551
 
                        fprintf(cf, "static int toku_log_fread_%s (FILE *infile, uint32_t len1, struct logtype_%s *data, struct x1764 *checksum)", lt->name, lt->name);
552
 
                        fprintf(cf, " {\n");
553
 
                        fprintf(cf, "  int r=0;\n");
554
 
                        fprintf(cf, "  uint32_t actual_len=5; // 1 for the command, 4 for the first len.\n");
555
 
                        fprintf(cf, "  r=toku_fread_%-16s(infile, &data->%-16s, checksum, &actual_len); if (r!=0) return r;\n", "LSN", "lsn");
556
 
                        DO_FIELDS(field_type, lt,
557
 
                                  fprintf(cf, "  r=toku_fread_%-16s(infile, &data->%-16s, checksum, &actual_len); if (r!=0) return r;\n", field_type->type, field_type->name));
558
 
                        fprintf(cf, "  uint32_t checksum_in_file, len_in_file;\n");
559
 
                        fprintf(cf, "  r=toku_fread_uint32_t_nocrclen(infile, &checksum_in_file); actual_len+=4;   if (r!=0) return r;\n");
560
 
                        fprintf(cf, "  r=toku_fread_uint32_t_nocrclen(infile, &len_in_file);    actual_len+=4;   if (r!=0) return r;\n");
561
 
                        fprintf(cf, "  if (checksum_in_file!=toku_x1764_finish(checksum) || len_in_file!=actual_len || len1 != len_in_file) return DB_BADFORMAT;\n");
562
 
                        fprintf(cf, "  return 0;\n");
563
 
                        fprintf(cf, "}\n\n");
564
 
                    });
565
 
    fprintf2(cf, hf, "int toku_log_fread (FILE *infile, struct log_entry *le)");
566
 
    fprintf(hf, ";\n");
567
 
    fprintf(cf, " {\n");
568
 
    fprintf(cf, "  uint32_t len1; int r;\n");
569
 
    fprintf(cf, "  uint32_t ignorelen=0;\n");
570
 
    fprintf(cf, "  struct x1764 checksum;\n");
571
 
    fprintf(cf, "  toku_x1764_init(&checksum);\n");
572
 
    fprintf(cf, "  r = toku_fread_uint32_t(infile, &len1, &checksum, &ignorelen); if (r!=0) return r;\n");
573
 
    fprintf(cf, "  int cmd=fgetc(infile);\n");
574
 
    fprintf(cf, "  if (cmd==EOF) return EOF;\n");
575
 
    fprintf(cf, "  char cmdchar = (char)cmd;\n");
576
 
    fprintf(cf, "  toku_x1764_add(&checksum, &cmdchar, 1);\n");
577
 
    fprintf(cf, "  le->cmd=(enum lt_cmd)cmd;\n");
578
 
    fprintf(cf, "  switch ((enum lt_cmd)cmd) {\n");
579
 
    DO_LOGTYPES(lt, {
580
 
                        fprintf(cf, "  case LT_%s:\n", lt->name);
581
 
                        fprintf(cf, "    return toku_log_fread_%s (infile, len1, &le->u.%s, &checksum);\n", lt->name, lt->name);
582
 
                    });
583
 
    fprintf(cf, "  };\n");
584
 
    fprintf(cf, "  return DB_BADFORMAT;\n"); // Should read past the record using the len field.
585
 
    fprintf(cf, "}\n\n");
586
 
    //fprintf2(cf, hf, "// Return 0 if there is something to read, return -1 if nothing to read, abort if an error.\n");
587
 
    fprintf2(cf, hf, "// Return 0 if there is something to read, -1 if nothing to read, >0 on error\n");
588
 
    fprintf2(cf, hf, "int toku_log_fread_backward (FILE *infile, struct log_entry *le)");
589
 
    fprintf(hf, ";\n");
590
 
    fprintf(cf, "{\n");
591
 
    fprintf(cf, "  memset(le, 0, sizeof(*le));\n");
592
 
    fprintf(cf, "  long pos = ftell(infile);\n");
593
 
    fprintf(cf, "  if (pos<=12) return -1;\n");
594
 
    fprintf(cf, "  int r = fseek(infile, -4, SEEK_CUR); \n");//              assert(r==0);\n");
595
 
    fprintf(cf, "  if (r!=0) return get_error_errno();\n");
596
 
    fprintf(cf, "  uint32_t len;\n");
597
 
    fprintf(cf, "  r = toku_fread_uint32_t_nocrclen(infile, &len); \n");//  assert(r==0);\n");
598
 
    fprintf(cf, "  if (r!=0) return 1;\n");
599
 
    fprintf(cf, "  r = fseek(infile, -(int)len, SEEK_CUR) ;  \n");//         assert(r==0);\n");
600
 
    fprintf(cf, "  if (r!=0) return get_error_errno();\n");
601
 
    fprintf(cf, "  r = toku_log_fread(infile, le); \n");//                   assert(r==0);\n");
602
 
    fprintf(cf, "  if (r!=0) return 1;\n");
603
 
    fprintf(cf, "  long afterpos = ftell(infile);\n");
604
 
    fprintf(cf, "  if (afterpos != pos) return 1;\n");
605
 
    fprintf(cf, "  r = fseek(infile, -(int)len, SEEK_CUR); \n");//           assert(r==0);\n");
606
 
    fprintf(cf, "  if (r!=0) return get_error_errno();\n");
607
 
    fprintf(cf, "  return 0;\n");
608
 
    fprintf(cf, "}\n\n");
609
 
 
610
 
    DO_LOGTYPES(lt, ({
611
 
            fprintf(cf, "static void toku_log_free_log_entry_%s_resources (struct logtype_%s *data", lt->name, lt->name);
612
 
            if (!lt->fields->type) fprintf(cf, " __attribute__((__unused__))");
613
 
            fprintf(cf, ") {\n");
614
 
            DO_FIELDS(field_type, lt,
615
 
                      fprintf(cf, "    toku_free_%s(data->%s);\n", field_type->type, field_type->name);
616
 
                      );
617
 
            fprintf(cf, "}\n\n");
618
 
            }));
619
 
    fprintf2(cf, hf, "void toku_log_free_log_entry_resources (struct log_entry *le)");
620
 
    fprintf(hf, ";\n");
621
 
    fprintf(cf, " {\n");
622
 
    fprintf(cf, "    switch ((enum lt_cmd)le->cmd) {\n");
623
 
    DO_LOGTYPES(lt, {
624
 
            fprintf(cf, "    case LT_%s:\n", lt->name);
625
 
            fprintf(cf, "        return toku_log_free_log_entry_%s_resources (&(le->u.%s));\n", lt->name, lt->name);
626
 
        });
627
 
    fprintf(cf, "    };\n");
628
 
    fprintf(cf, "    return;\n");
629
 
    fprintf(cf, "}\n\n");
630
 
}
631
 
 
632
 
static void
633
 
generate_logprint (void) {
634
 
    unsigned maxnamelen=0;
635
 
    fprintf2(pf, hf, "int toku_logprint_one_record(FILE *outf, FILE *f)");
636
 
    fprintf(hf, ";\n");
637
 
    fprintf(pf, " {\n");
638
 
    fprintf(pf, "    int cmd, r;\n");
639
 
    fprintf(pf, "    uint32_t len1, crc_in_file;\n");
640
 
    fprintf(pf, "    uint32_t ignorelen=0;\n");
641
 
    fprintf(pf, "    struct x1764 checksum;\n");
642
 
    fprintf(pf, "    toku_x1764_init(&checksum);\n");
643
 
    fprintf(pf, "    r=toku_fread_uint32_t(f, &len1, &checksum, &ignorelen);\n");
644
 
    fprintf(pf, "    if (r==EOF) return EOF;\n");
645
 
    fprintf(pf, "    cmd=fgetc(f);\n");
646
 
    fprintf(pf, "    if (cmd==EOF) return DB_BADFORMAT;\n");
647
 
    fprintf(pf, "    uint32_t len_in_file, len=1+4; // cmd + len1\n");
648
 
    fprintf(pf, "    char charcmd = (char)cmd;\n");
649
 
    fprintf(pf, "    toku_x1764_add(&checksum, &charcmd, 1);\n");
650
 
    fprintf(pf, "    switch ((enum lt_cmd)cmd) {\n");
651
 
    DO_LOGTYPES(lt, { if (strlen(lt->name)>maxnamelen) maxnamelen=strlen(lt->name); });
652
 
    DO_LOGTYPES(lt, {
653
 
                unsigned char cmd = (unsigned char)(0xff&lt->command_and_flags);
654
 
                fprintf(pf, "    case LT_%s: \n", lt->name);
655
 
                // We aren't using the log reader here because we want better diagnostics as soon as things go wrong.
656
 
                fprintf(pf, "        fprintf(outf, \"%%-%us \", \"%s\");\n", maxnamelen, lt->name);
657
 
                if (isprint(cmd)) fprintf(pf,"        fprintf(outf, \" '%c':\");\n", cmd);
658
 
                else                      fprintf(pf,"        fprintf(outf, \"0%03o:\");\n", cmd);
659
 
                fprintf(pf, "        r = toku_logprint_%-16s(outf, f, \"lsn\", &checksum, &len, 0);     if (r!=0) return r;\n", "LSN");
660
 
                DO_FIELDS(field_type, lt, {
661
 
                            fprintf(pf, "        r = toku_logprint_%-16s(outf, f, \"%s\", &checksum, &len,", field_type->type, field_type->name);
662
 
                            if (field_type->format) fprintf(pf, "\"%s\"", field_type->format);
663
 
                            else            fprintf(pf, "0");
664
 
                            fprintf(pf, "); if (r!=0) return r;\n");
665
 
                        });
666
 
                fprintf(pf, "        {\n");
667
 
                fprintf(pf, "          uint32_t actual_murmur = toku_x1764_finish(&checksum);\n");
668
 
                fprintf(pf, "          r = toku_fread_uint32_t_nocrclen (f, &crc_in_file); len+=4; if (r!=0) return r;\n");
669
 
                fprintf(pf, "          fprintf(outf, \" crc=%%08x\", crc_in_file);\n");
670
 
                fprintf(pf, "          if (crc_in_file!=actual_murmur) fprintf(outf, \" checksum=%%08x\", actual_murmur);\n");
671
 
                fprintf(pf, "          r = toku_fread_uint32_t_nocrclen (f, &len_in_file); len+=4; if (r!=0) return r;\n");
672
 
                fprintf(pf, "          fprintf(outf, \" len=%%u\", len_in_file);\n");
673
 
                fprintf(pf, "          if (len_in_file!=len) fprintf(outf, \" actual_len=%%u\", len);\n");
674
 
                fprintf(pf, "          if (len_in_file!=len || crc_in_file!=actual_murmur) return DB_BADFORMAT;\n");
675
 
                fprintf(pf, "        };\n");
676
 
                fprintf(pf, "        fprintf(outf, \"\\n\");\n");
677
 
                fprintf(pf, "        return 0;\n\n");
678
 
            });
679
 
    fprintf(pf, "    }\n");
680
 
    fprintf(pf, "    fprintf(outf, \"Unknown command %%d ('%%c')\", cmd, cmd);\n");
681
 
    fprintf(pf, "    return DB_BADFORMAT;\n");
682
 
    fprintf(pf, "}\n\n");
683
 
}
684
 
 
685
 
static void
686
 
generate_rollbacks (void) {
687
 
    DO_ROLLBACKS(lt, {
688
 
                    fprintf2(cf, hf, "void toku_logger_save_rollback_%s (TOKUTXN txn", lt->name);
689
 
                    DO_FIELDS(field_type, lt, {
690
 
                        if ( strcmp(field_type->type, "BYTESTRING") == 0 ) {
691
 
                            fprintf2(cf, hf, ", BYTESTRING *%s_ptr", field_type->name);
692
 
                        } 
693
 
                        else if ( strcmp(field_type->type, "FILENUMS") == 0 ) {
694
 
                            fprintf2(cf, hf, ", FILENUMS *%s_ptr", field_type->name);
695
 
                        }
696
 
                        else {
697
 
                            fprintf2(cf, hf, ", %s %s", field_type->type, field_type->name);
698
 
                        }
699
 
                    });
700
 
 
701
 
                    fprintf(hf, ");\n");
702
 
                    fprintf(cf, ") {\n");
703
 
                    fprintf(cf, "  toku_txn_lock(txn);\n");
704
 
                    fprintf(cf, "  ROLLBACK_LOG_NODE log;\n");
705
 
                    fprintf(cf, "  toku_get_and_pin_rollback_log_for_new_entry(txn, &log);\n");
706
 
                    // 'memdup' all BYTESTRINGS here
707
 
                    DO_FIELDS(field_type, lt, {
708
 
                        if ( strcmp(field_type->type, "BYTESTRING") == 0 ) {
709
 
                            fprintf(cf, "  BYTESTRING %s   = {\n"
710
 
                                    "    .len  = %s_ptr->len,\n"
711
 
                                    "    .data = cast_to_typeof(%s.data) toku_memdup_in_rollback(log, %s_ptr->data, %s_ptr->len)\n"
712
 
                                    "  };\n",
713
 
                                    field_type->name, field_type->name, field_type->name, field_type->name, field_type->name);
714
 
                        }
715
 
                        if ( strcmp(field_type->type, "FILENUMS") == 0 ) {
716
 
                            fprintf(cf, "  FILENUMS %s   = {\n"
717
 
                                    "    .num  = %s_ptr->num,\n"
718
 
                                    "    .filenums = cast_to_typeof(%s.filenums) toku_memdup_in_rollback(log, %s_ptr->filenums, %s_ptr->num * (sizeof (FILENUM)))\n"
719
 
                                    "  };\n",
720
 
                                    field_type->name, field_type->name, field_type->name, field_type->name, field_type->name);
721
 
                        }
722
 
                    });
723
 
                    {
724
 
                        int count=0;
725
 
                        fprintf(cf, "  uint32_t rollback_fsize = toku_logger_rollback_fsize_%s(", lt->name);
726
 
                        DO_FIELDS(field_type, lt, fprintf(cf, "%s%s", (count++>0)?", ":"", field_type->name));
727
 
                        fprintf(cf, ");\n");
728
 
                    }
729
 
                    fprintf(cf, "  struct roll_entry *v;\n");
730
 
                    fprintf(cf, "  size_t mem_needed = sizeof(v->u.%s) + __builtin_offsetof(struct roll_entry, u.%s);\n", lt->name, lt->name);
731
 
                    fprintf(cf, "  CAST_FROM_VOIDP(v, toku_malloc_in_rollback(log, mem_needed));\n");
732
 
                    fprintf(cf, "  assert(v);\n");
733
 
                    fprintf(cf, "  v->cmd = (enum rt_cmd)%u;\n", lt->command_and_flags&0xff);
734
 
                    DO_FIELDS(field_type, lt, fprintf(cf, "  v->u.%s.%s = %s;\n", lt->name, field_type->name, field_type->name));
735
 
                    fprintf(cf, "  v->prev = log->newest_logentry;\n");
736
 
                    fprintf(cf, "  if (log->oldest_logentry==NULL) log->oldest_logentry=v;\n");
737
 
                    fprintf(cf, "  log->newest_logentry = v;\n");
738
 
                    fprintf(cf, "  log->rollentry_resident_bytecount += rollback_fsize;\n");
739
 
                    fprintf(cf, "  txn->roll_info.rollentry_raw_count          += rollback_fsize;\n");
740
 
                    fprintf(cf, "  txn->roll_info.num_rollentries++;\n");
741
 
                    fprintf(cf, "  log->dirty = true;\n");
742
 
                    fprintf(cf, "  // spill and unpin assert success internally\n");
743
 
                    fprintf(cf, "  toku_maybe_spill_rollbacks(txn, log);\n");
744
 
                    fprintf(cf, "  toku_rollback_log_unpin(txn, log);\n");
745
 
                    fprintf(cf, "  toku_txn_unlock(txn);\n");
746
 
                    fprintf(cf, "}\n");
747
 
            });
748
 
 
749
 
    DO_ROLLBACKS(lt, {
750
 
                fprintf2(cf, hf, "void toku_logger_rollback_wbuf_nocrc_write_%s (struct wbuf *wbuf", lt->name);
751
 
                DO_FIELDS(field_type, lt, fprintf2(cf, hf, ", %s %s", field_type->type, field_type->name));
752
 
                fprintf2(cf, hf, ")");
753
 
                fprintf(hf, ";\n");
754
 
                fprintf(cf, " {\n");
755
 
 
756
 
                {
757
 
                    int count=0;
758
 
                    fprintf(cf, "  uint32_t rollback_fsize = toku_logger_rollback_fsize_%s(", lt->name);
759
 
                    DO_FIELDS(field_type, lt, fprintf(cf, "%s%s", (count++>0)?", ":"", field_type->name));
760
 
                    fprintf(cf, ");\n");
761
 
                    fprintf(cf, "  wbuf_nocrc_int(wbuf, rollback_fsize);\n");
762
 
                }
763
 
                fprintf(cf, "  wbuf_nocrc_char(wbuf, '%c');\n", (char)(0xff&lt->command_and_flags));
764
 
                DO_FIELDS(field_type, lt, fprintf(cf, "  wbuf_nocrc_%s(wbuf, %s);\n", field_type->type, field_type->name));
765
 
                fprintf(cf, "}\n");
766
 
            });
767
 
    fprintf2(cf, hf, "void toku_logger_rollback_wbuf_nocrc_write (struct wbuf *wbuf, struct roll_entry *r)");
768
 
    fprintf(hf, ";\n");
769
 
    fprintf(cf, " {\n  switch (r->cmd) {\n");
770
 
    DO_ROLLBACKS(lt, {
771
 
                fprintf(cf, "    case RT_%s: toku_logger_rollback_wbuf_nocrc_write_%s(wbuf", lt->name, lt->name);
772
 
                DO_FIELDS(field_type, lt, fprintf(cf, ", r->u.%s.%s", lt->name, field_type->name));
773
 
                fprintf(cf, "); return;\n");
774
 
            });
775
 
    fprintf(cf, "  }\n  assert(0);\n");
776
 
    fprintf(cf, "}\n");
777
 
    DO_ROLLBACKS(lt, {
778
 
                fprintf2(cf, hf, "uint32_t toku_logger_rollback_fsize_%s (", lt->name);
779
 
                int count=0;
780
 
                DO_FIELDS(field_type, lt, fprintf2(cf, hf, "%s%s %s", (count++>0)?", ":"", field_type->type, field_type->name));
781
 
                fprintf(hf, ");\n");
782
 
                fprintf(cf, ") {\n");
783
 
                fprintf(cf, "  return 1 /* the cmd*/\n");
784
 
                fprintf(cf, "         + 4 /* the int at the end saying the size */");
785
 
                DO_FIELDS(field_type, lt,
786
 
                          fprintf(cf, "\n         + toku_logsizeof_%s(%s)", field_type->type, field_type->name));
787
 
                fprintf(cf, ";\n}\n");
788
 
            });
789
 
    fprintf2(cf, hf, "uint32_t toku_logger_rollback_fsize(struct roll_entry *item)");
790
 
    fprintf(hf, ";\n");
791
 
    fprintf(cf, "{\n  switch(item->cmd) {\n");
792
 
    DO_ROLLBACKS(lt, {
793
 
                fprintf(cf, "    case RT_%s: return toku_logger_rollback_fsize_%s(", lt->name, lt->name);
794
 
                int count=0;
795
 
                DO_FIELDS(field_type, lt, fprintf(cf, "%sitem->u.%s.%s", (count++>0)?", ":"", lt->name, field_type->name));
796
 
                fprintf(cf, ");\n");
797
 
            });
798
 
    fprintf(cf, "  }\n  assert(0);\n  return 0;\n");
799
 
    fprintf(cf, "}\n");
800
 
 
801
 
    fprintf2(cf, hf, "int toku_parse_rollback(unsigned char *buf, uint32_t n_bytes, struct roll_entry **itemp, MEMARENA ma)");
802
 
    fprintf(hf, ";\n");
803
 
    fprintf(cf, " {\n  assert(n_bytes>0);\n  struct roll_entry *item;\n  enum rt_cmd cmd = (enum rt_cmd)(buf[0]);\n  size_t mem_needed;\n");
804
 
    fprintf(cf, "  struct rbuf rc = {buf, n_bytes, 1};\n");
805
 
    fprintf(cf, "  switch(cmd) {\n");
806
 
    DO_ROLLBACKS(lt, {
807
 
                fprintf(cf, "  case RT_%s:\n", lt->name);
808
 
                fprintf(cf, "    mem_needed = sizeof(item->u.%s) + __builtin_offsetof(struct roll_entry, u.%s);\n", lt->name, lt->name);
809
 
                fprintf(cf, "    CAST_FROM_VOIDP(item, toku_memarena_malloc(ma, mem_needed));\n");
810
 
                fprintf(cf, "    item->cmd = cmd;\n");
811
 
                DO_FIELDS(field_type, lt, fprintf(cf, "    rbuf_ma_%s(&rc, ma, &item->u.%s.%s);\n", field_type->type, lt->name, field_type->name));
812
 
                fprintf(cf, "    *itemp = item;\n");
813
 
                fprintf(cf, "    return 0;\n");
814
 
        });
815
 
    fprintf(cf, "  }\n  return EINVAL;\n}\n");
816
 
}
817
 
 
818
 
static void
819
 
generate_log_entry_functions(void) {
820
 
    fprintf(hf, "LSN toku_log_entry_get_lsn(struct log_entry *);\n");
821
 
    fprintf(cf, "LSN toku_log_entry_get_lsn(struct log_entry *le) {\n");
822
 
    fprintf(cf, "    return le->u.begin_checkpoint.lsn;\n");
823
 
    fprintf(cf, "}\n");
824
 
}
825
 
 
826
 
const char codefile[] = "log_code.cc";
827
 
const char printfile[] = "log_print.cc";
828
 
const char headerfile[] = "log_header.h";
829
 
int main (int argc, const char *const argv[]) {
830
 
    assert(argc==2); // the single argument is the directory into which to put things
831
 
    const char *dir = argv[1];
832
 
    size_t codepathlen   = sizeof(codefile) + strlen(dir) + 4;
833
 
    size_t printpathlen  = sizeof(printfile) + strlen(dir) + 4; 
834
 
    size_t headerpathlen = sizeof(headerfile) + strlen(dir) + 4; 
835
 
    char codepath[codepathlen];
836
 
    char printpath[printpathlen];
837
 
    char headerpath[headerpathlen];
838
 
    { int r = snprintf(codepath,   codepathlen,   "%s/%s", argv[1], codefile);    assert(r<(int)codepathlen); }
839
 
    { int r = snprintf(printpath,  printpathlen,  "%s/%s", argv[1], printfile);   assert(r<(int)printpathlen); }
840
 
    { int r = snprintf(headerpath, headerpathlen, "%s/%s", argv[1], headerfile);  assert(r<(int)headerpathlen); }
841
 
    chmod(codepath, S_IRUSR|S_IWUSR);
842
 
    chmod(headerpath, S_IRUSR|S_IWUSR);
843
 
    unlink(codepath);
844
 
    unlink(headerpath);
845
 
    cf = fopen(codepath, "w");
846
 
    if (cf==0) { int r = get_error_errno(); printf("fopen of %s failed because of errno=%d (%s)\n", codepath, r, strerror(r)); } // sometimes this is failing, so let's make a better diagnostic
847
 
    assert(cf!=0);
848
 
    hf = fopen(headerpath, "w");     assert(hf!=0);
849
 
    pf = fopen(printpath, "w");   assert(pf!=0);
850
 
    fprintf2(cf, hf, "/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */\n");
851
 
    fprintf2(cf, hf, "// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:\n");
852
 
    fprintf(hf, "#ifndef LOG_HEADER_H\n");
853
 
    fprintf(hf, "#define  LOG_HEADER_H\n");
854
 
    fprintf2(cf, hf, "/* Do not edit this file.  This code generated by logformat.c.  Copyright (c) 2007-2013 Tokutek Inc.    */\n");
855
 
    fprintf2(cf, hf, "#ident \"Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved.\"\n");
856
 
    fprintf2(cf, pf, "#include <stdint.h>\n");
857
 
    fprintf2(cf, pf, "#include <sys/time.h>\n");
858
 
    fprintf2(cf, pf, "#include <ft/fttypes.h>\n");
859
 
    fprintf2(cf, pf, "#include <ft/log-internal.h>\n");
860
 
    fprintf(hf, "#include <ft/ft-internal.h>\n");
861
 
    fprintf(hf, "#include <util/memarena.h>\n");
862
 
    generate_enum();
863
 
    generate_log_struct();
864
 
    generate_dispatch();
865
 
    generate_log_writer();
866
 
    generate_log_reader();
867
 
    generate_rollbacks();
868
 
    generate_log_entry_functions();
869
 
    generate_logprint();
870
 
    fprintf(hf, "#endif\n");
871
 
    {
872
 
        int r=fclose(hf); assert(r==0);
873
 
        r=fclose(cf); assert(r==0);
874
 
        r=fclose(pf); assert(r==0);
875
 
        // Make it tougher to modify by mistake
876
 
        chmod(codepath, S_IRUSR|S_IRGRP|S_IROTH);
877
 
        chmod(headerpath, S_IRUSR|S_IRGRP|S_IROTH);
878
 
    }
879
 
    return 0;
880
 
}
881