Repository navigation
Expand file tree
/
Copy pathmain.cpp
More file actions
96 lines (82 loc) · 2.77 KB
/
Copy pathmain.cpp
File metadata and controls
96 lines (82 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "Database.h"
#include "QueryProcessor.h"
#include <iostream>
#include <fstream>
#include <exception>
#include <csignal> // For signal handling
#include <atomic> // For thread-safe flag
#include <cstdlib>
#include <cerrno>
#ifdef _WIN32
#include <direct.h>
#define MKDIR(path) _mkdir(path)
#else
#include <sys/stat.h>
#include <sys/types.h>
#define MKDIR(path) mkdir(path, 0777)
#endif
// Global pointer to the database so the signal handler can save it.
// (Using a global is the standard POSIX way for simple signal handlers).
static Database* g_db = nullptr;
static std::atomic<bool> g_running{true};
bool ensureDirectoryExists(const std::string& path) {
if (MKDIR(path.c_str()) == 0 || errno == EEXIST) {
return true;
}
return false;
}
void signalHandler(int signum) {
std::cout << "\n[INFO] Interrupt signal (" << signum << ") received.\n";
if (g_db != nullptr) {
std::cout << "[INFO] Attempting to save database before exit...\n";
if (g_db->saveToFile("data/graph.db")) {
std::cout << "[INFO] Database saved successfully.\n";
} else {
std::cerr << "[ERROR] Failed to save database on exit.\n";
}
}
g_running = false;
exit(signum); // Exit cleanly
}
int main() {
const std::string dataDir = "data";
const std::string dbFile = dataDir + "/graph.db";
// 1. Register signal handlers for Ctrl+C and terminate signals
std::signal(SIGINT, signalHandler); // Ctrl+C
std::signal(SIGTERM, signalHandler); // Kill command
// 2. Ensure data directory exists
if (!ensureDirectoryExists(dataDir)) {
std::cerr << "[ERROR] Failed to create data directory: " << dataDir << "\n";
return 1;
}
Database db;
g_db = &db; // Point the global to our database instance
// 3. Load existing database if present
std::ifstream dbFileStream(dbFile);
if (dbFileStream.good()) {
dbFileStream.close();
if (db.loadFromFile(dbFile)) {
std::cout << "[INFO] Database loaded from " << dbFile << "\n";
} else {
std::cerr << "[WARN] Database file exists but failed to load. Starting with empty graph.\n";
}
} else {
std::cout << "[INFO] No existing database found. Starting fresh.\n";
}
// 4. Run interactive query loop
try {
QueryProcessor qp(db);
qp.runInteractive();
} catch (const std::exception& e) {
std::cerr << "[ERROR] Runtime error: " << e.what() << "\n";
}
// 5. Save database on normal exit
if (db.saveToFile(dbFile)) {
std::cout << "[INFO] Database saved to " << dbFile << "\n";
} else {
std::cerr << "[ERROR] Failed to save database.\n";
return 1;
}
g_db = nullptr; // Unregister before exit
return 0;
}