Bug #1229

並列にテーブルの作成や削除を行うとデータベースが壊れる

Added by Ryo Onodera about 6 years ago. Updated about 6 years ago.

Status:新規Start date:12/27/2011
Priority:NormalDue date:
Assignee:Ryo Onodera% Done:

0%

Category:-
Target version:-

Description

h2. 問題

並列にテーブルの作成や削除を行うとデータベースファイルが壊れるケースがある。

h2. 期待する状態

並列にテーブルの作成や削除を行ってもデータベースファイルが壊れないようにする。

h2. 解決方法

まずは、問題を簡単に再現できるスクリプトを用意する。

その後、そのスクリプトを元に直していく。

concurrent-schema-manipulation.rb Magnifier (3.25 KB) Ryo Onodera, 12/28/2011 04:08 pm

concurrent-schema-manipulation.rb Magnifier (3.67 KB) Ryo Onodera, 12/29/2011 06:11 pm

History

#1 Updated by Ryo Onodera about 6 years ago

添付したものが、問題を再現させるスクリプトです。

Ruby 1.9とgroongaのmaster(ea23e8bd7fdde20dc3723d8ed87f1179b50a6099)、rroongaのmaster(6aa26d1599a7fc0f1729facd88de2969667bd23d)で検証しました。

このスクリプトは、テーブルの作成と削除を繰り返し続けるものです。その間にある一定量のエラーが発生した場合に限り、終了します。

以下のように実行すると複数プロセスでテーブルの作成や削除を行います。1時間経たないうちに後述のエラーメッセージが発生します。

$ ruby1.9.1 ./concurrent-schema-manipulation.rb

以下のように実行すると1つのプロセスでテーブルの作成や削除を行います。1時間経っても、エラーメッセージが発生しません。

$ ruby1.9.1 ./concurrent-schema-manipulation.rb 1

このスクリプトではデータベースファイルを自動的に作成し、既に存在しているときは、再利用します。新規のデータベースファイルでスクリプトを実行するには、スクリプトを実行する前に、以下のようにして、既存のデータベースファイルを削除してください。

$ rm -rf /tmp/concurrent-schema-manipulation

エラーメッセージは、例えば以下のようなエラーメッセージが出ます。

./concurrent-schema-manipulation.rb:29:in `define_column': no such file or directory: syscall error 'stat' (No such file or directory): [#, name: , path: , domain: , range: (nil), flags: <>, encoding: <:utf8>, size: <0>>, ["status", "UInt32"]] (Groonga::NoSuchFileOrDirectory)
io.c:598: grn_io_remove()
    from ./concurrent-schema-manipulation.rb:29:in `do_create_table'
    from ./concurrent-schema-manipulation.rb:45:in `create_table'
    from ./concurrent-schema-manipulation.rb:137:in `block (2 levels) in manipulate_schema'
    from ./concurrent-schema-manipulation.rb:85:in `rescue_harmless_errors'
    from ./concurrent-schema-manipulation.rb:135:in `block in manipulate_schema'
    from ./concurrent-schema-manipulation.rb:112:in `fork'
    from ./concurrent-schema-manipulation.rb:112:in `run_in_separate_memory_address_space'
    from ./concurrent-schema-manipulation.rb:134:in `manipulate_schema'
    from ./concurrent-schema-manipulation.rb:149:in `block (2 levels) in run'
    from ./concurrent-schema-manipulation.rb:148:in `loop'
    from ./concurrent-schema-manipulation.rb:148:in `block in run'
    from ./concurrent-schema-manipulation.rb:106:in `fork'
    from ./concurrent-schema-manipulation.rb:106:in `block in run_each_worker'
    from ./concurrent-schema-manipulation.rb:105:in `times'
    from ./concurrent-schema-manipulation.rb:105:in `run_each_worker'
    from ./concurrent-schema-manipulation.rb:147:in `run'
    from ./concurrent-schema-manipulation.rb:155:in `
'

#2 Updated by Ryo Onodera about 6 years ago

  • Tracker changed from Feature to Bug

#3 Updated by Ryo Onodera about 6 years ago

複数のプロセスでテーブルの作成と削除を繰り返していると、以下のようにSEGVします。

./concurrent-schema-manipulation.rb:112: [BUG] Segmentation fault
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]

