/* */
This source file includes following definitions.
- setcordata
- main
1 /* -*- coding: utf-8; mode: c++; -*-
2 * Concordance to A. S. Pushkin's Works - Corpus Shared Memory Loader
3 * - 共有メモリに Corpus, TitleDB(作品名データベース) の map を構築する
4 * - アドレスハンドルを表示する
5 * - Web 環境からアクセスする場合は,Web server user 権限で実行すること
6 * $Id: CorpusLoaderDaemon.cpp 49 2014-06-06 15:26:02Z isao $
7 * Copyright (C) 2012, isao yasuda
8 */
9
10 #include <boost/timer.hpp>
11 #include "SharedMemoryCommon.hpp"
12 #include "DeclareFunctions.hpp"
13 #include "ConcordanceConfig.hpp"
14
15 // Corpus の位置情報とテクスト本文を切り出す
16 void setcordata(string& line, string& info, string& text)
17 {
18 string::size_type i = line.find(' '); // 位置情報と本文の区切り
19 info = line.substr(0, i); // 位置情報セット
20 text = line.substr(++i); // 本文セット
21 }
22
23 // Corpus 共有メモリロード主処理
24 int main(int argc, char** argv)
25 {
26 // 引数チェック
27 if (argc != 3) {
28 std::cerr << "Usage: " << argv[0] <<
29 " Corpus-file TitleDB-file" << std::endl;
30 exit(8);
31 }
32
33 // Daemonize
34 // ログファイルをオープンし,標準出力・エラー出力を接続
35 std::ofstream log(LOGFILE, std::ios::out | std::ios::app);
36 std::cout.rdbuf(log.rdbuf());
37 std::cerr.rdbuf(log.rdbuf());
38
39 // 起動済チェック
40 // すでに pid ファイルが存在していればただちに終了する
41 // pid ファイルが存在しなければ,初期作成し STARTING を書き込む
42 std::ifstream opidf;
43 opidf.open(CLPIDF);
44 if (opidf) {
45 log << "CorpusLoader already started." << std::endl;
46 return 1;
47 }
48 std::ofstream pidf(CLPIDF);
49 log << "CorpusLoader starting." << std::endl;
50 pidf << "STARTING";
51 pidf.close();
52
53 // 3 端末分離
54 if (pid_t pid = fork()) {
55 if (pid > 0) {
56 // ここは親プロセス。終了しなければならない
57 exit(0);
58 } else {
59 log << "CorpusLoader First fork failed." << std::endl;
60 log.close();
61 return 1;
62 }
63 }
64
65 // プロセスを新セッションリーダとし,プロセスを端末から切断
66 setsid();
67
68 // ルートディレクトリに移動
69 chdir("/");
70
71 // ファイルのパーミションマスクをクリア
72 umask(0);
73
74 // プロセスが制御端末を捕まえてしまうことのないことを確実化
75 if (pid_t pid = fork()) {
76 if (pid > 0) {
77 exit(0);
78 } else {
79 log << "CorpusLoader Second fork failed." << std::endl;
80 log.close();
81 return 1;
82 }
83 }
84
85 // コーパス,titledb ファイル存在チェック
86 std::ifstream icf;
87 icf.open(argv[1]);
88 if (!icf) {
89 std::cerr << "CorpusLoader " << argv[1] << " open failed." << std::endl;
90 remove(CLPIDF);
91 return 1;
92 }
93 std::ifstream itd;
94 itd.open(argv[2]);
95 if (!itd) {
96 std::cerr << "CorpusLoader " << argv[2] << " open failed." << std::endl;
97 remove(CLPIDF);
98 return 1;
99 }
100
101 // 標準入出力をクローズ,起動端末からデーモンを分離
102 close(0);
103 close(1);
104 close(2);
105
106 // デーモン化完了・共有メモリ処理開始メッセージ
107 pid_t pid = getpid();
108 log << "CorpusLoader daemon started. PID: " << pid << std::endl;
109
110 // シグナルハンドリング
111 sigset_t ss; // signal set
112 int signo; // signal number
113 bool flag = true; // signal wait flag: wait->true; terminate->false;
114
115 // シグナル集合を全シグナルにセット
116 sigfillset(&ss);
117 // シグナルをブロック
118 sigprocmask(SIG_BLOCK, &ss, NULL);
119
120 // 共有メモリを開始前と終了後に削除
121 shm_corpus_remove remover;
122
123 // 共有メモリを確保し,そのオブジェクトを取得
124 log << "CorpusLoader Corpus Shared Memory Construction." << std::endl;
125 log << "CorpusLoader Corpus: " << argv[1] << std::endl;
126 log << "CorpusLoader TitleDB: " << argv[2] << std::endl;
127 managed_shared_memory segment(create_only, SHMCRPS, SHMCRSZ);
128
129 // shared memory allocator
130 void_allocator valloc (segment.get_segment_manager());
131
132 // 処理時間タイマー
133 boost::timer t;
134
135 // 共有メモリ上に corpus map を構築
136 string ldata;
137 shmmap_type* corpus_map = segment.construct<shmmap_type>
138 ("CorpusMap")(std::less<char_string>(), valloc);
139 string cornum;
140 string corstr;
141 int corcnt = 0;
142 while (icf && getline(icf, ldata)) {
143 setcordata(ldata, cornum, corstr);
144 char_string keyinf(cornum.c_str(), valloc);
145 char_string mapped(corstr.c_str(), valloc);
146 cormap_type value(keyinf, mapped);
147 corpus_map->insert(value);
148 corcnt++;
149 }
150 icf.close();
151 log << "CorpusLoader\tCorpus " <<
152 corcnt << " lines constructed." << std::endl;
153 log << "CorpusLoader\t " << t.elapsed() <<
154 " sec elapsed." << std::endl;
155
156 // 共有メモリ上に title database map を構築
157 t.restart(); // タイマーをリセット
158 shmmap_type* tdb_map = segment.construct<shmmap_type>
159 ("TitleDBMap")(std::less<char_string>(), valloc);
160 string tdbnum;
161 string tdbstr;
162 int tdbcnt = 0;
163 while (itd && getline(itd, ldata)) {
164 setcordata(ldata, tdbnum, tdbstr);
165 char_string keyinf(tdbnum.c_str(), valloc);
166 char_string mapped(tdbstr.c_str(), valloc);
167 cormap_type value(keyinf, mapped);
168 tdb_map->insert(value);
169 tdbcnt++;
170 }
171 itd.close();
172 log << "CorpusLoader\tTitleDB " << tdbcnt <<
173 " lines constructed." << std::endl;
174 log << "CorpusLoader\t " << t.elapsed() <<
175 " sec elapsed." << std::endl;
176
177 // map のアドレスをクライアントに連絡するためのハンドル
178 managed_shared_memory::handle_t handle = 0;
179 // Config ファイル (すでにあったとしても内容を破棄)
180 std::ofstream conf(CONFIG, std::ios::out | std::ios::trunc);
181 // Corpus map
182 void* mp = static_cast<void*>(corpus_map);
183 handle = segment.get_handle_from_address(mp);
184 log << "CorpusLoader\tCorpus handle: " << handle << std::endl;
185 conf << "CORPUSHDL=" << handle << std::endl;
186 // Title DB map
187 mp = static_cast<void*>(tdb_map);
188 handle = segment.get_handle_from_address(mp);
189 log << "CorpusLoader\tTitleDB handle: " << handle << std::endl;
190 conf << "TITLDBHDL=" << handle << std::endl;
191 conf.close();
192
193 // PID ファイルに pid を書き込んで,共有メモリ処理完了を示す
194 pidf.open(CLPIDF);
195 pidf << pid;
196 pidf.close();
197
198 // 終了指示シグナルを待つ
199 log << "CorpusLoader waiting for termination signals: " <<
200 "SIGINT, SIGTERM, SIGHUP, SIGQUIT." << std::endl;
201 while (flag) {
202 if (sigwait(&ss, &signo) == 0) {
203 switch (signo) {
204 case SIGINT:
205 case SIGTERM:
206 case SIGHUP:
207 case SIGQUIT:
208 log << "CorpusLoader signal " << signo <<
209 " accepted." << std::endl;
210 flag = false;
211 break;
212 default:
213 log << "CorpusLoader signal " << signo <<
214 " ignored." << std::endl;
215 break;
216 }
217 }
218 }
219
220 // PID ファイル削除
221 remove(CLPIDF);
222 log << "CorpusLoader daemon terminated by signal " << signo <<
223 "." << std::endl;
224
225 return 0;
226 }
/* */