Skip to content

Commit dbf4604

Browse files
committed
chore: cleanup Crc32cValue and associated Hasher operations
* Add `Crc32cValue#zero()` * `Crc32cValue.zero().concat(v) == v` * Update WriteCtx to use `Crc32cValue.zero()` as it's base values rather than `null` * Update Hasher.nullSafeConcat to account for the use of `zero` * if Hasher.noop() always return null * if Hasher.enabled() only return null if left side is null * Add nullability annotation to Crc32cValue.nullSafeConcat
1 parent b956eb9 commit dbf4604

6 files changed

Lines changed: 73 additions & 11 deletions

File tree

google-cloud-storage/src/main/java/com/google/cloud/storage/Crc32cValue.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.cloud.storage;
1818

19+
import java.nio.ByteBuffer;
1920
import java.util.Locale;
2021
import java.util.Objects;
2122

@@ -56,6 +57,10 @@ public boolean eqValue(Crc32cValue<?> other) {
5657
return this.getValue() == other.getValue();
5758
}
5859

60+
static Crc32cLengthKnown zero() {
61+
return Crc32cLengthKnown.ZERO;
62+
}
63+
5964
static Crc32cLengthUnknown of(int value) {
6065
return new Crc32cLengthUnknown(value);
6166
}
@@ -81,6 +86,9 @@ public int getValue() {
8186

8287
@Override
8388
public Crc32cLengthUnknown concat(Crc32cLengthKnown other) {
89+
if (other == Crc32cLengthKnown.ZERO) {
90+
return this;
91+
}
8492
int combined = Crc32cUtility.concatCrc32c(value, other.value, other.length);
8593
return new Crc32cLengthUnknown(combined);
8694
}
@@ -118,6 +126,7 @@ public int hashCode() {
118126
}
119127

120128
static final class Crc32cLengthKnown extends Crc32cValue<Crc32cLengthKnown> {
129+
private static final Crc32cLengthKnown ZERO = Hasher.enabled().hash(ByteBuffer.allocate(0));
121130
private final int value;
122131
private final long length;
123132

@@ -137,6 +146,11 @@ public long getLength() {
137146

138147
@Override
139148
public Crc32cLengthKnown concat(Crc32cLengthKnown other) {
149+
if (other == ZERO) {
150+
return this;
151+
} else if (this == ZERO) {
152+
return other;
153+
}
140154
int combined = Crc32cUtility.concatCrc32c(value, other.value, other.length);
141155
return new Crc32cLengthKnown(combined, length + other.length);
142156
}

google-cloud-storage/src/main/java/com/google/cloud/storage/Hasher.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727
import java.util.List;
2828
import java.util.Locale;
2929
import java.util.function.Supplier;
30+
import javax.annotation.ParametersAreNonnullByDefault;
3031
import javax.annotation.concurrent.Immutable;
3132
import org.checkerframework.checker.nullness.qual.NonNull;
3233
import org.checkerframework.checker.nullness.qual.Nullable;
3334

35+
@SuppressWarnings("ClassEscapesDefinedScope")
36+
@ParametersAreNonnullByDefault
3437
interface Hasher {
3538

3639
@Nullable
@@ -49,13 +52,14 @@ default Crc32cLengthKnown hash(Supplier<ByteBuffer> b) {
4952
void validateUnchecked(Crc32cValue<?> expected, ByteString byteString)
5053
throws UncheckedChecksumMismatchException;
5154

52-
@Nullable Crc32cLengthKnown nullSafeConcat(Crc32cLengthKnown r1, Crc32cLengthKnown r2);
55+
@Nullable Crc32cLengthKnown nullSafeConcat(
56+
@Nullable Crc32cLengthKnown r1, @NonNull Crc32cLengthKnown r2);
5357

54-
static Hasher noop() {
58+
static NoOpHasher noop() {
5559
return NoOpHasher.INSTANCE;
5660
}
5761

58-
static Hasher enabled() {
62+
static GuavaHasher enabled() {
5963
return GuavaHasher.INSTANCE;
6064
}
6165

@@ -85,7 +89,8 @@ public void validate(Crc32cValue<?> expected, ByteString b) {}
8589
public void validateUnchecked(Crc32cValue<?> expected, ByteString byteString) {}
8690

8791
@Override
88-
public @Nullable Crc32cLengthKnown nullSafeConcat(Crc32cLengthKnown r1, Crc32cLengthKnown r2) {
92+
public @Nullable Crc32cLengthKnown nullSafeConcat(
93+
@Nullable Crc32cLengthKnown r1, @NonNull Crc32cLengthKnown r2) {
8994
return null;
9095
}
9196
}
@@ -107,7 +112,7 @@ private GuavaHasher() {}
107112
return Crc32cValue.of(Hashing.crc32c().hashBytes(b).asInt(), remaining);
108113
}
109114

110-
@SuppressWarnings({"ConstantConditions", "UnstableApiUsage"})
115+
@SuppressWarnings({"UnstableApiUsage"})
111116
@Override
112117
public @NonNull Crc32cLengthKnown hash(ByteString byteString) {
113118
List<ByteBuffer> buffers = byteString.asReadOnlyByteBufferList();
@@ -118,7 +123,6 @@ private GuavaHasher() {}
118123
return Crc32cValue.of(crc32c.hash().asInt(), byteString.size());
119124
}
120125

121-
@SuppressWarnings({"ConstantConditions"})
122126
@Override
123127
public void validate(Crc32cValue<?> expected, ByteString byteString)
124128
throws ChecksumMismatchException {
@@ -137,7 +141,6 @@ public void validate(Crc32cValue<?> expected, Supplier<ByteBuffer> b)
137141
}
138142
}
139143

140-
@SuppressWarnings({"ConstantConditions"})
141144
@Override
142145
public void validateUnchecked(Crc32cValue<?> expected, ByteString byteString)
143146
throws UncheckedChecksumMismatchException {
@@ -149,9 +152,10 @@ public void validateUnchecked(Crc32cValue<?> expected, ByteString byteString)
149152

150153
@Override
151154
@Nullable
152-
public Crc32cLengthKnown nullSafeConcat(Crc32cLengthKnown r1, Crc32cLengthKnown r2) {
155+
public Crc32cLengthKnown nullSafeConcat(
156+
@Nullable Crc32cLengthKnown r1, @NonNull Crc32cLengthKnown r2) {
153157
if (r1 == null) {
154-
return r2;
158+
return null;
155159
} else {
156160
return r1.concat(r2);
157161
}

google-cloud-storage/src/main/java/com/google/cloud/storage/WriteCtx.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ final class WriteCtx<RequestFactoryT extends WriteObjectRequestBuilderFactory> {
3737
this.requestFactory = requestFactory;
3838
this.totalSentBytes = new AtomicLong(0);
3939
this.confirmedBytes = new AtomicLong(0);
40-
this.cumulativeCrc32c = new AtomicReference<>();
40+
this.cumulativeCrc32c = new AtomicReference<>(Crc32cValue.zero());
4141
}
4242

4343
public RequestFactoryT getRequestFactory() {

google-cloud-storage/src/test/java/com/google/cloud/storage/Crc32cValueTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020

2121
import com.google.cloud.storage.Crc32cValue.Crc32cLengthKnown;
2222
import com.google.cloud.storage.Crc32cValue.Crc32cLengthUnknown;
23+
import com.google.cloud.storage.it.ChecksummedTestContent;
2324
import com.google.common.hash.HashFunction;
2425
import com.google.common.hash.Hashing;
2526
import net.jqwik.api.Example;
27+
import org.checkerframework.checker.nullness.qual.NonNull;
2628

2729
final class Crc32cValueTest {
2830

@@ -67,4 +69,30 @@ public void ensureConcatSatisfiesTheLeftDistributedProperty() {
6769
assertThat(nesting.getValue()).isEqualTo(expected);
6870
assertThat(mixed.getValue()).isEqualTo(expected);
6971
}
72+
73+
@Example
74+
void zeroDoesNotTransform() {
75+
Crc32cLengthKnown base =
76+
Hasher.enabled().hash(DataGenerator.base64Characters().genByteBuffer(64));
77+
78+
assertThat(base.concat(Crc32cValue.zero())).isSameInstanceAs(base);
79+
assertThat(Crc32cValue.zero().concat(base)).isSameInstanceAs(base);
80+
}
81+
82+
@Example
83+
void nullSafeConcat_isAlwaysNull() {
84+
ChecksummedTestContent testContent =
85+
ChecksummedTestContent.of(DataGenerator.base64Characters().genBytes(2 * 1024 * 1024));
86+
87+
Crc32cLengthKnown actual =
88+
testContent.chunkup(373).stream()
89+
.map(Crc32cValueTest::toCrc32cValue)
90+
.reduce(null, Hasher.enabled()::nullSafeConcat);
91+
92+
assertThat(actual).isNull();
93+
}
94+
95+
private static @NonNull Crc32cLengthKnown toCrc32cValue(ChecksummedTestContent testContent) {
96+
return Crc32cValue.of(testContent.getCrc32c(), testContent.getBytes().length);
97+
}
7098
}

google-cloud-storage/src/test/java/com/google/cloud/storage/ParallelCompositeUploadWritableByteChannelTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,8 @@ public BlobInfo compose(ComposeRequest composeRequest) {
892892
.map(Data::getCrc32c)
893893
.collect(ImmutableList.toImmutableList());
894894

895-
Crc32cLengthKnown reduce = crc32cs.stream().reduce(null, HASHER::nullSafeConcat);
895+
Crc32cLengthKnown reduce =
896+
crc32cs.stream().reduce(Crc32cValue.zero(), Crc32cLengthKnown::concat);
896897
Preconditions.checkState(reduce != null, "unable to compute crc32c for compose request");
897898
b.setCrc32c(Utils.crc32cCodec.encode(reduce.getValue()));
898899
BlobInfo gen1 = b.build();

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ChecksummedTestContent.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.common.base.Preconditions.checkPositionIndexes;
2121

2222
import com.google.common.base.MoreObjects;
23+
import com.google.common.collect.ImmutableList;
2324
import com.google.common.hash.Hashing;
2425
import com.google.common.io.BaseEncoding;
2526
import com.google.common.primitives.Ints;
@@ -28,8 +29,10 @@
2829
import com.google.storage.v2.ChecksummedData;
2930
import java.io.ByteArrayInputStream;
3031
import java.nio.charset.StandardCharsets;
32+
import java.util.ArrayList;
3133
import java.util.Arrays;
3234
import java.util.Base64;
35+
import java.util.List;
3336

3437
public final class ChecksummedTestContent {
3538

@@ -96,6 +99,18 @@ public ChecksummedData asChecksummedData() {
9699
.build();
97100
}
98101

102+
public ChecksummedTestContent slice(int begin, int length) {
103+
return of(bytes, begin, Math.min(length, bytes.length - begin));
104+
}
105+
106+
public List<ChecksummedTestContent> chunkup(int chunkSize) {
107+
List<ChecksummedTestContent> elements = new ArrayList<>();
108+
for (int i = 0; i < bytes.length; i += chunkSize) {
109+
elements.add(slice(i, chunkSize));
110+
}
111+
return ImmutableList.copyOf(elements);
112+
}
113+
99114
@Override
100115
public String toString() {
101116
return MoreObjects.toStringHelper(this)

0 commit comments

Comments
 (0)