文書管理システムにおける文書の管理構造
前置き
タイトルから早速、「文書」とか「文書管理システム」とか「管理構造」とかなんだろうという疑問が(自分の中でも(待て))湧いてきそうなのでその辺の整理から。
- 「文書」と言っているのは、WindowsやUNIX/Linuxにおける「ディレクトリやファイル」であったり、ブログサイトにおける「記事」であったり、(Web)メールシステムにおける「メール」であったり、といったもののこと。データベースレベルまで落とし込むと、たとえばRDBMSにおけるレコードであったり(もちろん、データの持ち方によっては複数のレコードにまたがっていたり、レコードというくくりでは表せない場合もあるだろうが)。
- 「文書管理システム」というのは、「文書」を何らかの形で保持、管理しているもので、各種OSなどで使用される「ファイルシステム」であったり、「ブログサイト」であったり、「(Web)メールシステム」や「メーラー」であったり、DBMSであったり、といったもののこと。
- 「管理構造」というのは、たとえば「ファイルシステム」が「ディレクトリに子ディレクトリ/子ファイルを保持することで階層を形成」していたり、「ブログサイト」が「記事と作成者の関係や記事につけられたタグを管理することで記事の分類分け」をしていたり、そういった「文書」の管理に使用しているデータ構造のこと。
まぁ、厳密に定義することが目的ではなく、自分がふと考えたことをダンプすることが目的なので、この辺にしておく。
はじめに
前置きが長くなったが、数年前に某文書管理システム(と自分は思っていたもの(何))があり、ざっくり分類すると階層構造で文書を管理するものなのだが、ルートからある文書にたどり着くためのパスが複数あるような構造。それに対して、「実パスがどうこう‥」という話をされて『実も虚もないような‥』というモヤっとした思いを抱きながら今まで過ごしてきたらしい。
それが、ここのところLinuxに触れる機会が再増(何)したためか、何かに気づいたらしい。
UNIX/Linuxのファイルシステム
UNIX/Linuxのファイルシステムにおいて、以下のようなディレクトリ/ファイル構造があるとする。(以下は「find / -exec ls -ld {} \;」の結果を簡略化したものと考えてもらえれば‥)
drwxr-xr-x / drwxr-xr-x /hoge drwxr-xr-x /hoge/foo drwxr-xr-x /hoge/foo/bar -rw-r--r-- /hoge/foo/bar/hoge.txt -rw-r--r-- /hoge/foo/bar/foo.txt drwxr-xr-x /hoge/fuga
ここで、以下のコマンドを実行してみる。
cd /hoge/fuga ln ../foo/bar/hoge.txt hoge.txt ln -s ../foo/bar/foo.txt foo.txt
すると、構造は以下のようになる。
drwxr-xr-x / drwxr-xr-x /hoge drwxr-xr-x /hoge/foo drwxr-xr-x /hoge/foo/bar -rw-r--r-- /hoge/foo/bar/hoge.txt -rw-r--r-- /hoge/foo/bar/foo.txt drwxr-xr-x /hoge/fuga -rw-r--r-- /hoge/fuga/hoge.txt lrwxrwxrwx /hoge/fuga/foo.txt -> ../foo/bar/foo.txt
ハードリンク型
上記のhoge.txtは、「/hoge/foo/bar/hoge.txt」と「/hoge/fuga/hoge.txt」という2つが存在するように見えるが、実体は同じである。もちろん「rm /hoge/foo/bar/hoge.txt」としても、hoge.txt自体は削除はされない(「/hoge/fuga/hoge.txt」で参照できるため)。
なので、「/hoge/foo/bar/hoge.txt」と「/hoge/fuga/hoge.txt」のどちらが実パスなのかを論じるのは無意味である。だって区別できないもの。(せいぜい、各親ディレクトリの更新日時が異なるくらい)
RDB上で表現するとしたら以下のような感じか。
<documents> +----+----------+------------+--------------------+ | id | name | type | contents | +----+----------+------------+--------------------+ | 0 | / | directory | -- | | 1 | hoge | directory | -- | | 2 | foo | directory | -- | | 3 | bar | directory | -- | | 4 | hoge.txt | file | HOGE.TXT | | 5 | foo.txt | file | FOO.TXT | | 6 | fuga | directory | -- | | 7 | foo.txt | sym-link | ../foo/bar/foo.txt | +----+----------+------------+--------------------+ <parents> +----+----------+ | id | child_id | +----+----------+ | 0 | 1 | | 1 | 2 | | 1 | 6 | | 2 | 3 | | 3 | 4 | | 3 | 5 | | 6 | 4 | | 6 | 7 | +----+----------+
「rm /hoge/foo/bar/hoge.txt」という操作は、
先に書いた「数年前に某文書管理システム(と自分は思っていたもの(何))」というのは、正にこのデータ構造を採用していた。
シンボリックリンク型
上記のfoo.txtは、「/hoge/foo/bar/foo.txt」と「/hoge/fuga/foo.txt」の2つのパスを持ち、hoge.txtと同様に見えるが、hoge.txtの場合とは微妙に異なる。それは「rm /hoge/foo/bar/foo.txt」をしたときに、foo.txtの実体が存在しなくなるという点。hoge.txtの場合と違って、「/hoge/fuga/foo.txt」は単なるタグとかラベルとかいうものに過ぎない。
この場合は、どっちが実パスなのかについて論じる意味が出てくる。
先のRDBで表した例でいうと、「rm /hoge/foo/bar/foo.txt」で{3, 5}というレコードが削除されると、id=5(foo.txt)を子として持つディレクトリがいなくなるので、
「/hoge/fuga/foo.txt」が指すものがなくなり、ゴミとなってしまうわけだが、ゴミ処理をちゃんとやろうと思ったら以下のようなテーブルを追加することになるだろうか。
<sym_links> +----+-----------+ | id | target_id | +----+-----------+ | 7 | 5 | +----+-----------+
ただ、注意したいのは、UNIX/Linuxにおけるファイルシステムではここまでは管理していないということ。それは「mv /hoge/fuga /」を実行したときに分かるが、「/fuga/foo.txt」(元 /hoge/fuga/foo.txt)が指すのは「/fuga/../foo/bar/foo.txt」であり、「/hoge/foo/bar/foo.txt」ではない。
ちなみに、ブログサイトやソーシャルブックマークなどにおける「タグ」は階層のないシンボリックリンク型であると言えるのではないだろうか。
終わりに
「はじめに」で書いたケースでは、結局のところ上記のハードリンク型とシンボリックリンク型の2つをちゃんと区別した作り/使い方になっていなかったために起こった問題のような気がする。(というのは当時もなんとなく言っていたような気がするが‥)