fix for trie index
[csql.git] / src / sqllog / FileSend.cxx
blobf2a8061da182aa6d424e472ff2f7e1d297f44b05
1 /***************************************************************************
2 * Copyright (C) 2007 by Prabakaran Thirumalai *
3 * praba_tuty@yahoo.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
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 *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include <os.h>
21 #include <SqlLogConnection.h>
22 #include <CSql.h>
24 FileSend::FileSend()
26 fdRedoLog = -1;
27 fdStmtLog = -1;
28 openRedoFile();
30 DbRetVal FileSend::openRedoFile()
32 if (fdRedoLog > 0) os::close(fdRedoLog);
33 if (fdStmtLog > 0) os::close(fdStmtLog);
34 char fileName[MAX_FILE_LEN];
35 char stmtFileName[MAX_FILE_LEN];
36 sprintf(fileName, "%s/csql.db.cur", Conf::config.getDbFile());
37 sprintf(stmtFileName, "%s/csql.db.stmt", Conf::config.getDbFile());
38 int durableMode = Conf::config.getDurableMode();
39 switch(durableMode) {
40 case 1:
41 case 2:
42 fdRedoLog = os::openFileForAppend(fileName, O_CREAT);
43 fdStmtLog = os::openFileForAppend(stmtFileName, O_CREAT);
44 break;
45 case 3:
46 fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_SYNC);
47 fdStmtLog = os::openFileForAppend(stmtFileName, O_CREAT|O_SYNC);
48 break;
49 case 4:
50 #ifdef SOLARIS
51 fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_DSYNC);
52 fdStmtLog = os::openFileForAppend(stmtFileName, O_CREAT|O_DSYNC);
53 #else
54 fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_DIRECT);
55 fdStmtLog = os::openFileForAppend(stmtFileName, O_CREAT|O_DIRECT);
56 #endif
57 break;
58 default:
59 fdRedoLog = os::openFileForAppend(fileName, O_CREAT);
60 fdStmtLog = os::openFileForAppend(stmtFileName, O_CREAT);
61 break;
63 if (-1 == fdRedoLog || -1 == fdStmtLog) {
64 printError(ErrSysInternal, "Unable to open redo log file");
65 return ErrSysInternal;
67 return OK;
70 FileSend::~FileSend() {
71 if (fdRedoLog > 0) os::close(fdRedoLog);
72 if (fdStmtLog > 0) os::close(fdStmtLog);
73 fdRedoLog = -1;
74 fdStmtLog = -1;
77 DbRetVal FileSend::prepare(int txnId, int stmtId, int len, char *stmt,
78 char *tblName, bool hasParam)
80 if (fdRedoLog < 0) {
81 printError(ErrBadArg, "Redo Log file not opened");
82 return ErrBadArg;
84 if (fdStmtLog < 0) {
85 printError(ErrBadArg, "Redo Stmt Log file not opened");
86 return ErrBadArg;
88 int fd =fdRedoLog;
89 if (hasParam) fd=fdStmtLog;
90 //The following structure needs strlen after stmt id for traversal in
91 //redolog file unlike msg queue structure where string is the last element
92 //and is not a continuous piece of memory.
93 int datalen = os::align(5 * sizeof(int) + len); // for len + txnId + msg type + stmtId + tableName + stmtstrlen + stmtstring
94 char *buf = (char*) malloc(datalen);
95 char *msg = buf;
96 //Note:: msg type is taken as -ve as we need to differentiate between
97 //statement id and logtype during recovery.
98 *(int*) msg = -1;
99 if (strlen(stmt) > 6 && ( strncasecmp(stmt,"CREATE", 6) == 0 ||
100 strncasecmp(stmt,"DROP", 4) == 0 ||
101 strncasecmp(stmt,"RENAME", 6) == 0 ||
102 strncasecmp(stmt,"ALTER", 5) == 0 ))
103 *(int*)msg = -4; //means prepare and execute the stmt
104 msg = msg+sizeof(int);
105 *(int *)msg = datalen;
106 msg = msg+sizeof(int);
107 *(int *)msg = txnId;
108 msg = msg+sizeof(int);
109 *(int *)msg = stmtId;
110 msg = msg+ sizeof(int);
111 *(int *)msg = os::align(len);
112 msg = msg+ sizeof(int);
113 msg[len-1] = '\0';
114 strcpy(msg, stmt);
115 int ret =0;
116 bool firstTime=true;
117 retry:
118 if (Conf::config.getDurableMode() != 1) {
119 ret = os::lockFile(fd);
120 if (-1 == ret) {
121 ::free(buf);
122 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
123 return ErrLockTimeOut;
126 ret = os::write(fd, buf, datalen);
127 if (Conf::config.getDurableMode() != 1) {
128 os::unlockFile(fd);
130 if (-1 == ret) {
131 DbRetVal rv = openRedoFile();
132 if (hasParam) fd=fdStmtLog; else fd=fdRedoLog;
133 if (OK == rv) {
134 logFine(Conf::logger, "Reopening redo log file");
135 if(firstTime) { firstTime = false; goto retry; }
137 printError(ErrOS, "Unable to write undo log");
138 ::free(buf);
139 return ErrOS;
141 ::free(buf);
142 return OK;
145 DbRetVal FileSend::commit(int len, void *data)
147 if (fdRedoLog < 0) {
148 printError(ErrBadArg, "Redo Log file not opened");
149 return ErrBadArg;
151 char *dat=(char*)data - sizeof(int);
152 *(int*)dat = -2; //type 2->commit
153 bool firstTime = true;
154 retry:
155 if (Conf::config.getDurableMode() != 1) {
156 int ret = os::lockFile(fdRedoLog);
157 if (-1 == ret) {
158 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
159 return ErrLockTimeOut;
162 int ret = os::write(fdRedoLog, dat, len+sizeof(int));
163 if (Conf::config.getDurableMode() != 1) {
164 os::unlockFile(fdRedoLog);
166 if (-1 == ret) {
167 DbRetVal rv = openRedoFile();
168 if (OK == rv) {
169 logFine(Conf::logger, "Reopening redo log file");
170 if(firstTime) { firstTime = false; goto retry; }
172 printError(ErrOS, "Unable to write undo log");
173 return ErrOS;
175 return OK;
177 DbRetVal FileSend::free(int txnId, int stmtId, bool hasParam)
179 if (fdRedoLog < 0) {
180 printError(ErrBadArg, "Redo Log file not opened");
181 return ErrBadArg;
183 if (fdStmtLog < 0) {
184 printError(ErrBadArg, "Redo Stmt Log file not opened");
185 return ErrBadArg;
187 int fd =fdRedoLog;
188 int buflen = 4 *sizeof(int);
189 char *msg = (char *) malloc(buflen);
190 char *ptr = msg;
191 *(int*)ptr = -3;
192 ptr += sizeof(int);
193 *(int *)ptr = 3 * sizeof(int); // for len + txnId + stmtId
194 ptr += sizeof(int);
195 *(int *)ptr = txnId;
196 ptr += sizeof(int);
197 *(int *)ptr = stmtId;
198 printDebug(DM_SqlLog, "stmtID sent = %d\n", *(int *)ptr);
199 bool firstTime = true;
200 retry:
201 if (Conf::config.getDurableMode() != 1) {
202 int ret = os::lockFile(fd);
203 if (-1 == ret) {
204 ::free(msg);
205 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
206 return ErrLockTimeOut;
209 int ret = os::write(fd, msg, buflen);
210 if (Conf::config.getDurableMode() != 1) {
211 os::unlockFile(fd);
213 if (-1 == ret) {
214 DbRetVal rv = openRedoFile();
215 if (hasParam) fd=fdStmtLog; else fd=fdRedoLog;
216 if (OK == rv) {
217 logFine(Conf::logger, "Reopening redo log file");
218 if(firstTime) { firstTime = false; goto retry; }
220 printError(ErrOS, "Unable to write undo log");
221 ::free(msg);
222 return ErrOS;
224 if (!hasParam) {
225 //For non parameterized stmts , no need to write in stmt log
226 ::free(msg);
227 return OK;
229 fd=fdStmtLog;
230 retry1:
231 if (Conf::config.getDurableMode() != 1) {
232 int ret = os::lockFile(fd);
233 if (-1 == ret) {
234 ::free(msg);
235 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
236 return ErrLockTimeOut;
240 ret = os::write(fd, msg, buflen);
241 if (Conf::config.getDurableMode() != 1) {
242 os::unlockFile(fd);
244 if (-1 == ret) {
245 DbRetVal rv = openRedoFile();
246 if (OK == rv) {
247 logFine(Conf::logger, "Reopening redo log file");
248 if(firstTime) { firstTime = false; goto retry1; }
250 printError(ErrOS, "Unable to write undo log");
251 ::free(msg);
252 return ErrOS;
254 ::free(msg);
255 return OK;
258 OfflineLog::OfflineLog()
260 fdOfflineLog = -1;
261 metadata = NULL;
262 createMetadataFile();
263 openOfflineLogFile();
266 DbRetVal OfflineLog::openOfflineLogFile()
268 char fileName[MAX_FILE_LEN];
269 int offlineLogFileSize = Conf::config.getOfflineLogFileSize();
270 fileSize = 0;
271 if (metadata == NULL) {
272 metadata = openMetadataFile();
273 if (metadata == NULL) {
274 printError(ErrOS, "Unable to open Metadata file");
275 return ErrOS;
278 char *ptr = (char *) metadata;
279 sprintf(fileName, "%s/offlineLogFile.%d",
280 Conf::config.getDbFile(), *(int *)ptr);
281 bool ret = false;
282 if ( ((ret = os::fileExists(fileName)) == true) &&
283 ((fileSize = os::getFileSize(fileName)) >= offlineLogFileSize) )
284 sprintf(fileName, "%s/offlineLogFile.%d",
285 Conf::config.getDbFile(), ++(*(int *)ptr));
286 else if (ret == true)
287 sprintf(fileName, "%s/offlineLogFile.%d", Conf::config.getDbFile(),
288 *(int *)ptr);
289 else {
290 sprintf(fileName, "%s/offlineLogFile.0", Conf::config.getDbFile());
291 *(int *) ptr = 0;
293 int durableMode = Conf::config.getDurableMode();
294 switch(durableMode) {
295 case 1:
296 case 2:
297 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT);
298 break;
299 case 3:
300 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT|O_SYNC);
301 break;
302 case 4:
303 #ifdef SOLARIS
304 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT|O_DSYNC);
305 #else
306 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT|O_DIRECT);
307 #endif
308 break;
309 default:
310 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT);
311 break;
313 if (-1 == fdOfflineLog) {
314 printError(ErrSysInternal, "Unable to open redo log file");
315 return ErrSysInternal;
317 ret = os::msync((char*)metadata, sizeof(int), MS_SYNC);
318 if (ret) {
319 printError(ErrOS, "Unable to sync file index to metadata file.");
320 return ErrOS;
322 return OK;
325 OfflineLog::~OfflineLog()
327 if (fdOfflineLog > 0) os::close(fdOfflineLog);
328 fdOfflineLog = -1;
331 DbRetVal OfflineLog::prepare(int txnId, int stId, int len, char *stmt,
332 char*tn, bool hasParam)
334 if (fdOfflineLog < 0) return ErrBadArg;
335 DbRetVal rv = OK;
336 if (fileSize > Conf::config.getOfflineLogFileSize())
338 rv = openOfflineLogFile();
339 if (rv != OK) return rv;
341 //The following structure needs strlen after stmt id for traversal in
342 //redolog file unlike msg queue structure where string is the last element
343 //and is not a continuous piece of memory.
344 int datalen = os::align(5 * sizeof(int) + len); // for len + txnId + msg type + stmtId + tableName + stmtstrlen + stmtstring
345 char *buf = (char*) malloc(datalen);
346 char *msg = buf;
347 //Note:: msg type is taken as -ve as we need to differentiate between
348 //statement id and logtype during recovery.
349 *(int*) msg = -1;
350 if (strlen(stmt) > 6 && ( strncasecmp(stmt,"CREATE", 6) == 0 || strncasecmp(stmt,"DROP", 4) == 0 ))
351 *(int*)msg = -4; //means prepare and execute the stmt
352 msg = msg+sizeof(int);
353 *(int *)msg = datalen;
354 msg = msg+sizeof(int);
355 *(int *)msg = txnId;
356 msg = msg+sizeof(int);
357 *(int *)msg = stId;
358 msg = msg+ sizeof(int);
359 *(int *)msg = os::align(len);
360 msg = msg+ sizeof(int);
361 msg[len-1] = '\0';
362 strcpy(msg, stmt);
363 int ret =0;
364 bool firstTime=true;
365 retry:
366 if (Conf::config.getDurableMode() != 1) {
367 ret = os::lockFile(fdOfflineLog);
368 if (-1 == ret) {
369 ::free(buf);
370 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
371 return ErrLockTimeOut;
374 ret = os::write(fdOfflineLog, buf, datalen);
375 if (Conf::config.getDurableMode() != 1) {
376 os::unlockFile(fdOfflineLog);
378 if (-1 == ret) {
379 DbRetVal rv = openOfflineLogFile();
380 if (OK == rv) {
381 logFine(Conf::logger, "Reopening redo log file");
382 if(firstTime) { firstTime = false; goto retry; }
384 printError(ErrOS, "Unable to write undo log");
385 ::free(buf);
386 return ErrOS;
388 ::free(buf);
389 fileSize += datalen;
390 return OK;
392 DbRetVal OfflineLog::commit(int len, void *data)
394 if (fdOfflineLog < 0) return ErrBadArg;
395 DbRetVal rv = OK;
396 if (fileSize > Conf::config.getOfflineLogFileSize())
398 rv = openOfflineLogFile();
399 if (rv != OK) return rv;
401 char *dat=(char*)data - sizeof(int);
402 *(int*)dat = -2; //type 2->commit
403 bool firstTime = true;
404 retry:
405 if (Conf::config.getDurableMode() != 1) {
406 int ret = os::lockFile(fdOfflineLog);
407 if (-1 == ret) {
408 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
409 return ErrLockTimeOut;
412 int ret = os::write(fdOfflineLog, dat, len+sizeof(int));
413 if (Conf::config.getDurableMode() != 1) {
414 os::unlockFile(fdOfflineLog);
416 if (-1 == ret) {
417 DbRetVal rv = openOfflineLogFile();
418 if (OK == rv) {
419 logFine(Conf::logger, "Reopening redo log file");
420 if(firstTime) { firstTime = false; goto retry; }
422 printError(ErrOS, "Unable to write undo log");
423 return ErrOS;
425 fileSize += len+sizeof(int);
426 return OK;
428 DbRetVal OfflineLog::free(int txnId, int stId, bool hasParam)
430 if (fdOfflineLog < 0) return ErrBadArg;
431 DbRetVal rv = OK;
432 if (fileSize > Conf::config.getOfflineLogFileSize())
434 rv = openOfflineLogFile();
435 if (rv != OK) return rv;
437 int buflen = 4 *sizeof(int);
438 char *msg = (char *) malloc(buflen);
439 char *ptr = msg;
440 *(int*)ptr = -3;
441 ptr += sizeof(int);
442 *(int *)ptr = 3 * sizeof(int); // for len + txnId + stmtId
443 ptr += sizeof(int);
444 *(int *)ptr = txnId;
445 ptr += sizeof(int);
446 *(int *)ptr = stId;
447 printDebug(DM_SqlLog, "stmtID sent = %d\n", *(int *)ptr);
448 bool firstTime = false;
449 retry:
450 if (Conf::config.getDurableMode() != 1) {
451 int ret = os::lockFile(fdOfflineLog);
452 if (-1 == ret) {
453 ::free(msg);
454 printError(ErrLockTimeOut,"Unable to get exclusive lock on redo log file");
455 return ErrLockTimeOut;
458 int ret = os::write(fdOfflineLog, msg, buflen);
459 if (Conf::config.getDurableMode() != 1) {
460 os::unlockFile(fdOfflineLog);
462 if (-1 == ret) {
463 DbRetVal rv = openOfflineLogFile();
464 if (OK == rv) {
465 logFine(Conf::logger, "Reopening redo log file");
466 if(firstTime) { firstTime = false; goto retry; }
468 printError(ErrOS, "Unable to write undo log");
469 ::free(msg);
470 return ErrOS;
472 ::free(msg);
473 fileSize += buflen;
474 return OK;
477 DbRetVal OfflineLog::createMetadataFile()
479 int fd = -1;
480 char mmapFile[128];
481 sprintf(mmapFile, "%s/offlineLogFile.dat", Conf::config.getDbFile());
482 int size = sizeof(int);
483 // int for offlineLogFile index + long for committed TxnID
484 char buffer[4];
485 if (os::fileExists(mmapFile)) return OK;
486 else {
487 fd = ::open(mmapFile, O_CREAT | O_RDWR, 0664);
488 if (fd == -1) {
489 printError(ErrOS, "Unable to create '%s'file to mmap", mmapFile);
490 return ErrOS;
492 memset(buffer, 0, size);
493 int sz = os::write(fd, buffer, size);
494 if (sz != size) {
495 printError(ErrOS, "Unable to initialize mmap file %s", mmapFile);
496 return ErrOS;
498 os::close(fd);
500 return OK;
503 void *OfflineLog::openMetadataFile()
505 char mmapFile[128];
506 int size = sizeof(int) + sizeof(long);
507 sprintf(mmapFile, "%s/offlineLogFile.dat", Conf::config.getDbFile());
508 file_desc fd = os::openFile(mmapFile, fileOpenWriteOnly, 0666);
509 if (fd == (file_desc)-1) {
510 printError(ErrOS, "Unable to open Mmap file %s", mmapFile);
511 return NULL;
513 metadata = os::mmap(NULL, size, mapProtRead | mapProtWrite, mapShared, fd, 0);
514 if (metadata == NULL) {
515 printError(ErrOS, "Unable to map the file %s to memory", mmapFile);
516 return NULL;
518 return metadata;