7/21の日記では,ページの階層構造をインデックス化することで,ページ表示時の処理を軽量化しようと考えたわけだが,実際にそれに着手しはじめた.

1.インデックスの論理構造

カモランドで使っているプラグインを調べたところ,以下の情報を使っていることが判った.
  • (A) 親ページ名 → 子ページ名のリスト
  • (B) 子ページ名 → 親ページ名

そのため,これらの情報をインデックスとして持つことにする.

2.インデックスの物理構造

物理的にどうやって持たせるか?だが,性能を考えるとメモリに持つのがよい.ただ,上記の(A)の想定だとデータ構造が入れ子構造(配列のハッシュ?)になるので,それが使えるかどうかも考える必要がある.

具体的には,以下のような構造のハッシュが要るのだと思う.

  • ハッシュキー:親ページ名
  • ハッシュ値:子ページ名配列へのリファレンス

IPC::SysV共有メモリ
使ったことは無いが,ここらへんを見ると, あまり凝ったデータを持てそうな気がしないので却下.

RAMディスク上のファイル
perltieを使ってハッシュをファイルにtieすれば,プログラム上はハッシュのままで扱えるので良さそうに思ったが, ここらへんを見ると,
(ハッシュのハッシュのような)複数レベルのデータ構造をdbmファイルにtieすることは
簡単にはできません。
らしい.

それで結局,カモランドの階層構造インデックス専用に,リストのハッシュを使えるようなperltieモジュールを作ることにした. このモジュールを使って,リストのハッシュをRAMディスク上のファイルに関連づけて保持する.

3.モジュールの実装

以下のプログラムになります.基本はYukiWikiDB.pmを拝借しています.それにリストのハッシュ保持機能を追加しただけです.

これを使って,RAMディスク上にカモランドのページの階層構造インデックスを保持できるようになったので, 今後はプラグインを順次このインデックスに対応させてゆけば良かろう.

ArrayHashDB.pm

package ArrayHashDB;

use strict;

# [使用例]
#
# (1) 書き込み
#	use ArrayHashDB;
#	tie(%db, "ArrayHashDB", ".");
#	$db{'カモランド'} = [qw(自宅サーバの構築 風景写真集 OracleMaster)];
#	untie(%db);
#
# (2) 読み込み
#	use ArrayHashDB;
#	tie(%db, "ArrayHashDB", ".");
#	my(@v) = @{$db{'カモランド'}};
#	foreach (@v) {
#		print "$_\n";
#	}
#	untie(%db);
#

# Constructor
sub new {
	return shift->TIEHASH(@_);
}

# tying
#
sub TIEHASH {
	my ($class, $db_directory) = @_;
	my $self = {
		dir => $db_directory,
		keys => [],
	};
	if (not -d $self->{dir}) {
		if (!mkdir($self->{dir}, 0777)) {
			die "mkdir(" . $self->{dir} . ") fail";
		}
	}
	return bless($self, $class);
}

# Store
#	$value: (reference of Array)
#
sub STORE {
	my ($self, $key, $value) = @_;

	my $filename = &make_filename($self, $key);
	my $data = join("\n", @$value);

	open(FILE, "+< $filename") or open(FILE, "> $filename") or die "Open $filename failed: $!\n";
	flock(FILE, 2) or die "Exclusive lock failed: $!\n";
	truncate(FILE, 0);
	print FILE $data;
	close(FILE);

	return $value;
}

# Fetch
#	return: (reference of Array)
#
sub FETCH {
	my ($self, $key) = @_;
	my $filename = &make_filename($self, $key);

	open(FILE, "$filename") or return(undef);
	flock(FILE, 1) or die "Share lock failed: $!\n";
	local $/; # これがないと、1行しか読めない
	my $value = <FILE>;
	close(FILE);
	return [split(/\n/, $value)];
}

# Exists
#
sub EXISTS {
	my ($self, $key) = @_;
	my $filename = &make_filename($self, $key);
	return -e($filename);
}

# Delete
#
sub DELETE {
	my ($self, $key) = @_;
	my $filename = &make_filename($self, $key);
	unlink $filename;
	# return delete $self->{$key};
}

# データ格納ファイル名の生成
sub make_filename {
	my ($self, $key) = @_;
	my $enkey = uc(unpack("H*", $key));
	return $self->{dir} . "/$enkey.txt";
}

モジュールの制限事項
  • リストの値に改行コードは使えません.データベースファイルで改行文字を区切り文字に使っているためです


© 2024 KMIソフトウェア