いろいろと考え事をしていたら

昨日、風呂(共用の大浴場)に行くときにいろいろと考え事をしていたら、
服を脱いで入る直前になってとあることに気づいた。

「あれ、シャンプーとかが無いような・・・。」

シャンプーとか入っている風呂セットを忘れた。
仕方がないので、風呂番の人に一言言って、取りに帰ったけど、
入る直前まで気づかなかったのは、最初の頃以来だなぁ。。。

まぁ、考えていた内容というのも、特に当たり障りもなく、
単純にソフトウェアの設計をどうしようか、ってずっと考えてた。

特に実害があったわけでもなく、まぁ、いいか。

Posted at : 2008-10-23 07:59:08 / Category : none

マラソン

日曜日につくばマラソンの試走会ということで、延々と走ってきました。
約28kmを3時間半ほどかけて走ってきたわけですが、最後の方は足に結構来てましたね。。。
おかげで、今日は全身筋肉痛でした。

試走会を終えた後は、サークルに行っていろいろとやっていた。
地磁気センサがモータから受ける磁気の影響について、実際に動かしながら検証したりしていた。
5人で1時間半ぐらいいろいろと試行錯誤したりして、なぜか、磁気の影響なのに
アースした方が良かったり、センサ部分にソースの小袋を乗っけると影響が少なくなったりとか、
よくわからないことになっていた。

今日はというと、朝からサーバの復旧作業をしたり、Mailmanをアップデートしたことに気づいて
ソースコードを修正したりとか、していた。
午後からは、サークルで使用するソフトウェアを作成していた。
GUI周りは結構使いやすいようになったと思う。

Posted at : 2008-10-21 03:02:24 / Category : none

忘れてた

今日が断水だって事を忘れていた・・・。
忘れていたというか、断水だって事は知っていたけど、起きたのが8時50分頃で
もう既に断水が開始されているときだったという・・・。

あと、前回調べたときのものをはてなの方にアップしておきました。

Subversionのファイルシステム周りを少し調べてみた - ysibataの日記
http://d.hatena.ne.jp/ysibata/20081016

さすがに、自分でも見づらかったので。。。

Posted at : 2008-10-18 10:09:07 / Category : none

さて、問題です。

以下のコードを実行すると正常に実行できません。
具体的には、ダイアログボックスが表示されずに、
すぐにエラーのダイアログが出てしまいます。

include <windows.h>

int main()
{
OPENFILENAME ofn;
char FilePath[MAX_PATH];

}

さて、どこが間違っているでしょうか?
答えは、以下の通りです。

include <windows.h>

int main()
{
OPENFILENAME ofn;
char FilePath[MAX_PATH] = "";

}

間違え探しみたいになっていますが、FilePathの初期化の部分をよく見てみましょう。
どうやら、GetOpenFileName関数の引数として渡す、OPENFILENAME構造体のlpstrFile変数には
nMaxFile以内に終端文字列のコードが無いとエラーが起きるようです。。。

全く気づかずに1時間半ぐらい無駄にしたぞ・・・。

Posted at : 2008-10-17 01:17:05 / Category : none

Subversionのファイルシステム周りを少し調べてみた

昨日、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 svn
versiont (getversion)(void);

