I was reading the RDoc for Enumerable#inject and I felt it needed some love.
I felt it needed some love
って素敵な言い回しですね。
自分が、日本語に訳そうとすると「愛が少し足りてない」みたいな否定型の言い回しになっちゃうのが難しいです。
I was reading the RDoc for Enumerable#inject and I felt it needed some love.
I felt it needed some love
って素敵な言い回しですね。
自分が、日本語に訳そうとすると「愛が少し足りてない」みたいな否定型の言い回しになっちゃうのが難しいです。
TextAEの修正をしようとしたときに、ふと「JavaScriptで書くのダルいな、Rubyなら…」という思いを抱きました。
具体的にどの文法という話ではないし、難しい修正でもなくて、機能変更前の機械的なリファクタリングです。 TextAEもJavaScriptも長いこと触っているので、手癖で書けます。しばらく「ダルい」みたいな感情を持ったことがありませんでした。
我ながらこんな思考が浮かんで驚きました。これがRubyの魅力?謎です。
たぶん、脳のどこかにkakikataのコードを書いてたときの回路が残っていたのだと思います。 実際、手を動かし始めたらサクサク直せました。
最新のruby.wasmをビルドするために rake npm:ruby-head-wasm-wasi
を実行したら次のエラーが出ました。
npx jco transpile --no-wasi-shim --instantiation --valid-lifting-optimization /home/ledsun/ruby.wasm/packages/npm-packages/ruby-head-wasm-wasi/tmp/ruby.component.wasm -o /home/ledsun/ruby.wasm/packages/npm-packages/ruby-head-wasm-wasi/dist/component npm ERR! code E404 npm ERR! 404 Not Found - GET https://registry.npmjs.org/jco - Not found npm ERR! 404 npm ERR! 404 'jco@*' is not in this registry. npm ERR! 404 npm ERR! 404 Note that you can also install from a npm ERR! 404 tarball, folder, http url, or git url. npm ERR! A complete log of this run can be found in: /home/ledsun/.npm/_logs/2024-04-30T01_24_05_969Z-debug-0.log rake aborted!
jcoという見慣れない名前があります。 名前からすると Add jco-generated TypeScript interface of the js gem world by kateinoigakukun · Pull Request #432 · ruby/ruby.wasm · GitHub が関係ありそうです。
jcoはgit submoduleで参照しています。
git submodule update --init
してみます。
ledsun@MSI:~/ruby.wasm[1]►git submodule update --init Submodule 'vendor/jco' (https://github.com/bytecodealliance/jco.git) registered for path 'vendor/jco' fatal: destination path '/home/ledsun/ruby.wasm/vendor/jco' already exists and is not an empty directory. fatal: clone of 'https://github.com/bytecodealliance/jco.git' into submodule path '/home/ledsun/ruby.wasm/vendor/jco' failed Failed to clone 'vendor/jco'. Retry scheduled fatal: destination path '/home/ledsun/ruby.wasm/vendor/jco' already exists and is not an empty directory. fatal: clone of 'https://github.com/bytecodealliance/jco.git' into submodule path '/home/ledsun/ruby.wasm/vendor/jco' failed Failed to clone 'vendor/jco' a second time, aborting
vendor/jco
が既にありました。
jcoは以前からあって、参照方法が変わったのかもしれません。
vendor/jco
を削除してgit submodule update --init
しなおします。
bin/setup
してみます。
error[E0463]: can't find crate for `core` | = note: the `wasm32-wasi` target may not be installed = help: consider downloading the target with `rustup target add wasm32-wasi` error[E0463]: can't find crate for `compiler_builtins` For more information about this error, try `rustc --explain E0463`. error: could not compile `cfg-if` (lib) due to 2 previous errors warning: build failed, waiting for other jobs to finish... Error: command exited with non-zero code `cargo build --workspace --target wasm32-wasi`: 101
rustcでのビルドでエラーが出ました。
エラーメッセージの通り rustup target add wasm32-wasi
をしてみます。
ledsun@MSI:~/ruby.wasm[1]►rustup target add wasm32-wasi info: downloading component 'rust-std' for 'wasm32-wasi' info: installing component 'rust-std' for 'wasm32-wasi' 18.6 MiB / 18.6 MiB (100 %) 16.6 MiB/s in 1s ETA: 0s
rustのライブラリーが古かったみたいです。 あとはいつも通り
bin/setup rake npm:ruby-head-wasm-wasi
でビルドできました。
よく見ると、gitの変更が残っています。
ledsun@MSI:~/ruby.wasm►git status On branch main Your branch is up to date with 'origin/main'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) (commit or discard the untracked or modified content in submodules) modified: vendor/jco (modified content) Untracked files: (use "git add <file>..." to include in what will be committed) packages/npm-packages/ruby-head-wasm-wasi/tmp/ no changes added to commit (use "git add" and/or "git commit -a")
git submoduleの方はわかります。
packages/npm-packages/ruby-head-wasm-wasi/tmp/
は、なんでしょうか?
ruby.component.wasm
というファイルが一つだけあります。
これは .gitignore
に入れても良さそうです。
それともビルド成功時に tmp
ディレクトリを消す方が良いのかな?
パッと判断がつきません。
インク吸入器コンバーターを洗って干しました。 組み立てやすい順番に並べて干していたつもりが、順番が入れ替わって良くわからなくなりました。 セーラーのコンバーターを分解して洗浄することに - 暮らしと手帳と万年筆 の写真の並び順を参考に組み立てました。
再発防止のために手順を記録します。
マネジメント入門 その2 - @ledsun blog につづいて 管理職必読 順番に読むと理解が深まる「マネジメントの名著」11冊 | 日経BOOKプラス で紹介されていた本の三冊名です。
前回から間が空きました。 読むのを途中でやめたからです。 最後まで読まないことにして、ここに日記だけ書いておきます。
この本は講演会での話し方の本でした。 大勢の前で話して、注目を集めて、高揚させて、伝えたいことを伝える感じの方法です。 もしかするとRubyKaigiで話すときの参考になるのかもしれません。 まあ、でも僕がしたいのはそういうことじゃないんですよね。 という感じで迷いながら6割位読みました。 続きを読むエネルギーは出てこなかったので、本棚にしまいます。
管理職向けの本て、組織のリーダー向けの本と中間管理職向けのの本があります。 今のところ興味があるのは、中間管理職向けの本です。 この本は組織のリーダー向けかな?と思いました。 「100人に話して30人にやる気にさせる話し方」をイメージしました。 中間管理職は沢山の人に語るより、個人とちょっとずつこまめに話す方が良いんじゃないかなあ?と予測しています。
ruby.wasmように値がJavaScriptのFalsyな値か判定する関数を実装しました。
def self.falsy?(value) value == JS::Null || value == JS::Undefined || # Use the strictly_eql? method to compare values using JavaScript's `===` operator. # This is because JavaScript's `==` operator is loose in its judgment. # For example, in JavaScript, `[] == ""` is true, but `[] === ""` is false. value.strictly_eql?(JS::EmptyString) || value.strictly_eql?(JS::False) || value.strictly_eql?(JS::Zero) || value.strictly_eql?(JS::NinusZero) || value.strictly_eql?(JS::BingIntZero) || # `Number.isNaN`` is used to compare whether a value is `NaN`` or not. # This is because `NaN == NaN` is false in JavaScript, but `Number.isNaN(NaN)` is true. JS.global[:Number].isNaN?(value) end
もっとシンプルになるかと思ってました。 思ったより複雑でした。
というのは、たとえば次の比較は真になります。
JS.eval('return []') == JS.eval("return ''")
なぜかというとJavaScriptの==
がなかなかマイルドだからです。
> []=='' true > !([]) false > !('') true > []==='' false
そういえば、昔「JavaScript: The Good Parts」を読んだときにこの説明がありました。
その教えを守り、JavaScriptでプログラム書くときは===
しか使いません。
それもESLintでAuto Fixしています。
そして、今ではこの仕様のことをすっかり忘れていました。
実装してから気がついたのですが、これは僕が欲しいものでは無かったです。 名前も悪くないし、実装自体は、なかなか気にいっています。 ただ、使い所が思いつかないので、プルリクエストにするのは、一旦やめておきます
いつか使い所を思いついたときのために、自分のリポジトリのブランチとしては残しておきます。
ruby.wasmを使ってRubyでフロントエンドフレームワークをつくったらどうなるかを考えてみましょう。
テンプレートエンジンはERBを使うと良さそうです。
イベントハンドラーのバインドはRailsのルーティングっぽくなる良さそうです。 次のイメージです。
OrbitalRing.routes.draw do click ".ok_button", to: "task.done" ... end
アプリケーションのレンダリング先のHTMLElementのidはangular風にapp_root
固定にしましょう。
たぶんこんな感じで初期化します。
OrbitarRing.initialize
を呼ぶOrbitarRing.initialize
はLayout
を継承したクラスのnew("#app_root")
を呼ぶLayout#new
はクラス内に定義されたテンプレートを呼び出すdef initialize(selector) JS.global.querySelector(selector)[:innerHTML] = template.result end def template ERB.new(<<~'END_HTML') <%= Task.reder_all %> END_HTML end
class Task def self.render_all template_all.result_with_hash elements: all end def self.template_all ERB.new(<<~'END_HTML') <ul class="tasks"> <% elements.each do %> <%= _1.render %> <% end %> </ul> END_HTML end def reder template.result_with_hash element: self end def template ERB.new(<<~'END_HTML') <li> <%= element.name %> <button class="ok_button" data-id="<%=id%>"> </li> END_HTML end def self.done(event) task = find_by(event[:target]{:dataset][:id]) task.done end def done is_done = true end end
ERBを良い感じに埋め込む方法ほしいですね。
Taskインスタンスを自動的に見つけて欲しいです。 何か良い感じのIDの埋め込み方が要りそうです。
OrbitarRing.initialize
はなんか良い感じでイベントハンドラーをバインドする。マネジメント入門 その1 - @ledsun blog につづいて 管理職必読 順番に読むと理解が深まる「マネジメントの名著」11冊 | 日経BOOKプラス で紹介されていた本の二冊名です。
1冊目同様、部長、課長くらいの日本企業の中間管理職向けの本です。 1冊目と比べると具体的な話が少なめでした。 1冊目で大枠をつかんで、2冊目で引き出しを増やす感じでしょうか。 「これしかやらない」というタイトルとは、あまり一致していないのかもしれません。
印象深かった内容
「自分がどうしたい」を考えないとか、「仕事を面白くする方法を知らない」とか、驚きです。 そういう人が居るのは知っていました。 そういう人を導いていくことがマネジメントに含まれるとは思っていませんでした。
エンジニアコミュニティにはそういう人少ないのです。 創立20年くらいの小企業にも少ないです。 いや、そうではなく、そういう人達は生き延びることができなくて退場していきます。
言われてみれば「そういう人達をモチベートして、退場しないで戦力にできる。戦力にできたら強い組織になる」のは、そらそうだなっと思いました。 選ばれた特質を既に備えている人を選別するのではなくて、備えられるように育てる。 そら、まっとうな話ですね。
2冊読んで2冊とも似たようなことが書いてあるので、まあ、そうなんだろうなって思います。 まじかあ・・・
管理職必読 順番に読むと理解が深まる「マネジメントの名著」11冊 | 日経BOOKプラス で紹介されていた本です。 とりあえず一冊目を読んでみました。
マネジメントの本は経営者からチームリーダー向けまでターゲットがわかりにくいことがあります。 この本は、部長、課長くらいの日本企業の中間管理職向けの本です。
1 on 1の話は3章からはじまります。 1~2章をつかってマネージャーの仕事を説明しています。 100ページくらいにコンパクトにまとまっていてわかりやすかったです。
1 on 1 の具体的なハウツーは3章に書いてあります。 僕の所属組織は筆者の方の所属組織とは形が違うのでハウツーをそのままでは使いにくいです。
4章以降も1 on 1と絡めてはいますが、マネージャーの仕事全般の話で興味深かったです。
印象深かった内容
この中でも特に自分に足りていない点は、次の2点かなと思います。
本当に、サーバントリーダーシップというか、部活のマネージャー的なマネージャーなんだなと、思いました。 新人マネージャーが一冊目に読む本として、内容の網羅具合もページのコンパクトさも良さそうです。
お仕事でソフトウェアを開発するプログラマーチームに対して、僕が持っているイメージを整理しました。
人数 | |||
---|---|---|---|
2 | リードとサブ | コンビ | |
3 | リードとサブ x 2 | コンビとサポート | チーム |
4 | リードとサブ x 3 | チームとサポート | チーム |
5 | マネージャーとメンバー x 4 | チームとサポート | コミュニティ |
この表は、右に行くほどチームが自律性高くふるまうことをあらわします。
自律性が高い方が良いとは限りません。 自律性が低いと5人以上のチームでは、チームマネジメントを専任する人が必要になると思います。 それをマネージャーとメンバーと表現しています。 プログラマーの中にはチームマネジメントを専任したくない方が一定数います。 もしも、プログラマーからチームリーダーになり、チームマネジメント専任になりたくない場合、チーム人数が少ないうちから自律性を高めておくのがオススメです。
チームの人数が増えてから自律性を高めるには時間が掛かります。 チームメンバー同士が対話する機会を設け練習を繰り返す必要があります。 週1回程度の話し合いの機会を半年~一年くらい続けると、自律性が高まるように思います。
チームの自律性を重視するときに注意事項があります。 2人チームがリードとサブになるかコンビになるかは、性格の相性に強く依存します。 2チームでは、自律性をあまり重視しない方が無難です。
一方、3~4人では自律性を重視すると良いと思います。 リードとサブ x n の状態で人数が増えると、リーダとチームメンバーのコミュニケーションが増え、チームメンバー同士のコミュニケーションが増えません。 リーダーがコミュニケーションにつかうコストが増え、チームメンバー同士のコミュニケーションを増やす施策が打てなくなります。 チームの人数が増えるとチームのパフォーマンスは一度下がります。 チームのパフォーマンスを上げるために、リーダとチームメンバーのコミュニケーションに時間を使いたくなると思います。 一度パフォーマンスが上がってからチームの自律性を高めようとしても、チームの自律性を高めるには再びパフォーマンスを一時的に下げる必要があります。 怖くてできません。 「パフォーマンスが上がっているし、自分が我慢すれば良い」と思いがちです。 人間は「自分が我慢すればよい」誘惑に抵抗するのに、ものすごいパワーが要ります。
上の表をみると、5人チームにコミュニティという謎の状態があります。 チームとコミュニティの違い、会社・組織をどう捉えるか | Social Change! に出てきているコミュニティをイメージしています。 なぜ、チームではなくコミュニティなのかというと、5人以上になると、ミッションに対して100%動いていないメンバーがでてきます。 4人のチームはめちゃくちゃ上手く行っていると4人分の成果がでます。 5人のチームはめちゃくちゃ上手く行っても4.5人分の成果です。
スキルの差からではなく、タスクの投入量が上手くコントロールできなくなるために起きます。 手の空くメンバーは特定の人物ではありません。時々によって手が空くメンバーは変わります。 タスクを上手く用意すれば5人分の成果がでるようになるかというと、僕の経験則では、なりません。
チームにミッション以外のことに取り組む余裕が生まれた状態と捉えるとよいです。 ミッションとは別の緊急ではないが重要なタスクを用意しておいて、チームメンバーに取り組ませるとよいでしょう。 これはチームの余裕です。 4人までのチームでは緊急ではないが重要なタスクは正式なタスクにしたり、リーダーが空き時間でこっそりやったりという工夫が必要です。 5人以上のチームがコミュニティになると、チームメンバーが自主的に緊急ではないが重要なタスクに取り組めるようになります。
また、もともと4.5人分の成果しか出ないので、メンバーの離脱や加入が容易になります。 一人離脱しても12.5パーセントしか下がらないのでインパクトが弱いです。 一人加入にしても1人分の成果は期待されないので、新メンバーの負担が低いです。 このメンバーの出入りが容易な状態が、チームではなく場でありコミュニティです。
チームの自律性を高めるコツは、チームメンバーに縄張りを作らせないことです。 人間は縄張り意識を持つと、その作業を他人にされるのが苦痛に感じます。 また、縄張り外の仕事するのがおっくうになります。
縄張りをつくらせないためには、リーダーはチームメンバーの扱いを変えてはいけません。 チームメンバーのスキル、年齢、性別、得意なことが違っても扱いを変えません。 経歴20年のベテランと新卒半年の新人の扱いを同じくします。 スキルが足りない部分のサポートは必要です。 スキルが足りている作業は平等に割り振ります。
チームメンバーによって実行速度の遅い速いの差はありますが、クリティカルパスに乗っていない作業は早さを気にする必要はありません。 また時間が掛かっても成果を出せた体験は、個人の成長に繋がります。 さらにクリティカルパスに乗っていない作業は早さを気にする必要が無いは頭で理解しても、なかなかその通りにふるまえません。 何度も実際に体験する必要があります。
平等に割り振らずに、ベテランにばかり難しい作業を振ると「この領域はおれの仕事」と縄張りを作りはじめます。 ベテランほど陥りやすいので、意図的にコントロールする必要があります。 コントロールせずに放置しておくと、よほどの人格者でないとブリリアントジャーク化します。 すでにブリリアントジャーク化していてコントロールできず、 短期的な成果よりチームの成長が重要な場面では、チームから外れてもらうことを考えてもいいかもしれません。
継続して開発していると、前回機能Aを担当した人に今回も機能Aをお願いしたくなります。 よほど急ぎでない限り担当はグルグル変えるようにしましょう。 繰り返しですが、クリティカルパスに乗っていない作業は早さを気にする必要はありません。 プロジェクトの進行が早くならないのに、縄張り作りを強化するのは、なにも得しませんよね。
MySQLのロックに関する調査メモ その3 - @ledsun blog の続きです。
SHOW ENGINE INNODB STATUS\G
で出力されるロック情報を眺めていたら意味がわかってきました。
まずテーブルに格納されているレコードの情報です。
select * from mysqlcasual; +----+------+------+ | id | col1 | col2 | +----+------+------+ | 1 | 2 | 0 | | 2 | 4 | 0 | | 3 | 6 | 0 | | 4 | 8 | 0 | | 5 | 10 | 0 | | 6 | 12 | 0 | | 7 | 14 | 0 | | 8 | 16 | 0 | +----+------+------+
begin;SELECT id, col1 FROM mysqlcasual WHERE col1 = 2 FOR UPDATE;
三つのロック情報が出てきます。 一つ目から見ていきます。
RECORD LOCKS space id 173 page no 4 n bits 80 index idx_col1 of table `sandbox`.`mysqlcasual` trx id 7731 lock_mode X Record lock, heap no 2 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 80000002; asc ;; 1: len 4; hex 80000001; asc ;;
index idx_col1 of table
はインデックス idx_col1 に対するロックであることを表しています。
lock_mode X
はネクストキーロックであることを表しています。無印がネクストキーロックです。
0: len 4; hex 80000002; asc ;; 1: len 4; hex 80000001; asc ;;
はロックしているレコードを表してます。
80000002
はcol1カラムの値が2、80000001
はidカラムの値です。
選択するレコードを変えてみます。
begin;SELECT id, col1 FROM mysqlcasual WHERE col1 = 4 FOR UPDATE;
RECORD LOCKS space id 173 page no 4 n bits 80 index idx_col1 of table `sandbox`.`mysqlcasual` trx id 7733 lock_mode X Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 80000004; asc ;; 1: len 4; hex 80000002; asc ;;
80000004
と80000002
になりました。
次のロック情報を見てみましょう。
RECORD LOCKS space id 173 page no 3 n bits 80 index PRIMARY of table `sandbox`.`mysqlcasual` trx id 7733 lock_mode X locks rec but not gap Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000002; asc ;; 1: len 6; hex 00000000162a; asc *;; 2: len 7; hex aa0000011e011d; asc ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000000; asc ;;
index PRIMARY of table
とあるので、プライマリーインデックスへのロックです。セカンダリーインデックスをロックするとプライマリーインデックスもロックされるやつですね。
lock_mode X locks rec but not gap
は、レコードロックを表してます。ギャップロックでないものがレコードロックです。
0: len 4; hex 80000002; asc ;; 1: len 6; hex 00000000162a; asc *;; 2: len 7; hex aa0000011e011d; asc ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000000; asc ;;
80000002
と80000004
と80000000
はレコードの値を表していそうです。
00000000162a
とaa0000011e011d
は謎です。プライマリーインデックスとidex_col1を表しているのかもしれません。
上は2つ目のレコードです。1つ目のレコードは下になります。
0: len 4; hex 80000001; asc ;; 1: len 6; hex 00000000162a; asc *;; 2: len 7; hex aa0000011e0110; asc ;; 3: len 4; hex 80000002; asc ;; 4: len 4; hex 80000000; asc ;;
00000000162a
は変わりません。
aa0000011e011d
はaa0000011e0110
になりました。
うーん、これはちょっとよくわかりません。
RECORD LOCKS space id 173 page no 4 n bits 80 index idx_col1 of table `sandbox`.`mysqlcasual` trx id 7733 lock_mode X locks gap before rec Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 80000006; asc ;; 1: len 4; hex 80000003; asc ;;
index idx_col1 of table
なのでidx_col1へのロックです。
lock_mode X locks gap before rec
なので、ギャップロックです。
0: len 4; hex 80000006; asc ;; 1: len 4; hex 80000003; asc ;;
は、3つ目のレコードを表しています。 ギャップロックなので、3つ目のレコードの手前までをロックしているようです。
もしかして、1つ目のネクストキーロックを、2つ目のレコードロックと3つ目のギャップロックで実現していることを表現しているのでしょうか?
MySQLのロックに関する調査メモ その2 - @ledsun blog の続きです。 概念だけ勉強しても理解に限度があります。 実際にロックを起こして観察してみました。
InnoDBのロックの範囲とネクストキーロックの話 - かみぽわーる を参考にしました。 MySQL Shellを起動しMySQLに接続します。
\connect --mysql --user root \use sandbox \sql
sandboxスキーマは練習用に作ってあったものを使い回しています。 テーブルを作成します。
CREATE TABLE `mysqlcasual` ( `id` int(11) NOT NULL AUTO_INCREMENT, `col1` int(11) NOT NULL, `col2` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `idx_col1` (`col1`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `mysqlcasual`(`col1`) VALUES (2),(4),(6),(8),(10),(12),(14),(16);
MySQL 5.7 以降では、ここからの手順が変わっています*1。
CREATE TABLE innodb_lock_monitor(a int) ENGINE=InnoDB;
の代わりに
SET GLOBAL innodb_status_output=ON; SET GLOBAL innodb_status_output_locks=ON;
します。 また、共有ロックではロックが表示されませんでした。
BEGIN; SELECT id, col1 FROM mysqlcasual WHERE col1 = 4 LOCK IN SHARE MODE;
の代わりに
BEGIN; SELECT id, col1 FROM mysqlcasual WHERE col1 = 4 FOR UPDATE;
を試しました。
SHOW ENGINE INNODB STATUS\G
を実行するとTRANSACTIONSセクションにロック情報が表示されました。
RECORD LOCKS space id 173 page no 4 n bits 80 index idx_col1 of table `sandbox`.`mysqlcasual` trx id 7717 lock_mode X Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 80000004; asc ;; 1: len 4; hex 80000002; asc ;;
RECORD LOCKS space id 173 page no 3 n bits 80 index PRIMARY of table `sandbox`.`mysqlcasual` trx id 7717 lock_mode X locks rec but not gap Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000002; asc ;; 1: len 6; hex 00000000162a; asc *;; 2: len 7; hex aa0000011e011d; asc ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000000; asc ;;
インデックスレコードロック?
RECORD LOCKS space id 173 page no 4 n bits 80 index idx_col1 of table `sandbox`.`mysqlcasual` trx id 7717 lock_mode X locks gap before rec Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 80000006; asc ;; 1: len 4; hex 80000003; asc ;;
ギャップロック?
出力された情報の読み方が謎です。
万年筆のインクです。
赤っぽいのかと思っていました。 茶色とオレンジの間ぐらいの色でした。 好きな感じの色です。
写真で見ると、赤ですね。
このメモは別の資料を見ながら書いたメモです。 メモだけ見ても意味が通じないと思います。
MySQLのロックに関する調査メモ その1 - @ledsun blog の続きです。
MySQLのロックについて - SH2の日記 のPDFを読みました。 面白かったです。
MySQL(というかInnoDB)の最初のスタート地点が「絶対にファントムリードさせたくない」なようです。 つまり一度トランザクションをはじめたら、他のトランザクションでの操作を見たくありません。 例えば、自トランザクションで見ている行と行の間に、他トランザクションからInsertされたくありません。 ということは行単位のロックでは足りなくて、自トランザクションで見ている範囲をロックしたいです。 これが、ギャップロックとネクストキーロックのようです。
今の段階ではギャップロックとネクストキーロックの違いはわかっていません。 特に、なぜネクストキーロックをしなければいけないのかよくわかりません。
どうもこの辺の思想は「トランザクション処理 概念と技法」のでしょうか?
もう一つ、MySQLの面白い特徴は、プライマリーインデックスのリーフに行があることです。
MySQL :: MySQL 8.0 リファレンスマニュアル :: 15.6.2.1 クラスタインデックスとセカンダリインデックス
すべての InnoDB テーブルは、行のデータが格納されているクラスタ化されたインデックスと呼ばれる特別なインデックスを持っています。
MySQL :: MySQL 8.0 リファレンスマニュアル :: 15.7.1 InnoDB ロック に次のように書いてあります。
レコードロックは、インデックスレコードのロックです。
どうもこういうことを説明しているみたいです。
また、セカンダリーインデックスをロックするときは、セカンダリーインデックスとプライマリーインデックスのインデックスレコードを両方ロックするそうです。