Skip to content

Commit 0fc95b6

Browse files
committed
Minor search module refactoring
1 parent 6072b6d commit 0fc95b6

6 files changed

Lines changed: 66 additions & 62 deletions

File tree

recoverpy/lib/search/grep_consumer.py

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
from recoverpy.models.search_params import SearchParams
99

1010

11-
class ResultProcessor:
11+
class ResultFilter:
1212
def __init__(self, search_params: SearchParams):
1313
self.search_params = search_params
1414

15-
def get_new_results(self, queue_object: Queue[bytes]) -> List[str]:
16-
"""Consume grep output queue and format results."""
15+
def filter_results(self, queue_object: Queue[bytes]) -> List[str]:
16+
"""Consume raw grep results, filter out false positives and return valid results."""
1717

1818
queue_list: List[bytes] = list(queue_object.queue)
1919
queue_size = len(queue_list)
@@ -27,12 +27,13 @@ def get_new_results(self, queue_object: Queue[bytes]) -> List[str]:
2727
return decoded_results
2828

2929
final_results = [
30-
result for result in decoded_results if self.is_result_format_valid(result)
30+
result for result in decoded_results if self._is_result_valid(result)
3131
]
3232
log.debug(f"result_processor - Found {len(final_results)} new results")
3333
return final_results
3434

35-
def is_result_format_valid(self, result: str) -> bool:
35+
def _is_result_valid(self, result: str) -> bool:
36+
"""Check if result contains all searched lines."""
3637
inode = int(get_inode(result))
3738
block_factor = self.search_params.block_size * 8
3839

@@ -42,6 +43,7 @@ def is_result_format_valid(self, result: str) -> bool:
4243
)
4344

4445
def _get_combined_block_output(self, inode: int, block_factor: int) -> str:
46+
"""Get combined output of current and next block."""
4547
block_index = inode // block_factor
4648
block_output = get_dd_output(
4749
self.search_params.partition, block_factor, block_index
@@ -51,22 +53,3 @@ def _get_combined_block_output(self, inode: int, block_factor: int) -> str:
5153
)
5254

5355
return decode_result(block_output) + decode_result(next_block_output)
54-
55-
def fix_line_start(self, line: str) -> str:
56-
result_index: int = line.find(self.search_params.searched_lines[0])
57-
return line[min(result_index, 15) :]
58-
59-
def fix_inode(self, inode: int) -> int:
60-
inode //= self.search_params.block_size
61-
62-
for _ in range(10):
63-
dd_output = self._get_dd_output(inode)
64-
if self.search_params.searched_lines[0] in decode_result(dd_output):
65-
return inode
66-
inode += 1
67-
return inode
68-
69-
def _get_dd_output(self, inode: int) -> bytes:
70-
return get_dd_output(
71-
self.search_params.partition, self.search_params.block_size, inode
72-
)

recoverpy/lib/search/search_engine.py

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,33 @@
33
from asyncio import AbstractEventLoop
44
from asyncio import Queue as AsyncQueue
55
from asyncio import new_event_loop
6+
from io import BufferedReader
67
from queue import Queue
78
from subprocess import Popen
89
from time import sleep
910
from typing import List
1011

11-
from recoverpy.lib.search.result_processor import ResultProcessor
12+
from recoverpy.lib.helper import get_dd_output, decode_result
13+
from recoverpy.lib.search.result_filter import ResultFilter
1214
from recoverpy.lib.search.thread_factory import (
1315
start_grep_process,
1416
start_progress_monitoring_thread,
15-
start_result_dequeue_thread,
16-
start_result_enqueue_thread,
17+
start_result_formatter_thread,
18+
start_grep_stdout_consumer_thread,
1719
)
1820
from recoverpy.log.logger import log
1921
from recoverpy.models.grep_result import GrepResult
2022
from recoverpy.models.search_params import SearchParams
2123
from recoverpy.models.search_progress import SearchProgress
2224

2325

26+
def _consume_grep_stdout(out: BufferedReader, queue: Queue[bytes]) -> None:
27+
log.debug("grep_consumer - Grep output enqueue thread started")
28+
for line in iter(out.readline, b""):
29+
queue.put(line)
30+
out.close()
31+
32+
2433
class SearchEngine:
2534
_grep_process: Popen[bytes]
2635
_seen_inodes: set[int] = set()
@@ -35,35 +44,37 @@ def _initialize_search_components(
3544
) -> None:
3645
self.search_params = SearchParams(partition, searched_string)
3746
self.search_progress = SearchProgress()
38-
self.result_processor = ResultProcessor(self.search_params)
47+
self.result_processor = ResultFilter(self.search_params)
3948

4049
async def start_search(self) -> None:
41-
self._initialize_grep_process()
50+
self._start_grep_process()
4251
self._start_auxiliary_threads()
4352

4453
def stop_search(self) -> None:
4554
self._grep_process.kill()
4655

47-
def _initialize_grep_process(self) -> None:
56+
def _start_grep_process(self) -> None:
4857
self._grep_process = start_grep_process(
4958
searched_string=self.search_params.searched_lines[0],
5059
partition=self.search_params.partition,
5160
)
5261

5362
def _start_auxiliary_threads(self) -> None:
54-
start_result_enqueue_thread(self._grep_process, self.results_queue)
55-
start_result_dequeue_thread(self._dequeue_results)
63+
start_grep_stdout_consumer_thread(
64+
_consume_grep_stdout, self._grep_process, self.results_queue
65+
)
66+
start_result_formatter_thread(self._format_results)
5667
start_progress_monitoring_thread(self._grep_process, self.search_progress)
5768

