-
Notifications
You must be signed in to change notification settings - Fork 689
Skip --checkpoint file statements with --resume
#1853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from io import TextIOWrapper | ||
| import os | ||
| import sys | ||
| import time | ||
|
|
@@ -19,6 +20,53 @@ | |
| from mycli.main import CliArgs, MyCli | ||
|
|
||
|
|
||
| class CheckpointReplayError(Exception): | ||
| pass | ||
|
|
||
|
|
||
| def replay_checkpoint_file( | ||
| batch_path: str, | ||
| checkpoint: TextIOWrapper | None, | ||
| resume: bool, | ||
| ) -> int: | ||
| if not resume: | ||
| return 0 | ||
|
|
||
| if checkpoint is None: | ||
| return 0 | ||
|
|
||
| if batch_path == '-': | ||
| raise CheckpointReplayError('--resume is incompatible with reading from the standard input.') | ||
|
|
||
| checkpoint_name = checkpoint.name | ||
| checkpoint.flush() | ||
| completed_count = 0 | ||
| try: | ||
| with click.open_file(batch_path) as batch_h, click.open_file(checkpoint_name, mode='r', encoding='utf-8') as checkpoint_h: | ||
| try: | ||
| batch_gen = statements_from_filehandle(batch_h) | ||
| except ValueError as e: | ||
| raise CheckpointReplayError(f'Error reading --batch file: {batch_path}: {e}') from None | ||
| for checkpoint_statement, _checkpoint_counter in statements_from_filehandle(checkpoint_h): | ||
| try: | ||
| batch_statement, _batch_counter = next(batch_gen) | ||
| except StopIteration: | ||
| raise CheckpointReplayError('Checkpoint script longer than batch script.') from None | ||
| except ValueError as e: | ||
| raise CheckpointReplayError(f'Error reading --batch file: {batch_path}: {e}') from None | ||
| if checkpoint_statement != batch_statement: | ||
| raise CheckpointReplayError(f'Statement mismatch: {checkpoint_statement}.') | ||
| completed_count += 1 | ||
| except ValueError as e: | ||
| raise CheckpointReplayError(f'Error reading --checkpoint file: {checkpoint.name}: {e}') from None | ||
| except FileNotFoundError as e: | ||
| raise CheckpointReplayError(f'FileNotFoundError: {e}') from None | ||
| except OSError as e: | ||
| raise CheckpointReplayError(f'OSError: {e}') from None | ||
|
|
||
| return completed_count | ||
|
|
||
|
|
||
| def dispatch_batch_statements( | ||
| mycli: 'MyCli', | ||
| cli_args: 'CliArgs', | ||
|
|
@@ -70,6 +118,7 @@ def main_batch_with_progress_bar(mycli: 'MyCli', cli_args: 'CliArgs') -> int: | |
| click.secho('--progress is only compatible with a plain file.', err=True, fg='red') | ||
| return 1 | ||
| try: | ||
| completed_statement_count = replay_checkpoint_file(cli_args.batch, cli_args.checkpoint, cli_args.resume) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like currently the batch file is getting opened three times; one in this new replay_checkpoint_file function, again on line 122, and again on line 172. Would it be possible to combine those somehow? Maybe returning something from replay_checkpoint_file to re-use.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point, but we would have to read the entire file into memory to provide the same guarantee, something we got away from in #1450 . |
||
| batch_count_h = click.open_file(cli_args.batch) | ||
| for _statement, _counter in statements_from_filehandle(batch_count_h): | ||
| goal_statements += 1 | ||
|
|
@@ -82,6 +131,10 @@ def main_batch_with_progress_bar(mycli: 'MyCli', cli_args: 'CliArgs') -> int: | |
| except ValueError as e: | ||
| click.secho(f'Error reading --batch file: {cli_args.batch}: {e}', err=True, fg='red') | ||
| return 1 | ||
| except CheckpointReplayError as e: | ||
| name = cli_args.checkpoint.name if cli_args.checkpoint else 'None' | ||
| click.secho(f'Error replaying --checkpoint file: {name}: {e}', err=True, fg='red') | ||
| return 1 | ||
| try: | ||
| if goal_statements: | ||
| pb_style = prompt_toolkit.styles.Style.from_dict({'bar-a': 'reverse'}) | ||
|
|
@@ -98,6 +151,8 @@ def main_batch_with_progress_bar(mycli: 'MyCli', cli_args: 'CliArgs') -> int: | |
| with ProgressBar(style=pb_style, formatters=custom_formatters, output=err_output) as pb: | ||
| for _pb_counter in pb(range(goal_statements)): | ||
| statement, statement_counter = next(batch_gen) | ||
| if statement_counter < completed_statement_count: | ||
| continue | ||
| dispatch_batch_statements(mycli, cli_args, statement, statement_counter) | ||
| except (ValueError, StopIteration, IOError, OSError, pymysql.err.Error) as e: | ||
| click.secho(str(e), err=True, fg='red') | ||
|
|
@@ -113,12 +168,19 @@ def main_batch_without_progress_bar(mycli: 'MyCli', cli_args: 'CliArgs') -> int: | |
| if not sys.stdin.isatty() and cli_args.batch != '-': | ||
| click.secho('Ignoring STDIN since --batch was also given.', err=True, fg='red') | ||
| try: | ||
| completed_statement_count = replay_checkpoint_file(cli_args.batch, cli_args.checkpoint, cli_args.resume) | ||
| batch_h = click.open_file(cli_args.batch) | ||
| except (OSError, FileNotFoundError): | ||
| click.secho(f'Failed to open --batch file: {cli_args.batch}', err=True, fg='red') | ||
| return 1 | ||
| except CheckpointReplayError as e: | ||
| name = cli_args.checkpoint.name if cli_args.checkpoint else 'None' | ||
| click.secho(f'Error replaying --checkpoint file: {name}: {e}', err=True, fg='red') | ||
| return 1 | ||
| try: | ||
| for statement, counter in statements_from_filehandle(batch_h): | ||
| if counter < completed_statement_count: | ||
| continue | ||
| dispatch_batch_statements(mycli, cli_args, statement, counter) | ||
| except (ValueError, StopIteration, IOError, OSError, pymysql.err.Error) as e: | ||
| click.secho(str(e), err=True, fg='red') | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you also check if
--batchmode is given with--resume? I.e. could use--executeand--resumecurrently.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea!