Skip to content

Commit f85429d

Browse files
committed
eventlog: add support for event transactions
1 parent aac93c0 commit f85429d

File tree

10 files changed

+570
-85
lines changed

10 files changed

+570
-85
lines changed

CHANGELOG.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
# Changelog
2+
23
All notable changes to this project will be documented in this file.
34

45
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
56
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
67

8+
## Unreleased
9+
10+
- BREAKING: Events are now grouped into transactions. This improves the UX around `git undo`, since it can undo groups of related events. This breaks the on-disk database format.
11+
712
## v0.2.0 - 2020-03-15
813

914
Ported to Rust. No new features.
1015

11-
* Performance for repeated calls to Git hooks is significantly improved. This can happen when rebasing large commit stacks.
12-
* The `git undo` UI has been changed to use a Rust-specific TUI library (`cursive`).
16+
- Performance for repeated calls to Git hooks is significantly improved. This can happen when rebasing large commit stacks.
17+
- The `git undo` UI has been changed to use a Rust-specific TUI library (`cursive`).
1318

1419
## v0.1.0 - 2020-12-18
1520

1621
First beta release. Supports these commands:
1722

18-
* `git sl`/`git smartlog`.
19-
* `git hide`/`git unhide`.
20-
* `git prev`/`git next`.
21-
* `git restack`.
22-
* `git undo`.
23+
- `git sl`/`git smartlog`.
24+
- `git hide`/`git unhide`.
25+
- `git prev`/`git next`.
26+
- `git restack`.
27+
- `git undo`.

src/commands/hide.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ fn recurse_on_commits<'repo, F: Fn(&Node) -> bool>(
113113
///
114114
/// Returns: exit code (0 denotes successful exit).
115115
pub fn hide(out: &mut impl Write, hashes: Vec<String>, recursive: bool) -> anyhow::Result<isize> {
116-
let timestamp = SystemTime::now();
116+
let now = SystemTime::now();
117117
let repo = get_repo()?;
118118
let conn = get_db_conn(&repo)?;
119119
let mut event_log_db = EventLogDb::new(&conn)?;
@@ -136,13 +136,13 @@ pub fn hide(out: &mut impl Write, hashes: Vec<String>, recursive: bool) -> anyho
136136
commits
137137
};
138138

139-
let timestamp = timestamp
140-
.duration_since(SystemTime::UNIX_EPOCH)?
141-
.as_secs_f64();
139+
let timestamp = now.duration_since(SystemTime::UNIX_EPOCH)?.as_secs_f64();
140+
let event_tx_id = event_log_db.make_transaction_id(now, "hide")?;
142141
let events = commits
143142
.iter()
144143
.map(|commit| Event::HideEvent {
145144
timestamp,
145+
event_tx_id,
146146
commit_oid: commit.id(),
147147
})
148148
.collect();
@@ -192,7 +192,7 @@ pub fn hide(out: &mut impl Write, hashes: Vec<String>, recursive: bool) -> anyho
192192
///
193193
/// Returns: exit code (0 denotes successful exit).
194194
pub fn unhide(out: &mut impl Write, hashes: Vec<String>, recursive: bool) -> anyhow::Result<isize> {
195-
let timestamp = SystemTime::now();
195+
let now = SystemTime::now();
196196
let repo = get_repo()?;
197197
let conn = get_db_conn(&repo)?;
198198
let mut event_log_db = EventLogDb::new(&conn)?;
@@ -215,13 +215,13 @@ pub fn unhide(out: &mut impl Write, hashes: Vec<String>, recursive: bool) -> any
215215
commits
216216
};
217217

218-
let timestamp = timestamp
219-
.duration_since(SystemTime::UNIX_EPOCH)?
220-
.as_secs_f64();
218+
let timestamp = now.duration_since(SystemTime::UNIX_EPOCH)?.as_secs_f64();
219+
let event_tx_id = event_log_db.make_transaction_id(now, "unhide")?;
221220
let events = commits
222221
.iter()
223222
.map(|commit| Event::UnhideEvent {
224223
timestamp,
224+
event_tx_id,
225225
commit_oid: commit.id(),
226226
})
227227
.collect();