58-
def _dequeue_results(self) -> None:
69+
def _format_results(self) -> None:
5970
loop = new_event_loop()
6071
while True:
61-
results = self.result_processor.get_new_results(self.results_queue)
62-
self._add_new_results(results, loop)
72+
results = self.result_processor.filter_results(self.results_queue)
73+
self._process_new_results(results, loop)
6374
log.debug(f"search_engine - Dequeued {len(results)} results")
6475
sleep(0.1)
6576

66-
def _add_new_results(self, results: List[str], loop: AbstractEventLoop) -> None:
77+
def _process_new_results(self, results: List[str], loop: AbstractEventLoop) -> None:
6778
for result in results:
6879
grep_result = self._create_grep_result(
6980
result, self.search_progress.result_count
@@ -83,8 +94,24 @@ def _create_grep_result(self, result: str, result_index: int) -> GrepResult:
8394
def _configure_grep_result(
8495
self, grep_result: GrepResult, result_index: int
8596
) -> None:
86-
grep_result.inode = self.result_processor.fix_inode(grep_result.inode)
87-
grep_result.line = self.result_processor.fix_line_start(grep_result.line)
97+
grep_result.inode = self._fix_inode(grep_result.inode)
98+
grep_result.line = self._fix_line_start(grep_result.line)
8899
grep_result.css_class = (
89100
"grep-result-odd" if result_index % 2 == 0 else "grep-result-even"
90101
)
102+
103+
def _fix_line_start(self, line: str) -> str:
104+
result_index: int = line.find(self.search_params.searched_lines[0])
105+
return line[min(result_index, 15) :]
106+
107+
def _fix_inode(self, inode: int) -> int:
108+
inode //= self.search_params.block_size
109+
110+
for _ in range(10):
111+
dd_output = get_dd_output(
112+
self.search_params.partition, self.search_params.block_size, inode
113+
)
114+
if self.search_params.searched_lines[0] in decode_result(dd_output):
115+
return inode
116+
inode += 1
117+
return inode

recoverpy/lib/search/thread_factory.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

3+
from io import BufferedReader
34
from queue import Queue
45
from subprocess import PIPE, Popen
56
from threading import Thread
67
from typing import Callable
78

89
from recoverpy.lib.helper import is_dependency_installed
9-
from recoverpy.lib.search.grep_consumer import enqueue_grep_output
1010
from recoverpy.lib.search.progress_monitoring import monitor_search_progress
1111
from recoverpy.log.logger import log
1212
from recoverpy.models.search_progress import SearchProgress
@@ -22,22 +22,24 @@ def start_grep_process(searched_string: str, partition: str) -> Popen[bytes]:
2222
)
2323

2424

25-
def start_result_enqueue_thread(
26-
grep_process: Popen[bytes], queue: Queue[bytes]
25+
def start_grep_stdout_consumer_thread(
26+
consume_function: Callable[[BufferedReader, Queue[bytes]], None],
27+
grep_process: Popen[bytes],
28+
queue: Queue[bytes],
2729
) -> None:
28-
log.debug("thread_factory - Starting result enqueue thread")
30+
log.debug("thread_factory - Starting grep stdout consumer thread")
2931
Thread(
30-
target=enqueue_grep_output,
32+
target=consume_function,
3133
args=(grep_process.stdout, queue),
3234
daemon=True,
3335
name="enqueue-grep-output-thread",
3436
).start()
3537

3638

37-
def start_result_dequeue_thread(dequeue_results: Callable[[], None]) -> None:
38-
log.debug("thread_factory - Starting result dequeue thread")
39+
def start_result_formatter_thread(format_function: Callable[[], None]) -> None:
40+
log.debug("thread_factory - Starting result formatter thread")
3941
Thread(
40-
target=dequeue_results,
42+
target=format_function,
4143
daemon=True,
4244
name="dequeue-results-thread",
4345
).start()

recoverpy/ui/widgets/grep_result_list.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,6 @@ def on_resize(self) -> None:
6464
def _resize_item(self, index: int) -> None:
6565
max_item_width = self.size.width - self.size.width // 20
6666
grep_result_line = self.grep_results[index].line
67-
cast(Label, self.grep_results[index].label).update(grep_result_line[:max_item_width])
67+
cast(Label, self.grep_results[index].label).update(
68+
grep_result_line[:max_item_width]
69+
)

tests/conftest.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import pytest
44

55
from recoverpy.lib.search.search_engine import SearchEngine
6-
76
from .fixtures import (
87
mock_dd_output,
98
mock_grep_process,
@@ -21,7 +20,11 @@ def system_calls_mock(session_mocker):
2120
new=mock_grep_process.mock_start_grep_process,
2221
)
2322
session_mocker.patch(
24-
"recoverpy.lib.search.result_processor.get_dd_output",
23+
"recoverpy.lib.search.result_filter.get_dd_output",
24+
side_effect=mock_dd_output.mock_dd_string_output,
25+
)
26+
session_mocker.patch(
27+
"recoverpy.lib.search.search_engine.get_dd_output",
2528
side_effect=mock_dd_output.mock_dd_string_output,
2629
)
2730
session_mocker.patch(

0 commit comments

Comments
 (0)