漆黒な技術メモ

管理人が必要に応じて自分のメモを好き勝手に投下するたまり場的ブログ

HDDアクセスがアクティブ状態で張り付いてしまったのを解決した話

最近、自分のデスクトップのディスクアクセスの様子がおかしかった。
自分のデスクトップはCドライブにSSD、DドライブにHDDを割り当てている。 そのDドライブのアクセスが異常に遅く、Dドライブにアクセスするアプリケーションが応答なしになることが頻発した。
その時のタスクマネージャのキャプチャがこちら
f:id:igbt3116redtrain:20171124212859p:plain

アクティブ時間がずっと100%になっているにも関わらず、読み書きバイト数は殆ど0に近い。

原因を探ってみる…がうまくいかない

まず行ったのがwindows updateとウイルスチェック
結論から言うと何も変わらなかった。

その次に行ったことはHDDの交換である。
HDDのS.M.A.R.T値を見ても特に異常は見られなかったが、稼働時間が4万時間を超えていたので「もしや」と思いディスクの中身を新しいHDDにクローンし交換した。
交換した後、1~2日ぐらいは症状が軽減したが、しばらくするとまた症状が復活してきた。

さらに原因を探るため、ググってこのあたりの記事などを参考にsuperfetchの無効化なども行ったが一向に改善しない www.pcdepot.co.jp

原因はマザボにあり

さらに原因を探るため"HDD 100% transfer 0Bytes"とググってみると、このような記事が出てきた。
www.tomshardware.com この回答の中に"SATAケーブルの交換を行い別のSATAポートにつなぐことを試してみては?"と書いてあった。
藁にも縋る思いでこの方策を実行しようと古いSATAケーブルを抜こうとすると…マザボの該当SATAポートがぐらついていた。
つまりSATAポートが壊れかけていたのである。思えば最初PCを組むときに配線パーツの都合で半ば無理やりSATAケーブルを挿しており、長時間SATAポートに横方向の圧力がかかり続けていたことが原因だったみたいだ。
SATAケーブルとポートを交換したところ…息を吹き返したようにサクサクHDDへアクセスできるようになった。
ストレージアクセスが冒頭のような状態になった方は、是非SATAケーブルとポートの交換を試していただきたい。

ubuntuユーザ作成の手順メモ

何回もやっているのに毎度手順を忘れてしまうのでメモにした。
ubuntuルート権限を持つユーザを新たに作り、公開鍵認証する手順を書いておく

$ sudo adduser username
 #ここらでパスワードが聞かれる。
 #Enter the new value, or press ENTER for the default とか聞かれるので特別必要なければEnter連打
$ sudo gpasswd -a username sudo
$ su username
$ cd ~
 #この辺でscpなどで公開鍵をサーバに転送しておく
$ mkdir .ssh
$ mv id_rsa.pub .ssh/
$ sudo chmod 700 .ssh/
$ cat id_rsa.pub >> authorized_keys
$ sudo chmod 600 authorized_keys
$ rm id_rsa.pub

【私的メモ】androidに通知を実装するために参考にするサイト一覧

久々の投稿
今まで何だかんだandroidで通知を実装したことがなかったので恥ずかしながらメモ

通知には二種類ある

ネットで「プッシュ通知」と検索すると、アプリを管理するサーバから一斉または個別にメッセージを配信して通知する仕組みの実装方法が引っかかる。
アプリだけで完結する通知(目覚ましとかに代表されるような通知)は「ローカルプッシュ」というらしい。

ローカルプッシュの実装で参考になりそうなサイト一覧

developer.android.com

qiita.com

サーバからのプッシュ通知の実装で参考になりそうなサイト一覧

qiita.com

https://firebase.google.com/docs/cloud-messaging/android/clientfirebase.google.com

また随時追加していこうと思う

C++のstd::string::clear()はメモリの解放をしてくれない話

まあ簡単に言うと自分のC++に対する知識が浅かったって話ですが…
研究のソースでstd::string::clear()を何回か使ってメモリの解放をした「つもり」でしたが、こいつは長さを0にセットするだけでメモリ領域は食ったままらしく、結果的にメモリリーク( std::bad_alloc )を起こして死にました。 ちなみに書いたソースはこんな感じ