src/commands/hooks.rs

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use fn_error_context::context;
1919
use crate::commands::gc::mark_commit_reachable;
2020
use crate::commands::restack::find_abandoned_children;
2121
use crate::core::config::{get_restack_warn_abandoned, RESTACK_WARN_ABANDONED_CONFIG_KEY};
22-
use crate::core::eventlog::{should_ignore_ref_updates, Event, EventLogDb, EventReplayer};
22+
use crate::core::eventlog::{
23+
should_ignore_ref_updates, Event, EventLogDb, EventReplayer, EventTransactionId,
24+
};
2325
use crate::core::formatting::Pluralize;
2426
use crate::core::graph::{make_graph, BranchOids, HeadOid, MainBranchOid};
2527
use crate::core::mergebase::MergeBaseDb;
@@ -63,6 +65,11 @@ pub fn hook_post_rewrite(out: &mut impl Write, rewrite_type: &str) -> anyhow::Re
6365
let now = SystemTime::now();
6466
let timestamp = now.duration_since(SystemTime::UNIX_EPOCH)?.as_secs_f64();
6567

68+
let repo = get_repo()?;
69+
let conn = get_db_conn(&repo)?;
70+
let mut event_log_db = EventLogDb::new(&conn)?;
71+
let event_tx_id = event_log_db.make_transaction_id(now, "hook-post-rewrite")?;
72+
6673
let (old_commits, events) = {
6774
let mut old_commits = Vec::new();
6875
let mut events = Vec::new();
@@ -83,6 +90,7 @@ pub fn hook_post_rewrite(out: &mut impl Write, rewrite_type: &str) -> anyhow::Re
8390
old_commits.push(old_commit_oid);
8491
events.push(Event::RewriteEvent {
8592
timestamp,
93+
event_tx_id,
8694
old_commit_oid,
8795
new_commit_oid,
8896
})
@@ -93,8 +101,6 @@ pub fn hook_post_rewrite(out: &mut impl Write, rewrite_type: &str) -> anyhow::Re
93101
(old_commits, events)
94102
};
95103

