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>
28 DbRetVal
FileSend::openRedoFile()
30 char fileName
[MAX_FILE_LEN
];
31 sprintf(fileName
, "%s/csql.db.cur", Conf::config
.getDbFile());
32 int durableMode
= Conf::config
.getDurableMode();
36 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
);
39 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
|O_SYNC
);
43 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DSYNC
);
45 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DIRECT
);
49 fdRedoLog
= os::openFileForAppend(fileName
, O_CREAT
);
52 if (-1 == fdRedoLog
) {
53 printError(ErrSysInternal
, "Unable to open redo log file");
54 return ErrSysInternal
;
61 if (fdRedoLog
> 0) os::closeFile(fdRedoLog
);
65 DbRetVal
FileSend::prepare(int txnId
, int stmtId
, int len
, char *stmt
, char *tblName
)
67 if (fdRedoLog
< 0) return ErrBadArg
;
68 //The following structure needs strlen after stmt id for traversal in
69 //redolog file unlike msg queue structure where string is the last element
70 //and is not a continuous piece of memory.
71 int datalen
= os::align(5 * sizeof(int) + len
); // for len + txnId + msg type + stmtId + tableName + stmtstrlen + stmtstring
72 char *buf
= (char*) malloc(datalen
);
74 //Note:: msg type is taken as -ve as we need to differentiate between
75 //statement id and logtype during recovery.
77 if (strlen(stmt
) > 6 && ( strncasecmp(stmt
,"CREATE", 6) == 0 || strncasecmp(stmt
,"DROP", 4) == 0 ))
78 *(int*)msg
= -4; //means prepare and execute the stmt
79 msg
= msg
+sizeof(int);
80 *(int *)msg
= datalen
;
81 msg
= msg
+sizeof(int);
83 msg
= msg
+sizeof(int);
85 msg
= msg
+ sizeof(int);
86 *(int *)msg
= os::align(len
);
87 msg
= msg
+ sizeof(int);
93 if (Conf::config
.getDurableMode() != 1) {
94 ret
= os::lockFile(fdRedoLog
);
97 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
98 return ErrLockTimeOut
;
101 ret
= os::write(fdRedoLog
, buf
, datalen
);
102 if (Conf::config
.getDurableMode() != 1) {
103 os::unlockFile(fdRedoLog
);
106 DbRetVal rv
= openRedoFile();
108 logFine(Conf::logger
, "Reopening redo log file");
109 if(firstTime
) { firstTime
= false; goto retry
; }
111 printError(ErrOS
, "Unable to write undo log");
119 DbRetVal
FileSend::commit(int len
, void *data
)
121 if (fdRedoLog
< 0) return ErrBadArg
;
122 char *dat
=(char*)data
- sizeof(int);
123 *(int*)dat
= -2; //type 2->commit
124 bool firstTime
= true;
126 if (Conf::config
.getDurableMode() != 1) {
127 int ret
= os::lockFile(fdRedoLog
);
129 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
130 return ErrLockTimeOut
;
133 int ret
= os::write(fdRedoLog
, dat
, len
+sizeof(int));
134 if (Conf::config
.getDurableMode() != 1) {
135 os::unlockFile(fdRedoLog
);
138 DbRetVal rv
= openRedoFile();
140 logFine(Conf::logger
, "Reopening redo log file");
141 if(firstTime
) { firstTime
= false; goto retry
; }
143 printError(ErrOS
, "Unable to write undo log");
148 DbRetVal
FileSend::free(int txnId
, int stmtId
)
150 int buflen
= 4 *sizeof(int);
151 char *msg
= (char *) malloc(buflen
);
155 *(int *)ptr
= 3 * sizeof(int); // for len + txnId + stmtId
159 *(int *)ptr
= stmtId
;
160 printDebug(DM_SqlLog
, "stmtID sent = %d\n", *(int *)ptr
);
161 bool firstTime
= false;
163 if (Conf::config
.getDurableMode() != 1) {
164 int ret
= os::lockFile(fdRedoLog
);
167 printError(ErrLockTimeOut
,"Unable to get exclusive lock on redo log file");
168 return ErrLockTimeOut
;
171 int ret
= os::write(fdRedoLog
, msg
, buflen
);
172 if (Conf::config
.getDurableMode() != 1) {
173 os::unlockFile(fdRedoLog
);
176 DbRetVal rv
= openRedoFile();
178 logFine(Conf::logger
, "Reopening redo log file");
179 if(firstTime
) { firstTime
= false; goto retry
; }
181 printError(ErrOS
, "Unable to write undo log");
189 OfflineLog::OfflineLog()
193 createMetadataFile();
194 openOfflineLogFile();
197 DbRetVal
OfflineLog::openOfflineLogFile()
199 char fileName
[MAX_FILE_LEN
];
200 int offlineLogFileSize
= Conf::config
.getOfflineLogFileSize();
202 if (metadata
== NULL
) {
203 metadata
= openMetadataFile();
204 if (metadata
== NULL
) {
205 printError(ErrOS
, "Unable to open Metadata file");
209 char *ptr
= (char *) metadata
;
210 sprintf(fileName
, "%s/offlineLogFile.%d",
211 Conf::config
.getDbFile(), *(int *)ptr
);
213 if ( ((ret
= ::access(fileName
, F_OK
)) == 0) &&
214 ((fileSize
= os::getFileSize(fileName
)) >= offlineLogFileSize
) )
215 sprintf(fileName
, "%s/offlineLogFile.%d",
216 Conf::config
.getDbFile(), ++(*(int *)ptr
));
218 sprintf(fileName
, "%s/offlineLogFile.%d", Conf::config
.getDbFile(),
221 sprintf(fileName
, "%s/offlineLogFile.0", Conf::config
.getDbFile());
224 int durableMode
= Conf::config
.getDurableMode();
225 switch(durableMode
) {
228 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
);
231 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_SYNC
);
235 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DSYNC
);
237 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
|O_DIRECT
);
241 fdOfflineLog
= os::openFileForAppend(fileName
, O_CREAT
);
244 if (-1 == fdOfflineLog
) {
245 printError(ErrSysInternal
, "Unable to open redo log file");
246 return ErrSysInternal
;
248 ret
= msync(metadata
, sizeof(int), MS_SYNC
);
250 printError(ErrOS
, "Unable to sync file index to metadata file.");
256 OfflineLog::~OfflineLog()
258 if (fdOfflineLog
> 0) os::closeFile(fdOfflineLog
);
262 DbRetVal
OfflineLog::prepare(int txnId
, int stId
, int len
, char *stmt
, char*tn
)
264 if (fdOfflineLog
< 0) return ErrBadArg
;
266 if (fileSize
> Conf::config
.getOfflineLogFileSize())
268 rv
= openOfflineLogFile();
269 if (rv
!= OK
) return rv
;
271 //The following structure needs strlen after stmt id for traversal in
272 //redolog file unlike msg queue structure where string is the last element
273 //and is not a continuous piece of memory.
274 // for len + txnId + msg type + stmtId + tableName + stmtstrlen +
276 int datalen
= os::align(5 * sizeof(int) + len
);
277 char *buf
= (char*) malloc(datalen
);
279 //Note:: msg type is taken as -ve as we need to differentiate between
280 //statement id and logtype during recovery.
282 if (strlen(stmt
) > 6 && ( strncasecmp(stmt
,"CREATE", 6) == 0 ||
283 strncasecmp(stmt
,"DROP", 4) == 0 ))
284 *(int*)msg
= -4; //means prepare and execute the stmt
285 msg
= msg
+sizeof(int);
286 *(int *)msg
= datalen
;
287 msg
= msg
+sizeof(int);
289 msg
= msg
+sizeof(int);
291 msg
= msg
+ sizeof(int);
292 *(int *)msg
= os::align(len
);
293 msg
= msg
+ sizeof(int);
299 if (Conf::config
.getDurableMode() != 1) {
300 ret
= os::lockFile(fdOfflineLog
);
303 printError(ErrLockTimeOut
,
304 "Unable to get exclusive lock on redo log file");
305 return ErrLockTimeOut
;
308 ret
= os::write(fdOfflineLog
, buf
, datalen
);
309 if (Conf::config
.getDurableMode() != 1) {
310 os::unlockFile(fdOfflineLog
);
313 DbRetVal rv
= openOfflineLogFile();
315 logFine(Conf::logger
, "Reopening redo log file");
316 if(firstTime
) { firstTime
= false; goto retry
; }
318 printError(ErrOS
, "Unable to write undo log");
327 DbRetVal
OfflineLog::commit(int len
, void *data
)
329 if (fdOfflineLog
< 0) return ErrBadArg
;
331 if (fileSize
> Conf::config
.getOfflineLogFileSize())
333 rv
= openOfflineLogFile();
334 if (rv
!= OK
) return rv
;
336 char *dat
=(char*)data
- sizeof(int);
337 *(int*)dat
= -2; //type 2->commit
338 bool firstTime
= true;
340 if (Conf::config
.getDurableMode() != 1) {
341 int ret
= os::lockFile(fdOfflineLog
);
343 printError(ErrLockTimeOut
,
344 "Unable to get exclusive lock on redo log file");
345 return ErrLockTimeOut
;
348 int ret
= os::write(fdOfflineLog
, dat
, len
+sizeof(int));
349 if (Conf::config
.getDurableMode() != 1) {
350 os::unlockFile(fdOfflineLog
);
353 DbRetVal rv
= openOfflineLogFile();
355 logFine(Conf::logger
, "Reopening redo log file");
356 if(firstTime
) { firstTime
= false; goto retry
; }
358 printError(ErrOS
, "Unable to write undo log");
361 fileSize
+= len
+sizeof(int);
365 DbRetVal
OfflineLog::free(int txnId
, int stId
)
367 if (fdOfflineLog
< 0) return ErrBadArg
;
369 if (fileSize
> Conf::config
.getOfflineLogFileSize())
371 rv
= openOfflineLogFile();
372 if (rv
!= OK
) return rv
;
374 int buflen
= 4 *sizeof(int);
375 char *msg
= (char *) malloc(buflen
);
379 *(int *)ptr
= 3 * sizeof(int); // for len + txnId + stmtId
384 printDebug(DM_SqlLog
, "stmtID sent = %d\n", *(int *)ptr
);
385 bool firstTime
= false;
387 if (Conf::config
.getDurableMode() != 1) {
388 int ret
= os::lockFile(fdOfflineLog
);
391 printError(ErrLockTimeOut
,
392 "Unable to get exclusive lock on redo log file");
393 return ErrLockTimeOut
;
396 int ret
= os::write(fdOfflineLog
, msg
, buflen
);
397 if (Conf::config
.getDurableMode() != 1) {
398 os::unlockFile(fdOfflineLog
);
401 DbRetVal rv
= openOfflineLogFile();
403 logFine(Conf::logger
, "Reopening redo log file");
404 if(firstTime
) { firstTime
= false; goto retry
; }
406 printError(ErrOS
, "Unable to write undo log");
415 DbRetVal
OfflineLog::createMetadataFile()
419 sprintf(mmapFile
, "%s/offlineLogFile.dat", Conf::config
.getDbFile());
420 int size
= sizeof(int);
421 // int for offlineLogFile index + long for committed TxnID
423 if (::access(mmapFile
, F_OK
) == 0) return OK
;
425 fd
= ::open(mmapFile
, O_CREAT
| O_RDWR
, 0664);
427 printError(ErrOS
, "Unable to create '%s'file to mmap", mmapFile
);
430 memset(buffer
, 0, size
);
431 int sz
= ::write(fd
, buffer
, size
);
433 printError(ErrOS
, "Unable to initialize mmap file %s", mmapFile
);
441 void *OfflineLog::openMetadataFile()
444 int size
= sizeof(int) + sizeof(long);
445 sprintf(mmapFile
, "%s/offlineLogFile.dat", Conf::config
.getDbFile());
446 int fd
= ::open(mmapFile
, O_RDWR
, 0666);
448 printError(ErrOS
, "Unable to open Mmap file %s", mmapFile
);
451 metadata
= os::mmap(NULL
, size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fd
, 0);
452 if (metadata
== NULL
) {
453 printError(ErrOS
, "Unable to map the file %s to memory", mmapFile
);