class Buffer {
public:
    Buffer();
    virtual ~Buffer();
  
    void setData(std::string data,int type);
  
    std::string getData();
    int getType();
  
    void clearData();
    bool isexistData();

private:
    std::string data;
    int type;
    bool existData;
};

Buffer::Buffer() :
        type(-1), existData(false) {
}

Buffer::~Buffer() {
}

void Buffer::setData(std::string data,
        int type) {
    this->data = data;
    this->type = type;
    existData = true;
}

std::string Buffer::getData() {
    return data;
}

int Buffer::getType() {
    return type;
}

void Buffer::clearData() {
    data.clear();
    existData = false;
}

bool Buffer::isexistData() {
    return existData;
}

こういう状況で、いくら Buffer::clearData() を呼び出してもメモリリークを起こすので不思議だなあと思ってたら、stackoverflowにそんなことが書いてありました。

Calling std::string::clear() merely sets the size to zero. The capacity() won’t change (nor will reserve()ing less memory than currently reserved change the capacity).

stackoverflow.com

stackoverflowには、解放したいんだったらBuffer::clearData()

void Buffer::clearData() {
  std::string().swap(data);
    existData = false;
}

で行う(空文字を確保したstd::stringとのメモリ領域スワップ、スコープが終われば元々dataで確保した領域はデストラクタが呼ばれて解放される)と良いと書いてありました。
でも、この書き方だとなにやってるかわかりづらいですよね…

std::shared_ptrに変える

まあそもそもバッファなんだからshared_ptrにしろよという突っ込みが聞こえてきそうですが、その話は棚に上げて… std::shared_ptrはじめスマートポインタは reset() で所有権を放棄、つまるところ(shared_ptrの場合はカウンタが0であれば)明示的にメモリを開放することができます。 というわけで該当部を以下のようなコードに変更して事なきを得ましたとさ。

void Buffer::clearData() {
    data.reset();
    existData = false;
}

SQLで「グループごとにn件出力する」というSELECT文を書く

皆様あけましておめでとうございます。本年もどうぞよろしくお願いいたします。
さて、今日はSQLを久しぶりにいじっていて詰まったことを書きたいと思います。

下のようなテーブルがあって、「SSIDごとにステータスがONの最新の結果をn件出力する」ということを実行しなければならない場面に遭遇しました。 例を出すと、下のようなテーブルから「ステータスがONの最新の結果を1件出力したい」とします。

id time ssid status
1 12:00 ssid1 ON
2 12:00 ssid2 ON
3 12:00 ssid3 ON
4 12:10 ssid1 ON
5 12:10 ssid2 ON
6 12:10 ssid3 ON
7 12:20 ssid1 ON
8 12:20 ssid2 OFF
9 12:20 ssid3 ON

すると、上のテーブルから下のような結果が出てくるのが理想になります。

id time ssid status
7 12:20 ssid1 ON
5 12:10 ssid2 ON
9 12:20 ssid3 ON

しかしこのような抽出は、group by句、where句などの単純なものではできません…
さて、どうするかと思って検索するとこのような記事に引っかかりました。

blogs.wankuma.com

今回はこの記事を全力で参考にして解決しました。

解法:IN句を用いた副問い合わせ

これを見た瞬間「ああ、副問い合わせとかそんなものあったなあ」となりました…(←ダメな奴)
最初に示した結果を抽出するには以下のようなSQLを書きます。

select * from table as t1
where id in 
(select id from table as t2 where t1.ssid=t2.ssid and status='ON' order by id desc limit 1)
order by ssid, id desc;

主問い合わせ文のwhere句にはid in の形で指定し、副問い合わせ文のwhere句の中でグループにしたいカラムを結合します(この場合は t1.ssid=t2.ssid )。
また、「ステータスがONの」などの他の条件や「N研抽出する」などのLIMIT句も副問い合わせ文の中に記述します。
あとは適宜並び替えなどをすれば完了です。

今日はここまで!