96-
let repo = get_repo()?;
97-
98104
let is_spurious_event = rewrite_type == "amend" && is_rebase_underway(&repo)?;
99105
if !is_spurious_event {
100106
let message_rewritten_commits = Pluralize {
@@ -106,8 +112,6 @@ pub fn hook_post_rewrite(out: &mut impl Write, rewrite_type: &str) -> anyhow::Re
106112
writeln!(out, "branchless: processing {}", message_rewritten_commits)?;
107113
}
108114

109-
let conn = get_db_conn(&repo)?;
110-
let mut event_log_db = EventLogDb::new(&conn)?;
111115
event_log_db.add_events(events)?;
112116

113117
let should_check_abandoned_commits = get_restack_warn_abandoned(&repo)?;
@@ -237,8 +241,10 @@ pub fn hook_post_checkout(
237241
let repo = get_repo()?;
238242
let conn = get_db_conn(&repo)?;
239243
let mut event_log_db = EventLogDb::new(&conn)?;
244+
let event_tx_id = event_log_db.make_transaction_id(now, "hook-post-checkout")?;
240245
event_log_db.add_events(vec![Event::RefUpdateEvent {
241246
timestamp: timestamp.as_secs_f64(),
247+
event_tx_id,
242248
old_ref: Some(String::from(previous_head_ref)),
243249
new_ref: Some(String::from(current_head_ref)),
244250
ref_name: String::from("HEAD"),
@@ -253,6 +259,7 @@ pub fn hook_post_checkout(
253259
pub fn hook_post_commit(out: &mut impl Write) -> anyhow::Result<()> {
254260
writeln!(out, "branchless: processing commit")?;
255261

262+
let now = SystemTime::now();
256263
let repo = get_repo()?;
257264
let conn = get_db_conn(&repo)?;
258265
let mut event_log_db = EventLogDb::new(&conn)?;
@@ -266,15 +273,21 @@ pub fn hook_post_commit(out: &mut impl Write) -> anyhow::Result<()> {
266273
.with_context(|| "Marking commit as reachable for GC purposes")?;
267274

268275
let timestamp = commit.time().seconds() as f64;
276+
let event_tx_id = event_log_db.make_transaction_id(now, "hook-post-commit")?;
269277
event_log_db.add_events(vec![Event::CommitEvent {
270278
timestamp,
279+
event_tx_id,
271280
commit_oid: commit.id(),
272281
}])?;
273282

274283
Ok(())
275284
}
276285

277-
fn parse_reference_transaction_line(now: SystemTime, line: &str) -> anyhow::Result<Option<Event>> {
286+
fn parse_reference_transaction_line(
287+
line: &str,
288+
now: SystemTime,
289+
event_tx_id: EventTransactionId,
290+
) -> anyhow::Result<Option<Event>> {
278291
match *line.split(' ').collect::<Vec<_>>().as_slice() {
279292
[old_value, new_value, ref_name] => {
280293
if !should_ignore_ref_updates(ref_name) {
@@ -283,6 +296,7 @@ fn parse_reference_transaction_line(now: SystemTime, line: &str) -> anyhow::Resu
283296
.with_context(|| "Processing timestamp")?;
284297
Ok(Some(Event::RefUpdateEvent {
285298
timestamp: timestamp.as_secs_f64(),
299+
event_tx_id,
286300
ref_name: String::from(ref_name),
287301
old_ref: Some(String::from(old_value)),
288302
new_ref: Some(String::from(new_value)),
@@ -312,7 +326,12 @@ pub fn hook_reference_transaction(
312326
if transaction_state != "committed" {
313327
return Ok(());
314328
}
315-
let timestamp = SystemTime::now();
329+
let now = SystemTime::now();
330+
331+
let repo = get_repo()?;
332+
let conn = get_db_conn(&repo)?;
333+
let mut event_log_db = EventLogDb::new(&conn)?;
334+
let event_tx_id = event_log_db.make_transaction_id(now, "reference-transaction")?;
316335

317336
let events: Vec<Event> = stdin()
318337
.lock()
@@ -322,7 +341,7 @@ pub fn hook_reference_transaction(
322341
Ok(line) => line,
323342
Err(_) => return None,
324343
};
325-
match parse_reference_transaction_line(timestamp, &line) {
344+
match parse_reference_transaction_line(&line, now, event_tx_id) {
326345
Ok(event) => event,
327346
Err(err) => {
328347
log::error!("Could not parse reference-transaction-line: {:?}", err);
@@ -345,10 +364,6 @@ pub fn hook_reference_transaction(
345364
"branchless: processing {}",
346365
num_reference_updates.to_string()
347366
)?;
348-
349-
let repo = get_repo()?;
350-
let conn = get_db_conn(&repo)?;
351-
let mut event_log_db = EventLogDb::new(&conn)?;
352367
event_log_db.add_events(events)?;
353368

354369
Ok(())
@@ -362,12 +377,14 @@ mod tests {
362377

363378
#[test]
364379
fn test_parse_reference_transaction_line() -> anyhow::Result<()> {
365-
let timestamp = SystemTime::UNIX_EPOCH;
366380
let line = "123abc 456def mybranch";
381+
let timestamp = SystemTime::UNIX_EPOCH;
382+
let event_tx_id = crate::core::eventlog::testing::make_dummy_transaction_id(789);
367383
assert_eq!(
368-
parse_reference_transaction_line(timestamp, &line)?,
384+
parse_reference_transaction_line(&line, timestamp, event_tx_id)?,
369385
Some(Event::RefUpdateEvent {
370386
timestamp: 0.0,
387+
event_tx_id,
371388
old_ref: Some(String::from("123abc")),
372389
new_ref: Some(String::from("456def")),
373390
ref_name: String::from("mybranch"),
@@ -376,10 +393,13 @@ mod tests {
376393
);
377394

378395
let line = "123abc 456def ORIG_HEAD";
379-
assert_eq!(parse_reference_transaction_line(timestamp, &line)?, None);
396+
assert_eq!(
397+
parse_reference_transaction_line(&line, timestamp, event_tx_id)?,
398+
None
399+
);
380400

381401
let line = "there are not three fields here";
382-
assert!(parse_reference_transaction_line(timestamp, &line).is_err());
402+
assert!(parse_reference_transaction_line(&line, timestamp, event_tx_id).is_err());
383403

384404
Ok(())
385405
}

src/commands/init.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ fn install_aliases(
213213
install_alias(out, &mut config, "restack", "restack")?;
214214
install_alias(out, &mut config, "undo", "undo")?;
215215

216-
let version_str = run_git_silent(repo, git_executable, &["version"])
216+
let version_str = run_git_silent(repo, git_executable, None, &["version"])
217217
.with_context(|| "Determining Git version")?;
218218
let version: GitVersion = version_str
219219
.parse()

src/commands/navigation.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ pub fn prev(
2626
num_commits: Option<isize>,
2727
) -> anyhow::Result<isize> {
2828
let exit_code = match num_commits {
29-
None => run_git(out, err, git_executable, &["checkout", "HEAD^"])?,
29+
None => run_git(out, err, git_executable, None, &["checkout", "HEAD^"])?,
3030
Some(num_commits) => run_git(
3131
out,
3232
err,
3333
git_executable,
34+
None,
3435
&["checkout", &format!("HEAD~{}", num_commits)],
3536
)?,
3637
};
@@ -199,6 +200,7 @@ pub fn next(
199200
out,
200201
err,
201202
git_executable,
203+
None,
202204
&["checkout", &current_oid.to_string()],
203205
)?;
204206
if result != 0 {

0 commit comments

Comments
 (0)