1 /*
2  * 学習の履歴などを管理するためのデータベース
3  * 文字列(xstr)をキーにして高速に行(row)を検索することができる.
4  * 複数のセクションをもつことができ,学習の違うフェーズなどに対応する
5  *  (セクション * 文字列 -> 行)
6  * 各行は文字列か数を持つ配列になっている
7  *
8  * 「パトリシア・トライ」というデータ構造を使用している。
9  * 自然言語の検索などを扱っている教科書を参照のこと
10  */
11 /*
12   This library is free software; you can redistribute it and/or
13   modify it under the terms of the GNU Lesser General Public
14   License as published by the Free Software Foundation; either
15   version 2 of the License, or (at your option) any later version.
16 
17   This library is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20   Lesser General Public License for more details.
21 
22   You should have received a copy of the GNU Lesser General Public
23   License along with this library; if not, write to the Free Software
24   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
25  */
26 /*
27  * Funded by IPA未踏ソフトウェア創造事業 2002 1/18
28  * Funded by IPA未踏ソフトウェア創造事業 2005
29  * Copyright (C) 2005 YOSHIDA Yuichi
30  * Copyright (C) 2000-2006 TABATA Yusuke
31  * Copyright (C) 2000-2003 UGAWA Tomoharu
32  * Copyright (C) 2001-2002 TAKAI Kosuke
33  */
34 /*
35  * パーソナリティ""は匿名パーソナリティであり,
36  * ファイルへの読み書きは行わない.
37  */
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 
46 #include "config.h"
47 #include <anthy/anthy.h>
48 #include <anthy/dic.h>
49 #include <anthy/alloc.h>
50 #include <anthy/conf.h>
51 #include <anthy/ruleparser.h>
52 #include <anthy/record.h>
53 #include <anthy/logger.h>
54 #include <anthy/prediction.h>
55 
56 #include "dic_main.h"
57 #include "dic_personality.h"
58 
59 /* 個人辞書をセーブするファイル名のsuffix */
60 #define ENCODING_SUFFIX ".utf8"
61 
62 
63 enum val_type {
64   RT_EMPTY, RT_VAL, RT_XSTR, RT_XSTRP
65 };
66 
67 /* 値 */
68 struct record_val {
69   enum val_type type;
70   union {
71     xstr str;
72     int val;
73     xstr* strp;
74   } u;
75 };
76 
77 /* 行 */
78 struct record_row {
79   xstr key;
80   int nr_vals;
81   struct record_val *vals;
82 };
83 
84 /* trie node管理用 */
85 struct trie_node {
86   struct trie_node *l;
87   struct trie_node *r;
88   int bit;
89   struct record_row row;
90   struct trie_node *lru_prev, *lru_next; /* 両端ループ */
91   int dirty; /* LRU のための used, sused ビット */
92 };
93 
94 /* trie treeのroot */
95 struct trie_root {
96   struct trie_node root;
97   allocator node_ator;
98 };
99 
100 #define LRU_USED  0x01
101 #define LRU_SUSED 0x02
102 #define PROTECT   0x04 /* 差分書き出し時に使う(LRUとは関係ない)
103 			*   差分書き出しでは、ファイルに書き出す前に
104 			*   ファイル上に他のプロセスが記録した更新を
105 			*   読み込む。それによって、これから追加しよ
106 			*   うとするノードが消されるのを防ぐ
107 			*/
108 /*
109  * LRU:
110  *   USED:  メモリ上で使われた
111  *   SUSED: 保存された used ビット
112  *
113  * LRUリスト上では、 USED は必ずリスト先頭に並んでいるが、 SUSED は
114  * フラグなしのノードと混在している可能性がある。
115  *
116  * n個を残すように指定された時の動作
117  *    1. used > n
118  *        LRU リストの先頭から n 番目以降を消す
119  *    2. used + sused > n
120  *        used -> 残す
121  *        sused -> sused フラグを落す
122  *        それ以外 -> 消す
123  *    3. それ以外
124  *        全て残す
125  * ファイルに書き出す時に、 used || sused -> sused として書き出す
126  */
127 
128 /** セクション */
129 struct record_section {
130   const char *name;
131   struct trie_root cols;
132   struct record_section *next;
133   int lru_nr_used, lru_nr_sused; /* LRU 用 */
134 };
135 
136 /** データベース */
137 struct record_stat {
138   struct record_section section_list; /* sectionのリスト*/
139   struct record_section *cur_section;
140   struct trie_root xstrs; /* xstr を intern するための trie */
141   struct trie_node *cur_row;
142   int row_dirty; /* cur_row が保存の必要があるか */
143   int encoding;
144   /**/
145   int is_anon;
146   const char *id;         /* パーソナリティのid */
147   char *base_fn; /* 基本ファイル 絶対パス */
148   char *journal_fn; /* 差分ファイル 絶対パス */
149   /**/
150   time_t base_timestamp; /* 基本ファイルのタイムスタンプ */
151   int last_update;  /* 差分ファイルの最後に読んだ位置 */
152   time_t journal_timestamp; /* 差分ファイルのタイムスタンプ */
153 };
154 
155 /* 差分が100KB越えたら基本ファイルへマージ */
156 #define FILE2_LIMIT 102400
157 
158 
159 /*
160  * xstr の intern:
161  *  個人ごと( record_stat ごと)に文字列を intern する。これは、
162  *  メモリの節約の他に、データベースの flush 時にデータベースに
163  *  由来する xstr が無効になるのを防ぐ目的がある。
164  *  したがって、データベースの flush 時でも xstr の intern 用
165  *  のデータベース xstrs はそのまま保存する。
166  *
167  *  xstrs: xstr の intern 用のデータベース
168  *         row の key を intern された xstr として使う。
169  *         row に value は持たない。
170  *                    (将来的には参照カウンタをつけてもいいかも)
171  *  参照: intern_xstr()
172  */
173 
174 /*
175  * 差分書き出し:
176  *  データベースの保存、複数の anthy ライブラリをリンクした
177  *  プロセスの学習履歴の同期のために、学習履歴の更新情報を
178  *  逐一ファイルに書き出す。
179  *
180  * ・基本ファイル  古い anthy の学習履歴と同じ形式。
181  *                 差分情報を適用する元となるファイル。
182  *                 基本的には起動時だけに読み込む。
183  *                 このプログラム中でファイル1,baseと呼ぶことがある。
184  * ・差分ファイル  基本ファイルに対する更新情報。
185  *                 データベースに対する更新がコミットされるたびに
186  *                 読み書きされる。
187  *                 このプログラム中でファイル2,journalと呼ぶことがある。
188  *  基本方針:
189  *     データベースに対する更新がコミットされると、まず差分ファイル
190  *     に他のプロセスが追加した更新情報を読み込み、その後に自分の
191  *     コミットした更新を差分ファイルに書き出す。
192  *     これらはロックファイルを用いてアトミックに行われる。また、
193  *     基本ファイル、差分ファイルとも、ロックを取っている間しか
194  *     オープンしていてはいけない。
195  *  追加と削除:
196  *     追加はすでにメモリ上で更新された row をコミットによって
197  *     メモリに書き出すため、
198  *       1. コミット対象 row 以外を差分ファイルの情報で
199  *       2. コミット対象 row を差分ファイルに書き出し
200  *     とする。削除はまだメモリ上に row が残っている状態でコミット
201  *     が行われる(削除要求をコミットとして扱う)ため、
202  *       1. 削除の情報を差分ファイルに書き出し
203  *       2. 差分ファイルの読み込みにより削除要求も実行する
204  *     とする。
205  *  基本ファイルの更新:
206  *     差分ファイルがある程度肥大化すると、差分ファイルの情報を
207  *     基本ファイルに反映して差分ファイルを空にする。
208  *     更新するプロセス:
209  *       差分ファイルに書き出しを行った後、差分ファイルの大きさを調べ、
210  *       肥大化していれば、そのときのメモリ上のデータベース(これには
211  *       全ての差分ファイルの更新が適用されている)を基本ファイルに
212  *       書き出す。
213  *     それ以外のプロセス:
214  *       差分ファイルを読む前に、基本ファイルが更新されているかを
215  *       ファイルのタイムスタンプで調べ、更新されていれば、コミット
216  *       された更新情報を直ちに更新ファイルに追加し、メモリ上の
217  *       データベースを flush した後基本ファイル、差分ファイルを
218  *       読み込み直す。
219  *       データベースの flush により、
220  *           ・cur_row が無効になる (NULL になる)
221  *           ・cur_section の有効性は保存される(sectionは解放しない)
222  *           ・xstr は intern していれば保存される
223  *                              (すべての xstr は intern されているはず)
224  *   結局、次の様になる:
225  *     if (基本ファイルが更新されている) {
226  *             差分ファイルへコミットされた更新を書き出す;
227  *             データベースのフラッシュ;
228  *             基本ファイルの読込と差分ファイルの最終読込位置クリア;
229  *             差分ファイルの読込と差分ファイルの最終読込位置更新;
230  *     } else {
231  *             if (追加) {
232  *                     差分ファイルの読込と差分ファイルの最終読込位置更新;
233  *                     差分ファイルへの書き出し;
234  *             } else {
235  *                     差分ファイルへの書き出し;
236  *                     差分ファイルの読込と差分ファイルの最終読込位置更新;
237  *             }
238  *     }
239  *     if (差分ファイルが大きい) {
240  *             基本ファイルへの書き出し;
241  *             差分ファイルのクリア;
242  *     }
243  */
244 
245 static allocator record_ator;
246 
247 /* trie操作用 */
248 static void init_trie_root(struct trie_root *n);
249 static int trie_key_nth_bit(xstr* key, int n);
250 static int trie_key_first_diff_bit_1byte(xchar c1, xchar c2);
251 static int trie_key_first_diff_bit(xstr *k1, xstr *k2);
252 static int trie_key_cmp(xstr *k1, xstr *k2);
253 static void trie_key_dup(xstr *dst, xstr *src);
254 static void trie_row_init(struct record_row *rc);
255 static void trie_row_free(struct record_row *rc);
256 static struct trie_node *trie_find(struct trie_root *root, xstr *key);
257 static struct trie_node *trie_insert(struct trie_root *root, xstr *key,
258 				     int dirty, int *nr_used, int *nr_sused);
259 static void trie_remove(struct trie_root *root, xstr *key,
260 			int *nr_used, int *nr_sused);
261 static struct trie_node *trie_first(struct trie_root *root);
262 static struct trie_node *trie_next(struct trie_root *root,
263 				   struct trie_node *cur);
264 static void trie_remove_all(struct trie_root *root,
265 			    int *nr_used, int *nr_sused);
266 static void trie_remove_old(struct trie_root *root, int count,
267 			    int* nr_used, int* nr_sused);
268 static void trie_mark_used(struct trie_root *root, struct trie_node *n,
269 			   int *nr_used, int *nr_sused);
270 
271 
272 /*
273  * トライの実装
274  * struct trie_nodeのうちrow以外の部分とrow.keyを使用
275  * 削除の時はtrie_row_freeを使ってrowの内容を解放
276  */
277 
278 #if 0
279 #define PUTNODE(x) ((x) == &root->root ? printf("root\n") : anthy_putxstrln(&(x)->row.key))
280 static int
281 debug_trie_dump(FILE* fp, struct trie_node* n, int encoding)
282 {
283   int cnt = 0;
284   char buf[1024];
285 
286   if (n->l->bit > n->bit) {
287     cnt = debug_trie_dump(fp, n->l, encoding);
288   } else {
289     if (n->l->row.key.len == -1) {
290       if (fp) {
291 	fprintf(fp, "root\n");
292       }
293     } else {
294       if (fp) {
295 	anthy_sputxstr(buf, &n->l->row.key, encoding);
296 	fprintf(fp, "%s\n", buf);
297       }
298       cnt = 1;
299     }
300   }
301 
302   if (n->r->bit > n->bit) {
303     return cnt + debug_trie_dump(fp, n->r, encoding);
304   } else {
305     if (n->r->row.key.len == -1) {
306       if(fp) {
307 	fprintf(fp, "root\n");
308       }
309     } else {
310       if(fp) {
311 	anthy_sputxstr(buf, &n->r->row.key, encoding);
312 	fprintf(fp, "%s\n", buf);
313       }
314       return cnt + 1;
315     }
316   }
317 
318   return cnt;
319 }
320 #endif
321 
322 static void
init_trie_root(struct trie_root * root)323 init_trie_root(struct trie_root *root)
324 {
325   struct trie_node* n;
326   root->node_ator = anthy_create_allocator(sizeof(struct trie_node), NULL);
327   n = &root->root;
328   n->l = n;
329   n->r = n;
330   n->bit = 0;
331   n->lru_next = n;
332   n->lru_prev = n;
333   n->dirty = 0;
334   trie_row_init(&n->row);
335   n->row.key.len = -1;
336 }
337 
338 /*
339  * bit0: 0
340  * bit1: headのキーだけ0
341  * bit2: 文字列のビット0
342  * bit3: 文字列のビット1
343  *   ...
344  * 文字列長を越えると0
345  */
346 static int
trie_key_nth_bit(xstr * key,int n)347 trie_key_nth_bit(xstr* key, int n)
348 {
349   switch (n) {
350   case 0:
351     return 0;
352   case 1:
353     return key->len + 1; /* key->len == -1 ? 0 : non-zero */
354   default:
355     {
356       int pos;
357       n -= 2;
358       pos = n / (sizeof(xchar) << 3);
359       if (pos >= key->len) {
360 	return 0;
361       }
362       return key->str[pos] & (1 << (n % (sizeof(xchar) << 3)));
363     }
364   }
365 }
366 
367 /* c1 == c2 では呼んではいけない */
368 static int
trie_key_first_diff_bit_1byte(xchar c1,xchar c2)369 trie_key_first_diff_bit_1byte(xchar c1, xchar c2)
370 {
371   int i;
372   int ptn;
373   for (i = 0, ptn = c1 ^ c2; !(ptn & 1); i++, ptn >>= 1 )
374     ;
375   return i;
376 }
377 
378 /*
379  * k1 == k2 では呼んではいけない
380  * ki->str[0 .. (ki->len - 1)]に0はないと仮定
381  */
382 #define MIN(a,b) ((a)<(b)?(a):(b))
383 static int
trie_key_first_diff_bit(xstr * k1,xstr * k2)384 trie_key_first_diff_bit(xstr *k1, xstr *k2)
385 {
386   int len;
387   int i;
388 
389   len = MIN(k1->len, k2->len);
390   if (len == -1) {
391     return 1;
392   }
393   for ( i = 0 ; i < len ; i++ ){
394     if (k1->str[i] != k2->str[i]) {
395       return (2 + (i * (sizeof(xchar) << 3)) +
396 	      trie_key_first_diff_bit_1byte(k1->str[i], k2->str[i]));
397     }
398   }
399   if (k1->len < k2->len) {
400     return (2 + (i * (sizeof(xchar) << 3)) +
401 	    trie_key_first_diff_bit_1byte(0, k2->str[i]));
402   } else {
403     return (2 + (i * (sizeof(xchar) << 3)) +
404 	    trie_key_first_diff_bit_1byte(k1->str[i], 0));
405   }
406 }
407 #undef MIN
408 
409 static int
trie_key_cmp(xstr * k1,xstr * k2)410 trie_key_cmp(xstr *k1, xstr *k2)
411 {
412   if (k1->len == -1 || k2->len == -1) {
413     return k1->len - k2->len;
414   }
415   return anthy_xstrcmp(k1, k2);
416 }
417 
418 static void
trie_key_dup(xstr * dst,xstr * src)419 trie_key_dup(xstr *dst, xstr *src)
420 {
421   dst->str = anthy_xstr_dup_str(src);
422   dst->len = src->len;
423 }
424 
425 /*
426  * 見つからなければ 0
427  */
428 static struct trie_node *
trie_find(struct trie_root * root,xstr * key)429 trie_find(struct trie_root *root, xstr *key)
430 {
431   struct trie_node *p;
432   struct trie_node *q;
433 
434   p = &root->root;
435   q = p->l;
436   while (p->bit < q->bit) {
437     p = q;
438     q = trie_key_nth_bit(key, p->bit) ? p->r : p->l;
439   }
440   return trie_key_cmp(&q->row.key,key) ? NULL : q;
441 }
442 
443 /*
444  * 最長マッチのための補助関数
445  *  key で探索して、始めて一致しなくなったノードを返す。
446  */
447 static struct trie_node *
trie_find_longest(struct trie_root * root,xstr * key)448 trie_find_longest (struct trie_root* root, xstr *key)
449 {
450   struct trie_node *p;
451   struct trie_node *q;
452 
453   p = &root->root;
454   q = p->l;
455   while (p->bit < q->bit) {
456     p = q;
457     q = trie_key_nth_bit(key, p->bit) ? p->r : p->l;
458   }
459 
460   return q;
461 }
462 
463 /*
464  * 追加したノードを返す
465  * すでに同じキーをもつノードがあるときは、追加せずに0を返す
466  */
467 static struct trie_node *
trie_insert(struct trie_root * root,xstr * key,int dirty,int * nr_used,int * nr_sused)468 trie_insert(struct trie_root *root, xstr *key,
469 	    int dirty, int *nr_used, int *nr_sused)
470 {
471   struct trie_node *n;
472   struct trie_node *p;
473   struct trie_node *q;
474   int i;
475 
476   p = &root->root;
477   q = p->l;
478   while (p->bit < q->bit) {
479     p = q;
480     q = trie_key_nth_bit(key, p->bit) ? p->r : p->l;
481   }
482   if (trie_key_cmp(&q->row.key,key) == 0) {
483     /* USED > SUSED > 0 で強い方を残す */
484     if (dirty == LRU_USED) {
485       trie_mark_used(root, q, nr_used, nr_sused);
486     } else if (q->dirty == 0) {
487       q->dirty = dirty;
488     }
489     return 0;
490   }
491   i = trie_key_first_diff_bit(&q->row.key, key);
492   p = &root->root;
493   q = p->l;
494   while (p->bit < q->bit && i > q->bit) {
495     p = q;
496     q = trie_key_nth_bit(key, p->bit) ? p->r : p->l;
497   }
498   n = anthy_smalloc(root->node_ator);
499   trie_row_init(&n->row);
500   trie_key_dup(&n->row.key, key);
501   n->bit = i;
502   if (trie_key_nth_bit(key, i)) {
503     n->l = q;
504     n->r = n;
505   } else {
506     n->l = n;
507     n->r = q;
508   }
509   if (p->l == q) {
510     p->l = n;
511   } else {
512     p->r = n;
513   }
514 
515   /* LRU の処理 */
516   if (dirty == LRU_USED) {
517     root->root.lru_next->lru_prev = n;
518     n->lru_prev = &root->root;
519     n->lru_next = root->root.lru_next;
520     root->root.lru_next = n;
521     (*nr_used)++;
522   } else {
523     root->root.lru_prev->lru_next = n;
524     n->lru_next = &root->root;
525     n->lru_prev = root->root.lru_prev;
526     root->root.lru_prev = n;
527     if (dirty == LRU_SUSED) {
528       (*nr_sused)++;
529     }
530   }
531   n->dirty = dirty;
532   return n;
533 }
534 
535 /*
536  * ノードを見つけると削除する
537  * 内部でtrie_row_freeを呼び、キーを含むデータ部分をfreeする
538  *
539  * データとノードを削除する。
540  * 削除対象のデータは削除対象のノードに格納されているとは
541  * 限らないことに注意。
542  * 1. 削除対象の葉を持つノードに削除対象の葉が含まれているとき
543  *  削除対象のノードは、子への枝のうち、生きのこる枝を親に渡して死ぬ
544  * 2. 削除対象の葉を持つノードの祖先に削除対象の葉が含まれているとき
545  *  1. に加えて、削除対象の葉をもつノードを殺して、代わりに削除
546  *  対象のノードを削除対象の葉をもつノードの位置に移動させ生かす
547  */
548 static void
trie_remove(struct trie_root * root,xstr * key,int * nr_used,int * nr_sused)549 trie_remove(struct trie_root *root, xstr *key,
550 	    int *nr_used, int *nr_sused)
551 {
552   struct trie_node *p;
553   struct trie_node *q;
554   struct trie_node **pp = NULL; /* gcc の warning 回避 */
555   struct trie_node **qq;
556   p = &root->root;
557   qq = &p->l;
558   q = *qq;
559   while (p->bit < q->bit) {
560     pp = qq;
561     p = q;
562     qq = trie_key_nth_bit(key,p->bit) ? &p->r : &p->l;
563     q = *qq;
564   }
565   if (trie_key_cmp(&q->row.key, key) != 0) {
566     return ;
567   }
568   if (p != q) {
569     /* case 2. */
570     struct trie_node *r;
571     struct trie_node *s;
572     r = &root->root;
573     s = r->l;
574     while (s != q) {
575       r = s;
576       s = trie_key_nth_bit(key, r->bit) ? r->r : r->l;
577     }
578     *pp = (p->r == q) ? p->l : p->r;
579     p->l = q->l;
580     p->r = q->r;
581     p->bit = q->bit;
582     if (trie_key_nth_bit(key, r->bit)) {
583       r->r = p;
584     } else {
585       r->l = p;
586     }
587     p = q;
588   } else {
589     *pp = (p->r == q) ? p->l : p->r;
590   }
591   p->lru_prev->lru_next = p->lru_next;
592   p->lru_next->lru_prev = p->lru_prev;
593   if (p->dirty == LRU_USED) {
594     (*nr_used)--;
595   } else if (p->dirty == LRU_SUSED) {
596     (*nr_sused)--;
597   }
598   trie_row_free(&p->row);
599   anthy_sfree(root->node_ator, p);
600 }
601 
602 /* head以外のノードがなければ 0 を返す */
603 static struct trie_node *
trie_first(struct trie_root * root)604 trie_first (struct trie_root *root)
605 {
606   return root->root.lru_next == &root->root ?
607     NULL : root->root.lru_next;
608 }
609 
610 /* 次のノードがなければ 0 を返す */
611 static struct trie_node *
trie_next(struct trie_root * root,struct trie_node * cur)612 trie_next (struct trie_root *root,
613 	   struct trie_node *cur)
614 {
615   return cur->lru_next == &root->root ? 0 : cur->lru_next;
616 }
617 
618 /*
619  * head以外全てのノードを削除する
620  * 内部でtrie_row_freeを呼び、キーを含むデータ部分をfreeする
621  */
622 static void
trie_remove_all(struct trie_root * root,int * nr_used,int * nr_sused)623 trie_remove_all (struct trie_root *root,
624 		 int *nr_used, int *nr_sused)
625 {
626   struct trie_node* p;
627   for (p = root->root.lru_next; p != &root->root; p = p->lru_next) {
628     trie_row_free(&p->row);
629   }
630   anthy_free_allocator(root->node_ator);
631   init_trie_root(root);
632   *nr_used = 0;
633   *nr_sused = 0;
634 }
635 
636 /*
637  * LRU リストの先頭から count 番目までを残して残りを解放する
638  */
639 static void
trie_remove_old(struct trie_root * root,int count,int * nr_used,int * nr_sused)640 trie_remove_old (struct trie_root *root, int count,
641 		 int *nr_used, int *nr_sused)
642 {
643   struct trie_node *p;
644   struct trie_node *q;
645 
646   if (*nr_used > count) {
647     for (p = root->root.lru_next; count; count--, p = p->lru_next)
648       ;
649     /* p から head までを消す */
650     for ( ; p != &root->root; p = q) {
651       q = p->lru_next;
652       trie_remove(root, &p->row.key, nr_used, nr_sused);
653     }
654   } else if (*nr_used + *nr_sused > count) {
655     for (p = root->root.lru_next; p->dirty == LRU_USED; p = p->lru_next)
656       ;
657     /*
658      * p から root まで  sused    -> dirty := 0
659      *                   それ以外 -> 消す
660      */
661     for ( ; p != &root->root; p = q) {
662       q = p->lru_next;
663       if (p->dirty == LRU_SUSED) {
664 	p->dirty = 0;
665       } else {
666 	trie_remove(root, &p->row.key, nr_used, nr_sused);
667       }
668     }
669     *nr_sused = 0;
670   }
671 }
672 
673 static void
trie_mark_used(struct trie_root * root,struct trie_node * n,int * nr_used,int * nr_sused)674 trie_mark_used (struct trie_root *root, struct trie_node *n,
675 		int *nr_used, int *nr_sused)
676 {
677   switch(n->dirty) {
678   case LRU_USED:
679     break;
680   case LRU_SUSED:
681     (*nr_sused)--;
682     /* fall through */
683   default:
684     n->dirty = LRU_USED;
685     (*nr_used)++;
686     break;
687   }
688   n->lru_prev->lru_next = n->lru_next;
689   n->lru_next->lru_prev = n->lru_prev;
690   root->root.lru_next->lru_prev = n;
691   n->lru_next = root->root.lru_next;
692   root->root.lru_next = n;
693   n->lru_prev = &root->root;
694 }
695 
696 /*
697  * トライの実装はここまで
698  */
699 
700 static xstr *
do_get_index_xstr(struct record_stat * rec)701 do_get_index_xstr(struct record_stat *rec)
702 {
703   if (!rec->cur_row) {
704     return 0;
705   }
706   return &rec->cur_row->row.key;
707 }
708 
709 static struct record_section*
do_select_section(struct record_stat * rst,const char * name,int flag)710 do_select_section(struct record_stat *rst, const char *name, int flag)
711 {
712   struct record_section *rsc;
713 
714   for (rsc = rst->section_list.next; rsc; rsc = rsc->next) {
715     if (!strcmp(name, rsc->name)) {
716       return rsc;
717     }
718   }
719 
720   if (flag) {
721     rsc = malloc(sizeof(struct record_section));
722     rsc->name = strdup(name);
723     rsc->next = rst->section_list.next;
724     rst->section_list.next = rsc;
725     rsc->lru_nr_used = 0;
726     rsc->lru_nr_sused = 0;
727     init_trie_root(&rsc->cols);
728     return rsc;
729   }
730 
731   return NULL;
732 }
733 
734 static struct trie_node*
do_select_longest_row(struct record_section * rsc,xstr * name)735 do_select_longest_row(struct record_section *rsc, xstr *name)
736 {
737   struct trie_node *mark, *found;
738   xstr xs;
739   int i;
740 
741   if ((NULL == name) || (NULL == name->str) || (name->len < 1) || (0 == name->str[0])) {
742     /* 辞書もしくは学習データが壊れていた時の対策 */
743     return NULL;
744   }
745 
746   mark = trie_find_longest(&rsc->cols, name);
747   xs.str = name->str;
748   for (i = (mark->row.key.len <= name->len) ? mark->row.key.len : name->len; i > 1; i--) {  /* 不正なメモリアクセスの修正 */
749     /* ルートノードは i == 1 でマッチするので除外
750      * trie_key_nth_bit 参照
751      */
752     xs.len = i;
753     found = trie_find(&rsc->cols, &xs);
754     if (found) {
755       return found;
756     }
757   }
758   return NULL;
759 }
760 
761 static struct trie_node*
do_select_row(struct record_section * rsc,xstr * name,int flag,int dirty)762 do_select_row(struct record_section* rsc, xstr *name,
763 		 int flag, int dirty)
764 {
765   struct trie_node *node;
766 
767   if (flag) {
768     node = trie_insert(&rsc->cols, name, dirty,
769 		       &rsc->lru_nr_used, &rsc->lru_nr_sused);
770     if (node) {
771       node->row.nr_vals = 0;
772       node->row.vals = 0;
773     } else {
774       node = trie_find(&rsc->cols, name);
775     }
776   } else {
777     node = trie_find(&rsc->cols, name);
778   }
779   return node;
780 }
781 
782 static void
do_mark_row_used(struct record_section * rsc,struct trie_node * node)783 do_mark_row_used(struct record_section* rsc, struct trie_node* node)
784 {
785   trie_mark_used(&rsc->cols, node, &rsc->lru_nr_used, &rsc->lru_nr_sused);
786 }
787 
788 static void
do_truncate_section(struct record_stat * s,int count)789 do_truncate_section(struct record_stat *s, int count)
790 {
791   if (!s->cur_section) {
792     return;
793   }
794 
795   trie_remove_old(&s->cur_section->cols, count,
796 		  &s->cur_section->lru_nr_used,
797 		  &s->cur_section->lru_nr_sused);
798 }
799 
800 
801 static struct trie_node*
do_select_first_row(struct record_section * rsc)802 do_select_first_row(struct record_section *rsc)
803 {
804   return trie_first(&rsc->cols);
805 }
806 
807 static struct trie_node*
do_select_next_row(struct record_section * rsc,struct trie_node * node)808 do_select_next_row(struct record_section *rsc,
809   struct trie_node* node)
810 {
811   return trie_next(&rsc->cols, node);
812 }
813 
814 
815 static int
do_get_nr_values(struct trie_node * node)816 do_get_nr_values(struct trie_node *node)
817 {
818   if (!node)
819     return 0;
820   return node->row.nr_vals;
821 }
822 
823 static struct record_val *
get_nth_val_ent(struct trie_node * node,int n,int f)824 get_nth_val_ent(struct trie_node *node, int n, int f)
825 {
826   struct record_row *col;
827   col = &node->row;
828   if (n < 0) {
829     return NULL;
830   }
831   if (n < do_get_nr_values(node)) {
832     return &col->vals[n];
833   }
834   if (f) {
835     int i;
836     col->vals = realloc(col->vals, sizeof(struct record_val)*(n + 1));
837     for (i = col->nr_vals; i < n+1; i++) {
838       col->vals[i].type = RT_EMPTY;
839     }
840     col->nr_vals = n + 1;
841     return &col->vals[n];
842   }
843   return NULL;
844 }
845 
846 static void
free_val_contents(struct record_val * v)847 free_val_contents(struct record_val* v)
848 {
849   switch (v->type) {
850   case RT_XSTR:
851     anthy_free_xstr_str(&v->u.str);
852     break;
853   case RT_XSTRP:
854   case RT_VAL:
855   case RT_EMPTY:
856   default:
857     break;
858   }
859 }
860 
861 static void
do_set_nth_value(struct trie_node * node,int nth,int val)862 do_set_nth_value(struct trie_node *node, int nth, int val)
863 {
864   struct record_val *v = get_nth_val_ent(node, nth, 1);
865   if (!v) {
866     return ;
867   }
868   free_val_contents(v);
869   v->type = RT_VAL;
870   v->u.val = val;
871 }
872 
873 static int
do_get_nth_value(struct trie_node * node,int n)874 do_get_nth_value(struct trie_node *node, int n)
875 {
876   struct record_val *v = get_nth_val_ent(node, n, 0);
877   if (v && v->type == RT_VAL) {
878     return v->u.val;
879   }
880   return 0;
881 }
882 
883 static xstr*
intern_xstr(struct trie_root * xstrs,xstr * xs)884 intern_xstr (struct trie_root* xstrs, xstr* xs)
885 {
886   struct trie_node* node;
887   int dummy;
888 
889   if ((NULL == xs) || (NULL == xs->str) || (xs->len < 1) || (0 == xs->str[0])) {
890     /* 辞書もしくは学習データが壊れていた時の対策 */
891     return NULL;
892   }
893   node = trie_find(xstrs, xs);
894   if (!node)
895     node = trie_insert(xstrs, xs, 0, &dummy, &dummy);
896   return &node->row.key;
897 }
898 
899 static void
do_set_nth_xstr(struct trie_node * node,int nth,xstr * xs,struct trie_root * xstrs)900 do_set_nth_xstr (struct trie_node *node, int nth, xstr *xs,
901 		 struct trie_root* xstrs)
902 {
903   struct record_val *v = get_nth_val_ent(node, nth, 1);
904   if (!v){
905     return ;
906   }
907   free_val_contents(v);
908   v->type = RT_XSTRP;
909   v->u.strp = intern_xstr(xstrs, xs);
910 }
911 
912 static void
do_truncate_row(struct trie_node * node,int n)913 do_truncate_row (struct trie_node* node, int n)
914 {
915   int i;
916   if (n < node->row.nr_vals) {
917     for (i = n; i < node->row.nr_vals; i++) {
918       free_val_contents(node->row.vals + i);
919     }
920     node->row.vals = realloc(node->row.vals,
921 				sizeof(struct record_val)* n);
922     node->row.nr_vals = n;
923   }
924 }
925 
926 static void
do_remove_row(struct record_section * rsc,struct trie_node * node)927 do_remove_row (struct record_section* rsc,
928 		  struct trie_node* node)
929 {
930   xstr* xs;
931   xs = anthy_xstr_dup(&node->row.key);
932   trie_remove(&rsc->cols, &node->row.key,
933 	      &rsc->lru_nr_used, &rsc->lru_nr_sused);
934 
935   anthy_free_xstr(xs);
936 }
937 
938 static xstr *
do_get_nth_xstr(struct trie_node * node,int n)939 do_get_nth_xstr(struct trie_node *node, int n)
940 {
941   struct record_val *v = get_nth_val_ent(node, n, 0);
942   if (v) {
943     if (v->type == RT_XSTR) {
944       return &v->u.str;
945     } else if (v->type == RT_XSTRP) {
946       return v->u.strp;
947     }
948   }
949   return 0;
950 }
951 
952 static void
lock_record(struct record_stat * rs)953 lock_record (struct record_stat* rs)
954 {
955   if (rs->is_anon) {
956     return ;
957   }
958   anthy_priv_dic_lock();
959 }
960 
961 static void
unlock_record(struct record_stat * rs)962 unlock_record (struct record_stat* rs)
963 {
964   if (rs->is_anon) {
965     return ;
966   }
967   anthy_priv_dic_unlock();
968 }
969 
970 /* 再読み込みの必要があるかをチェックする
971  * 必要があれば返り値が1になる */
972 static int
check_base_record_uptodate(struct record_stat * rst)973 check_base_record_uptodate(struct record_stat *rst)
974 {
975   struct stat st;
976   if (rst->is_anon) {
977     return 0;
978   }
979   anthy_check_user_dir();
980   if (stat(rst->base_fn, &st) < 0) {
981     return 0;
982   } else if (st.st_mtime == rst->base_timestamp) {
983     return 0;
984   }
985   return 1;
986 }
987 
988 
989 /*
990  * row format:
991  *  ROW := OPERATION SECTION KEY VALUE*
992  *  OPERATION := "ADD"    (追加またはLRU更新)
993  *               "DEL"    (削除)
994  *  SECTION := (文字列)
995  *  KEY     := TD
996  *  VALUE   := TD
997  *  TD      := TYPE DATA  (空白をあけずに書く)
998  *  TYPE    := "S"        (xstr)
999  *             "N"        (number)
1000  *  DATA    := (型ごとにシリアライズしたもの)
1001  */
1002 
1003 static char*
read_1_token(FILE * fp,int * eol)1004 read_1_token (FILE* fp, int* eol)
1005 {
1006   int c;
1007   char* s;
1008   int in_quote;
1009   int len;
1010 
1011   in_quote = 0;
1012   s = NULL;
1013   len = 0;
1014   while (1) {
1015     c = fgetc(fp);
1016     switch (c) {
1017     case EOF: case '\n':
1018       goto out;
1019     case '\\':
1020       c = fgetc(fp);
1021       if (c == EOF || c == '\n') {
1022 	goto out;
1023       }
1024       break;
1025     case '\"':
1026       in_quote = !in_quote;
1027       continue;
1028     case ' ': case '\t': case '\r':
1029       if (in_quote) {
1030 	break;
1031       }
1032       if (s != NULL) {
1033 	goto out;
1034       }
1035       break;
1036     default:
1037       break;
1038     }
1039 
1040     s = (char*) realloc(s, len + 2);
1041     s[len] = c;
1042     len ++;
1043   }
1044 out:
1045   if (s) {
1046     s[len] = '\0';
1047   }
1048   *eol = (c == '\n' || c == EOF);
1049   return s;
1050 }
1051 
1052 /* journalからADDの行を読む */
1053 static void
read_add_row(FILE * fp,struct record_stat * rst,struct record_section * rsc)1054 read_add_row(FILE *fp, struct record_stat* rst,
1055 	     struct record_section* rsc)
1056 {
1057   int n;
1058   xstr* xs;
1059   char *token;
1060   int eol;
1061   struct trie_node* node;
1062 
1063   token = read_1_token(fp, &eol);
1064   if (!token) {
1065     return ;
1066   }
1067 
1068   xs = anthy_cstr_to_xstr(/* xstr 型を表す S を読み捨てる */
1069 			  token + 1,
1070 			  rst->encoding);
1071   node = do_select_row(rsc, xs, 1, LRU_USED);
1072   anthy_free_xstr(xs);
1073   free(token);
1074 
1075   if (node->dirty & PROTECT) {
1076     /* 保存すべき row なので、差分ファイルを読み捨てる */
1077     while (!eol) {
1078       free(read_1_token(fp, &eol));
1079     }
1080     return ;
1081   }
1082 
1083   n = 0;
1084   while (!eol) {
1085     token = read_1_token(fp, &eol);
1086     if (token) {
1087       switch(*token) {
1088 	/* String 文字列 */
1089       case 'S':
1090 	{
1091 	  xstr* xs;
1092 	  xs = anthy_cstr_to_xstr(token + 1, rst->encoding);
1093 	  do_set_nth_xstr(node, n, xs, &rst->xstrs);
1094 	  anthy_free_xstr(xs);
1095 	}
1096 	break;
1097 	/* Number 数値 */
1098       case 'N':
1099 	do_set_nth_value(node, n, atoi(token + 1));
1100 	break;
1101       }
1102       free(token);
1103       n++;
1104     }
1105   }
1106   do_truncate_row(node, n);
1107 }
1108 
1109 /* journalからDELの行を読む */
1110 static void
read_del_row(FILE * fp,struct record_stat * rst,struct record_section * rsc)1111 read_del_row(FILE *fp, struct record_stat* rst,
1112 	     struct record_section* rsc)
1113 {
1114   struct trie_node* node;
1115   char* token;
1116   xstr* xs;
1117   int eol;
1118 
1119   token = read_1_token(fp, &eol);
1120   if (!token) {
1121     return ;
1122   }
1123 
1124   xs = anthy_cstr_to_xstr(/* xstr 型を表す S を読み飛ばす */
1125 			  token + 1,
1126 			  rst->encoding);
1127   if ((node = do_select_row(rsc, xs, 0, 0)) != NULL) {
1128     do_remove_row(rsc, node);
1129   }
1130   anthy_free_xstr(xs);
1131   free(token);
1132 }
1133 
1134 /** 差分ファイルから1行読み込む */
1135 static void
read_1_row(struct record_stat * rst,FILE * fp,char * op)1136 read_1_row(struct record_stat* rst, FILE* fp, char *op)
1137 {
1138   char* sec_name;
1139   struct record_section* rsc;
1140   int eol;
1141 
1142   sec_name = read_1_token(fp, &eol);
1143   if (!sec_name || eol) {
1144     free(sec_name);
1145     return ;
1146   }
1147   rsc = do_select_section(rst, sec_name, 1);
1148   free(sec_name);
1149   if (!rsc) {
1150     return ;
1151   }
1152 
1153   if (strcmp(op, "ADD") == 0) {
1154     read_add_row(fp, rst, rsc);
1155   } else if (strcmp(op, "DEL") == 0) {
1156     read_del_row(fp, rst, rsc);
1157   }
1158 }
1159 
1160 /*
1161  * journal(差分)ファイルを読む
1162  */
1163 static void
read_journal_record(struct record_stat * rs)1164 read_journal_record(struct record_stat* rs)
1165 {
1166   FILE* fp;
1167   struct stat st;
1168 
1169   if (rs->is_anon) {
1170     return ;
1171   }
1172   fp = fopen(rs->journal_fn, "r");
1173   if (fp == NULL) {
1174     return;
1175   }
1176   if (fstat(fileno(fp), &st) == -1) {
1177     fclose(fp);
1178     return ;
1179   }
1180   if (st.st_size < rs->last_update) {
1181     /* ファイルサイズが小さくなっているので、
1182      * 最初から読み込む */
1183     fseek(fp, 0, SEEK_SET);
1184   } else {
1185     fseek(fp, rs->last_update, SEEK_SET);
1186   }
1187   rs->journal_timestamp = st.st_mtime;
1188   while (!feof(fp)) {
1189     char *op;
1190     int eol;
1191     op = read_1_token(fp, &eol);
1192     if (op && !eol) {
1193       read_1_row(rs, fp, op);
1194     }
1195     free(op);
1196   }
1197   rs->last_update = ftell(fp);
1198   fclose(fp);
1199 }
1200 
1201 static void
write_string(FILE * fp,const char * str)1202 write_string(FILE* fp, const char* str)
1203 {
1204   fprintf(fp, "%s", str);
1205 }
1206 
1207 /* ダブルクオートもしくはバックスラッシュにバックスラッシュを付ける */
1208 static void
write_quote_string(FILE * fp,const char * str)1209 write_quote_string(FILE* fp, const char* str)
1210 {
1211   const char* p;
1212 
1213   for (p = str; *p; p++) {
1214     if (*p == '\"' || *p == '\\') {
1215       fputc('\\', fp);
1216     }
1217     fputc(*p, fp);
1218   }
1219 }
1220 
1221 static void
write_quote_xstr(FILE * fp,xstr * xs,int encoding)1222 write_quote_xstr(FILE* fp, xstr* xs, int encoding)
1223 {
1224   char* buf;
1225 
1226   if ((NULL == xs) || (NULL == xs->str) || (xs->len < 1) || (0 == xs->str[0])) {
1227     /* 辞書もしくは学習データが壊れていた時の対策 */
1228     return;
1229   }
1230 
1231   buf = (char*) alloca(xs->len * 6 + 2); /* EUC またはUTF8を仮定 */
1232   anthy_sputxstr(buf, xs, encoding);
1233   write_quote_string(fp, buf);
1234 }
1235 
1236 static void
write_number(FILE * fp,int x)1237 write_number(FILE* fp, int x)
1238 {
1239   fprintf(fp, "%d", x);
1240 }
1241 
1242 /* journalに1行追記する */
1243 static void
commit_add_row(struct record_stat * rst,const char * sname,struct trie_node * node)1244 commit_add_row(struct record_stat* rst,
1245 	       const char* sname, struct trie_node* node)
1246 {
1247   FILE* fp;
1248   int i;
1249 
1250   if (rst->is_anon)
1251     return ;
1252 
1253   fp = fopen(rst->journal_fn, "a");
1254   if (fp == NULL) {
1255     return;
1256   }
1257 
1258   write_string(fp, "ADD \"");
1259   write_quote_string(fp, sname);
1260   write_string(fp, "\" S\"");
1261   write_quote_xstr(fp, &node->row.key, rst->encoding);
1262   write_string(fp, "\"");
1263 
1264   for (i = 0; i < node->row.nr_vals; i++) {
1265     switch (node->row.vals[i].type) {
1266     case RT_EMPTY:
1267       write_string(fp, " E");
1268       break;
1269     case RT_VAL:
1270       write_string(fp, " N");
1271       write_number(fp, node->row.vals[i].u.val);
1272       break;
1273     case RT_XSTR:
1274       write_string(fp, " S\"");
1275       write_quote_xstr(fp, &node->row.vals[i].u.str, rst->encoding);
1276       write_string(fp, "\"");
1277       break;
1278     case RT_XSTRP:
1279       write_string(fp, " S\"");
1280       write_quote_xstr(fp, node->row.vals[i].u.strp, rst->encoding);
1281       write_string(fp, "\"");
1282       break;
1283     }
1284   }
1285   write_string(fp, "\n");
1286   rst->last_update = ftell(fp);
1287   fclose(fp);
1288 }
1289 
1290 /* 全ての row を解放する */
1291 static void
clear_record(struct record_stat * rst)1292 clear_record(struct record_stat* rst)
1293 {
1294   struct record_section *rsc;
1295   for (rsc = rst->section_list.next; rsc; rsc = rsc->next) {
1296     trie_remove_all(&rsc->cols, &rsc->lru_nr_used, &rsc->lru_nr_sused);
1297   }
1298   rst->cur_row = NULL;
1299 }
1300 
1301 /* 基本ファイルを読む */
1302 static void
read_session(struct record_stat * rst)1303 read_session(struct record_stat *rst)
1304 {
1305   char **tokens;
1306   int nr;
1307   struct record_section* rsc = NULL;
1308   while (!anthy_read_line(&tokens, &nr)) {
1309     xstr *xs;
1310     int i;
1311     int dirty = 0;
1312     struct trie_node* node;
1313 
1314     if (!strcmp(tokens[0], "---") && nr > 1) {
1315       /* セクションの切れ目 */
1316       rsc = do_select_section(rst, tokens[1], 1);
1317       goto end;
1318     }
1319     if (!rsc || nr < 2) {
1320       /* セクションが始まってない or 行が不完全 */
1321       goto end;
1322     }
1323     /* 行頭のLRUのマークを読む */
1324     if (tokens[0][0] == '-') {
1325       dirty = 0;
1326     } else if (tokens[0][0] == '+') {
1327       dirty = LRU_SUSED;
1328     }
1329     /* 次にindex */
1330     xs = anthy_cstr_to_xstr(&tokens[0][1], rst->encoding);
1331     node = do_select_row(rsc, xs, 1, dirty);
1332     anthy_free_xstr(xs);
1333     if (!node) {
1334       goto end;
1335     }
1336     /**/
1337     for (i = 1; i < nr; i++) {
1338       if (tokens[i][0] == '"') {
1339 	char *str;
1340 	str = strdup(&tokens[i][1]);
1341 	str[strlen(str) - 1] = 0;
1342 	xs = anthy_cstr_to_xstr(str, rst->encoding);
1343 	free(str);
1344 	do_set_nth_xstr(node, i-1, xs, &rst->xstrs);
1345 	anthy_free_xstr(xs);
1346       }else if (tokens[i][0] == '*') {
1347 	/* EMPTY entry */
1348 	get_nth_val_ent(node, i-1, 1);
1349       } else {
1350 	do_set_nth_value(node, i-1, atoi(tokens[i]));
1351       }
1352     }
1353   end:
1354     anthy_free_line();
1355   }
1356 }
1357 
1358 /* いまのデータベースを解放した後にファイルから読み込む */
1359 static void
read_base_record(struct record_stat * rst)1360 read_base_record(struct record_stat *rst)
1361 {
1362   struct stat st;
1363   if (rst->is_anon) {
1364     clear_record(rst);
1365     return ;
1366   }
1367   anthy_check_user_dir();
1368 
1369   if (anthy_open_file(rst->base_fn) == -1) {
1370     return ;
1371   }
1372 
1373   clear_record(rst);
1374   read_session(rst);
1375   anthy_close_file();
1376   if (stat(rst->base_fn, &st) == 0) {
1377     rst->base_timestamp = st.st_mtime;
1378   }
1379   rst->last_update = 0;
1380 }
1381 
1382 static FILE *
open_tmp_in_recorddir(void)1383 open_tmp_in_recorddir(void)
1384 {
1385   char *pn;
1386   const char *hd;
1387   const char *sid;
1388   sid = anthy_conf_get_str("SESSION-ID");
1389   hd = anthy_conf_get_str("HOME");
1390   pn = alloca(strlen(hd)+strlen(sid) + 10);
1391   sprintf(pn, "%s/.anthy/%s", hd, sid);
1392   return fopen(pn, "w");
1393 }
1394 
1395 /*
1396  * 一時ファイルからbaseファイルへrenameする
1397  */
1398 static void
update_file(const char * fn)1399 update_file(const char *fn)
1400 {
1401   const char *hd;
1402   char *tmp_fn;
1403   const char *sid;
1404   hd = anthy_conf_get_str("HOME");
1405   sid = anthy_conf_get_str("SESSION-ID");
1406   tmp_fn = alloca(strlen(hd)+strlen(sid) + 10);
1407 
1408   sprintf(tmp_fn, "%s/.anthy/%s", hd, sid);
1409   if (rename(tmp_fn, fn)){
1410     anthy_log(0, "Failed to update record file %s -> %s.\n", tmp_fn, fn);
1411   }
1412 }
1413 
1414 /* カラムを保存する */
1415 static void
save_a_row(FILE * fp,struct record_stat * rst,struct record_row * c,int dirty)1416 save_a_row(FILE *fp, struct record_stat* rst,
1417 	   struct record_row *c, int dirty)
1418 {
1419   int i;
1420   char *buf = alloca(c->key.len * 6 + 2);
1421   /* LRUのマークを出力 */
1422   if (dirty == 0) {
1423     fputc('-', fp);
1424   } else {
1425     fputc('+', fp);
1426   }
1427   anthy_sputxstr(buf, &c->key, rst->encoding);
1428   /* index を出力 */
1429   fprintf(fp, "%s ", buf);
1430   /**/
1431   for (i = 0; i < c->nr_vals; i++) {
1432     struct record_val *val = &c->vals[i];
1433     switch (val->type) {
1434     case RT_EMPTY:
1435       fprintf(fp, "* ");
1436       break;
1437     case RT_XSTR:
1438       /* should not happen */
1439       fprintf(fp, "\"");
1440       write_quote_xstr(fp, &val->u.str, rst->encoding);
1441       fprintf(fp, "\" ");
1442       abort();
1443       break;
1444     case RT_XSTRP:
1445       fprintf(fp, "\"");
1446       write_quote_xstr(fp, val->u.strp, rst->encoding);
1447       fprintf(fp, "\" ");
1448       break;
1449     case RT_VAL:
1450       fprintf(fp, "%d ", val->u.val);
1451       break;
1452     default:
1453       anthy_log(0, "Faild to save an unknown record. (in record.c)\n");
1454       break;
1455     }
1456   }
1457   fprintf(fp, "\n");
1458 }
1459 
1460 static void
update_base_record(struct record_stat * rst)1461 update_base_record(struct record_stat* rst)
1462 {
1463   struct record_section *sec;
1464   struct trie_node *col;
1465   FILE *fp;
1466   struct stat st;
1467 
1468   /* 一時ファイルを作ってrecordを書き出す */
1469   anthy_check_user_dir();
1470   fp = open_tmp_in_recorddir();
1471   if (!fp) {
1472     anthy_log(0, "Failed to open temporaly session file.\n");
1473     return ;
1474   }
1475   /* 各セクションに対して */
1476   for (sec = rst->section_list.next;
1477        sec; sec = sec->next) {
1478     if (!trie_first(&sec->cols)) {
1479       /*このセクションは空*/
1480       continue;
1481     }
1482     /* セクション境界の文字列 */
1483     fprintf(fp, "--- %s\n", sec->name);
1484     /* 各カラムを保存する */
1485     for (col = trie_first(&sec->cols); col;
1486 	 col = trie_next(&sec->cols, col)) {
1487       save_a_row(fp, rst, &col->row, col->dirty);
1488     }
1489   }
1490   fclose(fp);
1491 
1492   /* 本来の名前にrenameする */
1493   update_file(rst->base_fn);
1494 
1495   if (stat(rst->base_fn, &st) == 0) {
1496     rst->base_timestamp = st.st_mtime;
1497   }
1498   /* journalファイルを消す */
1499   unlink(rst->journal_fn);
1500   rst->last_update = 0;
1501 }
1502 
1503 static void
commit_del_row(struct record_stat * rst,const char * sname,struct trie_node * node)1504 commit_del_row(struct record_stat* rst,
1505 	       const char* sname, struct trie_node* node)
1506 {
1507   FILE* fp;
1508 
1509   fp = fopen(rst->journal_fn, "a");
1510   if (fp == NULL) {
1511     return;
1512   }
1513   write_string(fp, "DEL \"");
1514   write_quote_string(fp, sname);
1515   write_string(fp, "\" S\"");
1516   write_quote_xstr(fp, &node->row.key, rst->encoding);
1517   write_string(fp, "\"");
1518   write_string(fp, "\n");
1519   fclose(fp);
1520 }
1521 
1522 /*
1523  * sync_add: ADD の書き込み
1524  * sync_del_and_del: DEL の書き込みと削除
1525  *   どちらも書き込みの前に、他のプロセスによってディスク上に保存された
1526  *   更新をメモリ上に読み込む。
1527  *   このとき、データベースをフラッシュする可能性もある。データベースの
1528  *   フラッシュがあると、 cur_row と全ての xstr は無効になる。
1529  *   ただし、 cur_section の有効性は保存される。
1530  */
1531 static void
sync_add(struct record_stat * rst,struct record_section * rsc,struct trie_node * node)1532 sync_add(struct record_stat* rst, struct record_section* rsc,
1533 	 struct trie_node* node)
1534 {
1535   lock_record(rst);
1536   if (!check_base_record_uptodate(rst)) {
1537     node->dirty |= PROTECT;
1538     /* 差分ファイルだけ読む */
1539     read_journal_record(rst);
1540     node->dirty &= ~PROTECT;
1541     commit_add_row(rst, rsc->name, node);
1542   } else {
1543     /* 再読み込み */
1544     commit_add_row(rst, rsc->name, node);
1545     read_base_record(rst);
1546     read_journal_record(rst);
1547   }
1548   if (rst->last_update > FILE2_LIMIT) {
1549     update_base_record(rst);
1550   }
1551   unlock_record(rst);
1552 }
1553 
1554 static void
sync_del_and_del(struct record_stat * rst,struct record_section * rsc,struct trie_node * node)1555 sync_del_and_del(struct record_stat* rst, struct record_section* rsc,
1556 		 struct trie_node* node)
1557 {
1558   lock_record(rst);
1559   commit_del_row(rst, rsc->name, node);
1560   if (!check_base_record_uptodate(rst)) {
1561     read_base_record(rst);
1562   }
1563   read_journal_record(rst);
1564   if (rst->last_update > FILE2_LIMIT) {
1565     update_base_record(rst);
1566   }
1567   unlock_record(rst);
1568 }
1569 
1570 
1571 /*
1572  * prediction関係
1573  */
1574 
1575 static int
read_prediction_node(struct trie_node * n,struct prediction_t * predictions,int index)1576 read_prediction_node(struct trie_node *n, struct prediction_t* predictions, int index)
1577 {
1578   int i;
1579   int nr_predictions = do_get_nr_values(n);
1580   for (i = 0; i < nr_predictions; i += 2) {
1581     time_t t = do_get_nth_value(n, i);
1582     xstr* xs = do_get_nth_xstr(n, i + 1);
1583     if (t && xs) {
1584       if (predictions) {
1585 	predictions[index].timestamp = t;
1586 	predictions[index].src_str = anthy_xstr_dup(&n->row.key);
1587 	predictions[index].str = anthy_xstr_dup(xs);
1588       }
1589       ++index;
1590     }
1591   }
1592   return index;
1593 }
1594 
1595 
1596 /*
1597  * trie中をたどり、prefixがマッチしたらread_prediction_nodeを
1598  * 呼んでpredictionsの配列に結果を追加する。
1599  */
1600 static int
traverse_record_for_prediction(xstr * key,struct trie_node * n,struct prediction_t * predictions,int index)1601 traverse_record_for_prediction(xstr* key, struct trie_node *n,
1602 			       struct prediction_t* predictions, int index)
1603 {
1604   if (n->l->bit > n->bit) {
1605     index = traverse_record_for_prediction(key, n->l, predictions, index);
1606   } else {
1607     if (n->l->row.key.len != -1) {
1608       if (anthy_xstrncmp(&n->l->row.key, key, key->len) == 0) {
1609 	index = read_prediction_node(n->l, predictions, index);
1610       }
1611     }
1612   }
1613   if (n->r->bit > n->bit) {
1614     index = traverse_record_for_prediction(key, n->r, predictions, index);
1615   } else {
1616     if (n->r->row.key.len != -1) {
1617       if (anthy_xstrncmp(&n->r->row.key, key, key->len) == 0) {
1618 	index = read_prediction_node(n->r, predictions, index);
1619       }
1620     }
1621   }
1622   return index;
1623 }
1624 
1625 /*
1626  * key で探索
1627  * key の文字列長を越えるか、ノードが無くなったら探索打ち切り
1628  * trieのkeyが格納されているところでななくて葉を返す
1629  */
1630 static struct trie_node *
trie_find_for_prediction(struct trie_root * root,xstr * key)1631 trie_find_for_prediction (struct trie_root* root, xstr *key)
1632 {
1633   struct trie_node *p;
1634   struct trie_node *q;
1635 
1636   p = &root->root;
1637   q = p->l;
1638 
1639   while (p->bit < q->bit) {
1640     if (q->bit >= 2) {
1641       if ((q->bit - 2) / (int)(sizeof(xchar) << 3) >= key->len) {
1642 	break;
1643       }
1644     }
1645     p = q;
1646     q = trie_key_nth_bit(key, p->bit) ? p->r : p->l;
1647   }
1648   return p;
1649 }
1650 
1651 static int
prediction_cmp(const void * lhs,const void * rhs)1652 prediction_cmp(const void* lhs, const void* rhs)
1653 {
1654   struct prediction_t *lpre = (struct prediction_t*)lhs;
1655   struct prediction_t *rpre = (struct prediction_t*)rhs;
1656   return rpre->timestamp - lpre->timestamp;
1657 }
1658 
1659 int
anthy_traverse_record_for_prediction(xstr * key,struct prediction_t * predictions)1660 anthy_traverse_record_for_prediction(xstr* key, struct prediction_t* predictions)
1661 {
1662   struct trie_node* mark;
1663   int nr_predictions;
1664   if (anthy_select_section("PREDICTION", 0)) {
1665     return 0;
1666   }
1667 
1668   /* 指定された文字列をprefixに持つnodeを探す */
1669   mark = trie_find_for_prediction(&anthy_current_record->cur_section->cols, key);
1670   if (!mark) {
1671     return 0;
1672   }
1673   nr_predictions = traverse_record_for_prediction(key, mark, predictions, 0);
1674   if (predictions) {
1675     /* タイムスタンプで予測候補をソートする */
1676     qsort(predictions, nr_predictions, sizeof(struct prediction_t), prediction_cmp);
1677   }
1678   return nr_predictions;
1679 }
1680 
1681 /* Wrappers begin.. */
1682 int
anthy_select_section(const char * name,int flag)1683 anthy_select_section(const char *name, int flag)
1684 {
1685   struct record_stat* rst;
1686   struct record_section* rsc;
1687 
1688   rst = anthy_current_record;
1689   if (rst->row_dirty && rst->cur_section && rst->cur_row) {
1690     sync_add(rst, rst->cur_section, rst->cur_row);
1691   }
1692   rst->cur_row = NULL;
1693   rst->row_dirty = 0;
1694   rsc = do_select_section(rst, name, flag);
1695   if (!rsc) {
1696     return -1;
1697   }
1698   rst->cur_section = rsc;
1699   return 0;
1700 }
1701 
1702 int
anthy_select_row(xstr * name,int flag)1703 anthy_select_row(xstr *name, int flag)
1704 {
1705   struct record_stat* rst;
1706   struct trie_node* node;
1707 
1708   rst = anthy_current_record;
1709   if (!rst->cur_section) {
1710     return -1;
1711   }
1712   if (rst->row_dirty && rst->cur_row) {
1713     sync_add(rst, rst->cur_section, rst->cur_row);
1714     rst->row_dirty = 0;
1715   }
1716   node = do_select_row(rst->cur_section, name, flag, LRU_USED);
1717   if (!node) {
1718     return -1;
1719   }
1720   rst->cur_row = node;
1721   rst->row_dirty = flag;
1722   return 0;
1723 }
1724 
1725 int
anthy_select_longest_row(xstr * name)1726 anthy_select_longest_row(xstr *name)
1727 {
1728   struct record_stat* rst;
1729   struct trie_node* node;
1730 
1731   rst = anthy_current_record;
1732   if (!rst->cur_section)
1733     return -1;
1734 
1735   if (rst->row_dirty && rst->cur_row) {
1736     sync_add(rst, rst->cur_section, rst->cur_row);
1737     rst->row_dirty = 0;
1738   }
1739   node = do_select_longest_row(rst->cur_section, name);
1740   if (!node) {
1741     return -1;
1742   }
1743 
1744   rst->cur_row = node;
1745   rst->row_dirty = 0;
1746   return 0;
1747 }
1748 
1749 void
anthy_truncate_section(int count)1750 anthy_truncate_section(int count)
1751 {
1752   do_truncate_section(anthy_current_record, count);
1753 }
1754 
1755 void
anthy_truncate_row(int nth)1756 anthy_truncate_row(int nth)
1757 {
1758   struct trie_node *cur_row = anthy_current_record->cur_row;
1759   if (!cur_row) {
1760     return ;
1761   }
1762   do_truncate_row(cur_row, nth);
1763 
1764 }
1765 
1766 int
anthy_mark_row_used(void)1767 anthy_mark_row_used(void)
1768 {
1769   struct record_stat* rst = anthy_current_record;
1770   if (!rst->cur_row) {
1771     return -1;
1772   }
1773 
1774   do_mark_row_used(rst->cur_section, rst->cur_row);
1775   sync_add(rst, rst->cur_section, rst->cur_row);
1776   rst->row_dirty = 0;
1777   return 0;
1778 }
1779 
1780 void
anthy_set_nth_value(int nth,int val)1781 anthy_set_nth_value(int nth, int val)
1782 {
1783   struct record_stat* rst;
1784 
1785   rst = anthy_current_record;
1786   if (!rst->cur_row) {
1787     return;
1788   }
1789   do_set_nth_value(rst->cur_row, nth, val);
1790   rst->row_dirty = 1;
1791 }
1792 
1793 void
anthy_set_nth_xstr(int nth,xstr * xs)1794 anthy_set_nth_xstr(int nth, xstr *xs)
1795 {
1796   struct record_stat* rst = anthy_current_record;
1797   if (!rst->cur_row) {
1798     return;
1799   }
1800   do_set_nth_xstr(rst->cur_row, nth, xs, &rst->xstrs);
1801   rst->row_dirty = 1;
1802 }
1803 
1804 int
anthy_get_nr_values(void)1805 anthy_get_nr_values(void)
1806 {
1807   return do_get_nr_values(anthy_current_record->cur_row);
1808 }
1809 
1810 int
anthy_get_nth_value(int n)1811 anthy_get_nth_value(int n)
1812 {
1813   return do_get_nth_value(anthy_current_record->cur_row, n);
1814 }
1815 
1816 xstr *
anthy_get_nth_xstr(int n)1817 anthy_get_nth_xstr(int n)
1818 {
1819   return do_get_nth_xstr(anthy_current_record->cur_row, n);
1820 }
1821 
1822 int
anthy_select_first_row(void)1823 anthy_select_first_row(void)
1824 {
1825   struct record_stat* rst;
1826   struct trie_node* node;
1827 
1828   rst = anthy_current_record;
1829   if (!rst->cur_section)
1830     return -1;
1831 
1832   if (rst->row_dirty && rst->cur_row) {
1833     sync_add(rst, rst->cur_section, rst->cur_row);
1834     rst->row_dirty = 0;
1835   }
1836   node = do_select_first_row(rst->cur_section);
1837   if (!node) {
1838     return -1;
1839   }
1840   rst->cur_row = node;
1841   rst->row_dirty = 0;
1842   return 0;
1843 }
1844 
1845 int
anthy_select_next_row(void)1846 anthy_select_next_row(void)
1847 {
1848   struct record_stat* rst;
1849   struct trie_node* node;
1850 
1851   rst = anthy_current_record;
1852   if (!rst->cur_section || !rst->cur_row)
1853     return -1;
1854 
1855   /* sync_add() で cur_row が無効になることがあるので、
1856    * たとえ row_dirty でも sync_add() しない
1857    */
1858   rst->row_dirty = 0;
1859   node = do_select_next_row(rst->cur_section, rst->cur_row);
1860   if (!node)
1861     return -1;
1862   rst->cur_row = node;
1863   rst->row_dirty = 0;
1864   return 0;
1865 }
1866 
1867 xstr *
anthy_get_index_xstr(void)1868 anthy_get_index_xstr(void)
1869 {
1870   return do_get_index_xstr(anthy_current_record);
1871 }
1872 /*..Wrappers end*/
1873 
1874 /*
1875  * trie_row_init は何回よんでもいい
1876  */
1877 static void
trie_row_init(struct record_row * rc)1878 trie_row_init(struct record_row* rc)
1879 {
1880   rc->nr_vals = 0;
1881   rc->vals = NULL;
1882 }
1883 
1884 static void
trie_row_free(struct record_row * rc)1885 trie_row_free(struct record_row *rc)
1886 {
1887   int i;
1888   for (i = 0; i < rc->nr_vals; i++)
1889     free_val_contents(rc->vals + i);
1890   free(rc->vals);
1891   free(rc->key.str);
1892 }
1893 
1894 /* あるセクションのデータを全て解放する */
1895 static void
free_section(struct record_stat * r,struct record_section * rs)1896 free_section(struct record_stat *r, struct record_section *rs)
1897 {
1898   struct record_section *s;
1899   trie_remove_all(&rs->cols, &rs->lru_nr_used, &rs->lru_nr_sused);
1900   if (r->cur_section == rs) {
1901     r->cur_row = 0;
1902     r->cur_section = 0;
1903   }
1904   for (s = &r->section_list; s && s->next; s = s->next) {
1905     if (s->next == rs) {
1906       s->next = s->next->next;
1907     }
1908   }
1909   if (rs->name){
1910     free((void *)rs->name);
1911   }
1912   free(rs);
1913 }
1914 
1915 /* すべてのデータを解放する */
1916 static void
free_record(struct record_stat * rst)1917 free_record(struct record_stat *rst)
1918 {
1919   struct record_section *rsc;
1920   for (rsc = rst->section_list.next; rsc; ){
1921     struct record_section *tmp;
1922     tmp = rsc;
1923     rsc = rsc->next;
1924     free_section(rst, tmp);
1925   }
1926   rst->section_list.next = NULL;
1927 }
1928 
1929 void
anthy_release_section(void)1930 anthy_release_section(void)
1931 {
1932   struct record_stat* rst;
1933 
1934   rst = anthy_current_record;
1935   if (!rst->cur_section) {
1936     return ;
1937   }
1938   free_section(rst, rst->cur_section);
1939   rst->cur_section = 0;
1940 }
1941 
1942 void
anthy_release_row(void)1943 anthy_release_row(void)
1944 {
1945   struct record_stat* rst;
1946 
1947   rst = anthy_current_record;
1948   if (!rst->cur_section || !rst->cur_row) {
1949     return;
1950   }
1951 
1952   rst->row_dirty = 0;
1953   /* sync_del_and_del で削除もする */
1954   sync_del_and_del(rst, rst->cur_section, rst->cur_row);
1955   rst->cur_row = NULL;
1956 }
1957 
1958 static void
check_record_encoding(struct record_stat * rst)1959 check_record_encoding(struct record_stat *rst)
1960 {
1961   FILE *fp;
1962   if (anthy_open_file(rst->base_fn) == 0) {
1963     /* EUCの履歴ファイルがあった */
1964     anthy_close_file();
1965     return ;
1966   }
1967   fp = fopen(rst->journal_fn, "r");
1968   if (fp) {
1969     /* EUCの差分ファイルがあった */
1970     fclose(fp);
1971     return ;
1972   }
1973   rst->encoding = ANTHY_UTF8_ENCODING;
1974   strcat(rst->base_fn, ENCODING_SUFFIX);
1975   strcat(rst->journal_fn, ENCODING_SUFFIX);
1976 }
1977 
1978 static void
record_dtor(void * p)1979 record_dtor(void *p)
1980 {
1981   int dummy;
1982   struct record_stat *rst = (struct record_stat*) p;
1983   free_record(rst);
1984   if (rst->id) {
1985     free(rst->base_fn);
1986     free(rst->journal_fn);
1987   }
1988   trie_remove_all(&rst->xstrs, &dummy, &dummy);
1989 }
1990 
1991 void
anthy_reload_record(void)1992 anthy_reload_record(void)
1993 {
1994   struct stat st;
1995   struct record_stat *rst = anthy_current_record;
1996 
1997   if (stat(rst->journal_fn, &st) == 0 &&
1998       rst->journal_timestamp == st.st_mtime) {
1999     return ;
2000   }
2001 
2002   lock_record(rst);
2003   read_base_record(rst);
2004   read_journal_record(rst);
2005   unlock_record(rst);
2006 }
2007 
2008 void
anthy_init_record(void)2009 anthy_init_record(void)
2010 {
2011   record_ator = anthy_create_allocator(sizeof(struct record_stat),
2012 				       record_dtor);
2013 }
2014 
2015 static void
setup_filenames(const char * id,struct record_stat * rst)2016 setup_filenames(const char *id, struct record_stat *rst)
2017 {
2018   const char *home = anthy_conf_get_str("HOME");
2019   int base_len = strlen(home) + strlen(id) + 10;
2020 
2021   /* 基本ファイル */
2022   rst->base_fn = (char*) malloc(base_len +
2023 				strlen("/.anthy/last-record1_"));
2024   sprintf(rst->base_fn, "%s/.anthy/last-record1_%s",
2025 	  home, id);
2026   /* 差分ファイル */
2027   rst->journal_fn = (char*) malloc(base_len +
2028 				   strlen("/.anthy/last-record2_"));
2029   sprintf(rst->journal_fn, "%s/.anthy/last-record2_%s",
2030 	  home, id);
2031 }
2032 
2033 struct record_stat *
anthy_create_record(const char * id)2034 anthy_create_record(const char *id)
2035 {
2036   struct record_stat *rst;
2037 
2038   if (!id) {
2039     return NULL;
2040   }
2041 
2042   rst = anthy_smalloc(record_ator);
2043   rst->id = id;
2044   rst->section_list.next = 0;
2045   init_trie_root(&rst->xstrs);
2046   rst->cur_section = 0;
2047   rst->cur_row = 0;
2048   rst->row_dirty = 0;
2049   rst->encoding = ANTHY_EUC_JP_ENCODING;
2050 
2051   /* ファイル名の文字列を作る */
2052   setup_filenames(id, rst);
2053 
2054   rst->last_update = 0;
2055 
2056   if (!strcmp(id, ANON_ID)) {
2057     rst->is_anon = 1;
2058   } else {
2059     rst->is_anon = 0;
2060     anthy_check_user_dir();
2061   }
2062 
2063   /* ファイルから読み込む */
2064   lock_record(rst);
2065   check_record_encoding(rst);
2066   read_base_record(rst);
2067   read_journal_record(rst);
2068   unlock_record(rst);
2069 
2070   return rst;
2071 }
2072 
2073 void
anthy_release_record(struct record_stat * rs)2074 anthy_release_record(struct record_stat *rs)
2075 {
2076   anthy_sfree(record_ator, rs);
2077 }
2078