Skip to content

Commit d7c4f6d

Browse files
committed
GH-3696: Cache ParsedVersion in FileMetaData to eliminate redundant parsing
Parse the createdBy version string once during FileMetaData construction and cache the result as a transient field. This avoids redundant VersionParser.parse() calls at every downstream call site (R×C times during footer decode alone).
1 parent 2c9fbb3 commit d7c4f6d

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

parquet-hadoop/src/main/java/org/apache/parquet/hadoop/metadata/FileMetaData.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.io.Serializable;
2525
import java.util.Map;
2626
import java.util.Objects;
27+
import org.apache.parquet.VersionParser;
28+
import org.apache.parquet.VersionParser.ParsedVersion;
2729
import org.apache.parquet.crypto.InternalFileDecryptor;
2830
import org.apache.parquet.schema.MessageType;
2931

@@ -42,6 +44,7 @@ public enum EncryptionType {
4244
private final MessageType schema;
4345
private final Map<String, String> keyValueMetaData;
4446
private final String createdBy;
47+
private final transient ParsedVersion writerVersion;
4548
private final InternalFileDecryptor fileDecryptor;
4649
private final EncryptionType encryptionType;
4750

@@ -80,6 +83,7 @@ public FileMetaData(
8083
this.keyValueMetaData =
8184
unmodifiableMap(Objects.requireNonNull(keyValueMetaData, "keyValueMetaData cannot be null"));
8285
this.createdBy = createdBy;
86+
this.writerVersion = parseVersion(createdBy);
8387
this.fileDecryptor = fileDecryptor;
8488
this.encryptionType = encryptionType;
8589
}
@@ -118,4 +122,23 @@ public InternalFileDecryptor getFileDecryptor() {
118122
public EncryptionType getEncryptionType() {
119123
return encryptionType;
120124
}
125+
126+
/**
127+
* @return the parsed writer version, or {@code null} if {@code createdBy} is null, empty, or unparseable
128+
*/
129+
@JsonIgnore
130+
public ParsedVersion getWriterVersion() {
131+
return writerVersion;
132+
}
133+
134+
private static ParsedVersion parseVersion(String createdBy) {
135+
if (createdBy == null || createdBy.isEmpty()) {
136+
return null;
137+
}
138+
try {
139+
return VersionParser.parse(createdBy);
140+
} catch (RuntimeException | VersionParser.VersionParseException e) {
141+
return null;
142+
}
143+
}
121144
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.parquet.hadoop.metadata;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
import java.util.Collections;
24+
import org.apache.parquet.schema.MessageType;
25+
import org.apache.parquet.schema.PrimitiveType;
26+
import org.apache.parquet.schema.Type;
27+
import org.junit.jupiter.api.Test;
28+
29+
class FileMetaDataTest {
30+
31+
private static final MessageType SCHEMA = new MessageType(
32+
"test", new PrimitiveType(Type.Repetition.REQUIRED, PrimitiveType.PrimitiveTypeName.INT32, "id"));
33+
34+
@Test
35+
void validCreatedByIsParsed() {
36+
FileMetaData meta =
37+
new FileMetaData(SCHEMA, Collections.emptyMap(), "parquet-mr version 1.12.0 (build abc123)");
38+
39+
assertThat(meta.getWriterVersion()).isNotNull();
40+
assertThat(meta.getWriterVersion().application).isEqualTo("parquet-mr");
41+
assertThat(meta.getWriterVersion().version).isEqualTo("1.12.0");
42+
assertThat(meta.getWriterVersion().appBuildHash).isEqualTo("abc123");
43+
}
44+
45+
@Test
46+
void nullCreatedByReturnsNullWriterVersion() {
47+
FileMetaData meta = new FileMetaData(SCHEMA, Collections.emptyMap(), null);
48+
49+
assertThat(meta.getWriterVersion()).isNull();
50+
assertThat(meta.getCreatedBy()).isNull();
51+
}
52+
53+
@Test
54+
void emptyCreatedByReturnsNullWriterVersion() {
55+
FileMetaData meta = new FileMetaData(SCHEMA, Collections.emptyMap(), "");
56+
57+
assertThat(meta.getWriterVersion()).isNull();
58+
}
59+
60+
@Test
61+
void unparseableCreatedByReturnsNullWriterVersion() {
62+
FileMetaData meta = new FileMetaData(SCHEMA, Collections.emptyMap(), "no-version-here");
63+
64+
assertThat(meta.getWriterVersion()).isNull();
65+
}
66+
67+
@Test
68+
void versionWithoutBuildHash() {
69+
FileMetaData meta = new FileMetaData(SCHEMA, Collections.emptyMap(), "parquet-mr version 1.8.0");
70+
71+
assertThat(meta.getWriterVersion()).isNotNull();
72+
assertThat(meta.getWriterVersion().application).isEqualTo("parquet-mr");
73+
assertThat(meta.getWriterVersion().version).isEqualTo("1.8.0");
74+
assertThat(meta.getWriterVersion().appBuildHash).isNull();
75+
}
76+
}

0 commit comments

Comments
 (0)