Make new message UUIDs more URL encoding friendly

=, + and / require triplet encoding in URLs. Cleanup the base64
encoding string to use different characters. This only impacts
newly created string, existing strings will continue to require a
much longer encoding when sent in JSON messages from the REST API.

Also strip leading 'A'. Most strings start with a run of 'A' due
to the first few bytes of uuidPrefix always being 0.

Avoid long runs of - in the resulting IDs by mixing the bits using
the uuidPrefix as the salt for the mixer.

Change-Id: I0a7da0aec071329c840447a0914d14118f2f20a4
This commit is contained in:
Shawn O. Pearce
2012-11-23 22:27:20 -08:00
parent 04a17cfa75
commit d2cdaa609d
2 changed files with 11 additions and 5 deletions

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server;
import com.google.common.base.CharMatcher;
import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage;
@@ -35,6 +36,7 @@ import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.util.IdGenerator;
import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmConcurrencyException;
import com.google.gwtorm.server.OrmException;
@@ -66,7 +68,6 @@ import java.util.Set;
import java.util.regex.Matcher;
public class ChangeUtil {
private static final Logger log = LoggerFactory.getLogger(ChangeUtil.class);
private static int uuidPrefix;
@@ -83,7 +84,12 @@ public class ChangeUtil {
public static String messageUUID(final ReviewDb db) throws OrmException {
final byte[] raw = new byte[8];
fill(raw, db);
return Base64.encodeBytes(raw);
// Make the resulting base64 string more URL friendly.
return CharMatcher.is('A').trimLeadingFrom(
CharMatcher.is('=').trimTrailingFrom(Base64.encodeBytes(raw)))
.replace('+', '.')
.replace('/', '-');
}
private static synchronized void fill(byte[] raw, ReviewDb db)
@@ -93,7 +99,7 @@ public class ChangeUtil {
uuidSeq = Integer.MAX_VALUE;
}
NB.encodeInt32(raw, 0, uuidPrefix);
NB.encodeInt32(raw, 4, uuidSeq--);
NB.encodeInt32(raw, 4, IdGenerator.mix(uuidPrefix, uuidSeq--));
}
public static void touch(final Change change, ReviewDb db)

View File

@@ -43,13 +43,13 @@ public class IdGenerator {
/** Produce the next identifier. */
public int next() {
return mix(gen.getAndIncrement());
return mix(salt, gen.getAndIncrement());
}
private static final int salt = 0x9e3779b9;
/** A very simple bit permutation to mask a simple incrementer. */
static int mix(final int in) {
public static int mix(final int salt, final int in) {
short v0 = hi16(in);
short v1 = lo16(in);
v0 += ((v1 << 2) + 0 ^ v1) + (salt ^ (v1 >>> 3)) + 1;