ぽにょろん

思いついたこととメモ

2015年の振り返り

良い機会なので今年を振り返っておきます。

目次

ブログ始めました

一念発起して、ブログ始めてみました。
最初の頃は何とか更新していたのですが、年末に向かうにしたがって更新をサボってしまった(笑)

ただ、仕事やプライベートでやったことを纏めるのに改めて調べ直したり、サンプル書いたりして
かなり勉強になりました。

仕事

暗黒の炎上プロジェクトを続けたせいで、色々と消耗した一年でした。
得るものが少なく残業代を稼ぐだけの仕事でしたが、なんとかリリースできてよかったです。

退職します

というわけで、2015年12月31日付で現職を退職します。
来年からは取りあえず無職ということになりますが、人生頑張ります。

来年

メモだけでなくて、勉強会の参加レポやその他についても記事書いていけたらなと思っています。
少し(??)ゆっくりしたら再就職活動頑張ります。

c#からFirebirdのDBにアクセスした後、Exeの終了が遅い。その2。

Firebird Embeddedを使用した後、プロセスの終了が遅い件ですが、
その後色々調べたところ、似たような件で悩んでいる人はいるようでした。

stackoverflow.com

ただ、解決にはいたっていないようです。
試しに FbConnection.ClearAllPools() がどれくらい効果あるのか試してみました。

結論から言えば、ConnectionをPoolしているときはそれなりに効果ありますが、
やはり3秒は超えられない。
なにかのタイムアウト待ちなのか、どうなのか。

環境

  • Firebird Embedded 2.5.4
  • FirebirdSql.Data.FirebirdClient 4.8.0

検証

前回利用したものの最後に、ClearAllPools と Connection作る時にPooling を true にする処理を追加。

static void Main()
{
    var i = 0;
    var max = 2000;
    while (i < max)
    {
        var connectionBuilder = new FbConnectionStringBuilder();
        //.....諸々
        connectionBuilder.Pooling = true;
        using (var connection = new FbConnection(connectionBuilder.ConnectionString))
        {
            connection.Open();
            connection.Close();
        }
        i++;
    }
    FbConnection.ClearAllPools();
}

FbConnection.ClearAllPools() を呼ぶ場合と呼ばない場合の2種類を用意して、時間計測。

f:id:kowill:20151012230435p:plain

FirebirdClient2 : FbConnection.ClearAllPools()を呼ぶ方。
FirebirdClient : FbConnection.ClearAllPools()を呼ばない方。

あまり厳密ではないですが、手元で何度かやってみたけど、結果は変わらず。

c#からFirebirdのDBにアクセスした後、Exeの終了が遅い

c#からFirebirdのDBにアクセスした後のExeの終了が遅いということがありまして、少し調べてみました。

結論が正しいのかわかりませんがメモとして残しておきます。
※検証甘いです。

環境

  • Firebird Embedded 2.5.4
  • FirebirdSql.Data.FirebirdClient 4.8.0

現象

諸事情で、A.exe → B.exe といった呼び出しが複数回あるようなアプリ構造がありました。
B.exeの終了が遅いので、全体の処理がとても緩慢な感じに。
ということで、ミニマムコードを。

static void Main()
{
    using (var connection = new FbConnection(接続文字列))
    {
        connection.Open();
        connection.Close();
    }
}

これだけで、私の環境だとMainを抜けた後に3秒程かかりました。
ConnectionをOpenしなければ1秒未満です。

分析

まずは時間を。

var process = Process.Start(@"D:\tmp\FirebirdClient\FirebirdClient.exe);
process.WaitForExit();

//ExitCodeでHHmmss形式で終了時間をReturnするようにして、
//DateTime.NowをHHmmss形式にしたので差分をとる。
var elapsed = Utility.Subtract60(DateTime.Now.ToIntTime(), process.ExitCode);

Console.WriteLine($"Path: {path} / Seconds: {elapsed}");

f:id:kowill:20150927232141p:plain

ProcessMonitorで見てみると、

f:id:kowill:20150927230852p:plain

もしかして、また君ですか。
fb_trace_xxxには時折苦しめられておるのですが(笑)

解決策(??)

動作を見ている限り、fb_trace_xxxやfb_Lock_xxxなどのTempデータはNetProvider経由の場合、プロセス終了時にクリアされているようでした。
DelphiXE + FireDAC だと接続切っただけでクリアされていたような気がするんだけどなぁ。

ってなわけで、

[DllImport("kernel32", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);

手動でアンロードしてみる。

  • FirebirdSql.Data.FirebirdClient → × (そりゃそうだよね..)
  • fbembed.dll → ○ パリィ(°▽°)
static void Main()
{
    using (var connection = new FbConnection(接続文字列))
    {
        connection.Open();
        connection.Close();
    }
    UnloadDll(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), @"fbembed.dll"));
}
[DllImport("kernel32", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);

public static void UnloadDll(string path)
{
    foreach (ProcessModule dll in Process.GetCurrentProcess().Modules)
    {
        if (dll.FileName.Equals(path, StringComparison.OrdinalIgnoreCase))
        { 
            FreeLibrary(dll.BaseAddress);
        }
    }
}

f:id:kowill:20150927233213p:plain

これで良いのだろうか(笑)
動作に問題はなさそうなんですが、確かなことが分からず。
とりあえず、これで妥協してみようかなぁ。

試しにサンプル上げてみた。

github.com

.NET Framework 4.5.2 でXmlReaderのDTD読み込みの挙動が変わっていた

以前、少しはまってしまったので、メモしておきます。
先に解決策書いておくと、ちゃんとXmlResolverのインスタンス作成しておきましょう!です。

問題点

TargetFramworkを4から4.6に上げた際に、DTDの外部実体参照が読み込まれなくなってしまっていた。
その時の読み込み部分。

var reader = XmlReader.Create(path, new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse })  
<?xml version="1.0" encoding="utf-8" ?>  
<!DOCTYPE Samples[  
  <!ENTITY Sub1 SYSTEM "Body\Sub1.txt">  
]>  
<Samples>  
  <Title>あいうえお</Title>  
  <Body>&Sub1;</Body>  
</Samples>  

Titleは取れるが、Body部分が取れてこない。
f:id:kowill:20150923092528p:plain
試しに、TargetFramworkを変更してみると、

という結果に。

解決

ということで、おなじみのMSDN

XmlReader.Create メソッド (System.Xml)

書いてありました。

f:id:kowill:20150923092020p:plain

ありがとうMSDN

さらに原文の方を見ると、

f:id:kowill:20150923092023p:plain

はひ。そうですか、そうですよね。 という感じに。

というわけで、

var reader = XmlReader.Create(path, new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse, XmlResolver = new XmlUrlResolver() })  

みたいにしてあげれば良さそう。

f:id:kowill:20150923092726p:plain

というわけで解決。 そもそもの構造が良くなさそうってのもありますが、良い勉強になりました(笑)

ソースサンプル

XmlReaderでDTD読み込み

Postfix, Dovecotのversionを取得する

そう何度もやるもんじゃないので、version確認する方法をメモ。

CentOSの場合

よく使うのはCentOSなので、ついでに記載。

cat /etc/redhat-release  
>>> CentOS Linux release 7.2.1503(Core)  

Postfixの場合

postconf | grep mail_version  
>>>mail_version - 2.10.1  
>>>milter_macro_v = $mail_name $mail_versino

Dovecotの場合

dovecot --version  
>>>2.2.10