Merge "ChangeRebuilderImpl: Don't always drop updates when losing race"
This commit is contained in:
		@@ -584,7 +584,8 @@ public class ChangeNotes extends AbstractChangeNotes<ChangeNotes> {
 | 
				
			|||||||
          //
 | 
					          //
 | 
				
			||||||
          // Parse notes from the staged result so we can return something useful
 | 
					          // Parse notes from the staged result so we can return something useful
 | 
				
			||||||
          // to the caller instead of throwing.
 | 
					          // to the caller instead of throwing.
 | 
				
			||||||
          log.debug("Rebuilding change {} failed", getChangeId());
 | 
					          log.debug("Rebuilding change {} failed: {}",
 | 
				
			||||||
 | 
					              getChangeId(), e.getMessage());
 | 
				
			||||||
          args.metrics.autoRebuildFailureCount.increment(CHANGES);
 | 
					          args.metrics.autoRebuildFailureCount.increment(CHANGES);
 | 
				
			||||||
          rebuildResult = checkNotNull(r);
 | 
					          rebuildResult = checkNotNull(r);
 | 
				
			||||||
          checkNotNull(r.newState());
 | 
					          checkNotNull(r.newState());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -176,6 +176,16 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private static class ConflictingUpdateException extends OrmRuntimeException {
 | 
				
			||||||
 | 
					    private static final long serialVersionUID = 1L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ConflictingUpdateException(Change change, String expectedNoteDbState) {
 | 
				
			||||||
 | 
					      super(String.format(
 | 
				
			||||||
 | 
					          "Expected change %s to have noteDbState %s but was %s",
 | 
				
			||||||
 | 
					          change.getId(), expectedNoteDbState, change.getNoteDbState()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Result rebuild(NoteDbUpdateManager manager,
 | 
					  public Result rebuild(NoteDbUpdateManager manager,
 | 
				
			||||||
      ChangeBundle bundle) throws NoSuchChangeException, IOException,
 | 
					      ChangeBundle bundle) throws NoSuchChangeException, IOException,
 | 
				
			||||||
@@ -217,8 +227,13 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
 | 
				
			|||||||
      db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
 | 
					      db.changes().atomicUpdate(changeId, new AtomicUpdate<Change>() {
 | 
				
			||||||
        @Override
 | 
					        @Override
 | 
				
			||||||
        public Change update(Change change) {
 | 
					        public Change update(Change change) {
 | 
				
			||||||
          if (!Objects.equals(oldNoteDbState, change.getNoteDbState())) {
 | 
					          String currNoteDbState = change.getNoteDbState();
 | 
				
			||||||
 | 
					          if (Objects.equals(currNoteDbState, newNoteDbState)) {
 | 
				
			||||||
 | 
					            // Another thread completed the same rebuild we were about to.
 | 
				
			||||||
            throw new AbortUpdateException();
 | 
					            throw new AbortUpdateException();
 | 
				
			||||||
 | 
					          } else if (!Objects.equals(oldNoteDbState, currNoteDbState)) {
 | 
				
			||||||
 | 
					            // Another thread updated the state to something else.
 | 
				
			||||||
 | 
					            throw new ConflictingUpdateException(change, oldNoteDbState);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          change.setNoteDbState(newNoteDbState);
 | 
					          change.setNoteDbState(newNoteDbState);
 | 
				
			||||||
          return change;
 | 
					          return change;
 | 
				
			||||||
@@ -233,7 +248,15 @@ public class ChangeRebuilderImpl extends ChangeRebuilder {
 | 
				
			|||||||
        throw new OrmException(NoteDbUpdateManager.CHANGES_READ_ONLY);
 | 
					        throw new OrmException(NoteDbUpdateManager.CHANGES_READ_ONLY);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } catch (AbortUpdateException e) {
 | 
					    } catch (AbortUpdateException e) {
 | 
				
			||||||
      // Drop this rebuild; another thread completed it.
 | 
					      // Drop this rebuild; another thread completed it. It's ok to not execute
 | 
				
			||||||
 | 
					      // the update in this case, since the object referenced in the Result was
 | 
				
			||||||
 | 
					      // flushed to the repo by whatever thread won the race.
 | 
				
			||||||
 | 
					    } catch (ConflictingUpdateException e) {
 | 
				
			||||||
 | 
					      // Rethrow as an OrmException so the caller knows to use staged results.
 | 
				
			||||||
 | 
					      // Strictly speaking they are not completely up to date, but result we
 | 
				
			||||||
 | 
					      // send to the caller is the same as if this rebuild had executed before
 | 
				
			||||||
 | 
					      // the other thread.
 | 
				
			||||||
 | 
					      throw new OrmException(e.getMessage());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return r;
 | 
					    return r;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -206,7 +206,8 @@ public class DraftCommentNotes extends AbstractChangeNotes<DraftCommentNotes> {
 | 
				
			|||||||
          repo.scanForRepoChanges();
 | 
					          repo.scanForRepoChanges();
 | 
				
			||||||
        } catch (OrmException | IOException e) {
 | 
					        } catch (OrmException | IOException e) {
 | 
				
			||||||
          // See ChangeNotes#rebuildAndOpen.
 | 
					          // See ChangeNotes#rebuildAndOpen.
 | 
				
			||||||
          log.debug("Rebuilding change {} via drafts failed", getChangeId());
 | 
					          log.debug("Rebuilding change {} via drafts failed: {}",
 | 
				
			||||||
 | 
					              getChangeId(), e.getMessage());
 | 
				
			||||||
          args.metrics.autoRebuildFailureCount.increment(CHANGES);
 | 
					          args.metrics.autoRebuildFailureCount.increment(CHANGES);
 | 
				
			||||||
          checkNotNull(r.staged());
 | 
					          checkNotNull(r.staged());
 | 
				
			||||||
          return LoadHandle.create(
 | 
					          return LoadHandle.create(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user