My Daily Programming Life...

PersistentQueue

仕事でQueueをファイル上作る必要があってPersistentQueueクラス作った。
PopやPush、Frontとかのインターフェースをくっつけて、
インプリメンテーションはSQLiteを用いて行った。

Pushはバイト列をもらって、blob型で入れるだけ。Popはその逆の順番で出せばいい。でも、その順番を保障するために、idフィールドを入れておいた。auto_incrementになるので、いつも一番小さい値のやつを出せばいい。idは64bitもあるから、まあ、まず使い切ることはない。

このQueueには少し特別な仕様が要求されていて、あるファイルサイズを超えない範囲で追加可能というものが必要になっている。
1Byte単位で正確に指定されたファイルサイズを超えない必要はなかったので、SQLiteのPragma max_page_countを利用してサイズを制限することにした。

擬似コードはこんな感じ。
SetMaxSize( int size ){
sql = "pragma page_size";
int pagesize = GetValue( sql ); //SQLiteのページサイズ取得
int pagecount = size / pagesize;
sql = "pramga max_page_count=" + pagecount;
ExecQuery(sql); // max_page_countを設定
}

ちなみに、pagecountに0が入ると、サイズは制限されないっぽかった。

SetMaxSizeに指定されるものよりすでにファイルサイズが大きくなってしまっている場合には、それ以下にはmax_page_countの値は下がらない。でもそれからはPushできなくなるので今回の使用にはちょう
どよかった。

ただ、このままだと、Popしたときにファイルサイズがもとにもどらない。もともとSQLiteの使うファイルはレコードをdeleteしてもファイルサイズは勝手には減らない。それをするためにVACUUMというSQLを発行することが出来て、こうするとファイルのデフラグが行われる。
・・・ただ、これがかなり遅い。それなりにパフォーマンスが要求されたので、毎回PopしたときにVACUUMする訳にはいかない。
というわけで、とりあえずPop 100回に1回の割合でVACUUMを行うことにした。
ここら辺は要求される仕様と相談ですね。今回はこれでよさそう。クラスにはその値を設定できるようにはした。

SQLiteにはincremental_vacuumというのがあって、今回はそっちを利用した。
"pragma auto_vacuum = 2"として、"pragma incremental_vacuum"を実行すればいい。

0 コメント:

Post a Comment

feedSubscribe to my feed