【ちょっと技術的なことAdventCalender】 hackU実装振り返り-3. nodejsでpostgresに接続-

この記事はちょっと技術的なことAdventCalenderの24日目です。
クリスマスに風邪をこじらせてしまい書くのが遅れました…

先週あたりからhackU開発後記としてつらつら書いていますが、今日は可視化システムで必要だったnodejsとDBの連携についてお話ししようと思います。

nodejs×postgreSQL

恐らく座布団が定期的に送ってくるデータをため込んで可視化する…という作業にはNoSQLであるmongoDBとかの方がパフォーマンス的には正しい選択肢なのですが、 今回は開発時間をあまりとれなかったので、早めにシステムを組み上げるため研究室内での運用実績が多いpostgresを利用しました。
nodejsからpostgresを利用するにはpgというパッケージを利用します。いつものように$npm install pgでインストールします。
パッケージがインストールできたらあとはコードを書くだけです。

記述コード

ここでは、引数で渡された任意のsql文を実行し、結果をコンソールに出力するというプログラムを紹介します。

var pg = require('pg');
var DBhost = "postgres://username:password3@www.example.jp:5432/dbname";

sql_custom = function (query,socket) {
    var result;
    var client = new pg.Client(DBhost);
    client.connect(function (err) {
        if (err) throw err;
        client.query(query, function (err, value) {
            if (err) throw err;
            console.log("get data");
            console.log(value);
            client_select.end();
        });
    });
});

pg.Client型の変数を使いまわして2回以上接続切断を行うと例外を吐いて止まってしまったので、毎回接続前に新しいインスタンスを生成して 局所変数として扱うのが一番よさそうです。
このコードでも何回も接続と切断を繰り返すと”too many clients”的なエラーが出てしまうので、少しこの部分は改良の余地がありそうですが…
今日はここまで!ありがとうございました。

【ちょっと技術的なことAdventCalender】 hackU実装振り返り-2. mbed2台を直結する-

この記事はちょっと技術的なことAdventCalenderの21日目です。
今日は、以前に引き続きhack Uで苦労したことにうちの1つをつらつら書いていこうと思います。

前回「mbed×websocketをやろうとしたらライブラリの都合でmbed2台を直結することになった」というお話をしたと思います。
今日は、そこで苦労した「意外とちゃんとわかってなかった電気回路のお話し」をしようと思います。

mbed2台を直結する

mbedをはじめとしたマイコン関係のモノを繋ぐときには、p9,p10などのピンにジャンパ線を差し込み、UARTを利用したシリアル通信を行うのが一般的かと思います。 f:id:igbt3116redtrain:20161223050117p:plain
(https://www.switch-science.com/catalog/250/より引用)
しかし我々、シリアルポートを繋ぎ、サンプルプログラムを動かしても、通信できない…

なんかよくわからないけどシリアル通信はうまくいかないと判断し、仕方なく複数の空きピンを利用して並列送信をすることにしました。
しかしそれでもうまくいかない…

原因はソフトウェアではなく電気回路

単純な1,0のDigitalOutの通信がうまくいかないのはいくらなんでもおかしい、と思い、DigitalInをいろんなピンにつないで動きを見てみました。
すると、DigitalInと同じmbedのVCCでは入力を1とみなすのに、もう片方のmbedのVCCでは入力を0と判定しました。
ここでもしかしてと思い、一方のmbedのVCCからもう片方のmbedのGNDの電圧を測定すると…0Vでした。

つまり、ただVCCとGNDを用意すればいいだけではなく、きちんと「回路」を形成してあげる必要があるようです。
電気をきちんとわかってる人からしたら「何当たり前のことを言ってんだこいつは」と思われるかもしれませんが、ソフトウェアだけをいじってる人間はこの辺が意外とわかってなかったりするようです(byわかってなかった人)

回路を形成する

形成するといってもそんな難しいことではありません。通信用のピンの他に、互いのmbedのGNDをジャンパ線で直結するだけです。
f:id:igbt3116redtrain:20161223051742j:plain
これを行うだけで、2台のmbedの信号を無事やり取りすることができました!

今日はここまで