rufio 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 225c3d631526c9d005dc935b0ac6f6a2bfb27efbc31211ec4cf319864e0885bb
4
- data.tar.gz: 6148268cd607c98f42a9396b499cb5668c6b5f9001b583a245099d47415ab22a
3
+ metadata.gz: 6d9ba235b051414a23404dd8afdd87f292aef48b07f89612e57f0fcb2c0c99b0
4
+ data.tar.gz: e9a9273be387d14026c35cd36f7f9d805c0a951814e935f883d4138b0fe302d3
5
5
  SHA512:
6
- metadata.gz: 67f1e5730ed0eb0e8e71746c89729eaee14b8d0fbe503d8d54de626b4a4b30f3a79c284f73b662e5ec355a00df6806a73e693aa78a6f76ed953afe4ceaf4e889
7
- data.tar.gz: 485c7db79703f4f3f698dd64f94e9f383a9b1f1ec3fb4dad46a34ef116b26b15537607f0cf6c7a843adddd79f3b5dfdaa46519d6da75f307f74b631b6c56dd55
6
+ metadata.gz: 25e64b32573b24ab97c7719c4a3a0ead75e1d6f7965732c6b71ffe6dd753786413f346247ec835d8774ad3333a51caed21efca9b8cc0ee010a4d8944f4d72014
7
+ data.tar.gz: 3021168e7cb48ffa747d32416a7d24379fd2f8155998a6a74ff6734703818c525bacb1ee545033e65334c1f6b340fbdb49969354ba5ff6c6620bec71f716bb89
data/CHANGELOG.md CHANGED
@@ -7,19 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.33.0] - 2026-01-03
11
-
12
- ### Fixed
13
- - **🚨 CRITICAL: File Preview Performance Bug**: Fixed severe rendering delays (80ms → 1-2ms)
14
- - Root cause: Redundant processing inside rendering loop (38x per frame)
15
- - Impact: 97-99% improvement, 40-86x faster file preview
16
- - All text file previews now render in < 2ms
10
+ ## [0.34.0] - 2026-01-10
17
11
 
18
12
  ### Added
13
+ - **🚀 Async Scanner Architecture**: Complete async/parallel scanning implementation
14
+ - **Phase 1: Basic Async Scan**
15
+ - Zig pthread-based threading implementation
16
+ - State management (idle → scanning → done/cancelled/failed)
17
+ - Polling-based completion with progress tracking
18
+ - **Phase 2: Progress Reporting**
19
+ - Real-time progress API with mutex protection
20
+ - Thread-safe cancellation support
21
+ - Timeout handling for scan operations
22
+ - **Phase 3: Advanced Features**
23
+ - Promise-style interface with method chaining
24
+ - Fiber integration with Async library
25
+ - Parallel scanner with thread pool optimization
26
+ - **💎 AsyncScannerPromise**: Promise-style interface
27
+ - Method chaining with `.then()` callbacks
28
+ - Automatic resource cleanup on completion
29
+ - Works with both Ruby and Zig backends
30
+ - **🧵 AsyncScannerFiberWrapper**: Async/Fiber integration
31
+ - Non-blocking I/O with Ruby's Async library
32
+ - Concurrent scanning support
33
+ - Progress reporting with fiber-aware sleep
34
+ - **⚡ ParallelScanner**: Parallel scanning optimization
35
+ - Thread pool management (configurable max_workers)
36
+ - Batch directory scanning with result merging
37
+ - Error handling with partial failure support
38
+ - Backend switching (Ruby/Zig)
19
39
  - **⚡ Zig Native Scanner**: Experimental implementation with minimal binary size (52.6 KB)
20
40
  - Direct Ruby C API integration (no FFI overhead)
21
41
  - Competitive performance (within 6% of fastest implementations)
22
42
  - 5.97x smaller than Rust/Magnus implementation
43
+ - Async-ready handle-based design
23
44
  - **📊 YJIT Performance Analysis**: Comprehensive benchmarking of JIT compiler impact
24
45
  - Pure Ruby: 2-5% improvement with YJIT
25
46
  - Native extensions: No significant impact
@@ -28,7 +49,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
28
49
  - 4 detailed performance reports
29
50
  - Complete implementation comparison
30
51
 
