Skip to content

Latest commit

 

History

History
174 lines (133 loc) · 7.73 KB

20220116.md

File metadata and controls

174 lines (133 loc) · 7.73 KB

今週何知った? week:5

hackmd-github-sync-badge

[name=makicamel]

実例レースコンディション

イテレーション中に Hash のキーを破壊的に変更するとエラー

Ruby では Hash のイテレーション中に Hash に破壊的変更として新しいキーを挿入しようとするとエラーになる ref can't add a new key into hash during iterationが謎の状況で発生しているように見えるときは - 猫型の蓄音機は 1 分間に 45 回にゃあと鳴く

hash = { a: :b }
hash.each do |_k, _v|
  hash[:new_key] = :new_value
end
# (irb):3:in `block in <main>': can't add a new key into hash during iteration (RuntimeError)
# 	from (irb):2:in `each'
# 	from (irb):2:in `<main>'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/bin/irb:23:in `load'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/bin/irb:23:in `<main>'

Set でも同様に発生する(Array では起きない)。これは Ruby の Set が内部記憶として Hash を使うため(ref)。

コード例
set = Set.new([1])
set.each do |_|
  set << :new_value
end
# /Users/makicamel/.rbenv/versions/3.0.3/lib/ruby/3.0.0/set.rb:355:in `add': can't add a new key into hash during iteration (RuntimeError)
# 	from (irb):3:in `block in <main>'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/lib/ruby/3.0.0/set.rb:344:in `each_key'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/lib/ruby/3.0.0/set.rb:344:in `each'
# 	from (irb):2:in `<main>'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/bin/irb:23:in `load'
# 	from /Users/makicamel/.rbenv/versions/3.0.3/bin/irb:23:in `<main>'

array = [1]
array.each do |_|
  array << :new_value
  break
end
p array
# => [1, :new_value]

Coverband での実例

Coverband5.2.1 + 5.2.1.rc.1 で以下の不具合があった(master では修正済) can't add a new key into hash during iteration · Issue #436 · danmayer/coverband

# `@views_to_record` は Set なので他スレッドが `@views_to_record` に値を加えようとするとエラーになる
@views_to_record.each do |file|
  redis_store.hset(tracker_key, file, reported_time)
end

マルチスレッドによるエラーは以下のコードで再現できる

set = Set.new((1..100).to_a)

Thread.new do
  set.each do |_|
    sleep(0.1)
  end
end

Thread.new do
  set << 101
end

# #<Thread:0x00007f8b3b8d4cd0 (irb):9 run> terminated with exception (report_on_exception is true):
# /Users/makicamel/.rbenv/versions/3.0.3/lib/ruby/3.0.0/set.rb:355:in `add': can't add a new key into hash during iteration (RuntimeError)
# 	from (irb):10:in `block in <main>'

[name=ken3ypa]

IndexedDB

1. 調べようと思ったきっかけ

前回のFileSystemAccessAPIを調べている際に、FileSystemHandleオブジェクトをIndexedDBに保存することでブラウザを閉じたあとも永続化できるという記載があった。そのためIndexedDBについて調査した

2. 基本情報

2-1. 何ができるか

  • JavaScript経由でクライアント側で永続的なデータベースにデータを保存・読み出しが出来る。
    • オブジェクトストア(テーブル)を作成し、
    • LocalStorageやSessionStorageなどの Web Storage より高度な機能を提供
      • IndexやTransaction もサポートしている

2-2. バージョン

  • 2022/01/16現在、IndexedDB 2.0 が利用可能
    • Chromeでは 58 から対応
    • オブジェクトストアやインデックスの名前変更や getKey() などのメソッドが追加
  • IndexedDB 3.0 も準備されつつある

2-3. ブラウザのサポート

image.png (99.9 kB)

3. 比較

3-1. WebStorageについて

  • WebStorageはユーザーのローカル環境(ブラウザ)にデータを保存するための仕組み。Cookieよりも保存できる容量が大きい(5MB)
    • SessionStorage
      • 保存されたデータはセッションの終了時に消える。セッションはブラウザを開いている限り持続する。 ただし新しいタブやウィンドウを開くと、新しいセッションが開始される。
    • LocalStorage
      • 保存されたデータに保持期間の制限はなく、新しいタブやウィンドウを開いてもセッションは持続する。

3-2. WebStorage と IndexedDBの比較

名前 transaction index 容量 永続化
LocalStorage stringのみ なし なし 1オリジンあたり5MB あり
SessionStorage stringのみ なし なし 1オリジンあたり5MB ウィンドウやタブを閉じるまで
IndexedDB string, integer, floatなど複数の型をサポート あり あり 許可なしで10MB
許可するとブラウザごとに決められた容量まで
あり

3-3. 容量について補足

容量は動的に決まる

  • グローバルリミット
    • 最大容量は、ディスク空き容量の50% に決められる(たとえば500GBの容量があればブラウザのストレージサイズは250GB)
    • 上限に達すると「オリジン立ち退き」を実行してストレージの総量が上限を下回るまでデータを削除
  • グループリミット
    • オリジンごとに、グローバルリミットの20%として決められる(250GBであれば50GB)
      • グループリミットの場合は「オリジン立ち退き」は実行されない
      • Chromeでは66から 2GB またはグローバルリミットの10% までの容量が適用される
ストレージの利用可能な容量を調べる方法
  1. StorageManager API を利用する
if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}
typeof quota
// => 'object'

image.png (60.5 kB)

https://web.dev/storage-for-the-web/#check

2:DevTool -> Application -> Storage から確認

image.png (57.7 kB)

参考