fix for more than 3 table join wrong result
[csql.git] / src / sqllog / FileSend.cxx
blob5a37a78316325807cf126288ddc4b0d840b1866a
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 openRedoFile();
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();
33 switch(durableMode) {
34 case 1:
35 case 2:
36 fdRedoLog = os::openFileForAppend(fileName, O_CREAT);
37 break;
38 case 3:
39 fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_SYNC);
40 break;
41 case 4:
42 #ifdef SOLARIS
43 fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_DSYNC);
44 #else
45 fdRedoLog = os::openFileForAppend(fileName, O_CREAT|O_DIRECT);
46 #endif
47 break;
48 default:
49 fdRedoLog = os::openFileForAppend(fileName, O_CREAT);
50 break;
52 if (-1 == fdRedoLog) {
53 printError(ErrSysInternal, "Unable to open redo log file");
54 return ErrSysInternal;
56 return OK;
59 FileSend::~FileSend()
61 if (fdRedoLog > 0) os::closeFile(fdRedoLog);
62 fdRedoLog = -1;
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);
73 char *msg = buf;
74 //Note:: msg type is taken as -ve as we need to differentiate between
75 //statement id and logtype during recovery.
76 *(int*) msg = -1;
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);
82 *(int *)msg = txnId;
83 msg = msg+sizeof(int);
84 *(int *)msg = stmtId;
85 msg = msg+ sizeof(int);
86 *(int *)msg = os::align(len);
87 msg = msg+ sizeof(int);
88 msg[len-1] = '\0';
89 strcpy(msg, stmt);
90 int ret =0;
91 bool firstTime=true;
92 retry:
93 if (Conf::config.getDurableMode() != 1) {
94 ret = os::lockFile(fdRedoLog);
95 if (-1 == ret) {
96 ::free(buf);
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);
105 if (-1 == ret) {
106 DbRetVal rv = openRedoFile();
107 if (OK == rv) {
108 logFine(Conf::logger, "Reopening redo log file");
109 if(firstTime) { firstTime = false; goto retry; }
111 printError(ErrOS, "Unable to write undo log");
112 ::free(buf);
113 return ErrOS;
115 ::free(buf);
116 return OK;
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;
125 retry:
126 if (Conf::config.getDurableMode() != 1) {
127 int ret = os::lockFile(fdRedoLog);
128 if (-1 == ret) {
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);
137 if (-1 == ret) {
138 DbRetVal rv = openRedoFile();
139 if (OK == rv) {
140 logFine(Conf::logger, "Reopening redo log file");
141 if(firstTime) { firstTime = false; goto retry; }
143 printError(ErrOS, "Unable to write undo log");
144 return ErrOS;
146 return OK;
148 DbRetVal FileSend::free(int txnId, int stmtId)
150 int buflen = 4 *sizeof(int);
151 char *msg = (char *) malloc(buflen);
152 char *ptr = msg;
153 *(int*)ptr = -3;
154 ptr += sizeof(int);
155 *(int *)ptr = 3 * sizeof(int); // for len + txnId + stmtId
156 ptr += sizeof(int);
157 *(int *)ptr = txnId;
158 ptr += sizeof(int);
159 *(int *)ptr = stmtId;
160 printDebug(DM_SqlLog, "stmtID sent = %d\n", *(int *)ptr);
161 bool firstTime = false;
162 retry:
163 if (Conf::config.getDurableMode() != 1) {
164 int ret = os::lockFile(fdRedoLog);
165 if (-1 == ret) {
166 ::free(msg);
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);
175 if (-1 == ret) {
176 DbRetVal rv = openRedoFile();
177 if (OK == rv) {
178 logFine(Conf::logger, "Reopening redo log file");
179 if(firstTime) { firstTime = false; goto retry; }
181 printError(ErrOS, "Unable to write undo log");
182 ::free(msg);
183 return ErrOS;
185 ::free(msg);
186 return OK;
189 OfflineLog::OfflineLog()
191 fdOfflineLog = -1;
192 metadata = NULL;
193 createMetadataFile();
194 openOfflineLogFile();
197 DbRetVal OfflineLog::openOfflineLogFile()
199 char fileName[MAX_FILE_LEN];
200 int offlineLogFileSize = Conf::config.getOfflineLogFileSize();
201 fileSize = 0;
202 if (metadata == NULL) {
203 metadata = openMetadataFile();
204 if (metadata == NULL) {
205 printError(ErrOS, "Unable to open Metadata file");
206 return ErrOS;
209 char *ptr = (char *) metadata;
210 sprintf(fileName, "%s/offlineLogFile.%d",
211 Conf::config.getDbFile(), *(int *)ptr);
212 int ret = 0;
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));
217 else if (ret == 0)
218 sprintf(fileName, "%s/offlineLogFile.%d", Conf::config.getDbFile(),
219 *(int *)ptr);
220 else {
221 sprintf(fileName, "%s/offlineLogFile.0", Conf::config.getDbFile());
222 *(int *) ptr = 0;
224 int durableMode = Conf::config.getDurableMode();
225 switch(durableMode) {
226 case 1:
227 case 2:
228 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT);
229 break;
230 case 3:
231 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT|O_SYNC);
232 break;
233 case 4:
234 #ifdef SOLARIS
235 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT|O_DSYNC);
236 #else
237 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT|O_DIRECT);
238 #endif
239 break;
240 default:
241 fdOfflineLog = os::openFileForAppend(fileName, O_CREAT);
242 break;
244 if (-1 == fdOfflineLog) {
245 printError(ErrSysInternal, "Unable to open redo log file");
246 return ErrSysInternal;
248 ret = msync(metadata, sizeof(int), MS_SYNC);
249 if (ret) {
250 printError(ErrOS, "Unable to sync file index to metadata file.");
251 return ErrOS;
253 return OK;
256 OfflineLog::~OfflineLog()
258 if (fdOfflineLog > 0) os::closeFile(fdOfflineLog);
259 fdOfflineLog = -1;
262 DbRetVal OfflineLog::prepare(int txnId, int stId, int len, char *stmt, char*tn)
264 if (fdOfflineLog < 0) return ErrBadArg;
265 DbRetVal rv = OK;
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 +
275 // stmtstring
276 int datalen = os::align(5 * sizeof(int) + len);
277 char *buf = (char*) malloc(datalen);
278 char *msg = buf;
279 //Note:: msg type is taken as -ve as we need to differentiate between
280 //statement id and logtype during recovery.
281 *(int*) msg = -1;
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);
288 *(int *)msg = txnId;
289 msg = msg+sizeof(int);
290 *(int *)msg = stId;
291 msg = msg+ sizeof(int);
292 *(int *)msg = os::align(len);
293 msg = msg+ sizeof(int);
294 msg[len-1] = '\0';
295 strcpy(msg, stmt);
296 int ret =0;
297 bool firstTime=true;
298 retry:
299 if (Conf::config.getDurableMode() != 1) {
300 ret = os::lockFile(fdOfflineLog);
301 if (-1 == ret) {
302 ::free(buf);
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);
312 if (-1 == ret) {
313 DbRetVal rv = openOfflineLogFile();
314 if (OK == rv) {
315 logFine(Conf::logger, "Reopening redo log file");
316 if(firstTime) { firstTime = false; goto retry; }
318 printError(ErrOS, "Unable to write undo log");
319 ::free(buf);
320 return ErrOS;
322 ::free(buf);
323 fileSize += datalen;
324 return OK;
327 DbRetVal OfflineLog::commit(int len, void *data)
329 if (fdOfflineLog < 0) return ErrBadArg;
330 DbRetVal rv = OK;
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;
339 retry:
340 if (Conf::config.getDurableMode() != 1) {
341 int ret = os::lockFile(fdOfflineLog);
342 if (-1 == ret) {
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);
352 if (-1 == ret) {
353 DbRetVal rv = openOfflineLogFile();
354 if (OK == rv) {
355 logFine(Conf::logger, "Reopening redo log file");
356 if(firstTime) { firstTime = false; goto retry; }
358 printError(ErrOS, "Unable to write undo log");
359 return ErrOS;
361 fileSize += len+sizeof(int);
362 return OK;
365 DbRetVal OfflineLog::free(int txnId, int stId)
367 if (fdOfflineLog < 0) return ErrBadArg;
368 DbRetVal rv = OK;
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);
376 char *ptr = msg;
377 *(int*)ptr = -3;
378 ptr += sizeof(int);
379 *(int *)ptr = 3 * sizeof(int); // for len + txnId + stmtId
380 ptr += sizeof(int);
381 *(int *)ptr = txnId;
382 ptr += sizeof(int);
383 *(int *)ptr = stId;
384 printDebug(DM_SqlLog, "stmtID sent = %d\n", *(int *)ptr);
385 bool firstTime = false;
386 retry:
387 if (Conf::config.getDurableMode() != 1) {
388 int ret = os::lockFile(fdOfflineLog);
389 if (-1 == ret) {
390 ::free(msg);
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);
400 if (-1 == ret) {
401 DbRetVal rv = openOfflineLogFile();
402 if (OK == rv) {
403 logFine(Conf::logger, "Reopening redo log file");
404 if(firstTime) { firstTime = false; goto retry; }
406 printError(ErrOS, "Unable to write undo log");
407 ::free(msg);
408 return ErrOS;
410 ::free(msg);
411 fileSize += buflen;
412 return OK;
415 DbRetVal OfflineLog::createMetadataFile()
417 int fd = -1;
418 char mmapFile[128];
419 sprintf(mmapFile, "%s/offlineLogFile.dat", Conf::config.getDbFile());
420 int size = sizeof(int);
421 // int for offlineLogFile index + long for committed TxnID
422 char buffer[size];
423 if (::access(mmapFile, F_OK) == 0) return OK;
424 else {
425 fd = ::open(mmapFile, O_CREAT | O_RDWR, 0664);
426 if (fd == -1) {
427 printError(ErrOS, "Unable to create '%s'file to mmap", mmapFile);
428 return ErrOS;
430 memset(buffer, 0, size);
431 int sz = ::write(fd, buffer, size);
432 if (sz != size) {
433 printError(ErrOS, "Unable to initialize mmap file %s", mmapFile);
434 return ErrOS;
436 ::close(fd);
438 return OK;
441 void *OfflineLog::openMetadataFile()
443 char mmapFile[128];
444 int size = sizeof(int) + sizeof(long);
445 sprintf(mmapFile, "%s/offlineLogFile.dat", Conf::config.getDbFile());
446 int fd = ::open(mmapFile, O_RDWR, 0666);
447 if (fd == -1) {
448 printError(ErrOS, "Unable to open Mmap file %s", mmapFile);
449 return NULL;
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);
454 return NULL;
456 return metadata;