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::closeFile(fdRedoLog
);
33 if (fdStmtLog
> 0) os::closeFile(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::closeFile(fdRedoLog
);
72 if (fdStmtLog
> 0) os::closeFile(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 || strncasecmp(stmt
,"DROP", 4) == 0 ))
100 *(int*)msg
= -4; //means prepare and execute the stmt
101 msg
= msg
+sizeof(int);
102 *(int *)msg
= datalen
;
103 msg
= msg
+sizeof(int);
105 msg
= msg
+sizeof(int);
106 *(int *)msg
= stmtId
;
107 msg
= msg
+ sizeof(int);
108 *(int *)msg
= os::align(len
);
109 msg
= msg
+ sizeof(int);
115 if (Conf::config
.getDurableMode() != 1) {
116 ret
= os::lockFile(fd
);
119 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
120 return ErrLockTimeOut
;
123 ret
= os::write(fd
, buf
, datalen
);
124 if (Conf::config
.getDurableMode() != 1) {
128 DbRetVal rv
= openRedoFile();
129 if (hasParam
) fd
=fdStmtLog
; else fd
=fdRedoLog
;
131 logFine(Conf::logger
, "Reopening redo log file");
132 if(firstTime
) { firstTime
= false; goto retry
; }
134 printError(ErrOS
, "Unable to write undo log");
142 DbRetVal
FileSend::commit(int len
, void *data
)
145 printError(ErrBadArg
, "Redo Log file not opened");
148 char *dat
=(char*)data
- sizeof(int);
149 *(int*)dat
= -2; //type 2->commit
150 bool firstTime
= true;
152 if (Conf::config
.getDurableMode() != 1) {
153 int ret
= os::lockFile(fdRedoLog
);
155 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
156 return ErrLockTimeOut
;
159 int ret
= os::write(fdRedoLog
, dat
, len
+sizeof(int));
160 if (Conf::config
.getDurableMode() != 1) {
161 os::unlockFile(fdRedoLog
);
164 DbRetVal rv
= openRedoFile();
166 logFine(Conf::logger
, "Reopening redo log file");
167 if(firstTime
) { firstTime
= false; goto retry
; }
169 printError(ErrOS
, "Unable to write undo log");
174 DbRetVal
FileSend::free(int txnId
, int stmtId
, bool hasParam
)
177 printError(ErrBadArg
, "Redo Log file not opened");
181 printError(ErrBadArg
, "Redo Stmt Log file not opened");
185 int buflen
= 4 *sizeof(int);
186 char *msg
= (char *) malloc(buflen
);
190 *(int *)ptr
= 3 * sizeof(int); // for len + txnId + stmtId
194 *(int *)ptr
= stmtId
;
195 printDebug(DM_SqlLog
, "stmtID sent = %d\n", *(int *)ptr
);
196 bool firstTime
= true;
198 if (Conf::config
.getDurableMode() != 1) {
199 int ret
= os::lockFile(fd
);
202 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
203 return ErrLockTimeOut
;
206 int ret
= os::write(fd
, msg
, buflen
);
207 if (Conf::config
.getDurableMode() != 1) {
211 DbRetVal rv
= openRedoFile();
212 if (hasParam
) fd
=fdStmtLog
; else fd
=fdRedoLog
;
214 logFine(Conf::logger
, "Reopening redo log file");
215 if(firstTime
) { firstTime
= false; goto retry
; }
217 printError(ErrOS
, "Unable to write undo log");
222 //For non parameterized stmts , no need to write in stmt log
228 if (Conf::config
.getDurableMode() != 1) {
229 int ret
= os::lockFile(fd
);
232 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
233 return ErrLockTimeOut
;
237 ret
= os::write(fd
, msg
, buflen
);
238 if (Conf::config
.getDurableMode() != 1) {
242 DbRetVal rv
= openRedoFile();
244 logFine(Conf::logger
, "Reopening redo log file");
245 if(firstTime
) { firstTime
= false; goto retry1
; }
247 printError(ErrOS
, "Unable to write undo log");
255 OfflineLog::OfflineLog()
259 createMetadataFile();
260 openOfflineLogFile();
263 DbRetVal
OfflineLog::openOfflineLogFile()
265 char fileName
[MAX_FILE_LEN
];
266 int offlineLogFileSize
= Conf::config
.getOfflineLogFileSize();
268 if (metadata
== NULL
) {
269 metadata
= openMetadataFile();
270 if (metadata
== NULL
) {
271 printError(ErrOS
, "Unable to open Metadata file");
275 char *ptr
= (char *) metadata
;
276 sprintf(fileName
, "%s/offlineLogFile.%d",
277 Conf::config
.getDbFile(), *(int *)ptr
);
279 if ( ((ret
= ::access(fileName
, F_OK
)) == 0) &&
280 ((fileSize
= os::getFileSize(fileName
)) >= offlineLogFileSize
) )
281 sprintf(fileName
, "%s/offlineLogFile.%d",
282 Conf::config
.getDbFile(), ++(*(int *)ptr
));
284 sprintf(fileName
, "%s/offlineLogFile.%d", Conf::config
.getDbFile(),
287 sprintf(fileName
, "%s/offlineLogFile.0", Conf::config
.getDbFile());
290 int durableMode
= Conf::config
.getDurableMode();
291 switch(durableMode
) {
294 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
);
297 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_SYNC
);
301 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DSYNC
);
303 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DIRECT
);
307 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
);
310 if (-1 == fdOfflineLog
) {
311 printError(ErrSysInternal
, "Unable to open redo log file");
312 return ErrSysInternal
;
314 ret
= msync(metadata
, sizeof(int), MS_SYNC
);
316 printError(ErrOS
, "Unable to sync file index to metadata file.");
322 OfflineLog::~OfflineLog()
324 if (fdOfflineLog
> 0) os::closeFile(fdOfflineLog
);
328 DbRetVal
OfflineLog::prepare(int txnId
, int stId
, int len
, char *stmt
,
329 char*tn
, bool hasParam
)
331 if (fdOfflineLog
< 0) return ErrBadArg
;
333 if (fileSize
> Conf::config
.getOfflineLogFileSize())
335 rv
= openOfflineLogFile();
336 if (rv
!= OK
) return rv
;
338 //The following structure needs strlen after stmt id for traversal in
339 //redolog file unlike msg queue structure where string is the last element
340 //and is not a continuous piece of memory.
341 int datalen
= os::align(5 * sizeof(int) + len
); // for len + txnId + msg type + stmtId + tableName + stmtstrlen + stmtstring
342 char *buf
= (char*) malloc(datalen
);
344 //Note:: msg type is taken as -ve as we need to differentiate between
345 //statement id and logtype during recovery.
347 if (strlen(stmt
) > 6 && ( strncasecmp(stmt
,"CREATE", 6) == 0 || strncasecmp(stmt
,"DROP", 4) == 0 ))
348 *(int*)msg
= -4; //means prepare and execute the stmt
349 msg
= msg
+sizeof(int);
350 *(int *)msg
= datalen
;
351 msg
= msg
+sizeof(int);
353 msg
= msg
+sizeof(int);
355 msg
= msg
+ sizeof(int);
356 *(int *)msg
= os::align(len
);
357 msg
= msg
+ sizeof(int);
363 if (Conf::config
.getDurableMode() != 1) {
364 ret
= os::lockFile(fdOfflineLog
);
367 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
368 return ErrLockTimeOut
;
371 ret
= os::write(fdOfflineLog
, buf
, datalen
);
372 if (Conf::config
.getDurableMode() != 1) {
373 os::unlockFile(fdOfflineLog
);
376 DbRetVal rv
= openOfflineLogFile();
378 logFine(Conf::logger
, "Reopening redo log file");
379 if(firstTime
) { firstTime
= false; goto retry
; }
381 printError(ErrOS
, "Unable to write undo log");
389 DbRetVal
OfflineLog::commit(int len
, void *data
)
391 if (fdOfflineLog
< 0) return ErrBadArg
;
393 if (fileSize
> Conf::config
.getOfflineLogFileSize())
395 rv
= openOfflineLogFile();
396 if (rv
!= OK
) return rv
;
398 char *dat
=(char*)data
- sizeof(int);
399 *(int*)dat
= -2; //type 2->commit
400 bool firstTime
= true;
402 if (Conf::config
.getDurableMode() != 1) {
403 int ret
= os::lockFile(fdOfflineLog
);
405 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
406 return ErrLockTimeOut
;
409 int ret
= os::write(fdOfflineLog
, dat
, len
+sizeof(int));
410 if (Conf::config
.getDurableMode() != 1) {
411 os::unlockFile(fdOfflineLog
);
414 DbRetVal rv
= openOfflineLogFile();
416 logFine(Conf::logger
, "Reopening redo log file");
417 if(firstTime
) { firstTime
= false; goto retry
; }
419 printError(ErrOS
, "Unable to write undo log");
422 fileSize
+= len
+sizeof(int);
425 DbRetVal
OfflineLog::free(int txnId
, int stId
, bool hasParam
)
427 if (fdOfflineLog
< 0) return ErrBadArg
;
429 if (fileSize
> Conf::config
.getOfflineLogFileSize())
431 rv
= openOfflineLogFile();
432 if (rv
!= OK
) return rv
;
434 int buflen
= 4 *sizeof(int);
435 char *msg
= (char *) malloc(buflen
);
439 *(int *)ptr
= 3 * sizeof(int); // for len + txnId + stmtId
444 printDebug(DM_SqlLog
, "stmtID sent = %d\n", *(int *)ptr
);
445 bool firstTime
= false;
447 if (Conf::config
.getDurableMode() != 1) {
448 int ret
= os::lockFile(fdOfflineLog
);
451 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
452 return ErrLockTimeOut
;
455 int ret
= os::write(fdOfflineLog
, msg
, buflen
);
456 if (Conf::config
.getDurableMode() != 1) {
457 os::unlockFile(fdOfflineLog
);
460 DbRetVal rv
= openOfflineLogFile();
462 logFine(Conf::logger
, "Reopening redo log file");
463 if(firstTime
) { firstTime
= false; goto retry
; }
465 printError(ErrOS
, "Unable to write undo log");
474 DbRetVal
OfflineLog::createMetadataFile()
478 sprintf(mmapFile
, "%s/offlineLogFile.dat", Conf::config
.getDbFile());
479 int size
= sizeof(int);
480 // int for offlineLogFile index + long for committed TxnID
482 if (::access(mmapFile
, F_OK
) == 0) return OK
;
484 fd
= ::open(mmapFile
, O_CREAT
| O_RDWR
, 0664);
486 printError(ErrOS
, "Unable to create '%s'file to mmap", mmapFile
);
489 memset(buffer
, 0, size
);
490 int sz
= ::write(fd
, buffer
, size
);
492 printError(ErrOS
, "Unable to initialize mmap file %s", mmapFile
);
500 void *OfflineLog::openMetadataFile()
503 int size
= sizeof(int) + sizeof(long);
504 sprintf(mmapFile
, "%s/offlineLogFile.dat", Conf::config
.getDbFile());
505 int fd
= ::open(mmapFile
, O_RDWR
, 0666);
507 printError(ErrOS
, "Unable to open Mmap file %s", mmapFile
);
510 metadata
= os::mmap(NULL
, size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
511 if (metadata
== NULL
) {
512 printError(ErrOS
, "Unable to map the file %s to memory", mmapFile
);