PostgreSQLのTimestamp型をC言語アプリケーションで扱う

PostgreSQLの公式ドキュメントに記述がありますが、timestamp型はUNIX時刻のように、ある基点時刻からの経過秒数を表しています。

timestampの値は2000-01-01深夜を基準にした経過秒数として格納されます。

ということで、libpqを用いて取得されたtimestamp型の値に"2000-01-01T00:00:00ZのUNIX時刻"を足せばUNIX時刻に変換できます。

ただし、

timestampの値が8バイト整数(現在のデフォルト)で格納されていれば、すべての値についてμ秒精度が有効です。

との記述通り、timestamp型の値はマイクロ秒表現になっているので1000000で割ってから946684800(2000-01-01T00:00:00ZのUNIX時刻)を足すことでUNIX時刻に変換できます。

VPC内のLambdaからSQSに接続できない問題の解法

かなりハマったので記録。

ハマり状況

  • VPCのLambdaからSNSへのメッセージ送信
    (VPCSNSへのエンドポイント作成したので)送信できる。

  • Lambdaからのメッセージ送信先をSQSへ変更
    (VPCにSQSへのエンドポイント作成するも)送信できない

  • VPCのLambdaからSQSへのメッセージ送信
    送信できる

原因

クライアント作成時にエンドポイントの明示的な指定が必要でした。

client = boto3.client('sqs', endpoint_url='https://sqs.ap-northeast-1.amazonaws.com')
client.send_message(...)

最後に

SNSクライアントはエンドポイント指定しなくてもメッセージ送信できたので原因に気づくまで時間がかかってしまいました。

C/C++アプリケーションの64bit化対応

C/C++で書かれた業務アプリケーションを32bitから64bitへ移行させる機会があったのでやったことや観点など残しておきます。

環境

OS

Windows Server 2008 R2 → Windows Server 2016

コンパイラ

Visual Studio 2012 → Visual Studio 2017

修正の観点

プログラムは下記観点に沿ってチェック、修正しました。

  • データ型のサイズ変更の影響
  • 構造体パディング変更の影響
  • その他コンパイラ警告への対応
  • 実数型への対応
  • 2038年問題への対応

データ型のサイズ変更

データ型のサイズは、データモデルというものによって分けられます。

C/C++は規格上、整数型のビット幅は固定ではなく、相対的に決まっています。

short <= int <= long <= long long という感じです。

データモデルごとに整数型のビット幅をまとめたのが以下。

  データモデル     short     int     long     long long     pointer     処理系  
LLP64 16 32 32 64 64 Windows 64bit
LP64 16 32 64 64 64 一般的なUnix系64bit
ILP32 16 32 32 64 32 一般的な32bit

その他にもデータモデルはありますが、割愛。

表を見てわかる通り、Windows 32bitからWindows 64bitへの移行は、ポインタのサイズが変わります。綺麗に作ってあるプログラムなら問題ないのですが、intやlongにアドレス値を格納してたりするとバグります。

ただ、intやlongにアドレス値を代入しようとすると、コンパイラが警告を出してくれると思います。Visual Studio (VC++) 2017でももちろん警告してくれます。

構造体パディング変更

構造体やクラスをメモリ上に配置する際、配置の仕方を工夫することでアクセス速度があがります。コンパイラがこの工夫のために追加するのがパディングです。

Cの規格上、構造体メンバのメモリ配置の順番は宣言順になることが求められますが、メンバとメンバの間にパディングを挿入することが許されています。パディングはメンバとメンバの間および最後のメンバの後に挿入されます。

メンバ間パディング

後ろのメンバのオフセット(構造体先頭からの位置)が型サイズの倍数となるように挿入されます。

最終メンバ後パディング

構造体全体のサイズが、構造体メンバの中で最も大きい型サイズの倍数となるように挿入されます。

つまり

64bitに移行するとパディングが変わる可能性があります。Cでよくやる、バイナリの電文をそのまま構造体にキャストみたいな使い方だとパディングの差でバグります。

実例あげようと思いましたが面倒なので割愛。

その他コンパイラ警告

 セキュリティが強化されている関数を使用していないという警告が多数出ました。

strncpy()の代わりにstrncpy_s()を使え、memcpy()の代わりにmemcpy_s()を使えといった警告です。_s()のついた関数は、異常時に例外を発生させるため注意が必要です。基本的に関数名だけ変えて引数そのままだと挙動が変わります。

実数型への対応

これは64bit化というよりもハードウェア移行の影響です。CPUが変わると実数型の計算方法が変わる可能性があるとのこと。今回修正対象のアプリケーションは座標計算を行うため、修正の前後で計算結果にずれが発生すると問題になります。すべての座標計算をテストすることで確認しました。特定の計算結果を比較するだけで実数計算の誤差を確かめるような方法があればよかったのですが、わかりませんでした。

2038年問題への対応

時刻をtime_t型で扱っていれば64bit化で2038年問題もクリアされるのですが、残念ながらint型で時刻を扱っている箇所がありました。時刻計算をする際に一時的にint型変数にキャストされるといったケースも要注意です。

最後に

32bit時代のアプリケーションを64bit化するのは大変でした。