-- control frame ----------
c:0017 p:---- s:0048 b:0048 l:000047 d:000047 CFUNC  :fork
c:0016 p:0019 s:0045 b:0045 l:000044 d:000044 METHOD ./concurrent-schema-manipulation.rb:112
c:0015 p:0011 s:0040 b:0040 l:0007b8 d:0007b8 METHOD ./concurrent-schema-manipulation.rb:134
c:0014 p:0009 s:0037 b:0037 l:0009b0 d:000036 BLOCK  ./concurrent-schema-manipulation.rb:149
c:0013 p:---- s:0034 b:0034 l:000033 d:000033 FINISH
c:0012 p:---- s:0032 b:0032 l:000031 d:000031 CFUNC  :loop
c:0011 p:0009 s:0029 b:0029 l:0009b0 d:000028 BLOCK  ./concurrent-schema-manipulation.rb:148
c:0010 p:---- s:0027 b:0027 l:000026 d:000026 FINISH
c:0009 p:---- s:0025 b:0025 l:000024 d:000024 CFUNC  :fork
c:0008 p:0018 s:0022 b:0022 l:000014 d:000021 BLOCK  ./concurrent-schema-manipulation.rb:106
c:0007 p:---- s:0020 b:0020 l:000019 d:000019 FINISH
c:0006 p:---- s:0018 b:0018 l:000017 d:000017 CFUNC  :times
c:0005 p:0012 s:0015 b:0015 l:000014 d:000014 METHOD ./concurrent-schema-manipulation.rb:105
c:0004 p:0034 s:0010 b:0010 l:0009b0 d:0009b0 METHOD ./concurrent-schema-manipulation.rb:147
c:0003 p:0366 s:0006 b:0006 l:001ef8 d:000888 EVAL   ./concurrent-schema-manipulation.rb:155
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH
c:0001 p:0000 s:0002 b:0002 l:001ef8 d:001ef8 TOP   
---------------------------
-- Ruby level backtrace information ----------------------------------------
./concurrent-schema-manipulation.rb:155:in `
' ./concurrent-schema-manipulation.rb:147:in `run' ./concurrent-schema-manipulation.rb:105:in `run_each_worker' ./concurrent-schema-manipulation.rb:105:in `times' ./concurrent-schema-manipulation.rb:106:in `block in run_each_worker' ./concurrent-schema-manipulation.rb:106:in `fork' ./concurrent-schema-manipulation.rb:148:in `block in run' ./concurrent-schema-manipulation.rb:148:in `loop' ./concurrent-schema-manipulation.rb:149:in `block (2 levels) in run' ./concurrent-schema-manipulation.rb:134:in `manipulate_schema' ./concurrent-schema-manipulation.rb:112:in `run_in_separate_memory_address_space' ./concurrent-schema-manipulation.rb:112:in `fork' -- C level backtrace information ------------------------------------------- /usr/lib/libruby-1.9.1.so.1.9(rb_vm_bugreport+0x61) [0x7fb63ac13db1] /usr/lib/libruby-1.9.1.so.1.9(+0x592fe) [0x7fb63ab1b2fe] /usr/lib/libruby-1.9.1.so.1.9(rb_bug+0xa5) [0x7fb63ab1bd55] /usr/lib/libruby-1.9.1.so.1.9(+0xf3c84) [0x7fb63abb5c84] /lib/x86_64-linux-gnu/libc.so.6(+0x36420) [0x7fb63a759420] /home/ryoqun/local/lib/libgroonga.so.0(grn_io_close+0x28) [0x7fb63883331a] /home/ryoqun/local/lib/libgroonga.so.0(grn_ra_close+0x35) [0x7fb6388b6e97] /home/ryoqun/local/lib/libgroonga.so.0(grn_obj_close+0x4f2) [0x7fb6389606d3] /home/ryoqun/local/lib/libgroonga.so.0(grn_db_close+0x230) [0x7fb63892504c] /home/ryoqun/local/lib/libgroonga.so.0(grn_obj_close+0x41a) [0x7fb6389605fb] /home/ryoqun/local/lib/libgroonga.so.0(grn_obj_unlink+0x68) [0x7fb638960888] /home/ryoqun/work/rroonga/ext/groonga/groonga.so(+0xaf9d) [0x7fb638d21f9d] /home/ryoqun/local/lib/libgroonga.so.0(grn_ctx_fin+0xe6) [0x7fb638900ff1] /home/ryoqun/local/lib/libgroonga.so.0(grn_fin+0x59) [0x7fb638902789] /home/ryoqun/work/rroonga/ext/groonga/groonga.so(+0x15939) [0x7fb638d2c939] /usr/lib/libruby-1.9.1.so.1.9(rb_exec_end_proc+0x230) [0x7fb63ab21720] /usr/lib/libruby-1.9.1.so.1.9(+0x5f7fa) [0x7fb63ab217fa] /usr/lib/libruby-1.9.1.so.1.9(ruby_cleanup+0x133) [0x7fb63ab21973] /usr/lib/libruby-1.9.1.so.1.9(ruby_stop+0x9) [0x7fb63ab21c19] /usr/lib/libruby-1.9.1.so.1.9(+0xc11fb) [0x7fb63ab831fb] /usr/lib/libruby-1.9.1.so.1.9(+0x14aac6) [0x7fb63ac0cac6] /usr/lib/libruby-1.9.1.so.1.9(+0x141806) [0x7fb63ac03806] /usr/lib/libruby-1.9.1.so.1.9(+0x14743d) [0x7fb63ac0943d] /usr/lib/libruby-1.9.1.so.1.9(+0x14bf3b) [0x7fb63ac0df3b] /usr/lib/libruby-1.9.1.so.1.9(rb_rescue2+0x16b) [0x7fb63ab203eb] /usr/lib/libruby-1.9.1.so.1.9(+0x13eabe) [0x7fb63ac00abe] /usr/lib/libruby-1.9.1.so.1.9(+0x14aac6) [0x7fb63ac0cac6] /usr/lib/libruby-1.9.1.so.1.9(+0x141806) [0x7fb63ac03806] /usr/lib/libruby-1.9.1.so.1.9(+0x14743d) [0x7fb63ac0943d] /usr/lib/libruby-1.9.1.so.1.9(rb_yield+0x495) [0x7fb63ac0f155] /usr/lib/libruby-1.9.1.so.1.9(rb_protect+0xda) [0x7fb63ab2060a] /usr/lib/libruby-1.9.1.so.1.9(+0xc11f2) [0x7fb63ab831f2] /usr/lib/libruby-1.9.1.so.1.9(+0x14aac6) [0x7fb63ac0cac6] /usr/lib/libruby-1.9.1.so.1.9(+0x141806) [0x7fb63ac03806] /usr/lib/libruby-1.9.1.so.1.9(+0x14743d) [0x7fb63ac0943d] /usr/lib/libruby-1.9.1.so.1.9(rb_yield+0x26e) [0x7fb63ac0ef2e] /usr/lib/libruby-1.9.1.so.1.9(+0x95ed1) [0x7fb63ab57ed1] /usr/lib/libruby-1.9.1.so.1.9(+0x14aac6) [0x7fb63ac0cac6] /usr/lib/libruby-1.9.1.so.1.9(+0x141806) [0x7fb63ac03806] /usr/lib/libruby-1.9.1.so.1.9(+0x14743d) [0x7fb63ac0943d] /usr/lib/libruby-1.9.1.so.1.9(rb_iseq_eval_main+0xb2) [0x7fb63ac10432] /usr/lib/libruby-1.9.1.so.1.9(+0x5d4a2) [0x7fb63ab1f4a2] /usr/lib/libruby-1.9.1.so.1.9(ruby_exec_node+0x1d) [0x7fb63ab1ff9d] /usr/lib/libruby-1.9.1.so.1.9(ruby_run_node+0x1e) [0x7fb63ab21bde] ruby1.9.1(main+0x4b) [0x4007fb] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7fb63a74430d] ruby1.9.1() [0x400829] [NOTE] You may have encountered a bug in the Ruby interpreter or extension libraries. Bug reports are welcome. For details: http://www.ruby-lang.org/bugreport.html