/* The openfs/create/openfsforrecovery/upgradefs functions are
serialized so that they may use the common
pool parameter to
allocate fs-global objects such as the bdb env cache. /
svnerrort *(
create)(svnfst fs, const char *path, aprpoolt *pool,
aprpoolt *commonpool);
svn
error_t *(
openfs)(svnfst *fs, const char *path, aprpoolt *pool,
apr
poolt *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,
apr
poolt *pool,
apr
poolt *commonpool);
svnerrort (upgradefs)(svnfst *fs, const char *path, aprpoolt *pool,
apr
poolt *commonpool);
svnerrort (deletefs)(const char *path, aprpoolt *pool);
svn
errort (hotcopy)(const char *srcpath, const char destpath,
svn
booleant clean, aprpool_t *pool);
const char *(
getdescription)(void);
svn
errort (recover)(svnfst *fs,
svn
cancelfunct 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,
apr
pool_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
svn
fsparseid variant which takes an FS object, it should go
into the FS vtable. /
svnfsid_t *(
parseid)(const char *data, aprsizet len,
apr
poolt *pool);
} fs
libraryvtablet;

ファイルシステムごとの関数ポインタの構造体を取得するためには、
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,
fs
create,
fsopen,
fs
openforrecovery,
fsupgrade,
fs
deletefs,
fs
hotcopy,
fsgetdescription,
svnfsfs_recover,
fs
logfiles
};

このテーブルからFSFSでファイルシステムをオープンするにはfsopen関数を用いていることがわかる。
fs
open関数からは、svnfsfsopen関数が呼び出されている。
ここで、svnfsfs
open関数の中身を見てみることにする。

libsvnfsfsfs_fs.c 1000行目付近

svnerrort *
svnfsfs_open(svnfst *fs, const char *path, aprpoolt *pool)
{
fs
fsdatat *ffd = fs->fsapdata;
apr
filet *uuidfile;
int format, maxfilesperdir;
char buf[APR
UUIDFORMATTEDLENGTH + 2];
aprsizet limit;

fs->path = apr_pstrdup(fs->pool, path);

/* Read the FS format number. */
SVNERR(readformat(&format, &maxfilesperdir,
path
format(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の詳細なフォーマットを取得するために用いられている関数である。
read
format関数の中では、いくつかの関数を呼び出して、PATH_FORMAT定数で与えられる
ファイル(dbformat)の中身を読み込んで、戻り値を返している。

これで、リポジトリを開いて、詳細なバージョン情報を取得するまでがわかった。
それでは、次に、最初に出ていたfslibraryvtablet構造体のopenfs関数が
どうやって呼び出されているのかを見てみる。

open_fs関数を呼び出している関数を探していくと次のようなコールグラフとなる。

openfs()
← svn
fsopen(libsvnfsfs-loader.c 385行目付近)
← getrepos(libsvnrepos
epos.c 1306行目付近)
← svnreposopen(libsvn_repos
epos.c 1368行目付近)

最後のsvnreposopen関数のソースコードは次のようになっている。

svnerrort *
svnreposopen(svnrepost *reposp,
const char *path,
apr
pool_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 Repository object, created by svnreposopen() and svnreposcreate(). / struct svnrepost { / A Subversion filesystem object. */ svnfst *fs;

/* 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). */
apr
hasht *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 = SVNFSFS
FORMATNUMBER;
fs
fsdatat *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 (apr
hashget(fs->config, SVNFSCONFIGPRE14COMPATIBLE,
APR
HASHKEYSTRING))
format = 1;
else if (aprhashget(fs->config, SVNFSCONFIGPRE15COMPATIBLE,
APRHASHKEY_STRING))
format = 2;
}
ffd->format = format;

定数の定義は以下の通りとなっている。

define SVNFSCONFIGPRE14COMPATIBLE "pre-1.4-compatible"

define SVNFSCONFIGPRE15COMPATIBLE "pre-1.5-compatible"

つまり、「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
← fs
create(libsvnfsfsfs.c 180行目付近)
fslibraryvtablet構造体の関数テーブルをたどる
← svn
fscreate(libsvnfsfs-loader.c 352行目付近)

ここまでたどってきて、fs->configに値を代入している場所がわかる。
svnfscreate関数の中でsvnfsnew関数(libsvn_fsfs-loader.c 329行目付近)を呼び出しており、
その中で以下のように代入している。

svnfst *
svnfsnew(aprhasht fsconfig, aprpoolt *pool)
{
svn
fst *fs = aprpalloc(pool, sizeof(
fs));
fs->pool = pool;
fs->path = NULL;
fs->warning = defaultwarningfunc;
fs->warningbaton = NULL;
fs->config = fs
config;
fs->accessctx = NULL;
fs->vtable = NULL;
fs->fsap
data = NULL;
return fs;
}

svnfsnew関数では、単純に値を代入しているだけで、fs->configの実体を探すにはさらにたどる必要がある。
さらに、svnfscreate関数をたどると、svnreposcreate関数(libsvn_repos
epos.c)にたどり着く。
この関数の内容を以下に示す。

svnerrort *
svnreposcreate(svnrepost **reposp,
const char *path,
const char *unused
1,
const char *unused2,
apr
hasht *config,
apr
hasht *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 = SVN
REPOS_FORMATNUMBER;

/* Discover the type of the filesystem we are about to create. */
if (fsconfig)
{
repos->fs
type = aprhashget(fsconfig, SVNFSCONFIGFSTYPE,
APR
HASHKEYSTRING);
if (aprhashget(fsconfig, SVNFSCONFIGPRE14COMPATIBLE,
APR
HASHKEYSTRING))
repos->format = SVNREPOSFORMATNUMBER_LEGACY;
}

if (! repos->fstype)
repos->fs
type = DEFAULTFSTYPE;

/* Don't create a repository inside another repository. */
rootpath = svnreposfindrootpath(path, pool);
if (root
path != NULL)
return svnerrorcreatef(SVNERRREPOSBADARGS, NULL, ("'%s' is a "
"subdirectory of an existing repository rooted "
"at '%s'"), path, root
path);

/* 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
(svn
pathjoin(path, SVNREPOS__FORMAT, pool),
repos->format, pool));

*reposp = repos;
return SVN
NO_ERROR;
}

よくよく見てみると、svnfsfs_create関数と同じような形をしていることに気づく。
この段階になってようやく気づいたのだが、もしかしたら、Subversionのリポジトリは、
リポジトリとファイルシステムで分離されているのかもしれない。これについては、
おそらく、設計を見てみればわかるはずだが、今回は特に気にしないことにした。
あと、SVN
FSCONFIGPRE15_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", subcommand
crashtest, {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.
"),
{svnadmin
bdbtxnnosync, svnadminbdblogkeep,
svnadmin
configdir, svnadminfs_type, svnadminpre14compatible,
svnadmin
pre15compatible } },

おそらく、main関数を見てみるとコマンド引数とこの変数の値を使って、
いろいろと設定しているはずである。
これ以上追うと、また複雑な部分に入ってしまうので、ここら辺でconfigの値を追うのはやめておく。

最後に、コミットをしたときにリポジトリとファイルシステムが開かれるまでを見てみる。
svnコマンドのソースコードを見ると次のような記述が見つかる。

svnmain.c 380行目付近

{ "commit", svncl_commit, {"ci"},

おそらく、svncl_commit関数がコミットのコマンドラインでの処理を行うだろう、と仮定して
これを探ってみる。
ここからソースコードをたどってコールグラフを書くと次のようなコールの手順が見つかる。

svnclcommit(svncommit-cmd.c 40行目)
→ svn
clientcommit4(libsvnclientcommit.c 1348行目付近)
→ getraeditor(libsvnclientcommit.c 597行目付近)
→ svn
client_openrasessioninternal(libsvnclient
a.c 281行目付近)
→ svn
raopen3(libsvnra
a_loader.c 381行目付近)

RAとはRepository Accessの意味である。
svnraopen3関数では、RAの方法をどれにするか決定する。
RAはライブラリとして格納されており、以下のように定義されている。

libsvnra
a
loader.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;
svn
rainitfunct compatinitfunc;
} ralibraries[] = {
{
"neon",
dav
schemes,

ifdef SVNLIBSVNCLIENTLINKSRA_NEON

endif

},

{
"svn",
svn_schemes,

ifdef SVNLIBSVNCLIENTLINKSRA_SVN

endif

},

{
"local",
local_schemes,

ifdef SVNLIBSVNCLIENTLINKSRA_LOCAL

endif

},

{
"serf",
dav_schemes,

ifdef SVNLIBSVNCLIENTLINKSRA_SERF

endif

},

/* ADD NEW RA IMPLEMENTATIONS HERE (as they're written) */

/* sentinel */
{ NULL }
};

このライブラリを用いて、各スキームの値とユーザが指定したURLの形式を比較して、
どのRAを使用するか決定する。RAのライブラリには初期化関数のポインタも入っているので
それを利用して初期化処理を行う。
ここでは、ローカルアクセスのRAを使用してアクセスすると仮定して話を進めていく。

RAの方法としては、localの他にDavを使った方法などがあり、これからは抽象化されて
アクセスすることができる。このために、ファイルシステムの抽象化のときと同じように
関数テーブルが用意されていて、それを用いてアクセスするようになっている。
関数テーブルの定義は以下のようになっている。

libsvnra
a
loader.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 svn
racallbacks2t *callbacks,
void *callbackbaton,
apr
hasht *config,
apr
pool_t *pool);
/
URL is guaranteed to have what getreposroot() returns as a prefix. /
svnerrort *(
reparent)(svnrasession_t *session,
const char *url,

例えば、localであれば以下の関数テーブルが使用される。

libsvnra
a
plugin.c 1389行目付近

static const svnravtablet ralocalvtable =
{
ralocalversion,
svnralocalgetdescription,
svn
ra_local
getschemes,
svn
ralocalopen,
svn
ralocalreparent,
svn
ralocalgetsessionurl,
svn
ralocalgetlatestrevnum,
svn
ralocalgetdatedrevision,
svn
ralocalchangerevprop,
svn
ralocalrevproplist,
svnralocalrevprop,
svn
ra_local
getcommiteditor,
svnralocalgetfile,
svn
ra_local
getdir,
svn
ralocalgetmergeinfo,
svnralocaldoupdate,
svn
ra_local
doswitch,
svn
ralocaldostatus,
svnralocaldodiff,
svn
ra_local
getlog,
svn
ralocaldocheckpath,
svn
ralocalstat,
svn
ralocalgetuuid,
svnralocalgetreposroot,
svnralocal
getlocations,
svn
ralocalgetlocationsegments,
svn
ralocalgetfilerevs,
svn
ralocallock,
svn
ralocalunlock,
svn
ralocalgetlock,
svnralocalgetlocks,
svn
ra_local
replay,
svnralocalhascapability,
svn
ra_local
replay_range
};

さて、ここまででRAが抽象化されていることがわかり、リポジトリをオープンする部分の
手前まで来ている。
再度、svnraopen3関数を読み進めていくと、関数テーブルのうちのopensession関数を呼び出している。
open
session関数は関数テーブルで抽象化されて、ローカルアクセスの場合は、
svnralocalopen関数(libsvnralocal
aplugin.c 411行目付近)となる。
svn
ra_local
open関数では、svnralocalsplitURL関数(libsvnralocalspliturl.c 26行目付近)を呼び出している。
svnralocal
splitURL関数の中を見ると、ようやくお目当ての関数にたどり着く。
下の方にsvn
repos_open関数があり、この関数でリポジトリを開いていることがわかる。

svnralocalsplitURL関数でリポジトリを開くというのも、なんとなく納得がいかない感じもするが
svn
ra_local
split_URL関数の呼び出し元の処理を見ていると、どうもこの関数でオープンの処理を
しているようである。

長々とSubversionの一部について書いてみたけど、これで5時間近くかかった・・・。
ただ、内部構造もなんとなくわかったし、実際に運用されているもののコードを見るというのも勉強になって良い。
バージョン管理ソフトなら、実際にどのようにバージョンを保持しているのか、とか、そういうことを
調べてみるのも良かったのかもしれないが、今回は、ファイルシステムの互換性が保たれるかどうか
ということが知りたかったので、そこら辺を重点的に調べてみた。
Blogなどで誰かが書いてあるものを読んで理解するのも良いが、ソースコードが公開されているのであれば、
そのような情報を探すだけではなく、直接ソースコードを見た方が早い場合もあるだろう。

間違っている部分などありましたら、指摘していただければ幸いです。
また、日本語が書き殴ったような文章になっているのは、すいません。
時間があるときにでも、もう少しまともにまとめたいと思っています。

Posted at : 2008-10-15 15:54:07 / Category : none

SubversionとTracのアップデート

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のエラーログにも残っていないため、原因を特定するのに時間がかかった)

Posted at : 2008-10-15 01:28:20 / Category : none

学園祭が終わって

ロボコンも終わり、学園祭の出展も終わり、これで一段落かな。

ロボコンは、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学期後半もがんばっていきましょう。

Posted at : 2008-10-15 00:17:39 / Category : none

学園祭

明日から、大学の学園祭(雙峰祭)が始まる。
そして、ロボコンは明日の12時より開始。
予選は3位だったので、2回出走権があり、たぶん、6番目と最後から数番目の2回だと思う。
今日は徹夜なので、がんばていきましょう。。。

Posted at : 2008-10-10 08:14:34 / Category : none

日記

書こうと思って、後から後からと思っていると忘れてしまう。
簡単に日記を書いておく。

金曜日から土曜日にかけては、ロボコン恒例の徹夜作業。
結局、途中で前日のレポートの疲れが響いて、3時間ほど仮眠を取りました。

ロボコンの予選の結果は、3位だった。1位とはモータの差で負けるのは明白で、
2位とはアルゴリズムの差で負けてしまうのは、ある意味明白だったので、順当といえば順当。
決勝もがんばっていこう。

日曜日は、つくばチャレンジの試走会。
ロボコンの予選が終わってから急いでGPSのデータをGoogleMapに反映させるための
ソフトウェアを作った。
これについては、後からソースコードをあげようかと考え中。
割と役に立たないこともない。ただ、GPSのハードウェア自体が結構するのだけど。

月曜日。T2Kのうちの筑波大にあるものを見てきました。
ラックの中に刺さっているサーバの中身を見せてもらったり、
割と貴重なものを見せてもらえた。
Infiniband×4の構成でバス幅が足りないかと思ったら、
特注(ちょっとこれは曖昧。まぁ、要は一般の市場には出回っていない)のマザーらしい。

さて、そろそろノートのバッテリがやばい。
気が向いたら、また明日以降に書くこととしよう。

Posted at : 2008-10-07 23:24:28 / Category : none

レポート大体終わった

4時半に寝て7時に起床。2時間半の仮眠でした。
まぁ、なんとか起きれたわけだけど。。。

そこから、レポートをやったらなんとか終わりました。
数式を解かないといけないところもあったけど、意外とラプラス変換とか
覚えていて、すぐに解けた。

あとは、授業中に手直しして、数式の部分を書いて、図を貼り付けるだけ、と。

Posted at : 2008-10-03 08:06:13 / Category : none

なんとか

なんとか、実験のレポートで検討課題が残り2問の所まで書き終えた。
現在、28ページで図表番号が55までいっている。
とりあえず、明日も徹夜らしいので、ここら辺で仮眠を取っておこう・・・。
今日、昨日と起きたら9時半だったという非常事態が続いているので、気をつけないと・・・。
たまたま、今日も昨日も9時半から授業で、ほとんど支障を来さなかったが、
明日は、1時間目の8時40分からある上に、必修の電磁気だから遅刻するとまずい。

Posted at : 2008-10-03 04:11:30 / Category : none

コンデンサ爆発

ロボットのコンデンサが爆発した訳じゃありません・・・。
ロボットの方はいたって順調で、軽くプログラム組んで、適当に
外を走らせてみたら一発で目標点まで行けましたとさ。
最初の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&amp;feature=related

おそらく、普通に使っている分には、(よっぽど変な物を使わない限り)
こうなるはず。

いろいろと調べてみると、定格の電圧内であれば、防爆弁で
被害を小さくすることが出来るのかな。

Posted at : 2008-10-02 05:09:22 / Category : none

終わった

今日の課題を見て、とりあえずやってみた。
Not Foundを返すのを忘れていたり、コピペしたせいで
別の関数を呼び出しているのにずっと気づかなかったりしたけど、
なんとか終わった。

ということで、今日の授業は出ません。
講義の方をさぼったのは、初めてかもしれないが・・・。

Posted at : 2008-10-01 09:52:49 / Category : none

起きたら8時25分

起きたら、8時25分だった。1時間目から授業なのに・・・。

どうせ、出席を取っていない授業だから、行かなくてもいいかなぁ、と
思いつつ、授業中に重要な連絡していたらどうしよう、とか考えてしまう。
なので、とりあえず、今日の講義内容を見てから考えようと思って、
ソフトウェア技法のページを見たら、こんな一文があった。

2008-09-19: 10/1 の授業は,9:30 から開始 します.

ぇー。

まぁ、何かの巡り合わせだと思って、出席しておくか。

Posted at : 2008-10-01 08:38:19 / Category : none

今気づいた

Math for CSの課題があることに気づいた。
いや、正確には昨晩から確かめよう、確かめようと思っていたんだけど、
別のタスクを消化していたら、それができなかった。
前回集めなかったからなぁ。。。逆に言えば、今回集める可能性はあるだろうけど。
メール書いたら、やろうか・・・。

Posted at : 2008-09-30 08:08:03 / Category : none

資料を書いていたら

委員会の資料をテキストエディタで書いて、Wordに貼り付けたら3ページ、2016文字となっていた。
単純に文章をまとめる能力が無いだけなのか、それとも、ちゃんとした内容が書かれているのか。
まぁ、もう少し体裁を整えて、文章を推敲してみましょう。現状だと、書き殴っただけなので。

今日は、寝れない気がする。というか、寝ると木曜徹夜(実験レポート)→
金曜徹夜(ロボコン予選)→土曜徹夜(つくばチャレンジのソフトウェア作成)→
日曜徹夜(情報特別演習の打ち合わせのため、ある程度のものを仕上げる必要有り)という
おぞましい状況になる。書きながらこの事実に気づいた訳だけど・・・。
金曜徹夜は恒例行事のため確定だから、いかにして他を回避するかだな。
従って、できるだけ実験のレポートを進める必要がある、と。。。

それにしても、日記を6日も書かなかったのは、4年間の中でも初めてな気がする。
(ただし、受験による3ヶ月間の空白は除く)
忙しかったのは確かだけど、死ぬほど忙しかったわけでもなく、
ネタがなかったわけでもなく、書く気がなかったわけでもなく・・・。
まぁ、結果として書いてないのだから、書く気がなかったというのが、正しいのだろう。

ということで、今日からはちゃんと再開していきます。

Posted at : 2008-09-30 01:11:56 / Category : none

とあることに気づいた

ふと、風呂場にあった体重計に乗ってみたら、体重が51kgだった・・・。
8月の終わり頃、実家から帰ってきたとき56,7kgあったと思うんだけどなぁ。。。
さすがに、50kg切ったらやばいな。

Posted at : 2008-09-24 11:45:00 / Category : none

ロボコン用プログラムの高速化 + 軽量化

ロボコン用プログラムの高速化と軽量化を実施中。

高速化は、マイコン1個で二つのセンサとモータ類を動かさないといけないので、
かなり絞り上げないときつい。
一応、マイコンのスペックは以下の通り。

SH7125(SH/Tiny)
内部クロック:50MHz(1クロック約20ns、基本命令は1クロックで実行可)、5段パイプライン
周辺クロック:25MHz(1クロック約40ns)
内蔵ROM:128KB(だったはず・・・もしかしたら、64KBかも)
内蔵RAM:8KB
(クロックの設定は、ソフトウェアで切り替えを行う)

既に、マイコン講習会で配布されたマイコン用ソフトウェアがあるので
それを手直しする形で修正を行った。
まぁ、どうせ、ロボコンに出場する人でここを見ている人は、このソフトウェアを
使うことはなさそうなので、どうすれば高速化されるか書いておく。
一応、ロボコンが終わったらサークルの方に報告しておきますかね。

手始めにAD変換の高速化をやってみた。
ハードウェアマニュアルを見ながら、AD変換の変換にかかる時間を計算。

まず、割り込みを使って常時取得するようになっていたので、これを削除。
マニュアルを見てみるとわかるんだけど、1回のスキャンで200ステート(約8μs)とか
かかるので、処理としてはかなり重たい処理になる。
(おそらく、1回のスキャンで8μsかかって、8個のAD変換ポート全部行った場合、64μsかかるはず)

連続スキャンモードで、全部のポートをスキャンする必要は無いので、シングルモードに変更して、
個々に値を取ることにした。

関数呼び出しのオーバーヘッドを気にするのであれば、一度の処理で必要なポートだけ
スキャンしてしまって、大域変数に放り込んでおいた方がいいかもしれない。
(たぶん、一回関数を呼び出すと20ステップくらいになる?
引数はないけど、ローカル変数があって、戻り値がある)

試しにinline修飾詞をつけてみた。しかし、HEW付属のコンパイラがinlineに対応していない。
設定をよくよく見てみたら、案の定、C++が使える。拡張子をcppに変えて、inline使ったら
コンパイルが通った。
「全部cppにすればいいんじゃない?」って思ったけど、C言語とC++って速度的にどうなんだろう。
自分の中では、classとか使わなければそこまで遅くならない感じもする。

次に、クロックの設定を確認。
リザーブの値が間違っていたのを修正。たぶん、間違っていても動くだろうけど。。。一応。

SCIに対してのprintf関数の調子がおかしい。
何故か、ヘッダを追加したら解決。
いや、コンパイルエラーとか特に出てなかったし、objファイルは生成されていたから
リンクされていると思ったんだけどなぁ・・・。

コンペアマッチタイマー(CMT)の1が正常に動かない。
いろいろと探っていたら、割り込みの値が設定されてないわな・・・。

AD変換のチェック機能の実装完了。とりあえず、ラインセンサのチェックはできるようになった。
後は、モータの動かし方とかを考えながら寝るとしようか。

Posted at : 2008-09-22 04:25:52 / Category : none

あーあ

モータドライバのICがご臨終されたらしい。終わった。
一度、ちゃんと動いていたのに、コネクタで接続するように
変更したら、そのときに失敗したみたいだな。。。
直接、自分が見た訳じゃないから、どのような原因が
あったのか、推測だけど。。。

状況としては、2相ステッピングモータのドライバで、
A相を出力する部分が動いていて、B相を出力する部分が
死んでいる感じがするな。
そんな中途半端な壊れ方をするのか、よくわからないけど・・・。

それで、様子がおかしくなってから4時間配線いじくり回して、
配線を疑うよりICを疑った方が早いよ、って話になって、
今日また2時間くらいかけて配線するんだろうな。

まぁ、人の配線を見るのも良い勉強だし、自分自身で配線するのも
よりよい配線をしようという気持ちになって、良いのかもしれないね。

と、書いたのが今日の午前9時頃。
午後1時頃から作業を開始したら、とんでもないことが起こった。

半田付けしていたら、ICの足の一つが基板の穴に入っていないことに気づいた。
仕方がないので、ピンセットとペンチを使っていろいろとやっていたら、
ポロッっと・・・、ICの足が根本から折れたとさ・・・。

猛烈な絶望感に襲われ、これが終わったら大学に行こうと思っていたけど、
その気さえも失われ、何もかものやる気がしなくなった・・・。

ICだって1200円もするから高いよね、とか、明日か明後日に
秋葉原へ買い出しフラグかなぁ、、、とか、いろいろと考えていた。

結局は、先輩がいくつか在庫を持っているということだったので、
売ってもらうことにした。本当に感謝。。。

とりあえず、今晩は大学に泊まり込み決定だな。

Posted at : 2008-09-21 17:08:53 / Category : none

つくばエクスプレス

asahi.com(朝日新聞社):平日32本増 つくばエクスプレス10月から通勤帯強化 - ビジネス
http://www.asahi.com/business/update/0917/TKY200809170005.html

これは、期待。具体的にどうなるかはまだよく読んでないけど。
とりあえず、複素関数論の後にでも考えてみるか。

ぁー、って、よくよく考えたら平日か・・・。
うーん、平日だとあんまり利用しないかもなぁ。

Posted at : 2008-09-18 09:26:49 / Category : none