1 /***************************************************************************
2 * Copyright (C) 2007 by Prabakaran Thirumalai *
3 * praba_tuty@yahoo.com *
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. *
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. *
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 ***************************************************************************/
21 #include <SqlLogConnection.h>
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();
42 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
);
43 fdStmtLog
= os::openFileForAppend(stmtFileName
, O_CREAT
);
46 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
|O_SYNC
);
47 fdStmtLog
= os::openFileForAppend(stmtFileName
, O_CREAT
|O_SYNC
);
51 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DSYNC
);
52 fdStmtLog
= os::openFileForAppend(stmtFileName
, O_CREAT
|O_DSYNC
);
54 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DIRECT
);
55 fdStmtLog
= os::openFileForAppend(stmtFileName
, O_CREAT
|O_DIRECT
);
59 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
);
60 fdStmtLog
= os::openFileForAppend(stmtFileName
, O_CREAT
);
63 if (-1 == fdRedoLog
|| -1 == fdStmtLog
) {
64 printError(ErrSysInternal
, "Unable to open redo log file");
65 return ErrSysInternal
;
70 FileSend::~FileSend() {
71 if (fdRedoLog
> 0) os::close(fdRedoLog
);
72 if (fdStmtLog
> 0) os::close(fdStmtLog
);
77 DbRetVal
FileSend::prepare(int txnId
, int stmtId
, int len
, char *stmt
,
78 char *tblName
, bool hasParam
)
81 printError(ErrBadArg
, "Redo Log file not opened");
85 printError(ErrBadArg
, "Redo Stmt Log file not opened");
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
);
96 //Note:: msg type is taken as -ve as we need to differentiate between
97 //statement id and logtype during recovery.
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);
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);
118 if (Conf::config
.getDurableMode() != 1) {
119 ret
= os::lockFile(fd
);
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) {
131 DbRetVal rv
= openRedoFile();
132 if (hasParam
) fd
=fdStmtLog
; else fd
=fdRedoLog
;
134 logFine(Conf::logger
, "Reopening redo log file");
135 if(firstTime
) { firstTime
= false; goto retry
; }
137 printError(ErrOS
, "Unable to write undo log");
145 DbRetVal
FileSend::commit(int len
, void *data
)
148 printError(ErrBadArg
, "Redo Log file not opened");
151 char *dat
=(char*)data
- sizeof(int);
152 *(int*)dat
= -2; //type 2->commit
153 bool firstTime
= true;
155 if (Conf::config
.getDurableMode() != 1) {
156 int ret
= os::lockFile(fdRedoLog
);
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
);
167 DbRetVal rv
= openRedoFile();
169 logFine(Conf::logger
, "Reopening redo log file");
170 if(firstTime
) { firstTime
= false; goto retry
; }
172 printError(ErrOS
, "Unable to write undo log");
177 DbRetVal
FileSend::free(int txnId
, int stmtId
, bool hasParam
)
180 printError(ErrBadArg
, "Redo Log file not opened");
184 printError(ErrBadArg
, "Redo Stmt Log file not opened");
188 int buflen
= 4 *sizeof(int);
189 char *msg
= (char *) malloc(buflen
);
193 *(int *)ptr
= 3 * sizeof(int); // for len + txnId + stmtId
197 *(int *)ptr
= stmtId
;
198 printDebug(DM_SqlLog
, "stmtID sent = %d\n", *(int *)ptr
);
199 bool firstTime
= true;
201 if (Conf::config
.getDurableMode() != 1) {
202 int ret
= os::lockFile(fd
);
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) {
214 DbRetVal rv
= openRedoFile();
215 if (hasParam
) fd
=fdStmtLog
; else fd
=fdRedoLog
;
217 logFine(Conf::logger
, "Reopening redo log file");
218 if(firstTime
) { firstTime
= false; goto retry
; }
220 printError(ErrOS
, "Unable to write undo log");
225 //For non parameterized stmts , no need to write in stmt log
231 if (Conf::config
.getDurableMode() != 1) {
232 int ret
= os::lockFile(fd
);
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) {
245 DbRetVal rv
= openRedoFile();
247 logFine(Conf::logger
, "Reopening redo log file");
248 if(firstTime
) { firstTime
= false; goto retry1
; }
250 printError(ErrOS
, "Unable to write undo log");
258 OfflineLog::OfflineLog()
262 createMetadataFile();
263 openOfflineLogFile();
266 DbRetVal
OfflineLog::openOfflineLogFile()
268 char fileName
[MAX_FILE_LEN
];
269 int offlineLogFileSize
= Conf::config
.getOfflineLogFileSize();
271 if (metadata
== NULL
) {
272 metadata
= openMetadataFile();
273 if (metadata
== NULL
) {
274 printError(ErrOS
, "Unable to open Metadata file");
278 char *ptr
= (char *) metadata
;
279 sprintf(fileName
, "%s/offlineLogFile.%d",
280 Conf::config
.getDbFile(), *(int *)ptr
);
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(),
290 sprintf(fileName
, "%s/offlineLogFile.0", Conf::config
.getDbFile());
293 int durableMode
= Conf::config
.getDurableMode();
294 switch(durableMode
) {
297 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
);
300 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_SYNC
);
304 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DSYNC
);
306 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DIRECT
);
310 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
);
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
);
319 printError(ErrOS
, "Unable to sync file index to metadata file.");
325 OfflineLog::~OfflineLog()
327 if (fdOfflineLog
> 0) os::close(fdOfflineLog
);
331 DbRetVal
OfflineLog::prepare(int txnId
, int stId
, int len
, char *stmt
,
332 char*tn
, bool hasParam
)
334 if (fdOfflineLog
< 0) return ErrBadArg
;
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
);
347 //Note:: msg type is taken as -ve as we need to differentiate between
348 //statement id and logtype during recovery.
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);
356 msg
= msg
+sizeof(int);
358 msg
= msg
+ sizeof(int);
359 *(int *)msg
= os::align(len
);
360 msg
= msg
+ sizeof(int);
366 if (Conf::config
.getDurableMode() != 1) {
367 ret
= os::lockFile(fdOfflineLog
);
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
);
379 DbRetVal rv
= openOfflineLogFile();
381 logFine(Conf::logger
, "Reopening redo log file");
382 if(firstTime
) { firstTime
= false; goto retry
; }
384 printError(ErrOS
, "Unable to write undo log");
392 DbRetVal
OfflineLog::commit(int len
, void *data
)
394 if (fdOfflineLog
< 0) return ErrBadArg
;
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;
405 if (Conf::config
.getDurableMode() != 1) {
406 int ret
= os::lockFile(fdOfflineLog
);
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
);
417 DbRetVal rv
= openOfflineLogFile();
419 logFine(Conf::logger
, "Reopening redo log file");
420 if(firstTime
) { firstTime
= false; goto retry
; }
422 printError(ErrOS
, "Unable to write undo log");
425 fileSize
+= len
+sizeof(int);
428 DbRetVal
OfflineLog::free(int txnId
, int stId
, bool hasParam
)
430 if (fdOfflineLog
< 0) return ErrBadArg
;
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
);
442 *(int *)ptr
= 3 * sizeof(int); // for len + txnId + stmtId
447 printDebug(DM_SqlLog
, "stmtID sent = %d\n", *(int *)ptr
);
448 bool firstTime
= false;
450 if (Conf::config
.getDurableMode() != 1) {
451 int ret
= os::lockFile(fdOfflineLog
);
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
);
463 DbRetVal rv
= openOfflineLogFile();
465 logFine(Conf::logger
, "Reopening redo log file");
466 if(firstTime
) { firstTime
= false; goto retry
; }
468 printError(ErrOS
, "Unable to write undo log");
477 DbRetVal
OfflineLog::createMetadataFile()
481 sprintf(mmapFile
, "%s/offlineLogFile.dat", Conf::config
.getDbFile());
482 int size
= sizeof(int);
483 // int for offlineLogFile index + long for committed TxnID
485 if (os::fileExists(mmapFile
)) return OK
;
487 fd
= ::open(mmapFile
, O_CREAT
| O_RDWR
, 0664);
489 printError(ErrOS
, "Unable to create '%s'file to mmap", mmapFile
);
492 memset(buffer
, 0, size
);
493 int sz
= os::write(fd
, buffer
, size
);
495 printError(ErrOS
, "Unable to initialize mmap file %s", mmapFile
);
503 void *OfflineLog::openMetadataFile()
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
);
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
);