31
- For detailed information, see [CHANGELOG_v0.33.0.md](./docs/CHANGELOG_v0.33.0.md)
52
+ ### Fixed
53
+ - **🚨 CRITICAL: File Preview Performance Bug**: Fixed severe rendering delays (80ms → 1-2ms)
54
+ - Root cause: Redundant processing inside rendering loop (38x per frame)
55
+ - Impact: 97-99% improvement, 40-86x faster file preview
56
+ - All text file previews now render in < 2ms
57
+ - **🔧 Zig Cancellation Handling**: Fixed cancelled state not properly propagating
58
+ - Changed error handling to preserve cancellation state
59
+ - Prevents "failed" state when scan is intentionally cancelled
60
+
61
+ ### Changed
62
+ - **Ruby 4.0 Compatibility**: Added `fiddle` gem dependency (required in Ruby 4.0+)
63
+ - **Async Library Integration**: Deprecated API warnings resolved
64
+ - Updated to use `Kernel#sleep` instead of `Async::Task#sleep`
65
+
66
+ ### Technical Details
67
+ - **Test Coverage**: 483 tests, 1899 assertions (100% pass rate)
68
+ - **Async Scanner Tests**: 8 fiber tests, 10 promise tests, 10 parallel tests
69
+ - **Ruby ABI Independence**: Handle-based design (u64) avoids Ruby ABI coupling
70
+ - **Thread Safety**: Pthread mutex protection for all shared state
71
+ - **GVL Freedom**: Native threads run independently of Ruby's GVL
72
+
73
+ For detailed information, see [CHANGELOG_v0.34.0.md](./docs/CHANGELOG_v0.34.0.md)
32
74
 
33
75
  ## [0.32.0] - 2026-01-02
