ソースコードから理解する技術-UnderSourceCode

手を動かす(プログラムを組む)ことで技術を理解するブログ

Golangの組み込みDBとして使えるBoltについて

はじめに

前回にも書きましたが、Golangの組み込みDBとして使うことができるBoltを見つけたので、使ってみました。
GitHub - boltdb/bolt: An embedded key/value database for Go.

以下、このDBについて紹介していきたいと思います。

Boltとは

BoltはKeyValue型のデータベースで、これ自体がGolangで実装されています。
シンプルで早いDBを目指しており、またAPIやファイルフォーマットは既に安定した(stable)な状態のようです。
Golangの組み込みDBとして使うには良い選択肢ではないでしょうか。。。

Boltの特徴

Boltは以下の特徴を持っています。

1. Golangで実装されていて組み込みDBとして使える
2. データ自体が別ファイルとして保存される
3. データの集合をBucketという単位で扱う

Boltはデータの集合を「Bucket」という単位で扱います。
このBucketの中にKeyValue形式でデータを登録します。
データの集合という意味では、BucketRDBなどのテーブルに近いですが、Bucketはネストさせることができます。
これらについては、サンプルプログラムにてより詳しく見てみます。

4. トランザクションはスレッドセーフではない

これは注意点だと思います。
READMEには以下のようにあります。

Individual transactions and all objects created from them (e.g. buckets, keys) are not thread safe. To work with data in multiple goroutines you must start a transaction for each one or use locking to ensure only one goroutine accesses a transaction at a time.

GitHub - boltdb/bolt: An embedded key/value database for Go.

goroutineなどから使うときには同時にアクセスが行われないよう注意する必要があります。

サンプルプログラム

Boltを使ってサンプルプログラムを書いてみました。
一つのBucketに登録・参照・削除するプログラムと、Bucketをネストさせるプログラムです。

一つのBucketに登録・参照・削除するプログラム

まずは一つのBucketに登録・参照・削除するプログラムです。
以下のようになります。

登録・更新
db, err := bolt.Open(dbFile, 0600, nil)
(中略)

