Skip to content

Instantly share code, notes, and snippets.

@kazuho
Last active February 20, 2016 18:47
Show Gist options
  • Save kazuho/5027236 to your computer and use it in GitHub Desktop.
Save kazuho/5027236 to your computer and use it in GitHub Desktop.
MessagePackの文字列型追加において、Extended型を導入する提案

#MessagePackの文字列型追加において、Extended型を導入する提案

本提案は https://gist.github.com/frsyuki/5022569 https://gist.github.com/frsyuki/5022460 において提案された「バイナリ型」の構造に変更を施すものである。

##解決しようとする問題

  • MessagePackへの拡張は今後行われないとしても、独自に拡張する提案が今後頻発しそう
  • 拡張フォーマットは、既存のMessagePackに対して後方互換にならない(なりようがない)ため、相互運用性を損なう可能性が高い。これが問題

##提案する手法

今回文字列型とバイナリ型を導入するにあたり、型システムを拡張可能なものとし、拡張された型は、古いバージョンのcodecにおいては、バイナリとして扱われるような設計とすべき。

こうすることで、今後型の拡張が行われたとしても、旧バージョンのツールでラウンドトリップ問題が発生しないことを保証できるし、結局、ツールというものは自分の知ってる型のデータしか扱わないので、それで問題ない。

##フォーマット

https://gist.github.com/frsyuki/5022569 に以下の変更を施すべき。

0xc4-0xc9,0xd4,0xd5 FixExtended (0bytes - 7bytes extended type)
0xd6 Extended 8 (extended type)  // new
0xd7 Extended 16 (extended type)  // new
0xd8 Extended 32 (extended type)  // new

0xd9 string 8 (String type)  // new
0xda string 16 (String type)  // changed from raw 16
0xdb string 32 (String type)  // changed from raw 32

Extended = ExtendedTAG n-OCTETS (nは各FixExtended,Extended8,16,32で規定)

ExtendedTAG = 0x00 - binary 0xf0-0xff - private extension

全てのtypeを使い切るが、今後の拡張はExtendedTagを使って可能だし、その場合確実に後方互換性を保証できる。

###拡張例

たとえばtime_t型をTAG=0x31として追加する場合:

0xc7 0x31 0x51 0x2a 0xd5 0xb0 ; is Feb 25 03:08:32 2013 (0x512ad5b0)

たとえばShift_JIS型をTAG=0x32として追加する場合:

0xd6 0x0a 0x32 0x82 0xb1 0x82 0xf1 0x82 0xc9 0x82 0xbf 0x82 0xcd ; こんにちは

##FAQ

###Q.256個のExtendedTAGを使い切ったらどうなるか?

ExtendedTAGを1バイトとして定義しても可変長の構造として定義しても、後方互換性の観点から言うと優劣は存在しない。

なぜなら、2バイトのExtendedTAGが必要になったら、「データの先頭もExtendedTAGだよーというExtendedTAGを導入すればいい」から。その必要性がある実装は対応するだろうし、対応しない実装では、未知の型をもつバイナリとして扱われるから、後方互換性は維持される。

そこで、現時点でExtendedTAGを可変長フォーマットとして提案することで、提案がリジェクトされる可能性を危惧し、このような提案としている。

@frsyuki
Copy link

frsyuki commented Feb 25, 2013

@kazuho reserved bytesを残すべきではないという意見に賛成です。 @kenn
その意味で 0xc1 も NEVER USED に割り当てるのが良いのでは無いかと思っています。

NEVER USED を作る理由は:例えばJava版の実装だと、デシリアライザの実装で「次の型」を表すフィールドを1バイトで持っています。そこで「まだ読んでない」を表すために 0xc6 を使っている。0xc6は読んだ時点でエラーになるので、「次の型」として0xc6が使われることは無い。
特に 0xc6 にこだわりはなく、0xc6 を 0xc1 に変えるのは実装の詳細の変更だけで済みます。

@kazuho
Copy link
Author

kazuho commented Feb 26, 2013

@frsyuki @kenn
個人的には 0xc1 に TinyExtended8 (つまり8バイト長のExtended) を割り振ることができると、圧縮率上がるし、拡張ポイントを完全に防げるかなぁ、と思わないでもないです。

あるいは 0xc1 を never に残す場合(僕は現時点でこちらのアプローチに賛成です)、TinyExtended を本当に 0-7 バイトに割り当てるのでいいのか、という話もあります。たとえば、0 1 2 4 6 8 10 12 のほうがいいのかもしれない。だが、歯抜けになるのも良くないよねという(特に小さいデータほど圧縮効率が悪くなるのは、データ型の分布を事前に予測できないというのであれば避けるべきですから)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment