§5-2. darktableのデータの保管場所
darktableを個人の趣味として使うのであれば普通にインストールしたままで問題はないと思います。しかし仕事で使うとなると出来ないことがあるのではないでしょうか。これはマニュアルに整理されいることではないのであくまでも個人的な見解と言うことで読んでください。(2022年1月時点でまだマニュアルも読み込んでいないので随時アップデートしたいと思います)
外部ストレージの利用と課題
ストレージが足りない!
まず最初に出くわす問題はおそらく「ストレージが足りない!」か「ノートPCが壊れて写真が消えてしまった!」という事ではないでしょうか?もう、後者は目も当てられません。ちなみに現在私のメインのdarktableには
写真枚数 約20000枚(ここ4年ぐらいの写真、重複あり)
フィルムロールサイズ 320GB(サイドカーファイル含む)
DBのサイズ data.dbが約300MB、library.dbが約1.1GB
これならこの前1TBのSSDに変えた僕のLaptopならば問題はありません。ただ標準のSSDは512GBですから320GBを写真で専有してしまうとすこし窮屈ですね。このようにデスクトップやノートPCで単体で使っていると写真でディスクがいっぱいになってしまいます。特に仕事で使われるとなるとその量は個人の比ではないと思います。そうなると外部ストレージで写真を保管したいと言うことになると思います。外部ストレージにもいくつか種類があります。
USBの外付けディスク
NAS(自宅および社内)
クラウドサービス
1は特に問題はないでしょう。2に関しては僕が普段の写真の管理フォルダーとしてNAS(Linuxでのsshのファイル共有)を利用していますので問題はありません。darktableのドキュメントでも1や2の利用は想定されています。3はクラウドサービスの種類によると思います。最低でもファイルシステムとして認識できるサービスであれば問題ないでしょう。そういう意味ではWindows+OneDriveは問題なく利用できると思います。クラウドサービスでもWebブラウザーでしかアクセスできないようなものは利用するのは難しいでしょう。
またdarktableが想定している外部ストレージはフィルムロールつまり写真を置く場所のみだと思います。概要で少し触れたdarktableのデータベースを保存する場所は各PCのローカルディスクを想定していると思われます。
外部ストレージを使う課題
外部ストレージを使うことで、特にlaptopのストレージの容量の制限という課題からは開放されましたが、新たな問題が発生します。それは外出先で使うために外部ストレージを持ち運ぶ必要があると言うことです。しかしこれは非現実的です。
こんなストレージ持ち歩けますか?
usbとメモリや小さいssdもありますが、サイズには制限がありますし、万が一紛失した場合など…、考えたくないですね。
そこでdarktableはフィルムロールを保存している場所を外部ストレージにして、外部ストレージがないところでも使えるようにするcacheという機能があります。これは一時的に外部ストレージの写真データをローカルのストレージに複製して外部ストレージがなくても作業ができるようにする機能です。しかしCacheにコピーされるのはあくまでも写真データとサイドカー(xmpファイル)です。DBはローカルのストレージにある必要があります。
データベースは共有できるのか?
darktableはsqliteというリレーショナルを使っています。これは他のリレーショナルDBと違い複数のユーザからの書き込み処理が出来ません。一般的なOracleとかMySQL、PosgreSqlなど複数のユーザからの処理が大前提となり、その上でデータの一元性を保証するために多くの技術が使われています。SQLiteは基本1データベースは複数からの読み込み処理は許可しても書き込み処理は許可しません。読み込み処理にしても、気をつけないとと作業途中にデータベースがアップデートされたら内容の保証ができるかわかりません。つまりdarktabeが持つ2つのデータベースdata.dbとlibrary.dbが複数からの利用の妨げになりそうです。
darktableのユースケース
ひとりだけど複数のPCで利用する
僕はまさにこの環境になります。darktableはDesktop Linuxとlaptop Linuxあと一応Macにも入っておりNAS(sshによるファイル共有)で利用しています。この場合DBもNAS上において利用しています。おそらくDBをNASにおいて複数のPCで共有することは正式には推奨されない方法になります。darktableのDBは前述したSQLiteの制限を受けるためです。そのため複数のPCで同時にdarktableを起動して変更した場合、DBが壊れる恐れがあります。僕は一人で利用してかつ同時に起動しないようにしているので、今の所問題は出ていません。
複数のユーザーで共同作業をすることはできない?
会社で本格的にdarktableを使おうとすると必要になるのではないかと思います。複数のPCで使えるなら、複数のユーザでも使えるのか?おそらく無理だと思われます。例えば
AさんとBさんが同じ写真を加工している。
AさんとBさんが同じフィルムロールの写真を修正している
AさんとBさんが同じタグを別々につけてしまった
などなど、対応できそうにないシナリオがあります。僕もdarktableの勉強を始めたばかりなので本当は「こんなやり方でできる」というのがあるかもしれませんが、今の所難しいのではと思います。前述したように写真ファイルはNASのストレージに入れて共有はできてもDBを共有する方法がないからです。DBをそれぞれのユーザのローカルストレージに入れて使うことはできると思うのですが、タグや加工情報をどこまで共有できるか難しいと思います。また2から3にんであれば問題ないとかもしれませんが、人数が多くなればなるほどSQLiteでは多くの読み込み/書き込みトランザクションを正しく処理するのは難しいと思います。ただ、共同作業は難しいかもしれませんが、分担作業はできるかもしれません。
これから考えたいこと
複数の異なる環境を利用する
この方法が会社で使う場合には良いのではないかと思います。一台一台darktableをインストールしてフィルムロールを一部共有しながら利用するということです。
仕事ですからうまく作業を分担すればできるかもしれません。例えば
カメラマンが撮影をし、darktableに写真を登録し、よく撮れた写真の選択までを行う。
選択された写真のレタッチの修正はアシスタントが別のPCで行う。
ということであればフィルムロールの共有で、データベースは共有しなくて実現ができるかもしれません。ただこの場合もそれぞれのDBの内容はシンクロしませんから、うまく仕事ができるようにメンテナンスなどは必要になると思います。
今のところdarktableを入れただけではこれができるかまだわかりません。すこし調べてまとめていきたいと思います。
僕も個人的に管理しているデータとnoteを書くためのデータを分けていて、別々のdarktableの環境を作って、使い分けています。キャッシュを使うのもお手頃ですが、異なる環境感でのデータのやり取りができれば、こちらの方がスケーラビリティーも維持できていいのではないかと思います。
SQLiteから他のリレーショナルDBに変更できるか?
SQLiteの実装はとても簡単です。そこから他のフリーのリレーショナルDBに切り替えるとなるとプログラムの修正が必要になります。またリレーショナルデータベースを変えたから問題ないかと言うことでもないと思います。もともと一人利用を考え作られているとするとトランザクションの設計から見直す必要もありそうです。パフォーマンスも問題になりますし、クライアント・サーバにした場合、Laptopにいれてオフラインで使いたいなど、持ち運ぶ場合に大きな課題になりそうです。
僕自身現在darktableのコードを読み解く自身はありません。楽しそうですが。
データベースの中身
data.dbのSchema
CREATE TABLE db_info (key VARCHAR PRIMARY KEY, value VARCHAR);
CREATE TABLE tags (id INTEGER PRIMARY KEY, name VARCHAR, synonyms VARCHAR, flags INTEGER);
CREATE TABLE styles (id INTEGER PRIMARY KEY, name VARCHAR, description VARCHAR, iop_list VARCHAR);
CREATE TABLE style_items (styleid INTEGER, num INTEGER, module INTEGER, operation VARCHAR(256), op_params BLOB, enabled INTEGER, blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256));
CREATE TABLE presets (name VARCHAR, description VARCHAR, operation VARCHAR, op_version INTEGER, op_params BLOB, enabled INTEGER, blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256), model VARCHAR, maker VARCHAR, lens VARCHAR, iso_min REAL, iso_max REAL, exposure_min REAL, exposure_max REAL, aperture_min REAL, aperture_max REAL, focal_length_min REAL, focal_length_max REAL, writeprotect INTEGER, autoapply INTEGER, filter INTEGER, def INTEGER, format INTEGER);
CREATE TABLE locations (tagid INTEGER PRIMARY KEY, type INTEGER, longitude REAL, latitude REAL, delta1 REAL, delta2 REAL, ratio FLOAT, polygons BLOB, FOREIGN KEY(tagid) REFERENCES tags(id));
Library.dbのSchema
CREATE TABLE db_info (key VARCHAR PRIMARY KEY, value VARCHAR);
CREATE TABLE film_rolls (id INTEGER PRIMARY KEY, access_timestamp INTEGER, folder VARCHAR(1024) NOT NULL);
CREATE TABLE images (id INTEGER PRIMARY KEY AUTOINCREMENT, group_id INTEGER, film_id INTEGER, width INTEGER, height INTEGER, filename VARCHAR, maker VARCHAR, model VARCHAR, lens VARCHAR, exposure REAL, aperture REAL, iso REAL, focal_length REAL, focus_distance REAL, datetime_taken CHAR(20), flags INTEGER, output_width INTEGER, output_height INTEGER, crop REAL, raw_parameters INTEGER, raw_denoise_threshold REAL, raw_auto_bright_threshold REAL, raw_black INTEGER, raw_maximum INTEGER, license VARCHAR, sha1sum CHAR(40), orientation INTEGER, histogram BLOB, lightmap BLOB, longitude REAL, latitude REAL, altitude REAL, color_matrix BLOB, colorspace INTEGER, version INTEGER, max_version INTEGER, write_timestamp INTEGER, history_end INTEGER, position INTEGER, aspect_ratio REAL, exposure_bias REAL, import_timestamp INTEGER DEFAULT -1, change_timestamp INTEGER DEFAULT -1, export_timestamp INTEGER DEFAULT -1, print_timestamp INTEGER DEFAULT -1, FOREIGN KEY(film_id) REFERENCES film_rolls(id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY(group_id) REFERENCES images(id) ON DELETE RESTRICT ON UPDATE CASCADE);
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE selected_images (imgid INTEGER PRIMARY KEY);
CREATE TABLE history (imgid INTEGER, num INTEGER, module INTEGER, operation VARCHAR(256), op_params BLOB, enabled INTEGER, blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256), FOREIGN KEY(imgid) REFERENCES images(id) ON UPDATE CASCADE ON DELETE CASCADE);
CREATE TABLE masks_history (imgid INTEGER, num INTEGER, formid INTEGER, form INTEGER, name VARCHAR(256), version INTEGER, points BLOB, points_count INTEGER, source BLOB, FOREIGN KEY(imgid) REFERENCES images(id) ON UPDATE CASCADE ON DELETE CASCADE);
CREATE TABLE tagged_images (imgid INTEGER, tagid INTEGER, position INTEGER, PRIMARY KEY (imgid, tagid),FOREIGN KEY(imgid) REFERENCES images(id) ON UPDATE CASCADE ON DELETE CASCADE);
CREATE TABLE color_labels (imgid INTEGER, color INTEGER);
CREATE TABLE meta_data (id INTEGER, key INTEGER, value VARCHAR);
CREATE TABLE module_order (imgid INTEGER PRIMARY KEY, version INTEGER, iop_list VARCHAR);
CREATE TABLE history_hash (imgid INTEGER PRIMARY KEY, basic_hash BLOB, auto_hash BLOB, current_hash BLOB, mipmap_hash BLOB, FOREIGN KEY(imgid) REFERENCES images(id) ON UPDATE CASCADE ON DELETE CASCADE);
CREATE INDEX images_datetime_taken_nc ON images (datetime_taken COLLATE NOCASE);
CREATE TABLE sqlite_stat1(tbl,idx,stat);
CREATE TABLE legacy_presets (name varchar, description varchar, operation varchar, op_version integer, op_params blob, enabled integer, blendop_params blob, blendop_version integer, multi_priority integer, multi_name varchar, model varchar, maker varchar, lens varchar, iso_min real, iso_max real, exposure_min real, exposure_max real, aperture_min real, aperture_max real, focal_length_min real, focal_length_max real, writeprotect integer, autoapply integer, filter integer, def integer, format integer);
追記
2022年1月2日の時点で自由に思うままに書きましたが、ひょっとしたら僕が知らないだけでなにか良い方法がdarktableにあるのかもしれません。調べたら改修したいと思います。
Adobeのlightroomとかなら複数での共同作業なんてできるのでしょうかね〜。