ふと、お菓子が食べたくなって、適当にあったウナギパイを食べた。
食べた直後に賞味期限を見たら、切れていることに気づき、
さらに、材料一覧を見たら「ピーナツ」の文字が・・・。
あちゃー、と思いつつ、元に戻すこともできないので、
飲み物を適当に飲んで何も見なかったことにしておいた。
おそらく、少量だから大丈夫だということにしておこう。うん。
ということで、賞味期限が極端に短いお菓子には気をつけましょう。
お菓子だと思って賞味期限が長いと思いこんでると酷いことになります・・・。
特別演習は、とりあえず、なんとかなった。
しかし、そろそろやっていかないとな。
今日になって気づいたけど、明日の数値計算法が無いようなものなので、
午前中だけの授業になるみたい。
米が無くなってきているし、少し買い物に行ってこようかな。
そういえば、今日、麻婆豆腐を作ろうと思ったら、素がないことに気づいた。
レシートを確認してみたら、確かに購入していない。
よくよく考えてみると、麻婆豆腐の素を買おうとおもって、その前に、
挽肉を一応見てこようか、と思ったきりで、忘れてしまっていた。
仕方がないので、余っている食材で適当に野菜炒めを作りました。
ニュースサイトを巡回していて気づいたんだけど、Windowsファイル共有の
SMBプロトコルとCIFSプロトコルの仕様って、ちゃんと公開されているね。
まとめて、関係するPDFをダウンロードして展開したら、400Mbyte程あった・・・。
さて、適当に本を読んで寝よう。
先ほどまでものすごく眠かったけど、宿舎に戻ってきたら眠くなくなった。
かといって、まだ設計が固まっていないので、考えながら寝た後、
6時くらいに起きてから実装しようか。。。
今日は、スポーツデーの駅伝に参加してきました。参加した皆さんお疲れ様でした。
全体としては、17チーム中、9位くらいだったはず。
自分のタイムは、4.8kmを20分30秒だったので、概ね、1kmあたり4分くらいのペース。
昼飯を食べるタイミングが良くなくて、最後にスピードを一気に上げたら、吐きそうになった。
とりあえず、疲れました・・・。
とうとうグランドファイナルが終わりました。
結果はというと、また、4位・・・。もう少しなんだけどなぁ。
来年以降は今のところは考え中。主専攻実験次第、ってところかなぁ。
来年は、パソコン載せたり、DCモータ使ったりしてみたいですね。
今まで忘れていたのだけど、実家にあるサーバのバックアップを手元に
持っていないことに気づいた。
一応、RAID構成になっているから、すぐに壊れるということは
ないだろうけど、もし、両方とも壊れたら、まずいな。
ということで、適当なノートパソコン用のバックアップを取っている
サーバにバックアップをさせることにした。
手帳に課題の締め切りとか、予定とかを書き込んでいたら、来週が酷い。
直近の予定で、特別演習があるんだけど、昨日も疲れて寝てしまって
ほとんど手がつけられていない。今日徹夜フラグですか・・・。
一応、予定としては以下のものを実装したい。
・クライアントの解放、接続周りを改良する。
・ログを読みやすく、かつ、多く出すようにする。
・Linuxでコンパイルできるようにする。
・計算範囲の分割ができるようにする。
まぁ、1日あればできなくも・・・。
コード量的には、500行から800行程度書き足せばなんとかなりそう。
今からは、スポーツデーの駅伝に出てきます。
自分の区間は、4.88km。さて、どれくらいの記録になることか。。。
いろいろと、がんばっていきましょう。
風邪・・・というより、風邪が中途半端に治った状態で、
鼻が詰まったりしているような状態。
寝て治すのが一番良いと思うのですが、あまり寝ている時間もないので、
薬を飲んで何とかしています。。。
とはいっても、結局の所、薬と疲れで、宿舎に戻ってきても
12時半頃からいつの間にか寝ていて、起きたら午前4時半、ということを
ここ数日繰り返しています。。。本末転倒な気もするけど。
明日は、ロボコンのグランドファイナルです。
今日は雨なので、試走できないな・・・。
さて、どうするか。。。
昨日、風呂(共用の大浴場)に行くときにいろいろと考え事をしていたら、
服を脱いで入る直前になってとあることに気づいた。
「あれ、シャンプーとかが無いような・・・。」
シャンプーとか入っている風呂セットを忘れた。
仕方がないので、風呂番の人に一言言って、取りに帰ったけど、
入る直前まで気づかなかったのは、最初の頃以来だなぁ。。。
まぁ、考えていた内容というのも、特に当たり障りもなく、
単純にソフトウェアの設計をどうしようか、ってずっと考えてた。
特に実害があったわけでもなく、まぁ、いいか。
日曜日につくばマラソンの試走会ということで、延々と走ってきました。
約28kmを3時間半ほどかけて走ってきたわけですが、最後の方は足に結構来てましたね。。。
おかげで、今日は全身筋肉痛でした。
試走会を終えた後は、サークルに行っていろいろとやっていた。
地磁気センサがモータから受ける磁気の影響について、実際に動かしながら検証したりしていた。
5人で1時間半ぐらいいろいろと試行錯誤したりして、なぜか、磁気の影響なのに
アースした方が良かったり、センサ部分にソースの小袋を乗っけると影響が少なくなったりとか、
よくわからないことになっていた。
今日はというと、朝からサーバの復旧作業をしたり、Mailmanをアップデートしたことに気づいて
ソースコードを修正したりとか、していた。
午後からは、サークルで使用するソフトウェアを作成していた。
GUI周りは結構使いやすいようになったと思う。
今日が断水だって事を忘れていた・・・。
忘れていたというか、断水だって事は知っていたけど、起きたのが8時50分頃で
もう既に断水が開始されているときだったという・・・。
あと、前回調べたときのものをはてなの方にアップしておきました。
Subversionのファイルシステム周りを少し調べてみた - ysibataの日記
http://d.hatena.ne.jp/ysibata/20081016
さすがに、自分でも見づらかったので。。。
以下のコードを実行すると正常に実行できません。
具体的には、ダイアログボックスが表示されずに、
すぐにエラーのダイアログが出てしまいます。
int main()
{
OPENFILENAME ofn;
char FilePath[MAX_PATH];
}
さて、どこが間違っているでしょうか?
答えは、以下の通りです。
int main()
{
OPENFILENAME ofn;
char FilePath[MAX_PATH] = "";
}
間違え探しみたいになっていますが、FilePathの初期化の部分をよく見てみましょう。
どうやら、GetOpenFileName関数の引数として渡す、OPENFILENAME構造体のlpstrFile変数には
nMaxFile以内に終端文字列のコードが無いとエラーが起きるようです。。。
全く気づかずに1時間半ぐらい無駄にしたぞ・・・。
昨日、Subversionのアップデートをしていて、リポジトリのファイルシステムのバージョン周りで
どのように互換性が保たれているのか、気になったので調べてみた。
ソースコードは以下のURLのものを使用した。
http://subversion.tigris.org/downloads/subversion-1.5.3.tar.bz2
まず、ファイルシステムにどのようにアクセスしているのか、という事を見てみる。
ファイルシステムへのアクセスは、FSFSとBDBがサポートされているため、抽象化されている。
抽象化する際には、関数ポインタの構造体を用いて抽象化を行っているようである。
(SubversionがC++を使っていれば、クラスを使って抽象化していただろう)
fs-loader.h 60行付近
/*** Top-level library vtable type ***/
typedef struct fslibraryvtablet
{
/* This field should always remain first in the vtable.
Apart from that, it can be changed however you like, since exact
version equality is required between loader and module. This policy
was weaker during 1.1.x, but only in ways which do not conflict with
this statement, now that the minor version has increased. */
const svnversiont (getversion)(void);
/* The openfs/create/openfsforrecovery/upgradefs functions are
serialized so that they may use the commonpool parameter to
allocate fs-global objects such as the bdb env cache. /
svnerrort *(create)(svnfst fs, const char *path, aprpoolt *pool,
aprpoolt *commonpool);
svnerror_t *(openfs)(svnfst *fs, const char *path, aprpoolt *pool,
aprpoolt *commonpool);
/* openforrecovery() is like open(), but used to fill in an fs pointer
that will be passed to recover(). We assume that the open() method
might not be immediately appropriate for recovery. /
svnerrort *(openfsforrecovery)(svnfst *fs, const char *path,
aprpoolt *pool,
aprpoolt *commonpool);
svnerrort (upgradefs)(svnfst *fs, const char *path, aprpoolt *pool,
aprpoolt *commonpool);
svnerrort (deletefs)(const char *path, aprpoolt *pool);
svnerrort (hotcopy)(const char *srcpath, const char destpath,
svnbooleant clean, aprpool_t *pool);
const char *(getdescription)(void);
svnerrort (recover)(svnfst *fs,
svncancelfunct cancelfunc, void *cancelbaton,
aprpoolt *pool);
/* Provider-specific functions should go here, even if they could go
in an object vtable, so that they are all kept together. /
svnerrort *(bdblogfiles)(aprarrayheadert **logfiles,
const char *path, svnbooleant onlyunused,
aprpool_t *pool);
/* This is to let the base provider implement the deprecated
svnfsparseid, which we've decided doesn't belong in the FS
API. If we change our minds and decide to add a real
svnfsparseid variant which takes an FS object, it should go
into the FS vtable. /
svnfsid_t *(parseid)(const char *data, aprsizet len,
aprpoolt *pool);
} fslibraryvtablet;
ファイルシステムごとの関数ポインタの構造体を取得するためには、
getlibraryvtable関数(fs-loader.cの200行目)を使って関数ポインタの構造体を取得する。
取得する際のキーには、svnfstype関数(fs-loader.cの217行目)からのファイルシステムタイプの情報を
使って、関数ポインタの構造体を取得している。
svnfstype関数では、リポジトリのdb/fs-typeファイル(内部的にはFSTYPEFILENAME定数でファイル名が
指定されている)の内容をそのまま返している。
次に、実際にリポジトリを開いて、詳細なバージョン情報を取得するところまでを見てみる。
先の説明でfslibraryvtablet構造体のopenfs関数からファイルシステムがオープンされる。
さらに、そのopen_fs関数は関数ポインタを保持しているだけなので、実体を探す必要がある。
ここでは、FSFSの中身を見ることとして、FSFSの関数ポインタのテーブルを以下に示す。
libsvnfsfsfs.c 314行目付近
static fslibraryvtablet libraryvtable = {
fsversion,
fscreate,
fsopen,
fsopenforrecovery,
fsupgrade,
fsdeletefs,
fshotcopy,
fsgetdescription,
svnfsfs_recover,
fslogfiles
};
このテーブルからFSFSでファイルシステムをオープンするにはfsopen関数を用いていることがわかる。
fsopen関数からは、svnfsfsopen関数が呼び出されている。
ここで、svnfsfsopen関数の中身を見てみることにする。
libsvnfsfsfs_fs.c 1000行目付近
svnerrort *
svnfsfs_open(svnfst *fs, const char *path, aprpoolt *pool)
{
fsfsdatat *ffd = fs->fsapdata;
aprfilet *uuidfile;
int format, maxfilesperdir;
char buf[APRUUIDFORMATTEDLENGTH + 2];
aprsizet limit;
fs->path = apr_pstrdup(fs->pool, path);
/* Read the FS format number. */
SVNERR(readformat(&format, &maxfilesperdir,
pathformat(fs, pool), pool));
/* Now we've got a format number no matter what. */
ffd->format = format;
ffd->maxfilesperdir = maxfilesperdir;
SVNERR(checkformat(format));
/* Read in and cache the repository uuid. */
SVNERR(svniofileopen(&uuidfile, pathuuid(fs, pool),
APRREAD | APRBUFFERED, APROSDEFAULT, pool));
limit = sizeof(buf);
SVNERR(svnioreadlengthline(uuidfile, buf, &limit, pool));
ffd->uuid = apr_pstrdup(fs->pool, buf);
SVNERR(svniofileclose(uuid_file, pool));
SVNERR(getyoungest(&(ffd->youngestrevcache), path, pool));
return SVNNOERROR;
}
この中で、readformat関数を呼び出している。
この関数がFSFSの詳細なフォーマットを取得するために用いられている関数である。
readformat関数の中では、いくつかの関数を呼び出して、PATH_FORMAT定数で与えられる
ファイル(dbformat)の中身を読み込んで、戻り値を返している。
これで、リポジトリを開いて、詳細なバージョン情報を取得するまでがわかった。
それでは、次に、最初に出ていたfslibraryvtablet構造体のopenfs関数が
どうやって呼び出されているのかを見てみる。
open_fs関数を呼び出している関数を探していくと次のようなコールグラフとなる。
openfs()
← svnfsopen(libsvnfsfs-loader.c 385行目付近)
← getrepos(libsvnrepos
epos.c 1306行目付近)
← svnreposopen(libsvn_repos
epos.c 1368行目付近)
最後のsvnreposopen関数のソースコードは次のようになっている。
svnerrort *
svnreposopen(svnrepost *reposp,
const char *path,
aprpool_t *pool)
{
/ Fetch a repository object initialized with a shared read/write
lock on the database. */
SVNERR(getrepos(repos_p, path, FALSE, FALSE, TRUE, pool));
return SVNNOERROR;
}
この中のsvnrepost変数について調べてみると、以下のような記述がある。
/* The path to the repository's top-level directory. */
char *path;
/* The path to the repository's conf directory. */
char *conf_path;
/* The path to the repository's hooks directory. */
char *hook_path;
/* The path to the repository's locks directory. */
char *lock_path;
/* The path to the Berkeley DB filesystem environment. */
char *db_path;
/* The format number of this repository. */
int format;
/* The FS backend in use within this repository. */
const char *fs_type;
/* If non-null, a list of all the capabilities the client (on the
current connection) has self-reported. Each element is a
'const char ', one of SVNRACAPABILITY_.
aprarrayheadert *clientcapabilities;
/* Maps SVNREPOSCAPABILITYfoo keys to "yes" or "no" values.
If a capability is not yet discovered, it is absent from the table.
Most likely the keys and values are constants anyway (and
sufficiently well-informed internal code may just compare against
those constants' addresses, therefore). */
aprhasht *repositorycapabilities;
};
最初の方に、repositoryオブジェクトを作成するには、svnreposopen関数か
svnreposcreate関数を呼び出す必要があるとなっている。
従って、リポジトリを開くには、svnreposopen関数を呼び出せばいいことがわかる。
以上のことをまとめると、svnreposopen関数を呼び出すと、関数の中でバージョン情報を取得したり
して、リポジトリを開くことがわかった。また、BDBとFSFSとの切り替えは、
関数テーブルを用意して、formatファイルの情報を元に使用する関数テーブルを切り替えている。
FSFSのバージョンごとの仕様の違いについては、libsvnfsfsstructureファイルに書いてある。
コード上では、以下のようにしてバージョンごとに振り分けて互換性を保つようになっている。
libsvnfsfsfs_fs.c 4803行目付近
この中のSVNFSFS_MINNOGLOBALIDSFORMAT定数は、libsvnfs_fsfs.hの中で定義されており、
バージョンの閾値を定数で保持している。
ここまでで、FSFSの互換性が保たれていることがわかる。
ここに来て、バージョンがどのように決定されるか気になってくる。次にそれを見てみる。
FSFSのバージョンが決定されるのは、もちろんファイルシステムが作成されたときであるので、
その部分を探してみるとsvnfsfs__create関数が見つかる。
libsvnfsfsfs_fs.c 5370行目付近
svnerrort *
svnfsfscreate(svnfst *fs,
const char *path,
aprpoolt *pool)
{
int format = SVNFSFSFORMATNUMBER;
fsfsdatat *ffd = fs->fsap_data;
fs->path = aprpstrdup(pool, path);
/* See if we had an explicitly requested pre-1.4- or pre-1.5-compatible. */
if (fs->config)
{
if (aprhashget(fs->config, SVNFSCONFIGPRE14COMPATIBLE,
APRHASHKEYSTRING))
format = 1;
else if (aprhashget(fs->config, SVNFSCONFIGPRE15COMPATIBLE,
APRHASHKEY_STRING))
format = 2;
}
ffd->format = format;
定数の定義は以下の通りとなっている。
つまり、「pre-1.4-compatible」と、リポジトリを作成するときに引数を
つけると、指定されたバージョンで作成されることが何となくわかる。
実際、「pre-1.4-compatible」と検索してみると、Format1の形式で作成されることが書いてある。
aprhashget関数は、APR = Apache Portable Runtimeの意味であり、そのうちのハッシュ機能が
この関数である。
この関数の使い方については、以下のページが大変参考になる。
ハッシュテーブルを使ってみる - kurukuru-papaの日記
http://d.hatena.ne.jp/kurukuru-papa/20080114/1200289172
fs->configがハッシュテーブルであり、これがどこから来るのかをたどってみる。
svnfsfs__create関数のコールグラフをたどると次のようになる。
svnfsfs_create
← fscreate(libsvnfsfsfs.c 180行目付近)
fslibraryvtablet構造体の関数テーブルをたどる
← svnfscreate(libsvnfsfs-loader.c 352行目付近)
ここまでたどってきて、fs->configに値を代入している場所がわかる。
svnfscreate関数の中でsvnfsnew関数(libsvn_fsfs-loader.c 329行目付近)を呼び出しており、
その中で以下のように代入している。
svnfst *
svnfsnew(aprhasht fsconfig, aprpoolt *pool)
{
svnfst *fs = aprpalloc(pool, sizeof(fs));
fs->pool = pool;
fs->path = NULL;
fs->warning = defaultwarningfunc;
fs->warningbaton = NULL;
fs->config = fsconfig;
fs->accessctx = NULL;
fs->vtable = NULL;
fs->fsapdata = NULL;
return fs;
}
svnfsnew関数では、単純に値を代入しているだけで、fs->configの実体を探すにはさらにたどる必要がある。
さらに、svnfscreate関数をたどると、svnreposcreate関数(libsvn_repos
epos.c)にたどり着く。
この関数の内容を以下に示す。
svnerrort *
svnreposcreate(svnrepost **reposp,
const char *path,
const char *unused1,
const char *unused2,
aprhasht *config,
aprhasht *fsconfig,
aprpoolt *pool)
{
svnrepost *repos;
svnerrort *err;
const char *root_path;
/* Allocate a repository object, filling in the format we will create. */
repos = createsvnrepost(path, pool);
repos->format = SVNREPOS_FORMATNUMBER;
/* Discover the type of the filesystem we are about to create. */
if (fsconfig)
{
repos->fstype = aprhashget(fsconfig, SVNFSCONFIGFSTYPE,
APRHASHKEYSTRING);
if (aprhashget(fsconfig, SVNFSCONFIGPRE14COMPATIBLE,
APRHASHKEYSTRING))
repos->format = SVNREPOSFORMATNUMBER_LEGACY;
}
if (! repos->fstype)
repos->fstype = DEFAULTFSTYPE;
/* Don't create a repository inside another repository. */
rootpath = svnreposfindrootpath(path, pool);
if (rootpath != NULL)
return svnerrorcreatef(SVNERRREPOSBADARGS, NULL, ("'%s' is a "
"subdirectory of an existing repository rooted "
"at '%s'"), path, rootpath);
/* Create the various files and subdirectories for the repository. */
SVNERRW(createreposstructure(repos, path, fs_config, pool),
_("Repository creation failed"));
/* Lock if needed. */
SVNERR(lockrepos(repos, FALSE, FALSE, pool));
/* Create an environment for the filesystem. /
if ((err = svnfscreate(&repos->fs, repos->dbpath, fsconfig, pool)))
{
/ If there was an error making the filesytem, e.g. unknown/supported
* filesystem type. Clean up after ourselves. Yes this is safe because
* createreposstructure will fail if the path existed before we started
* so we can't accidentally remove a directory that previously existed. */
svnerrorclear(svnioremove_dir2(path, FALSE, NULL, NULL, pool));
return err;
}
/* This repository is ready. Stamp it with a format number. */
SVNERR(svniowriteversionfile
(svnpathjoin(path, SVNREPOS__FORMAT, pool),
repos->format, pool));
*reposp = repos;
return SVNNO_ERROR;
}
よくよく見てみると、svnfsfs_create関数と同じような形をしていることに気づく。
この段階になってようやく気づいたのだが、もしかしたら、Subversionのリポジトリは、
リポジトリとファイルシステムで分離されているのかもしれない。これについては、
おそらく、設計を見てみればわかるはずだが、今回は特に気にしないことにした。
あと、SVNFSCONFIGPRE15_COMPATIBLEに関する記述がないけど、これって大丈夫なのかな・・・?
svnreposcreate関数からさらにたどって、subcommand_create関数(svnadminmain.c 520行目付近)から
呼び出されており、さらにこの関数は、以下の変数の関数ポインタに設定されていることがわかる。
(svnadminmain.c 309行目付近)
/* Array of available subcommands.
* The entire list must be terminated with an entry of nulls.
*/
static const svnoptsubcommanddesct cmdtable[] =
{
{"crashtest", subcommandcrashtest, {0}, N_
("usage: svnadmin crashtest REPOS_PATH
"
"Open the repository at REPOS_PATH, then abort, thus simulating
"
"a process that crashes while holding an open repository handle.
"),
{0} },
{"create", subcommandcreate, {0}, N
("usage: svnadmin create REPOS_PATH
"
"Create a new, empty repository at REPOSPATH.
"),
{svnadminbdbtxnnosync, svnadminbdblogkeep,
svnadminconfigdir, svnadminfs_type, svnadminpre14compatible,
svnadminpre15compatible } },
おそらく、main関数を見てみるとコマンド引数とこの変数の値を使って、
いろいろと設定しているはずである。
これ以上追うと、また複雑な部分に入ってしまうので、ここら辺でconfigの値を追うのはやめておく。
最後に、コミットをしたときにリポジトリとファイルシステムが開かれるまでを見てみる。
svnコマンドのソースコードを見ると次のような記述が見つかる。
svnmain.c 380行目付近
{ "commit", svncl_commit, {"ci"},
おそらく、svncl_commit関数がコミットのコマンドラインでの処理を行うだろう、と仮定して
これを探ってみる。
ここからソースコードをたどってコールグラフを書くと次のようなコールの手順が見つかる。
svnclcommit(svncommit-cmd.c 40行目)
→ svnclientcommit4(libsvnclientcommit.c 1348行目付近)
→ getraeditor(libsvnclientcommit.c 597行目付近)
→ svnclient_openrasessioninternal(libsvnclient
a.c 281行目付近)
→ svnraopen3(libsvnra
a_loader.c 381行目付近)
RAとはRepository Accessの意味である。
svnraopen3関数では、RAの方法をどれにするか決定する。
RAはライブラリとして格納されており、以下のように定義されている。
libsvnra
aloader.c 76行目付近
static const struct ralibdefn {
/* the name of this RA library (e.g. "neon" or "local") */
const char *ra_name;
const char * const schemes;
/ the initialization function if linked in; otherwise, NULL */
svnrainitfunct initfunc;
svnrainitfunct compatinitfunc;
} ralibraries[] = {
{
"neon",
davschemes,
},
{
"svn",
svn_schemes,
},
{
"local",
local_schemes,
},
{
"serf",
dav_schemes,
},
/* ADD NEW RA IMPLEMENTATIONS HERE (as they're written) */
/* sentinel */
{ NULL }
};
このライブラリを用いて、各スキームの値とユーザが指定したURLの形式を比較して、
どのRAを使用するか決定する。RAのライブラリには初期化関数のポインタも入っているので
それを利用して初期化処理を行う。
ここでは、ローカルアクセスのRAを使用してアクセスすると仮定して話を進めていく。
RAの方法としては、localの他にDavを使った方法などがあり、これからは抽象化されて
アクセスすることができる。このために、ファイルシステムの抽象化のときと同じように
関数テーブルが用意されていて、それを用いてアクセスするようになっている。
関数テーブルの定義は以下のようになっている。
libsvnra
aloader.h 34行目付近
/* The RA layer vtable. /
typedef struct svnravtablet {
/ This field should always remain first in the vtable. /
const svnversiont *(get_version)(void);
/* Return a short description of the RA implementation, as a localized
* string. /
const char *(get_description)(void);
/* Return a list of actual URI schemes supported by this implementation.
* The returned array is NULL-terminated. /
const char * const *(getschemes)(aprpool_t *pool);
/* Implementations of the public API functions. */
/* All fields in SESSION, except priv, have been initialized by the
time this is called. SESSION->priv may be set by this function. /
svnerrort *(opensession)(svnrasessiont session,
const char *reposURL,
const svnracallbacks2t *callbacks,
void *callbackbaton,
aprhasht *config,
aprpool_t *pool);
/ URL is guaranteed to have what getreposroot() returns as a prefix. /
svnerrort *(reparent)(svnrasession_t *session,
const char *url,
例えば、localであれば以下の関数テーブルが使用される。
libsvnra
aplugin.c 1389行目付近
static const svnravtablet ralocalvtable =
{
ralocalversion,
svnralocalgetdescription,
svnra_localgetschemes,
svnralocalopen,
svnralocalreparent,
svnralocalgetsessionurl,
svnralocalgetlatestrevnum,
svnralocalgetdatedrevision,
svnralocalchangerevprop,
svnralocalrevproplist,
svnralocalrevprop,
svnra_localgetcommiteditor,
svnralocalgetfile,
svnra_localgetdir,
svnralocalgetmergeinfo,
svnralocaldoupdate,
svnra_localdoswitch,
svnralocaldostatus,
svnralocaldodiff,
svnra_localgetlog,
svnralocaldocheckpath,
svnralocalstat,
svnralocalgetuuid,
svnralocalgetreposroot,
svnralocalgetlocations,
svnralocalgetlocationsegments,
svnralocalgetfilerevs,
svnralocallock,
svnralocalunlock,
svnralocalgetlock,
svnralocalgetlocks,
svnra_localreplay,
svnralocalhascapability,
svnra_localreplay_range
};
さて、ここまででRAが抽象化されていることがわかり、リポジトリをオープンする部分の
手前まで来ている。
再度、svnraopen3関数を読み進めていくと、関数テーブルのうちのopensession関数を呼び出している。
opensession関数は関数テーブルで抽象化されて、ローカルアクセスの場合は、
svnralocalopen関数(libsvnralocal
aplugin.c 411行目付近)となる。
svnra_localopen関数では、svnralocalsplitURL関数(libsvnralocalspliturl.c 26行目付近)を呼び出している。
svnralocalsplitURL関数の中を見ると、ようやくお目当ての関数にたどり着く。
下の方にsvnrepos_open関数があり、この関数でリポジトリを開いていることがわかる。
svnralocalsplitURL関数でリポジトリを開くというのも、なんとなく納得がいかない感じもするが
svnra_localsplit_URL関数の呼び出し元の処理を見ていると、どうもこの関数でオープンの処理を
しているようである。
長々とSubversionの一部について書いてみたけど、これで5時間近くかかった・・・。
ただ、内部構造もなんとなくわかったし、実際に運用されているもののコードを見るというのも勉強になって良い。
バージョン管理ソフトなら、実際にどのようにバージョンを保持しているのか、とか、そういうことを
調べてみるのも良かったのかもしれないが、今回は、ファイルシステムの互換性が保たれるかどうか
ということが知りたかったので、そこら辺を重点的に調べてみた。
Blogなどで誰かが書いてあるものを読んで理解するのも良いが、ソースコードが公開されているのであれば、
そのような情報を探すだけではなく、直接ソースコードを見た方が早い場合もあるだろう。
間違っている部分などありましたら、指摘していただければ幸いです。
また、日本語が書き殴ったような文章になっているのは、すいません。
時間があるときにでも、もう少しまともにまとめたいと思っています。
Subversion 1.4.4 + Trac 0.10.4の環境からSubversion 1.5.2 + Trac 0.11.1へアップデートを行った。
その他の関係する環境は以下の通り。
OS:FreeBSD 7.0
Webサーバ:Apache2.2系列
自分の環境では、アップグレードを行おうとしたところ以下のエラーが出てアップグレードができなかった。
===> Installing for neon28-0.28.3
** Command failed [exit code 1]: /usr/bin/script -qa /tmp/portupgrade.83960.0 env UPGRADETOOL=portupgrade UPGRADEPORT=subversion-1.4.41 UPGRADEPORTVER=1.4.41 make
** Fix the problem and try again.
** Listing the failed packages (-:ignored / *:skipped / !:failed)
! devel/subversion (subversion-1.4.4_1) (unknown build error)
原因としては、SubversionとTracがneonを使っているが、現状で入っているSubversionとTracに
依存しているのがneon26で、新しいバージョンに依存しているのがneon28であるため、
neon28をインストールしようとして衝突して途中でエラーが出る。
(実際にアップグレードの作業を行う前には、バックアップを取った状態で作業を行ってください)
そのため、まず、SubversionとTracをアンインストールした。
pkgdelete subversion-python-1.4.41
pkgdelete subversion-1.4.41
pkg_delete ja-trac-0.10.4
次に、neonをアンインストールする。
pkgdelete neon26-0.26.41
これでパッケージが削除されているので、次にインストールを行う。
cd /usr/ports/devel/subversion/
make WITHMODDAVSVN=YES WITHAPACHE2APR=YES WITHOUTBDB=YES
make install
cd /usr/ports/japanese/trac/
make
make install
Subversionに関しては、アップグレードに伴って、特に移行作業は必要なく、
本体のみのアップグレードで問題は起きなかった。
(FSFSのバージョンはあがっているので、それのバージョンを変更することは可能なはず。
ただ、以前のバージョンでも互換性が保たれているようなので、変更はしなかった。)
Tracは、アップグレードの作業が別途必要になる。
それぞれのTracのプロジェクトに対して、以下のコマンドを実行する。
trac-admin <プロジェクトのパス> upgrade
trac-admin <プロジェクトのパス> wiki upgrade
これを行わないと、Internal Server Error(500)が発生して、表示ができない。
(apacheのエラーログにも残っていないため、原因を特定するのに時間がかかった)
ロボコンも終わり、学園祭の出展も終わり、これで一段落かな。
ロボコンは、4位でした・・・。前日の午後5時頃からぶっ通しで
22時間ほどいろいろと調整をしたけど、結局間に合わなかった。
測域センサだけだと、やっぱり無理があるのだろうか・・・。
いや、できないことはないと思うんだけどなぁ・・・。
というか、少なくともスロープのあたりで失敗したのは、
直前の変更が問題っぽかった感じもするが。。。
まぁ、徹夜で集中力も落ちていて、もうちょっと冷静になれば
いくらでも解決方法は出てくるんだけどね。。。
学園祭の出店の方は、みなさんお疲れさんでした。
MAXコーヒープリンというものを作って売ったわけですが、
なんとか、300個完売できてよかったと思いますよ。
自分は、2日目だけ、裏方でプリンを生産していただけで
売り込みは全然していませんでしたが・・・。
一気にやることが終わると、気力も一気に抜ける。
昨日は、1.5mのLANケーブルを数本作ったり、Mercurialを
インストールしたり、数値計算法の課題を締め切りの1時間前から
はじめて終わらず、中途半端な状態で出したり、
先輩といろいろと話をしながらラーメンを食べに行ったり、そんな感じだった。
宿舎に戻ってから、一仕事しようとしたけど、気づいたら寝ていて、
起きたら朝の5時だった。起きるのも面倒なので、2度寝して、8時40分に起床。
なんとも、だらけた生活。
そういうわけで、今日からは、また別のことに注力していくとしよう。
とりあえず、2学期中に溜まっているタスクはこんな感じかな。
・つくばチャレンジ2008のソフトウェア
・つくばマラソン
・つくばロボットコンテストのグランドファイナル(これは、優先度が低い)
・情報特別演習(そろそろリポジトリの中身でも公開してもいい気がする)
・coins-admin周りで色々(特にWebメール周りをそろそろどうにかせねば)
・open-coins周りで色々(いろいろと試してみたい)
・TOEICの勉強をやる
・自分の研究も忘れずに
・WORDの記事とかその他諸々(宿舎ネットワークの話も含めて)
・積み本もどんどん消化して、そろそろ別の本の購入も。。。
・期末テストはほどほどにがんばりましょう
・ネットワーク周りの勉強もしたい
・Interfaceの付録基板のColdFireをつかっていろいろとやってみる
・さっさと自宅サーバの設定を終わらせる!
他にもいろいろとタスクがあったような気がする。
(といって、上のリストに当初は情報特別演習を書き忘れていた)
そんなこんなで、2学期後半もがんばっていきましょう。
明日から、大学の学園祭(雙峰祭)が始まる。
そして、ロボコンは明日の12時より開始。
予選は3位だったので、2回出走権があり、たぶん、6番目と最後から数番目の2回だと思う。
今日は徹夜なので、がんばていきましょう。。。
書こうと思って、後から後からと思っていると忘れてしまう。
簡単に日記を書いておく。
金曜日から土曜日にかけては、ロボコン恒例の徹夜作業。
結局、途中で前日のレポートの疲れが響いて、3時間ほど仮眠を取りました。
ロボコンの予選の結果は、3位だった。1位とはモータの差で負けるのは明白で、
2位とはアルゴリズムの差で負けてしまうのは、ある意味明白だったので、順当といえば順当。
決勝もがんばっていこう。
日曜日は、つくばチャレンジの試走会。
ロボコンの予選が終わってから急いでGPSのデータをGoogleMapに反映させるための
ソフトウェアを作った。
これについては、後からソースコードをあげようかと考え中。
割と役に立たないこともない。ただ、GPSのハードウェア自体が結構するのだけど。
月曜日。T2Kのうちの筑波大にあるものを見てきました。
ラックの中に刺さっているサーバの中身を見せてもらったり、
割と貴重なものを見せてもらえた。
Infiniband×4の構成でバス幅が足りないかと思ったら、
特注(ちょっとこれは曖昧。まぁ、要は一般の市場には出回っていない)のマザーらしい。
さて、そろそろノートのバッテリがやばい。
気が向いたら、また明日以降に書くこととしよう。
4時半に寝て7時に起床。2時間半の仮眠でした。
まぁ、なんとか起きれたわけだけど。。。
そこから、レポートをやったらなんとか終わりました。
数式を解かないといけないところもあったけど、意外とラプラス変換とか
覚えていて、すぐに解けた。
あとは、授業中に手直しして、数式の部分を書いて、図を貼り付けるだけ、と。
なんとか、実験のレポートで検討課題が残り2問の所まで書き終えた。
現在、28ページで図表番号が55までいっている。
とりあえず、明日も徹夜らしいので、ここら辺で仮眠を取っておこう・・・。
今日、昨日と起きたら9時半だったという非常事態が続いているので、気をつけないと・・・。
たまたま、今日も昨日も9時半から授業で、ほとんど支障を来さなかったが、
明日は、1時間目の8時40分からある上に、必修の電磁気だから遅刻するとまずい。
ロボットのコンデンサが爆発した訳じゃありません・・・。
ロボットの方はいたって順調で、軽くプログラム組んで、適当に
外を走らせてみたら一発で目標点まで行けましたとさ。
最初の1,2メートルの様子を見ていて「あぁ、これはいけるな」と
思って見ていたら、案の定、目標点までは行くことが出来た。
さすがに、これだけうまくいくと、昨年の悪夢がよみがえる・・・。
予選は1位だったのに、決勝、グランドファイナルとうまくいかず、
あまりよい結果ではなかった。
いくつかアルゴリズムを検証してみる必要があるだろうな。
後は、まだ、RAMに2KByte程度の空きがあるはずだから、
そこを上手く使って内部にマップを作るのも良い手だろう。
現状では、オドメトリとかプログラムレベルでの距離補正が
完了していないので、それは予選以降で考えることにしよう。
現状の目標は、無難に予選5位以内に入ること。
あと、2日だからがんばっていきましょう。
さて、コンデンサ爆発についてですが、実験のレポートを
書いていてふと思ったことです。
普段、電解コンデンサとかセラミックコンデンサとかをロボコンで
使っていて、電解コンデンサの極性を間違えた場合に爆発するとは
言うけど、実際どれくらい爆発するのか試したことがなかった。
まぁ、最近のコンデンサは爆発までいくことは珍しいとも聞くけど、
実際の所はよくわからない。
とりあえず、爆発するというのがどういうことなのか、ということで
こういう時のためのyoutubeで検索してみた。
YouTube - コンデンサ破裂実験
http://jp.youtube.com/watch?v=LZ4O6JcLQgU
YouTube - コンデンサー爆発 1
http://jp.youtube.com/watch?v=rfUsUkTe_gg
おそらく、前者は古いコンデンサを使っている感じがする。
後者は、かなり意図的にやっているよね、これ。
YouTube - 防爆弁作動!
http://jp.youtube.com/watch?v=gPim_6NOFJ4&feature=related
おそらく、普通に使っている分には、(よっぽど変な物を使わない限り)
こうなるはず。
いろいろと調べてみると、定格の電圧内であれば、防爆弁で
被害を小さくすることが出来るのかな。
今日の課題を見て、とりあえずやってみた。
Not Foundを返すのを忘れていたり、コピペしたせいで
別の関数を呼び出しているのにずっと気づかなかったりしたけど、
なんとか終わった。
ということで、今日の授業は出ません。
講義の方をさぼったのは、初めてかもしれないが・・・。
起きたら、8時25分だった。1時間目から授業なのに・・・。
どうせ、出席を取っていない授業だから、行かなくてもいいかなぁ、と
思いつつ、授業中に重要な連絡していたらどうしよう、とか考えてしまう。
なので、とりあえず、今日の講義内容を見てから考えようと思って、
ソフトウェア技法のページを見たら、こんな一文があった。
2008-09-19: 10/1 の授業は,9:30 から開始 します.
ぇー。
まぁ、何かの巡り合わせだと思って、出席しておくか。