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 +4 -4
- data/CHANGELOG.md +50 -8
- data/lib/rufio/async_scanner_fiber.rb +154 -0
- data/lib/rufio/async_scanner_promise.rb +66 -0
- data/lib/rufio/command_logger.rb +3 -0
- data/lib/rufio/native/rufio_zig.bundle +0 -0
- data/lib/rufio/native_scanner.rb +252 -233
- data/lib/rufio/native_scanner_zig.rb +215 -82
- data/lib/rufio/parallel_scanner.rb +173 -0
- data/lib/rufio/version.rb +1 -1
- data/lib/rufio.rb +3 -1
- data/lib_zig/rufio_native/Makefile +2 -1
- data/lib_zig/rufio_native/src/main.zig +328 -117
- data/lib_zig/rufio_native/src/main.zig.sync +205 -0
- metadata +7 -10
- data/lib/rufio/native/rufio_native.bundle +0 -0
- data/lib/rufio/native_scanner_magnus.rb +0 -194
- data/lib_rust/rufio_native/.cargo/config.toml +0 -2
- data/lib_rust/rufio_native/Cargo.lock +0 -346
- data/lib_rust/rufio_native/Cargo.toml +0 -18
- data/lib_rust/rufio_native/build.rs +0 -46
- data/lib_rust/rufio_native/src/lib.rs +0 -197
- /data/docs/{CHANGELOG_v0.33.0.md → CHANGELOG_v0.34.0.md} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6d9ba235b051414a23404dd8afdd87f292aef48b07f89612e57f0fcb2c0c99b0
|
|
4
|
+
data.tar.gz: e9a9273be387d14026c35cd36f7f9d805c0a951814e935f883d4138b0fe302d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
-
|
|
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
|
data/lib/rufio/command_logger.rb
CHANGED
|
Binary file
|