return db.Update(func(tx *bolt.Tx) error {
    b, err := tx.CreateBucketIfNotExists([]byte(bucket))
    (中略)
    err = b.Put(keybytes(id), []byte(data))
参照
db, err := bolt.Open(dbFile, 0600, nil)
(中略)

db.View(func(tx *bolt.Tx) error {
    b := tx.Bucket([]byte(bucket))
    c := b.Cursor()
    for k, v := c.First(); k != nil; k, v = c.Next() {
        (何らかの処理)
    }
削除
db, err := bolt.Open(dbFile, 0600, nil)
(中略)

db.Update(func(tx *bolt.Tx) error {
  b := tx.Bucket([]byte(bucket))
  err := b.Delete(key)
  return err
})

先にも書いたようにBoltは「Bucket」の中にデータを格納します。
なので処理の流れは

1. DBを開く(このときデータファイルが存在しなければ作成される)
2. Bucketを作る or 参照する
3. Bucketに対して登録・参照・削除する

という形となります。

Bucketをネストさせるプログラム

次にBucketをネストさせるプログラムです。
こちらも登録・参照を行います。

登録

db, err := bolt.Open(dbFile, 0600, nil)
(中略)

err = insert(db)
(中略)

func insert(db *bolt.DB) error {
	return db.Update(func(tx *bolt.Tx) error {
		// create root bucket.
		users, err := tx.CreateBucketIfNotExists([]byte(rootBucket))
		if err != nil {
			return err
		}

		// create nested bucket.
		tom, err := users.CreateBucketIfNotExists([]byte(tomBucket))
		if err != nil {
			return err
		}

		// insert.
		err = tom.Put([]byte("key1"), []byte("tom's todo"))
		if err != nil {
			return err
		}

		// create nested bucket.
		ken, err := users.CreateBucketIfNotExists([]byte(kenBucket))
		if err != nil {
			return err
		}

		// insert.
		err = ken.Put([]byte("key1"), []byte("ken's todo1"))
		if err != nil {
			return err
		}
		err = ken.Put([]byte("key2"), []byte("ken's todo2"))
		if err != nil {
			return err
		}

		return nil
	})
}

参照

db, err := bolt.Open(dbFile, 0600, nil)
(中略)

err = reference(db)
(中略)

func reference(db *bolt.DB) error {
	return db.View(func(tx *bolt.Tx) error {
		users := tx.Bucket([]byte(rootBucket))

		// select from nested bucket.
		tom := users.Bucket([]byte(tomBucket))
		c := tom.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			fmt.Printf("key:%v, value:%s\n", k, string(v))
		}

		// select from nested bucket.
		ken := users.Bucket([]byte(kenBucket))
		c = ken.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			fmt.Printf("key:%v, value:%s\n", k, string(v))
		}

		return nil
	})
}

処理順としては

1. DBを開く
2. RootとなるBucketを作る or 参照する
3. ネストしたBucketを作る or 参照する
4. ネストしたBucketに登録 or 削除を行う

となります。

まとめ

このような感じでBoltを使ってデータを登録・削除・参照することができました。
公式のREADMEも充実しているので、使うときには一読することをお勧めします。

今回私が作ったサンプルプログラムは以下となります。
GitHub - SrcHndWng/go-learning-boltdb-todo
GitHub - SrcHndWng/go-learning-boltdb-bucket-nest

GolangのローカルDBとしてBoltを使ってみた

前回の記事でBitcoinについて調べていましたが、その時参考にした記事ではローカルDBとしてBoltを使っていました。

Bolt

GitHub - boltdb/bolt: An embedded key/value database for Go.

Boltは上記になります。READMEが結構充実しているので、使うときには一読したようが良さそうです。
Bolt自体がGolangで実装されているため、Golangで作るアプリの組み込みDBとして使うことができます。
データはバイナリとは別のファイルで独立して保管されます。

BoltはKeyValue形式のデータベースで、シンプルな作りを目指しているようです。
データの集合を表す「Bucket」の中に、一つのKey・一つのValueをbyte配列で格納します。
またこの「Bucket」をネストさせることもできるようです。

使ってみて

今回はBoltを使い、Todoを登録・参照・削除するコンソールアプリを作ってみました。
作ったものは以下になります。

GitHub - SrcHndWng/go-learning-boltdb-todo

先にも書いたように「Bucket」の中にデータを格納する方式です。
なので登録・参照・削除とも「Bucket」に対して操作を行うことになります。

ソースで表すと以下のようになります。

登録・更新

return db.Update(func(tx *bolt.Tx) error {
    b, err := tx.CreateBucketIfNotExists([]byte(bucket))
    (中略)
    err = b.Put(keybytes(id), []byte(data))

参照

db.View(func(tx *bolt.Tx) error {
    b := tx.Bucket([]byte(bucket))
    c := b.Cursor()
    for k, v := c.First(); k != nil; k, v = c.Next() {
        (何らかの処理)
    }

削除

db.Update(func(tx *bolt.Tx) error {
  b := tx.Bucket([]byte(bucket))
  err := b.Delete(key)
  return err
})

Bitcoinの実装について調べてみた

タイトルにあるように、Bitcoinの実装について調べてみました。
色々なサイトがあったのですが、個人的には以下のサイトが分かりやすかったので紹介します。

Building Blockchain in Go. Part 1: Basic Prototype - Going the distance

こちらのサイトはGolangでのBitcoinの実装について書かれており、実装は7回に分かれて書かれています。
特に最初の2回は、それぞれ

を扱っており、実装も合わせて分かりやすく感じました。

以下、私が写経したソースです。
GitHub - SrcHndWng/go-learning-blockchain

part3についてはCLI化の処理をurfave/cliを使って実装し直しました。
CLI化については以下のサイトを参考にしました。

コマンドラインツールを作るときに参考にしている資料 | SOTA

JSON Web Tokenを返すGolang Serverを実装してみた

タイトルにあるように、JSON Web Tokenを返すGolang Serverを実装してみました。
認証が必要なAPIがあり、そのAPIのみTokenの検証を行なった後にアクセス可能にするケースを想定しています。

とは言っても、基本的には
Authentication in Golang with JWTs
を写経しています。

参考にしたサイトではWeb側の画面なども実装していますが、私の方は認証周り、Token周りを知りたかっただけなので
以下のような変更を加えました。

  • 画面はindex.htmlのみ
  • Tokenを取得するAPI(get-token)は固定のユーザー名、パスワードでBasic認証を行う
  • Tokenの判定についてはvalidateToken()という関数にて行うように変更

ソースは以下になります。
GitHub - SrcHndWng/go-learning-webapp-auth

使い方はREADMEにも記述しましたが、バイナリを実行したら以下のようなcurlで叩くことができます。

$ curl -v http://localhost:8080/status # APIのステータス確認
$ curl -v http://localhost:8080/products # Tokenを渡していないためエラー
$ curl -u username:password -v http://localhost:8080/get-token # Tokenの取得。username、passwordは固定。
$ TOKEN=上記で取得したトークン
$ curl -v http://localhost:8080/products -H "Authorization: $TOKEN"

ポイントとなるのは、Token周り、Basic認証を実装しているauth/login.goとauth/token.goです。
Tokenを取得する際のBasic認証はlogin.goのLogin()にて、Tokenの検証はtoken.goのValidateToken()にて実装してあります。

google-java-formatでJavaのコードをフォーマットしてみる

まあタイトル通りのことをしたので、そのメモです。

https://github.com/google/google-java-format

を参考に

https://github.com/google/google-java-format/releases

から「google-java-format-1.6-all-deps.jar」をダウンロードしました。

使い方は

$ java -jar path_to/google-java-format-1.6-all-deps.jar --help

で大体わかります。


私の場合は

  • インデントは4つ
  • フォーマットしてファイルを上書き保存したい

ので

$ java -jar path_to/google-java-format-1.6-all-deps.jar --aosp --replace path_to/your_program.java

のように「--aosp」「--replace」オプションをつけて実行しました。


フォーマットスタイルを任意に指定することはできないようですが、とりあえずサクッとフォーマットしたい場合にはいいかもです。

urfave/cliを使ってみた

Building a Network Command Line Interface in Go | TutorialEdge.net という記事を見つけました。

https://github.com/urfave/cli
このライブラリを使い、いくつかのネットワークコマンドを実行するCLIアプリを作ってみる記事です。

今回はこの記事を写経してみました。私が作ったソースは以下になります。
GitHub - SrcHndWng/go-learning-network-cli

単純に写経した訳ではなく

  • 「net.LookupNS(c.String("url"))」→「host」に修正
  • コマンド作成処理を独立したパッケージ(Commands)に切り出した

などの改変を行なっています。

GolangCLIアプリを作る際にはflagパッケージを使うことが多いかと思いますが
より簡単に作りたい場合などはurfave/cliを検討してもいいかもしれません。

Java 10 + Spring BootでTwitter Botを作成してみた

タイトルにあるように、Java 10でTwitter Botを作成してみました。
まあ今後、Java 8から10への移行案件とかもあるかもしれないし、
ということで予習を兼ねて。。。

作ったものとしては、前回書いたGolangでのTwitter Botと同等機能を
持つものになります。
前回の記事はこちら。
GolangでTwitter Botを作成してみた - ソースコードから理解する技術-UnderSourceCode

仕事の予習も兼ねているので、フレームワークはSpring Boot 2系を使ってみました。
あんまり2系固有の機能は使っていないですが。

Spring Bootを使う際、私はSpring Initializr(https://start.spring.io/)でプロジェクトの
雛形を作ることが多いです。
Java 10 で動かすにあたり、作成した雛形のbuild.gradleに以下の定義を行いました。

sourceCompatibility = 10
targetCompatibility = 10

Java 10 ということで、積極的にローカル変数の宣言には「var」を使ったのですが
個人的にはソースがスッキリとして好ましいですね。

作ったものは以下になります。
GitHub - SrcHndWng/learningTwitterRandomSearch

以下、参考にしたサイトです。
http://robo.genv.sophia.ac.jp/wp_robot/?p=1866
Twitter4J - 設定
Twitter Streaming APIをTwitter4Jで試してみる - @thorikiriのてょりっき
スレッドを終了させる | じっくり学ぶ Java講座 [初心者向け・入門]