Remove sequence-based UID generation for messages

Unique identifiers for ChangeMessages and PatchLineComments were
generated using a seed from a database sequence, mixed together with
IdGenerator. In the spirit of killing ReviewDb, use a
cryptographically secure pseudorandom number generator to generate
these IDs instead. Follow the same "xxxxxxxx_xxxxxxxx" format so IDs
look similar.

I suppose the goal of the sequence-based approach was to decrease the
chance of collision by including a piece of state in each ID that is
guaranteed unique across the server. However, the chance of collision
for any 8-byte identifier can never be less than 1/2^64 no matter what
implementation we choose.

By definition a cryptographically secure PRNG generates random data
that is evenly distributed across the entire byte space, so the PRNG
implementation also has a 1/2^64 chance of collisions; we're just
swapping one rare-collision implementation with another. (This assumes
no bugs or weaknesses in the PRNG implementation, but with all due
respect to Shawn, I don't think the JDK's PRNG is any more likely to
have collision-introducing flaws than our hand-written IdGenerator.)

This change actually has no effect on ChangeMessage IDs that are
stored in or read from NoteDb, because ChangeNotesParser always
populates the ChangeMessage UUID field with the SHA-1 in the notes
graph of the commit that introduced the message; ReviewDb UUIDs are
simply discarded. The messageUuid method is still called during
creation because of the implementation details of ChangeMessagesUtil,
but that ID is not used for storage.

This change does have an effect on the IDs generated for
PatchLineComments, which also use messageUuid for their IDs, despite
the somewhat confusing fact that the ReviewDb interface implies the ID
is just for ChangeMessages.

While we're in there, rename the method to messageUuid to match the
Google Java Style Guide for camelCase names.

Change-Id: I7d157b9e8f87b41d4e7a146b705012863c27d42e
This commit is contained in:
Dave Borowitz
2017-01-05 12:30:27 -05:00
parent 2428f4fce9
commit 5a142312e9
22 changed files with 75 additions and 237 deletions

View File

@@ -17,10 +17,8 @@ package com.google.gerrit.server;
import static java.util.Comparator.comparingInt;
import com.google.common.collect.Ordering;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Singleton;
import org.eclipse.jgit.lib.Ref;
@@ -28,14 +26,15 @@ import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Map;
import java.util.Random;
@Singleton
public class ChangeUtil {
private static final Object uuidLock = new Object();
private static final int SEED = 0x2418e6f9;
private static int uuidPrefix;
private static int uuidSeq;
private static final Random UUID_RANDOM = new SecureRandom();
private static final BaseEncoding UUID_ENCODING =
BaseEncoding.base16().lowerCase();
private static final int SUBJECT_MAX_LENGTH = 80;
private static final String SUBJECT_CROP_APPENDIX = "...";
@@ -44,28 +43,12 @@ public class ChangeUtil {
public static final Ordering<PatchSet> PS_ID_ORDER =
Ordering.from(comparingInt(PatchSet::getPatchSetId));
/**
* Generate a new unique identifier for change message entities.
*
* @param db the database connection, used to increment the change message
* allocation sequence.
* @return the new unique identifier.
* @throws OrmException the database couldn't be incremented.
*/
public static String messageUUID(ReviewDb db) throws OrmException {
int p;
int s;
synchronized (uuidLock) {
if (uuidSeq == 0) {
uuidPrefix = db.nextChangeMessageId();
uuidSeq = Integer.MAX_VALUE;
}
p = uuidPrefix;
s = uuidSeq--;
}
String u = IdGenerator.format(IdGenerator.mix(SEED, p));
String l = IdGenerator.format(IdGenerator.mix(p, s));
return u + '_' + l;
/** @return a new unique identifier for change message entities. */
public static String messageUuid() {
byte[] buf = new byte[8];
UUID_RANDOM.nextBytes(buf);
return UUID_ENCODING.encode(buf, 0, 4) + '_'
+ UUID_ENCODING.encode(buf, 4, 4);
}
public static PatchSet.Id nextPatchSetId(Map<String, Ref> allRefs,