34
76
 
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'async'
5
+ ASYNC_GEM_AVAILABLE = true
6
+ rescue LoadError
7
+ ASYNC_GEM_AVAILABLE = false
8
+ end
9
+
10
+ module Rufio
11
+ # Fiber(Asyncライブラリ)統合用ラッパークラス
12
+ #
13
+ # Asyncライブラリと統合し、ノンブロッキングで非同期スキャンを実行します。
14
+ #
15
+ # 使用例:
16
+ # Async do
17
+ # scanner = NativeScannerRubyCore.new
18
+ # wrapper = AsyncScannerFiberWrapper.new(scanner)
19
+ # entries = wrapper.scan_async('/path')
20
+ # puts "Found #{entries.length} entries"
21
+ # end
22
+ #
23
+ class AsyncScannerFiberWrapper
24
+ def initialize(scanner)
25
+ @scanner = scanner
26
+ end
27
+
28
+ # 非同期スキャンを開始し、Fiberで完了を待つ
29
+ #
30
+ # @param path [String] スキャンするディレクトリのパス
31
+ # @param timeout [Integer, nil] タイムアウト秒数(オプション)
32
+ # @return [Array<Hash>] スキャン結果
33
+ def scan_async(path, timeout: nil)
34
+ # スキャンを開始
35
+ @scanner.scan_async(path)
36
+
37
+ # Fiberでポーリング
38
+ poll_until_complete(timeout: timeout)
39
+ end
40
+
41
+ # 高速スキャン(エントリ数制限付き)
42
+ #
43
+ # @param path [String] スキャンするディレクトリのパス
44
+ # @param max_entries [Integer] 最大エントリ数
45
+ # @param timeout [Integer, nil] タイムアウト秒数(オプション)
46
+ # @return [Array<Hash>] スキャン結果
47
+ def scan_fast_async(path, max_entries, timeout: nil)
48
+ # スキャンを開始
49
+ @scanner.scan_fast_async(path, max_entries)
50
+
51
+ # Fiberでポーリング
52
+ poll_until_complete(timeout: timeout)
53
+ end
54
+
55
+ # 進捗報告付きスキャン
56
+ #
57
+ # @param path [String] スキャンするディレクトリのパス
58
+ # @param timeout [Integer, nil] タイムアウト秒数(オプション)
59
+ # @yield [current, total] 進捗情報を受け取るブロック
60
+ # @return [Array<Hash>] スキャン結果
61
+ def scan_async_with_progress(path, timeout: nil, &block)
62
+ # スキャンを開始
63
+ @scanner.scan_async(path)
64
+
65
+ # 進捗付きでポーリング
66
+ poll_until_complete_with_progress(timeout: timeout, &block)
67
+ end
68
+
69
+ # スキャンをキャンセル
70
+ def cancel
71
+ @scanner.cancel
72
+ end
73
+
74
+ # 状態を取得
75
+ #
76
+ # @return [Symbol] 現在の状態
77
+ def get_state
78
+ @scanner.get_state
79
+ end
80
+
81
+ # 進捗を取得
82
+ #
83
+ # @return [Hash] 進捗情報 {current:, total:}
84
+ def get_progress
85
+ @scanner.get_progress
86
+ end
87
+
88
+ private
89
+
90
+ # 完了までポーリング(Fiberでスリープ)
91
+ def poll_until_complete(timeout: nil)
92
+ start_time = Time.now
93
+
94
+ loop do
95
+ state = @scanner.get_state
96
+
97
+ case state
98
+ when :done
99
+ result = @scanner.get_results
100
+ @scanner.close
101
+ return result
102
+ when :failed
103
+ @scanner.close
104
+ raise StandardError, "Scan failed"
105
+ when :cancelled
106
+ @scanner.close
107
+ raise StandardError, "Scan cancelled"
108
+ end
109
+
110
+ if timeout && (Time.now - start_time) > timeout
111
+ @scanner.close
112
+ raise StandardError, "Timeout"
113
+ end
114
+
115
+ # Fiberでスリープ(ノンブロッキング)
116
+ sleep 0.01
117
+ end
118
+ end
119
+
120
+ # 進捗報告付きでポーリング
121
+ def poll_until_complete_with_progress(timeout: nil, &block)
122
+ start_time = Time.now
123
+
124
+ loop do
125
+ state = @scanner.get_state
126
+ progress = @scanner.get_progress
127
+
128
+ # 進捗コールバック実行
129
+ yield(progress[:current], progress[:total]) if block_given?
130
+
131
+ case state
132
+ when :done
133
+ result = @scanner.get_results
134
+ @scanner.close
135
+ return result
136
+ when :failed
137
+ @scanner.close
138
+ raise StandardError, "Scan failed"
139
+ when :cancelled
140
+ @scanner.close
141
+ raise StandardError, "Scan cancelled"
142
+ end
143
+
144
+ if timeout && (Time.now - start_time) > timeout
145
+ @scanner.close
146
+ raise StandardError, "Timeout"
147
+ end
148
+
149
+ # Fiberでスリープ(ノンブロッキング)
150
+ sleep 0.01
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rufio
4
+ # Promise風インターフェースで非同期スキャンを扱うクラス
5
+ #
6
+ # 使用例:
7
+ # scanner = NativeScannerRubyCore.new
8
+ # AsyncScannerPromise.new(scanner)
9
+ # .scan_async('/path')
10
+ # .then { |entries| entries.select { |e| e[:type] == 'file' } }
11
+ # .then { |files| files.map { |f| f[:name] } }
12
+ # .wait
13
+ #
14
+ class AsyncScannerPromise
15
+ def initialize(scanner)
16
+ @scanner = scanner
17
+ @callbacks = []
18
+ end
19
+
20
+ # 非同期スキャンを開始
21
+ #
22
+ # @param path [String] スキャンするディレクトリのパス
23
+ # @return [AsyncScannerPromise] self(メソッドチェーン用)
24
+ def scan_async(path)
25
+ @scanner.scan_async(path)
26
+ self
27
+ end
28
+
29
+ # 高速スキャンを開始(エントリ数制限付き)
30
+ #
31
+ # @param path [String] スキャンするディレクトリのパス
32
+ # @param max_entries [Integer] 最大エントリ数
33
+ # @return [AsyncScannerPromise] self(メソッドチェーン用)
34
+ def scan_fast_async(path, max_entries)
35
+ @scanner.scan_fast_async(path, max_entries)
36
+ self
37
+ end
38
+
39
+ # コールバックを登録
40
+ #
41
+ # @yield [result] 前のステップの結果を受け取るブロック
42
+ # @return [AsyncScannerPromise] self(メソッドチェーン用)
43
+ def then(&block)
44
+ @callbacks << block if block_given?
45
+ self
46
+ end
47
+
48
+ # スキャン完了を待ち、コールバックを順次実行
49
+ #
50
+ # @param timeout [Integer, nil] タイムアウト秒数(オプション)
51
+ # @return [Object] 最後のコールバックの戻り値、またはスキャン結果
52
+ def wait(timeout: nil)
53
+ result = @scanner.wait(timeout: timeout)
54
+
55
+ # 登録されたコールバックを順次実行
56
+ @callbacks.each do |callback|
57
+ result = callback.call(result)
58
+ end
59
+
60
+ result
61
+ ensure
62
+ # 完了後はスキャナーを自動的にクローズ
63
+ @scanner.close
64
+ end
65
+ end
66
+ end
@@ -27,6 +27,9 @@ module Rufio
27
27
 
28
28
  content = format_log_content(command, output, timestamp, success, error)
29
29
 
30
+ # ディレクトリが存在しない場合は作成(バックグラウンドスレッドでの実行時の競合を防ぐ)
31
+ FileUtils.mkdir_p(@log_dir) unless Dir.exist?(@log_dir)
32
+
30
33
  File.write(filepath, content)
31
34
  end
32
35
 
Binary file