#4 Updated by Ryo Onodera about 6 years ago

あまり関連が無いのですが、ちょっと気になることがあります。

テーブル、カラムの作成時に払い出されるIDが再利用されているようなのですが、もしかしたらABA問題に似た問題が発生しているかもしれません。。

Process 1が"Cache001"でgrn_ctx_get()する。そしてテーブルが返されます。このときローカルのメモリ空間のgrn_objが作成され、header.typeがGRN_TABLE_HASH_KEYでIDが370としてコピーされます。

Process 2が"Cache001"テーブルを削除する。IDの370が未使用になる。

Process 3が"Cache002.status"カラムを作成する。この時IDの370が再利用される。データベースファイル上ではID:370のheader.typeがGRN_OBJ_COLUMN_SCALARとなる。

Process 1が処理を再開する。このプロセスのローカルのメモリ空間のgrn_objではID:370のheader.typeがGRN_TABLE_HASH_KEYとみなされて処理が続行される。

よくないことが起こる。

#5 Updated by Ryo Onodera about 6 years ago

  • File concurrent-schema-manipulation.rb added

細かな修正をした新しい再現スクリプトを添付します。

#6 Updated by Ryo Onodera about 6 years ago

  • File deleted (concurrent-schema-manipulation.rb)

#7 Updated by Ryo Onodera about 6 years ago

すいません。編集途中のものを添付してしまったので、新しいのを添付しなおします。

Also available in: Atom PDF