Unified · Split
| @@ -40,7 +40,6 @@ impl std::borrow::BorrowMut<RefEdit> for Edit { · 39 unmodified lines | ||
| 40 | 40 | pub struct Transaction<'s> { |
| 41 | 41 | store: &'s file::Store, |
| 42 | 42 | packed_transaction: Option<packed::Transaction>, |
| 43 | − packed: Option<packed::Buffer>, | |
| 44 | 43 | updates: Option<Vec<Edit>>, |
| 45 | 44 | } |
| 46 | 45 | |
| @@ -236,8 +235,9 @@ impl<'s> Transaction<'s> { · 189 unmodified lines | ||
| 236 | 235 | ) |
| 237 | 236 | .map_err(Error::PreprocessingFailed)?; |
| 238 | 237 | |
| 239 | − if let Some(packed) = self.store.packed()? { | |
| 238 | + if self.store.packed_refs_path().is_file() { | |
| 240 | 239 | let mut edits_for_packed_transaction = Vec::<RefEdit>::new(); |
| 240 | + let mut needs_packed_refs_lookups = false; | |
| 241 | 241 | for edit in updates.iter() { |
| 242 | 242 | let log_mode = match edit.update.change { |
| 243 | 243 | Change::Update { |
| @@ -257,19 +257,23 @@ impl<'s> Transaction<'s> { · 13 unmodified lines | ||
| 257 | 257 | Change::Delete { .. } => { |
| 258 | 258 | edits_for_packed_transaction.push(edit.update.clone()); |
| 259 | 259 | } |
| 260 | − _ => {} | |
| 260 | + _ => { | |
| 261 | + needs_packed_refs_lookups = true; | |
| 262 | + } | |
| 261 | 263 | } |
| 262 | 264 | } |
| 263 | 265 | |
| 264 | − if !edits_for_packed_transaction.is_empty() { | |
| 265 | − self.packed_transaction = Some( | |
| 266 | − packed | |
| 267 | − .into_transaction(lock_fail_mode) | |
| 268 | − .map_err(Error::PackedTransactionAcquire)? | |
| 269 | − .prepare(edits_for_packed_transaction)?, | |
| 270 | − ); | |
| 271 | − } else { | |
| 272 | − self.packed = Some(packed); | |
| 266 | + // We create a transaction even for empty packed edits to assure nobody else can change | |
| 267 | + // it while we perform checks against previous values. | |
| 268 | + if !edits_for_packed_transaction.is_empty() || needs_packed_refs_lookups { | |
| 269 | + if let Some(packed) = self.store.packed()? { | |
| 270 | + self.packed_transaction = Some( | |
| 271 | + packed | |
| 272 | + .into_transaction(lock_fail_mode) | |
| 273 | + .map_err(Error::PackedTransactionAcquire)? | |
| 274 | + .prepare(edits_for_packed_transaction)?, | |
| 275 | + ); | |
| 276 | + } | |
| 273 | 277 | } |
| 274 | 278 | } |
| 275 | 279 | |
| @@ -278,10 +282,7 @@ impl<'s> Transaction<'s> { · 2 unmodified lines | ||
| 278 | 282 | if let Err(err) = Self::lock_ref_and_apply_change( |
| 279 | 283 | self.store, |
| 280 | 284 | lock_fail_mode, |
| 281 | − self.packed_transaction | |
| 282 | − .as_ref() | |
| 283 | − .map(|t| t.buffer()) | |
| 284 | − .or_else(|| self.packed.as_ref()), | |
| 285 | + self.packed_transaction.as_ref().map(|t| t.buffer()), | |
| 285 | 286 | change, |
| 286 | 287 | ) { |
| 287 | 288 | let err = match err { |
| @@ -440,10 +441,10 @@ impl<'s> Transaction<'s> { · 152 unmodified lines | ||
| 440 | 441 | } |
| 441 | 442 | } |
| 442 | 443 | } |
| 443 | − let packed = match self.packed_transaction { | |
| 444 | − Some(transaction) => Some(transaction.commit().map_err(Error::PackedTransactionCommit)?.1), | |
| 445 | − None => self.packed, | |
| 446 | − }; | |
| 444 | + let packed = self | |
| 445 | + .packed_transaction | |
| 446 | + .map(|t| t.commit().map(|r| r.1).map_err(Error::PackedTransactionCommit)) | |
| 447 | + .transpose()?; | |
| 447 | 448 | Ok((updates.into_iter().map(|edit| edit.update).collect(), packed)) |
| 448 | 449 | } |
| 449 | 450 | None => panic!("BUG: must call prepare before commit"), |
| @@ -461,7 +462,6 @@ impl file::Store { · 11 unmodified lines | ||
| 461 | 462 | Transaction { |
| 462 | 463 | store: self, |
| 463 | 464 | packed_transaction: None, |
| 464 | − packed: None, | |
| 465 | 465 | updates: None, |
| 466 | 466 | } |
| 467 | 467 | } |