woshidan's loose leaf

ぼんやり勉強しています

Athenaのテーブル定義にファイル中に存在しない列を定義した場合の振る舞いについて

後からAthenaのテーブル定義に列を追加したい、みたいな場合に気になったので、メモ。

テーブル定義に存在する列で検索対象データ内で型が違うものは怒られますが、テーブル定義に存在して検索対象のデータに存在しない列についてはNULL扱いみたいでした。

以下試したクエリ。

CREATE EXTERNAL TABLE IF NOT EXISTS logs_with_absent (
  `id` String,
  absent_str String, // 存在しない列
  absent_int int     // 存在しない列
  ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' LOCATION 's3://woshidan-exmaple-test/athena_empty_key_test';
Query successful. 
SELECT COUNT(*) FROM "mydatabase"."logs_with_absent" WHERE "logs_with_absent"."absent_str" IS NULL limit 10 ;
=> 1
SELECT COUNT(*) FROM "mydatabase"."logs_with_absent" WHERE "logs_with_absent"."absent_int" = 0 limit 10 ;
=> 0
SELECT COUNT(*) FROM "mydatabase"."logs_with_absent" WHERE "logs_with_absent"."absent_int" IS NULL limit 10 ;
=> 1

先週の反省会

  • いまの日時 [NSDate date]
    • 日付を扱うには NSCalendaer, 決まったフォーマットで文章にしたい場合は NSDateFormatter
    • NSDateFormatter にセットする DateFormat の文字列には時間に関係しない文字列( yyyy, MM, dd みたいなもの以外 )が含まれている場合、 [NSDateFormatter stringFromDate:] の戻り値が空文字列となる
  • [[NSString alloc] initWithFormat:] -> [NSString stringWithFormat:]
  • Javaではstreamのcloseはfinally節でやるのが定石
    • closeもIOExceptionの可能性があるので、finallyの中でtry-catchする
try {
    InputStream is = ...;
    is.open()
} catch (IOException ex1) {
    // ... 
} finally {
    try {
        is.close()
    } catch (IOException ex2) {
        // ...
    }
    
}
  • [Java] ループのブロックの中でしか使わない変数はそこで宣言した方がわかりやすそうだが、つどつど宣言することによるコスト増にならないか?
  • xcocdebuildでビルドしてる時、GUIXCodeで他のアプリ開いてるとバグってxcodebuldのビルドこける

リモートのタグのコミットが欲しいときは git ls-remote --tags

$ git ls-remote --tags
From git@github.com:woshidan/tag-test.git
srcdiep0r4vns19wth7aoy399qv2or8or64zrkwd    refs/tags/1.0.0
51eow33h7d87xiye3uunrcb6vl2hieourjd1pzy4    refs/tags/1.0.0^{} // git checkout refs/tags 1.0.0 で飛ぶコミット 
ubg7kxcgqoss7r4zewq103y58e6xj3dmo0ru5mp3    refs/tags/1.1.1
mx00rsw5psy4ge0fssf07j3wc9qjbcuo3dgm78n3    refs/tags/1.1.1^{}
m91sf879ws8deyz1js219im2lpltghr4aqhv5mx9    refs/tags/1.2.0
wx2us06hq8trsloubhqllfaoo8my4qe2wthbgbrg    refs/tags/1.2.0^{}
0ihu1zvz2z1qd94e0cwlk3ba2c88be9xjlsngjsh    refs/tags/2.0.0
kh4hqgokh2uml5ingivvyd0ucvtcy85wmx6li6ii    refs/tags/2.0.0^{}

BitBucketにgitでアクセス、あるいは新しいサイトでssh認証するときの鍵の登録と確認の手順

https://qiita.com/yyosuke/items/986dabc9906674e2ea97 を参考にSSHの公開鍵をBitBucketに登録。

~/.ssh/configbitbucket.org に当該の秘密鍵を使ってアクセスするように設定する。

# サイトごとに鍵を分けた方が良い。。。
Host bitbucket.org
  HostName bitbucket.org
  IdentityFile ~/.ssh/bitbucket/id_rsa
  User git
  Port 22
  TCPKeepAlive yes
  IdentitiesOnly yes
$ ssh -T bitbucket.org
The authenticity of host 'bitbucket.org (104.192.143.2)' can't be established.
RSA key fingerprint is SHA256:UvlgyNccfRyg8jrD8dzU2lwwd4dDWYbx4NfILUjQkKL(この値はダミー).
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'bitbucket.org,104.192.143.2' (RSA) to the list of known hosts.
logged in as UserName.

You can use git or hg to connect to Bitbucket. Shell access is disabled.

あとはほぼGitHubと同じで、remote リポジトリを指定するときのホストが bitbucket.org になっているだけ。

`NS_SWIFT_NAME` マクロでObjective-CのコードがSwiftからどう見えるか規定できる

Objective-Cで書いたメソッドのシグネチャはSwiftから呼び出す時にメソッド名の一部の単語がパラメータ名の一部へ変換されるものがある。

// Objective-C
- (void)addToBox:(Item *)item;
// Swift 2.3
addToBox(item)

// Swift 3.0
add(toBox: item)

この変換具合がSwift2系と3系で結構違う上に前置詞などを使った動詞の塊が切り取られて引数のラベルみたいに扱われてしまう。

すると、主に一番最初の引数の意味が違って見えることがある。たとえば、 上記の例の Swfit 3.0 のシグネチャでは toBox というラベルがついてしまっているが、第一引数はItemのインスタンスであってBoxのインスタンスではないが、そういう風に見える。

なので、Objective-C + 複数のSwiftのバージョンに対応する必要がある場合はドキュメントなどのサンプルコードをどう書くか悩ましかったりする。

こういう場合、 NS_SWIFT_NAME を使って Swift ではこういうシグネチャで表示してほしい、という個別設定が可能。

- (void)addToBox:(Item *)item;
NS_SWIFT_NAME(addToBox(item:));

参考

qiita.com

Swift3でCountdownLatchを作る、あるいはSemaphoreのtimeoutをSwift3で書く

テストの都合でラッチが欲しかったので、GCDのSemaphoreのラッパークラスを書こうと思ったんですね。

それで、 https://github.com/zhuhaow/CountdownLatch を参考にすれば割と簡単では! と思ったんですが、GCDの記法がSwift3で変わりすぎていて死ぬかと思った。のでメモ。

// 参考元: https://github.com/zhuhaow/CountdownLatch
import Foundation

class CountDownLatch {
    var count: Int
    private let dispatchQueue = DispatchQueue(label: "CountdownQueue")
    // 参考: https://qiita.com/codelynx/items/56ce2f91cd3f4f409aeb
    let semaphore = DispatchSemaphore(value: 0)
    let timeInSec : Int
    
    init?(count: Int, timeInSec: Int) {
        guard count > 0 else {
            return nil
        }
        
        self.count = count
        self.timeInSec = timeInSec
    }
    
    func countdown() {
        dispatchQueue.async {
            self.count -= 1
            if self.count == 0 {
                self.semaphore.signal()
            }
        }
    }
    
    func await() -> Bool {
        // 参考: http://www.brilliantraven.com/code-snippets/grand-central-dispatch.html
        let result = semaphore.wait(timeout: DispatchTime.now() + DispatchTimeInterval.seconds(self.timeInSec))
        if (result == .success) {
            return true
        } else {
            return false
        }
    }
}

CouuntDownLatch を使う側のコードは以下

    func doTask() {
        let countDownLatch = CountDownLatch(count: 1, timeInSec: 30)!
        checkTimeoutBeforeCompletion(latch: countDownLatch)

        // なんか重い処理する

        countDownLatch.countdown()
    }

    func checkTimeoutBeforeCompletion(latch: CountDownLatch) {
        let queue = DispatchQueue(label: "background", attributes: .concurrent)
        queue.async {
            let processedOnTime = latch.await()
            if (processedOnTime) {
                NSLog("processed on time")
            } else {
                assertionFailure("遅いぞ!!!!")
            }
        }
    }

計数型セマフォについて

http://woshidan.hatenadiary.jp/entry/2017/08/27/005353 で使い方の勉強をした気がするんですが意味がよくわかってなかったので。

計数型セマフォは「チケットを配ってチケットをもらえたスレッドは処理を先へ進めることができる」みたいなもの。 ここから下はチケットを配ってもらえたスレッドにしか実行させない、みたいな箇所で

semaphore.await();
dispatch_semaphore_wait(semaphore, time);

のように、wait っぽい関数を置く。 (少なくともObjCの場合は) wait 関数から抜ける時にセマフォのカウンタ(比喩でいうとチケットの枚数)がデクリメントする。

初期化時にセマフォが何枚のチケットを持っているか指定して、チケットを配られたスレッドたちが実行する処理の中でチケットを返したり(Semaphoreのカウンタをインクリメントする)する。

ObjCの場合、Semaphoreのカウンタをインクリメントする処理は以下。

dispatch_semaphore_signal(semaphore)

なので、全体の処理としてはこんな感じになる。

// セマフォの用意
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

// セマフォのところで待つ時間
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);

// ここからセマフォで用意したチケットの枚数ぶん以上のスレッドは実行してくれるなよ
long result = dispatch_semaphore_wait(semaphore, time);
// 上の行を通り過ぎるとセマフォのカウンタは1減っている

if (result == 0) {
    // セマフォのカウンタが1以上だった or 待機時間中にセマフォのカウンタが1以上になったので
    // 処理が進められる

    // 排他制御したかった処理

    // この処理の最後あたりでセマフォのカウンタを戻しておきましょう
    dispatch_semaphore_signal(semaphore)
} else {
    // 指定時間待機したけどセマフォのカウンタが0のままだった
}

現場からは以上です。

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?