1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.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 ***************************************************************************/
18 #include<SessionImpl.h>
22 #include<Transaction.h>
24 #include<CacheTableLoader.h>
25 #include<sys/wait.h> //TODO::move this to os.h
26 char* version
= "csql-linux-i686-3.0GA";
31 bool recoverFlag
=false;
33 SessionImpl
*session
= NULL
;
34 static void sigTermHandler(int sig
)
36 printf("Received signal %d\nStopping the server\n", sig
);
39 static void sigChildHandler(int sig
)
41 os::signal(SIGCHLD
, sigChildHandler
);
43 waitpid(-1, &stat
, WNOHANG
);
44 //TODO::move waitpid to os wrapper
47 bool checkDead(pid_t pid
)
49 int ret
= os::kill(pid
, 0);
52 printError(ErrWarning
, "No permission to check process %d is alive.");
59 DbRetVal
releaseAllResources(Database
*sysdb
, ThreadInfo
*info
)
61 printf("Releasing all the resources for process %d %lu\n", info
->pid_
, info
->thrid_
);
62 //recover for all the mutexes in has_
63 for (int i
=0; i
< MAX_MUTEX_PER_THREAD
; i
++)
65 if (info
->has_
[i
] != NULL
)
67 printf("Dead Procs: %d %lu holding mutex %x %s \n", info
->pid_
, info
->thrid_
, info
->has_
[i
], info
->has_
[i
]->name
);
68 logFine(Conf::logger
, "Dead Procs: %d %lu holding mutex %x %s \n", info
->pid_
, info
->thrid_
, info
->has_
[i
], info
->has_
[i
]->name
);
69 //TODO::recovery of mutexes
70 sysdb
->recoverMutex(info
->has_
[i
]);
75 TransactionManager
*tm
= new TransactionManager();
76 LockManager
*lm
= new LockManager(sysdb
);
77 for (int i
= 0 ;i
< MAX_THREADS_PER_PROCESS
; i
++)
79 if (info
->thrTrans_
[i
].trans_
!= NULL
&& info
->thrTrans_
[i
].trans_
->status_
== TransRunning
)
81 printf("Rollback Transaction %x\n", info
->thrTrans_
[i
].trans_
);
82 tm
->rollback(lm
, info
->thrTrans_
[i
].trans_
);
83 info
->thrTrans_
[i
].trans_
->status_
= TransNotUsed
;
92 DbRetVal
cleanupDeadProcs(Database
*sysdb
)
94 DbRetVal rv
= sysdb
->getProcessTableMutex(false);
97 printError(rv
,"Unable to get process table mutex");
102 pthread_t thrid
= os::getthrid();
105 ThreadInfo
* pInfo
= sysdb
->getThreadInfo(0);
107 ThreadInfo
* freeSlot
= NULL
;
108 for (; i
< Conf::config
.getMaxProcs(); i
++)
110 //check whether it is alive
111 if (pInfo
->pid_
!=0 && checkDead(pInfo
->pid_
)) releaseAllResources(sysdb
, pInfo
);
114 sysdb
->releaseProcessTableMutex(false);
119 DbRetVal
logActiveProcs(Database
*sysdb
)
121 DbRetVal rv
= sysdb
->getProcessTableMutex(false);
124 printError(rv
,"Unable to get process table mutex");
127 ThreadInfo
* pInfo
= sysdb
->getThreadInfo(0);
129 ThreadInfo
* freeSlot
= NULL
;
130 for (; i
< Conf::config
.getMaxProcs(); i
++)
132 if (pInfo
->pid_
!=0 ) {
133 logFine(Conf::logger
, "Registered Procs: %d %lu\n", pInfo
->pid_
, pInfo
->thrid_
);
134 printf("Client process with pid %d is still registered\n", pInfo
->pid_
);
135 if( pInfo
->pid_
!= asyncpid
&& pInfo
->pid_
!= cachepid
&&
136 pInfo
->pid_
!= sqlserverpid
)
141 sysdb
->releaseProcessTableMutex(false);
142 if (count
) return ErrSysInternal
; else return OK
;
144 void startCacheServer()
147 sprintf(execName
, "%s/bin/csqlcacheserver", os::getenv("CSQL_INSTALL_ROOT"));
149 //printf("filename is %s\n", execName);
150 cachepid
= os::createProcess(execName
, "csqlcacheserver");
152 printf("Cache Receiver Started\t [PID=%d]\n",cachepid
);
156 void startServiceClient()
159 sprintf(execName
, "%s/bin/csqlsqlserver", os::getenv("CSQL_INSTALL_ROOT"));
160 //printf("filename is %s\n", execName);
162 sqlserverpid
= os::createProcess(execName
, "csqlsqlserver");
163 if (sqlserverpid
!= -1)
164 printf("Network Server Started\t [PID=%d] [PORT=%d]\n", sqlserverpid
,Conf::config
.getPort());
169 void startAsyncServer()
172 sprintf(execName
, "%s/bin/csqlasyncserver", os::getenv("CSQL_INSTALL_ROOT"));
173 //printf("filename is %s\n", execName);
175 asyncpid
= os::createProcess(execName
, "csqlasyncserver");
177 printf("Async Cache Server Started [PID=%d]\n", asyncpid
);
184 printf("Usage: csqlserver [-c] [-v]\n");
185 printf(" v -> print the version.\n");
186 printf(" c -> recover all cached tables from the target database.\n");
187 printf("Description: Start the csql server and initialize the database.\n");
190 int main(int argc
, char **argv
)
194 while ((c
= getopt(argc
, argv
, "cv?")) != EOF
)
198 case '?' : { opt
= 10; break; } //print help
199 case 'c' : { opt
= 1; break; } //recover all the tables from cache
200 case 'v' : { opt
= 2; break; } //print version
210 printf("%s\n",version
);
213 session
= new SessionImpl();
214 DbRetVal rv
= session
->readConfigFile();
217 printf("Unable to read the configuration file \n");
220 os::signal(SIGINT
, sigTermHandler
);
221 os::signal(SIGTERM
, sigTermHandler
);
222 os::signal(SIGCHLD
, sigChildHandler
);
223 rv
= Conf::logger
.startLogger(Conf::config
.getLogFile(), true);
226 printf("Unable to start the Conf::logger\n");
230 logFine(Conf::logger
, "Server Started");
231 int ret
= session
->initSystemDatabase();
234 //printf(" System Database Initialization failed\n");
235 printf("Attaching to exising database\n");
238 session
= new SessionImpl();
239 ret
= session
->open(DBAUSER
, DBAPASS
);
241 printf("Unable to attach to existing database\n");
246 struct timeval timeout
, tval
;
249 Database
* sysdb
= session
->getSystemDatabase();
253 if (isInit
) UID
.create();
255 if(isInit
&& Conf::config
.useDurability())
257 char dbRedoFileName
[1024];
258 char dbChkptSchema
[1024];
259 char dbChkptMap
[1024];
260 char dbChkptData
[1024];
261 char dbBackupFile
[1024];
263 //check for check point file if present recover
264 sprintf(dbChkptSchema
, "%s/db.chkpt.schema1", Conf::config
.getDbFile());
265 if (FILE *file
= fopen(dbChkptSchema
, "r")) {
267 sprintf(cmd
, "cp -f %s %s/db.chkpt.schema", dbChkptSchema
, Conf::config
.getDbFile());
268 int ret
= system(cmd
);
270 Conf::logger
.stopLogger();
271 session
->destroySystemDatabase();
276 sprintf(dbChkptMap
, "%s/db.chkpt.map1", Conf::config
.getDbFile());
277 if (FILE *file
= fopen(dbChkptMap
, "r")) {
279 sprintf(cmd
, "cp -f %s %s/db.chkpt.map", dbChkptMap
, Conf::config
.getDbFile());
280 int ret
= system(cmd
);
282 Conf::logger
.stopLogger();
283 session
->destroySystemDatabase();
288 sprintf(dbChkptData
, "%s/db.chkpt.data", Conf::config
.getDbFile());
289 sprintf(dbBackupFile
, "%s/db.chkpt.data1", Conf::config
.getDbFile());
291 if (!Conf::config
.useMmap() && (fl
= fopen(dbBackupFile
, "r"))) {
293 sprintf(cmd
, "cp %s/db.chkpt.data1 %s", Conf::config
.getDbFile(), dbChkptData
);
294 int ret
= system(cmd
);
296 printError(ErrOS
, "Unable to take backup for chkpt data file");
300 if (FILE *file
= fopen(dbChkptData
, "r")) {
302 int ret
= system("recover");
304 printf("Recovery failed\n");
305 Conf::logger
.stopLogger();
306 session
->destroySystemDatabase();
312 //check for redo log file if present apply redo logs
313 sprintf(dbRedoFileName
, "%s/csql.db.cur", Conf::config
.getDbFile());
314 if (FILE *file
= fopen(dbRedoFileName
, "r"))
317 int ret
= system("redo -a");
319 printf("Recovery failed. Redo log file corrupted\n");
320 Conf::logger
.stopLogger();
321 session
->destroySystemDatabase();
326 // take check point at this moment
327 sprintf(dbChkptSchema
, "%s/db.chkpt.schema", Conf::config
.getDbFile());
328 sprintf(dbChkptMap
, "%s/db.chkpt.map", Conf::config
.getDbFile());
329 sprintf(dbChkptData
, "%s/db.chkpt.data", Conf::config
.getDbFile());
330 ret
= system("checkpoint");
332 printf("Unable to create checkpoint file. Database corrupted.\n");
333 Conf::logger
.stopLogger();
334 session
->destroySystemDatabase();
338 ret
= unlink(dbRedoFileName
);
340 printf("Unable to delete redo log file. Delete and restart the server\n");
341 Conf::logger
.stopLogger();
342 session
->destroySystemDatabase();
348 bool isCacheReq
= false, isSQLReq
= false;
350 if (opt
== 1 && isInit
&& ! Conf::config
.useDurability()) {
351 if (Conf::config
.useCache()) {
352 printf("Database server recovering cached tables...\n");
353 int ret
= system("cachetable -R");
355 printf("Cached Tables recovery failed %d\n", ret
);
356 Conf::logger
.stopLogger();
357 session
->destroySystemDatabase();
361 printf("Cached Tables recovered\n");
363 printf("Cache mode is not set in csql.conf. Cannot recover\n");
364 Conf::logger
.stopLogger();
365 session
->destroySystemDatabase();
370 //TODO:: kill all the child servers and restart if !isInit
372 if(Conf::config
.useCsqlSqlServer()) {
374 startServiceClient();
376 if ( (Conf::config
.useCache() &&
377 Conf::config
.getCacheMode()==ASYNC_MODE
)) {
378 int msgid
= os::msgget(Conf::config
.getMsgKey(), 0666);
379 if (msgid
!= -1) os::msgctl(msgid
, IPC_RMID
, NULL
);
382 if (Conf::config
.useCache() && Conf::config
.useTwoWayCache()) {
386 printf("Database Server Started...\n");
391 tval
.tv_sec
= timeout
.tv_sec
;
392 tval
.tv_usec
= timeout
.tv_usec
;
393 os::select(0, 0, 0, 0, &tval
);
395 //send signal to all the registered process..check they are alive
396 cleanupDeadProcs(sysdb
);
398 //TODO::if it fails to start 5 times, exit
399 if (isCacheReq
&& cachepid
!=0 && checkDead(cachepid
))
402 if (logActiveProcs(sysdb
) != OK
) {srvStop
= 0; goto reloop
; }
403 if (cachepid
) os::kill(cachepid
, SIGTERM
);
404 if(asyncpid
) os::kill(asyncpid
, SIGTERM
);
405 if (sqlserverpid
) os::kill(sqlserverpid
, SIGTERM
);
406 //if (recoverFlag) dumpData();
407 if (Conf::config
.useDurability() && Conf::config
.useMmap()) {
409 char *startAddr
= (char *) sysdb
->getMetaDataPtr();
410 msync(startAddr
+ Conf::config
.getMaxSysDbSize(),Conf::config
.getMaxDbSize(), MS_SYNC
);
411 munmap(startAddr
+ Conf::config
.getMaxSysDbSize(), Conf::config
.getMaxDbSize());
413 logFine(Conf::logger
, "Server Exiting");
414 printf("Server Exiting\n");
415 logFine(Conf::logger
, "Server Ended");
417 session
->destroySystemDatabase();
418 Conf::logger
.stopLogger();
425 //TODO::TAKE exclusive lock
426 sprintf(cmd
, "csqldump >%s/csql.db.chkpt.1",Conf::config
.getDbFile());
427 int ret
= system(cmd
);
428 if (ret
!= 0) return;
429 sprintf(cmd
, "rm -rf %s/csql.db.cur", Conf::config
.getDbFile());
430 if (ret
!= 0) return;
431 sprintf(cmd
, "mv %s/csql.db.chkpt.1 %s/csql.db.chkpt", Conf::config
.getDbFile());
432 if (ret
!= 0) return;