Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use Deno.Kv to create a database of dictionaries #170

Merged
merged 11 commits into from
Dec 28, 2023

Conversation

uga-rosa
Copy link
Member

話題のDeno KV (組み込み key-value database) を使って辞書をデータベース化します。
config.databasePath から有効化できます。

@uga-rosa uga-rosa force-pushed the database branch 4 times, most recently from bce0fa1 to a1410a0 Compare December 25, 2023 15:12
@uga-rosa uga-rosa marked this pull request as ready for review December 25, 2023 15:16
@uga-rosa uga-rosa requested review from kuuote and Shougo and removed request for kuuote December 25, 2023 23:59
@tani
Copy link
Contributor

tani commented Dec 27, 2023

興味深い機能追加だと思います。
実装がアドホックになっているため、設計を再検討しリファクタリングする余地がありそうです。
まず確認ですが、この変更の意図は、DenoKVをキャッシュDBに使うということですね。

今の実装は以下の順番になっています。

  • (1) データベースパスが設定されているなら、
  • (2) データベースを初期化し、
  • (3) 通常通り辞書を読み込み、
  • (4) データベースにキャッシュする
  • (3-4*) もじ既に格納されているなら読み込みがスキップする。
    これは、元実装 (3)に (1,2,4)をラップする事で実現しています。

私の懸念は、本来パスの設定と、機能の有効化/無効化は直交する操作であるのに、パスの設定から暗黙に機能が有効化されてしまうことです。

また設計についても懸念があります。
Deno KVは、インメモリ型とファイル型の2つがあったはずです。(ですよね?)
つまりDenoKVを有効化すること自体はデフォルト化しても良く、
キャッシュする(ファイルに保存する)ことの有無のみを
切り替える実装にするほうが全体の見通しが立ちそうです。

今は、Map()を使うか、DenoKVを使うかということで、Mapの機能とDenoKVの機能に重複があり、
コードが複雑化しているように思えます。

もし不正確なところがありましたら、指摘していただければ幸いです。

@Shougo
Copy link
Contributor

Shougo commented Dec 27, 2023

私の懸念は、本来パスの設定と、機能の有効化/無効化は直交する操作であるのに、パスの設定から暗黙に機能が有効化されてしまうことです。

デフォルトのパスをプラグインがわできめられなかったので、こういう実装になったと理解しています

@uga-rosa
Copy link
Member Author

uga-rosa commented Dec 27, 2023

インメモリなDeno KVを使う場合、現状のMapを使った実装よりも初期化が遅くなってしまいます(手元では200 ms -> 1300 msほどの変化)。重複はありますが仕方ないのかなと

@tani
Copy link
Contributor

tani commented Dec 27, 2023

  • DenoKV版: 初回は遅いが、2回目以降は高速に起動
  • 従来版: 初回は(相対的に)高速だが、2回目以降も同様の速度で起動

という状態なのですね。

@uga-rosa
Copy link
Member Author

uga-rosa commented Dec 27, 2023

そうですね。巨大な辞書を使っており現在の起動時間に不満のある人にとっては良い選択肢になるはずです。
常にDeno.Kvを使うように実装を整理してみたものを別ブランチにpushしておきました。気になるようでしたら試してみてください。console.logでかかった時間を吐きます。
https://github.com/uga-rosa/skkeleton/tree/database-as-default

@kuuote
Copy link
Member

kuuote commented Dec 27, 2023

データベースへの変換がすごく遅いのでインメモリの有効化はしない方がいいと思います

@kuuote
Copy link
Member

kuuote commented Dec 27, 2023

このPRでやるべきかは不明ですが、事前に変換する方式で辞書形式の1つにしてしまうのもありかもですね

@tani
Copy link
Contributor

tani commented Dec 27, 2023

JISYO(新辞書形式)でも変換済みのDBが配布できるか検討してみます。
その場合, タイムスタンプで比較するのは不味いかもれません。

あと、複数辞書対応は出来ていますかね?ちょっとコードリーディングでできておらず...

@uga-rosa uga-rosa force-pushed the database branch 2 times, most recently from 0a214ff to 3f60b54 Compare December 27, 2023 05:30
@uga-rosa
Copy link
Member Author

データベースは単独のファイルですが、keyの中にpathを入れることで辞書ごとに候補を管理できるようにしています。また、各辞書のmtimeも保存しているので、辞書それぞれの更新を検知して再構築を行います。

@uga-rosa
Copy link
Member Author

jisyo/deno_kv.ts を分離し、コミットを整理しました。

@Shougo
Copy link
Contributor

Shougo commented Dec 27, 2023

試しました。確かに初回だけ DB 作成に時間がかかりますが、あとは問題なさそう

@Shougo
Copy link
Contributor

Shougo commented Dec 27, 2023

今は、Map()を使うか、DenoKVを使うかということで、Mapの機能とDenoKVの機能に重複があり、
コードが複雑化しているように思えます。

実装の重複とは skk_dictionary.ts と deno_kv.ts のことでしょうか?
jisyo についてはいつか実装を分離したいので重複は問題ないと思います。

@uga-rosa
Copy link
Member Author

データベースを手動で更新するためのAPIを追加しました

@uga-rosa
Copy link
Member Author

uga-rosa commented Dec 27, 2023

一つバグ見つけたので少し待ってください。kv.list はこの書き方だと完全一致の補完候補が取れないらしい
Deno.Kvのバグっぽい気もするけどどうしようかなこれ

@uga-rosa
Copy link
Member Author

denoland/deno#21711
これです。とりあえず今動くコードをpushしました。

@uga-rosa
Copy link
Member Author

テストも入れて通ってるので明日の夜まで特に指摘なければそのままマージします。

@uga-rosa
Copy link
Member Author

uga-rosa commented Dec 28, 2023

https://github.com/denoland/denokv/blob/a5ae69f1dd58283ae124771e0d136a6b1815d7a5/proto/codec.rs#L36

Deno.AtomicOperation を使うとき、total key size が 81920 バイトを越えてコミットするとエラーが出ます。key は TypeScript のレイヤーでは Deno.KvKey ですが、Rust のレイヤーで u8 のバイト列に変換されます。この際、要素ごとに元の型を特定するための識別子や末尾に区切りの 0x00 が追加されます。

今回使う文字列の場合で説明すると

  1. 配列の各要素に対して文字列であることの識別子 0x02 から開始
  2. 各要素の文字列をバイト列に変換し、0x000xFF でエスケープ
  3. 末尾に 0x00 を追加

となるので、['a', 'bc']0x02 0x61 0x00 0x02 0x62 0x63 0x00 の7バイトになります。

また、mutation 自体の回数が 1000 を越えるとそれもエラーが出ます。これらの条件から IO が発生する this.#atm.commit() の回数を最小化しています。

@uga-rosa uga-rosa merged commit 6021153 into vim-skk:main Dec 28, 2023
2 checks passed
@uga-rosa uga-rosa deleted the database branch December 28, 2023 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants