libstdc++ std::list のイテレータのみで erase() を実行

最近 あまり日記を書いてないな.仕事で忙しい上に,気分の問題で外に出て運動もしてなかったからな.
STL std::list::erase(std::list::iterator) に不満を抱いた.リストの要素の削除は,削除される要素の左右隣に閉じた操作であってリストのヘッドを参照する必要はないのに,どうしてヘッド・オブジェクトのメンバ関数としてのみ提供されているのか!?
GNU libstdc++ 限定となってしまうが,コードを読んだら削除対象のイテレータのみで対応するノードを削除する方法を編み出すことができた.VC++libc++ は単に見てないが,内部メンバの名前が同じとは思えないからそのままでは動かないだろう... 名前だけの手直しで動く可能性もあるが,アクセス権とかが違うかも.

#include <iostream>
#include <list>
#include <string>
#include <algorithm>
using namespace std;

typedef list<string> List;

int main() {
    List lst{ string("a"), string("b"), string("c") };
    auto it = lst.begin();
    advance(it, 1);
 
    // _M_next->_M_prev = _M_prev; _M_prev->_M_next = _M_next;
    it._M_node->_M_unhook();

    delete static_cast<_List_node<string> *>(it._M_node);

    for (auto &s : lst)
         cout << s << endl;
}

もちろん,ちゃんと valgrind --leak-check=full で確認してある.

totSize += sizeof hdr.chunkSize;

「おっかしーな, totSize が外側プロトコルのヘッダの size メンバと比べて全然小さいぞ??」

ああ.

祖父は私に将棋を教える際に「下手〜の考〜え 休むに似〜たり〜」と拍子を付けて唄っていたものだったが... いやぁほんとにその通りですな.プログラミングには気合と同様に十分な睡眠が大事だ.

という当然のことをしみじみ実感したある夏の日.2014年1月28日.

RAID10リビルド中

年末年始の一時帰国でアキバに寄り,HGSTの HDS721010CLA332 を買ってきた.1 TB, 7200 rpm, キャッシュ 32 MB.大事なのはセクタ・サイズ512 Bということ.RAIDケース内の残り3個の WD10EALS に合わせた.店で売ってるHDDは大半が4Kセクタ (AFT) で,私のように明確なレガシー相互運用の目的を持った人しか512Bセクタのものは買わないようだ.時の流れ...

ちなみに片肺運転が発覚した頃に取った badblocks(8) のログがこちら.他のファイルシステムも個別に調べたけど問題はなかった.

root@zbox:~# badblocks -nvs /dev/disk/by-label/Corega_Btrfs
Checking for bad blocks in non-destructive read-write mode
From block 0 to 104863262
Checking for bad blocks (non-destructive read-write test)
Testing with random pattern: 7243428 done, 24:58 elapsed. (0/0/0 errors)
7243429 done, 25:09 elapsed. (1/0/0 errors)
7243430 done, 25:22 elapsed. (2/0/0 errors)
7243431 done, 25:33 elapsed. (3/0/0 errors)
done
Pass completed, 4 bad blocks found. (4/0/0 errors)

誕生日おめ〜〜 ┌iii┐ ε-(・ε・´)

金曜にヒヤリハット未満の軽微な問題が出たんだが,その再発防止に仕掛けた新しいアラートが祝日を考慮してなかったせいで,今朝false positiveが出た.それを見て慌てて,社外にまで

おはようございます.大変申し訳ございませんが,本日はシステム立ち上げに少々お時間をいただきたく思います.弊社側で作業が完了し次第,追ってご連絡いたします.

とかメッセージを送ってしまった.つらぽよ...
6時半に出社するのが最近段々辛くなって,ずるずると7時頃まで遅くなる日が多い.しかしこういう事態に落ち着いて対処するにはやはりきっちり6時半出社を守らないと...
こんなタイトル付けて不敬罪で成田で「あーちょっとあなたはこちらへ」って連れていかれたらどうしよう...

体重 60.8 kg

あんま減ってない... 晩ご飯に飯屋に出かけて飯を食うのを控えて,買ってきた豆腐を冷や奴で食べるとか始めたんだが.水分や排泄で一日に1 kg強の変動は普通なので,12/5の 62 kg からほとんど変わってないとも言える.59の桁に早く移りたい... そうすればやる気も出るだろう.

RAID10ケースが片肺運転

昨年8月末に当地に引っ越した際にトランクに入れて持ってきたものの,電源ケーブルを忘れて置物になっていたCoregaRAIDケース (1 TB×4÷2のRAID10).

3年半前... 時が経つの早すぎぃ!
こないだの10月の2度目の一時帰国でようやく対応する電源ケーブルを持ってきて復活させたのだが,飛行機で来た無理が祟ったのか,それとも当地の気候が合わないのか,はたまたずっと火を入れてなかったのが逆にまずかったか,HDDが1玉 死んでしまった.早急に代わりを手配せねばならん.HDD RAIDだからRAIDが崩壊したらデータを回収できる自信がない.早いとこHDDを調達せねば.この際 モデルの差は気にせず,シンガの電気屋でとりあえず1 TBなら何でもいいから買ってこようと思う.シンガの電気屋はこれまでいくつか回ったが,基本的に内蔵用 3.5"HDDはあんまり売ってない.店員に聞いて店の奥から出してもらう感じで,モデルに選択の余地も大して無い.物流に関しては日本との差をいつもひしひしと感じる.Amazon.SG もないので,米または日本のAmazonから国際発送になってしまったり.

Javaの System.sleep() が、Linux CLOCK_MONOTONICを全力で無駄にしている

この辺りを手元で確認したという話.

Thread.sleep() で5秒スリープするJavaプログラム

import java.text.SimpleDateFormat;
import java.util.Date;

public class Sleep5Sec {
    public static void main(String[] args) {
        try {
            SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss.SSS");
            final Date d0 = new Date();
            final long t0 = System.nanoTime();
            Thread.sleep(5 * 1000);
            final long t1 = System.nanoTime();
            final Date d1 = new Date();
            System.out.printf("%15d - %15d => %13.6f ms%n", t1, t0, 1e-6 * (t1 - t0));
            System.out.printf("%15s - %15s => %6d%7s ms%n",
                fmt.format(d1), fmt.format(d0), d1.getTime() - d0.getTime(), "");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

さらに「現在時刻を3秒進ませる/遅らせる」シェルコマンド(1秒弱の誤差が出るのはご勘弁):

$ sudo date -s @$[ `date +%s` + 3 ]
2013年 12月 16日 月曜日 13:03:25 SGT
$ sudo date -s @$[ `date +%s` - 3 ]
2013年 12月 16日 月曜日 13:03:44 SGT

これらを組み合わせてみる:

$ java Sleep5Sec
(別端末上で素早く時刻を3秒進ませる)
5149670129719 - 5144669487622 => 5000.642097 ms
13:43:11.145 - 13:43:04.088 =>       7057 ms
$ java Sleep5Sec
(別端末上で素早く時刻を3秒遅らせる)
5174094020305 - 5165450038923 => 8643.981382 ms
13:43:29.893 - 13:43:24.893 =>       5000 ms

うーん,つらぽよ...
この非対称性は,時刻を遅らせた方はspurious wakeup的な事象が起きたと誤認されて(外の雨音で目覚めたが目覚まし時計を見るとまだ朝4時なので寝直すイメージ)Javaランタイム内でもう一度「残り時間」をスリープするsyscallを呼んでると解釈.

もっと厳密にやるときはCPUのキャッシュやhotspotちゃんを温めたりするんだけど,今回の試験で見えた差は明らかにそういうレイヤではないのでスキップ.
なおLinux syscallレイヤではこのような問題は起きないことも合わせて実験済み:

#define _POSIX_C_SOURCE 199309L

#include <time.h>
#include <errno.h>
#include <stdio.h>

int main(void) {
    struct timespec slp = { 5, 0 }, rest, t0, t1, m0, m1;

    clock_gettime(CLOCK_REALTIME, &t0);
    clock_gettime(CLOCK_MONOTONIC, &m0);
    while (nanosleep(&slp, &rest) && (EINTR == errno || EAGAIN == errno))
        slp = rest;
    clock_gettime(CLOCK_REALTIME, &t1);
    clock_gettime(CLOCK_MONOTONIC, &m1);

    const long long GIGA = 1000 * 1000 * 1000,
        a = GIGA * t0.tv_sec + t0.tv_nsec,
        b = GIGA * t1.tv_sec + t1.tv_nsec,
        c = GIGA * m0.tv_sec + m0.tv_nsec,
        d = GIGA * m1.tv_sec + m1.tv_nsec;
    printf("%20lld - %20lld = %13.6f\n", b, a, 1e-6 * (b - a));
    printf("%20lld - %20lld = %13.6f\n", d, c, 1e-6 * (d - c));

    return 0;
}

ちゃんとmanにも明記されている:

NOTES

... Linux measures the time using the CLOCK_MONOTONIC clock. ...

次回はソケットのタイムアウトで実験.
実験環境:

$ lsb_release -a
LSB Version:   (略)
Distributor ID: Ubuntu
Description:    Ubuntu 12.04.2 LTS
Release:        12.04
Codename:       precise
$ uname -a      
Linux kaidev01 3.2.0-57-generic #87-Ubuntu SMP Tue Nov 12 21:35:10 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
$ java -version
java version "1.7.0_25"
OpenJDK Runtime Environment (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

CPUはIvy橋 Core i7-3770の4コア × HT.