This is an automated email from the ASF dual-hosted git repository.

xbli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new f4a4bf389a Custom configuration property reader for segment metadata 
files (#12440)
f4a4bf389a is described below

commit f4a4bf389a5a81d116e38ea73280277a23080b43
Author: Abhishek Sharma <abhishek.sha...@spothero.com>
AuthorDate: Wed Jun 5 17:30:56 2024 -0400

    Custom configuration property reader for segment metadata files (#12440)
    
    * Added versioned configuration reader/writer
    
    * Added methods to read/write segment metadata with versioned reader/writer
---
 .../pinot/spi/env/CommonsConfigurationUtils.java   | 179 +++++++++++++----
 ...ctory.java => ConfigFilePropertyIOFactory.java} |   2 +-
 .../apache/pinot/spi/env/PinotConfiguration.java   |   6 +-
 ...aderFactory.java => PropertyIOFactoryKind.java} |  40 +++-
 ...yReaderFactory.java => VersionedIOFactory.java} |  19 +-
 .../pinot/spi/env/VersionedPropertyReader.java     |  61 ++++++
 ...erFactory.java => VersionedPropertyWriter.java} |  23 ++-
 .../spi/env/CommonsConfigurationUtilsTest.java     |  48 ++++-
 .../pinot/spi/env/PinotConfigurationTest.java      |   4 +-
 .../pinot/spi/env/VersionedPropertyConfigTest.java | 223 +++++++++++++++++++++
 ...segment-metadata-with-version-header.properties | 125 ++++++++++++
 ...ment-metadata-without-version-header.properties | 123 ++++++++++++
 pom.xml                                            |   6 +
 13 files changed, 790 insertions(+), 69 deletions(-)

diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/CommonsConfigurationUtils.java
 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/CommonsConfigurationUtils.java
index 0613230e09..10c9f7151d 100644
--- 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/CommonsConfigurationUtils.java
+++ 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/CommonsConfigurationUtils.java
@@ -18,8 +18,10 @@
  */
 package org.apache.pinot.spi.env;
 
-import com.google.common.base.Preconditions;
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
 import java.util.Iterator;
@@ -42,29 +44,21 @@ import org.apache.commons.lang3.StringUtils;
  * Provide utility functions to manipulate Apache Commons {@link 
Configuration} instances.
  */
 public class CommonsConfigurationUtils {
+  // value to be used to set the global separator for versioned properties 
configuration.
+  // the value is same of PropertiesConfiguration `DEFAULT_SEPARATOR` constant.
+  public static final String VERSIONED_CONFIG_SEPARATOR = " = ";
   private static final Character DEFAULT_LIST_DELIMITER = ',';
+  public static final String VERSION_HEADER_IDENTIFIER = "version";
 
-  private CommonsConfigurationUtils() {
-  }
+  // usage: default header version of all configurations.
+  // if properties configuration doesn't contain header version, it will be 
considered as 1
+  public static final String DEFAULT_PROPERTIES_CONFIGURATION_HEADER_VERSION = 
"1";
 
-  /**
-   * Instantiate a {@link PropertiesConfiguration} from a {@link File}.
-   * @param file containing properties
-   * @return a {@link PropertiesConfiguration} instance. Empty if file does 
not exist.
-   */
-  public static PropertiesConfiguration fromFile(File file)
-      throws ConfigurationException {
-    return fromFile(file, false, true);
-  }
+  // usage: used in reading segment metadata or other properties 
configurations with 'VersionedIOFactory' IO Factory.
+  // version signifies that segment metadata or other properties 
configurations contains keys with no special character.
+  public static final String PROPERTIES_CONFIGURATION_HEADER_VERSION_2 = "2";
 
-  /**
-   * Instantiate a {@link PropertiesConfiguration} from an {@link InputStream}.
-   * @param stream containing properties
-   * @return a {@link PropertiesConfiguration} instance.
-   */
-  public static PropertiesConfiguration fromInputStream(InputStream stream)
-      throws ConfigurationException {
-    return fromInputStream(stream, false, true);
+  private CommonsConfigurationUtils() {
   }
 
   /**
@@ -74,20 +68,20 @@ public class CommonsConfigurationUtils {
    */
   public static PropertiesConfiguration fromPath(String path)
       throws ConfigurationException {
-    return fromPath(path, false, true);
+    return fromPath(path, true, null);
   }
 
   /**
    * Instantiate a {@link PropertiesConfiguration} from an {@link String}.
    * @param path representing the path of file
-   * @param setIOFactory representing to set the IOFactory or not
    * @param setDefaultDelimiter representing to set the default list delimiter.
+   * @param ioFactoryKind representing to set IOFactory. It can be null.
    * @return a {@link PropertiesConfiguration} instance.
    */
-  public static PropertiesConfiguration fromPath(@Nullable String path, 
boolean setIOFactory,
-      boolean setDefaultDelimiter)
+  public static PropertiesConfiguration fromPath(@Nullable String path, 
boolean setDefaultDelimiter,
+      @Nullable PropertyIOFactoryKind ioFactoryKind)
       throws ConfigurationException {
-    PropertiesConfiguration config = 
createPropertiesConfiguration(setIOFactory, setDefaultDelimiter);
+    PropertiesConfiguration config = 
createPropertiesConfiguration(setDefaultDelimiter, ioFactoryKind);
     // if provided path is non-empty, load the existing properties from 
provided file path
     if (StringUtils.isNotEmpty(path)) {
       FileHandler fileHandler = new FileHandler(config);
@@ -99,14 +93,24 @@ public class CommonsConfigurationUtils {
   /**
    * Instantiate a {@link PropertiesConfiguration} from an {@link InputStream}.
    * @param stream containing properties
-   * @param setIOFactory representing to set the IOFactory or not
+   * @return a {@link PropertiesConfiguration} instance.
+   */
+  public static PropertiesConfiguration fromInputStream(InputStream stream)
+      throws ConfigurationException {
+    return fromInputStream(stream, true, 
PropertyIOFactoryKind.DefaultIOFactory);
+  }
+
+  /**
+   * Instantiate a {@link PropertiesConfiguration} from an {@link InputStream}.
+   * @param stream containing properties
    * @param setDefaultDelimiter representing to set the default list delimiter.
+   * @param ioFactoryKind representing to set IOFactory. It can be null.
    * @return a {@link PropertiesConfiguration} instance.
    */
-  public static PropertiesConfiguration fromInputStream(@Nullable InputStream 
stream, boolean setIOFactory,
-      boolean setDefaultDelimiter)
+  public static PropertiesConfiguration fromInputStream(@Nullable InputStream 
stream,
+      boolean setDefaultDelimiter, @Nullable PropertyIOFactoryKind 
ioFactoryKind)
       throws ConfigurationException {
-    PropertiesConfiguration config = 
createPropertiesConfiguration(setIOFactory, setDefaultDelimiter);
+    PropertiesConfiguration config = 
createPropertiesConfiguration(setDefaultDelimiter, ioFactoryKind);
     // if provided stream is not null, load the existing properties from 
provided input stream.
     if (stream != null) {
       FileHandler fileHandler = new FileHandler(config);
@@ -115,16 +119,45 @@ public class CommonsConfigurationUtils {
     return config;
   }
 
+  /**
+   * Instantiate a Segment Metadata {@link PropertiesConfiguration} from a 
{@link File}.
+   * @param file containing properties
+   * @param setDefaultDelimiter representing to set the default list delimiter.
+   * @return a {@link PropertiesConfiguration} instance.
+   */
+  public static PropertiesConfiguration getSegmentMetadataFromFile(File file, 
boolean setDefaultDelimiter)
+      throws ConfigurationException {
+    PropertyIOFactoryKind ioFactoryKind = 
PropertyIOFactoryKind.DefaultIOFactory;
+
+    // if segment metadata contains version header with value '2', set 
VersionedIOFactory as IO factory.
+    if 
(PROPERTIES_CONFIGURATION_HEADER_VERSION_2.equals(getConfigurationHeaderVersion(file)))
 {
+      ioFactoryKind = PropertyIOFactoryKind.VersionedIOFactory;
+    }
+
+    return fromFile(file, setDefaultDelimiter, ioFactoryKind);
+  }
+
+  /**
+   * Instantiate a {@link PropertiesConfiguration} from a {@link File}.
+   * @param file containing properties
+   * @return a {@link PropertiesConfiguration} instance. Empty if file does 
not exist.
+   */
+  public static PropertiesConfiguration fromFile(File file)
+      throws ConfigurationException {
+    return fromFile(file, true, PropertyIOFactoryKind.DefaultIOFactory);
+  }
+
   /**
    * Instantiate a {@link PropertiesConfiguration} from a {@link File}.
    * @param file containing properties
-   * @param setIOFactory representing to set the IOFactory or not
    * @param setDefaultDelimiter representing to set the default list delimiter.
+   * @param ioFactoryKind representing to set IOFactory. It can be null.
    * @return a {@link PropertiesConfiguration} instance.
    */
-  public static PropertiesConfiguration fromFile(@Nullable File file, boolean 
setIOFactory, boolean setDefaultDelimiter)
+  public static PropertiesConfiguration fromFile(@Nullable File file,
+      boolean setDefaultDelimiter, @Nullable PropertyIOFactoryKind 
ioFactoryKind)
       throws ConfigurationException {
-    PropertiesConfiguration config = 
createPropertiesConfiguration(setIOFactory, setDefaultDelimiter);
+    PropertiesConfiguration config = 
createPropertiesConfiguration(setDefaultDelimiter, ioFactoryKind);
     // check if file exists, load the existing properties.
     if (file != null && file.exists()) {
       FileHandler fileHandler = new FileHandler(config);
@@ -133,13 +166,37 @@ public class CommonsConfigurationUtils {
     return config;
   }
 
+  /**
+   * save the segment metadata configuration content into the provided file 
based on the version header.
+   * @param propertiesConfiguration a {@link PropertiesConfiguration} instance.
+   * @param file a {@link File} instance.
+   * @param versionHeader a Nullable {@link String} instance.
+   */
+  public static void saveSegmentMetadataToFile(PropertiesConfiguration 
propertiesConfiguration, File file,
+      @Nullable String versionHeader) {
+    if (StringUtils.isNotEmpty(versionHeader)) {
+      String header = getVersionHeaderString(versionHeader);
+      propertiesConfiguration.setHeader(header);
+
+      // checks whether the provided versionHeader equals to 
VersionedIOFactory kind.
+      // if true, set IO factory as VersionedIOFactory
+      if (PROPERTIES_CONFIGURATION_HEADER_VERSION_2.equals(versionHeader)) {
+        // set versioned IOFactory
+        
propertiesConfiguration.setIOFactory(PropertyIOFactoryKind.VersionedIOFactory.getInstance());
+        // setting the global separator makes sure the configurations gets 
written with ' = ' separator.
+        // global separator overrides the separator set at the key level as 
well.
+        
propertiesConfiguration.getLayout().setGlobalSeparator(VERSIONED_CONFIG_SEPARATOR);
+      }
+    }
+    saveToFile(propertiesConfiguration, file);
+  }
+
   /**
    * Save the propertiesConfiguration content into the provided file.
    * @param propertiesConfiguration a {@link PropertiesConfiguration} instance.
    * @param file a {@link File} instance.
    */
   public static void saveToFile(PropertiesConfiguration 
propertiesConfiguration, File file) {
-    Preconditions.checkNotNull(file, "File object can not be null for saving 
configurations");
     FileHandler fileHandler = new FileHandler(propertiesConfiguration);
     fileHandler.setFile(file);
     try {
@@ -276,20 +333,64 @@ public class CommonsConfigurationUtils {
     return value.replace("\0\0", ",");
   }
 
-  private static PropertiesConfiguration createPropertiesConfiguration(boolean 
setIOFactory,
-      boolean setDefaultDelimiter) {
+  /**
+   * creates the instance of the {@link 
org.apache.commons.configuration2.PropertiesConfiguration}
+   * with custom IO factory based on kind {@link 
org.apache.commons.configuration2.PropertiesConfiguration.IOFactory}
+   * and legacy list delimiter {@link 
org.apache.commons.configuration2.convert.LegacyListDelimiterHandler}
+   *
+   * @param setDefaultDelimiter sets the default list delimiter.
+   * @param ioFactoryKind IOFactory kind, can be null.
+   * @return PropertiesConfiguration
+   */
+  private static PropertiesConfiguration createPropertiesConfiguration(boolean 
setDefaultDelimiter,
+     @Nullable PropertyIOFactoryKind ioFactoryKind) {
     PropertiesConfiguration config = new PropertiesConfiguration();
 
-    // setting IO Reader Factory
-    if (setIOFactory) {
-      config.setIOFactory(new ConfigFilePropertyReaderFactory());
+    // setting IO Reader Factory of the configuration.
+    if (ioFactoryKind != null) {
+      config.setIOFactory(ioFactoryKind.getInstance());
     }
 
-    // setting DEFAULT_LIST_DELIMITER
+    // setting the DEFAULT_LIST_DELIMITER
     if (setDefaultDelimiter) {
       config.setListDelimiterHandler(new 
LegacyListDelimiterHandler(DEFAULT_LIST_DELIMITER));
     }
 
     return config;
   }
+
+  /**
+   * checks whether the configuration file first line is version header or not.
+   * @param file configuration file
+   * @return String
+   * @throws ConfigurationException exception.
+   */
+  private static String getConfigurationHeaderVersion(File file)
+      throws ConfigurationException {
+    String versionValue = DEFAULT_PROPERTIES_CONFIGURATION_HEADER_VERSION;
+    if (file.exists()) {
+      try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+        String fileFirstLine = reader.readLine();
+        // header version is written as a comment and start with '# '
+        String versionHeaderCommentPrefix = String.format("# %s", 
VERSION_HEADER_IDENTIFIER);
+        // check whether the file has the version header or not
+        if (StringUtils.startsWith(fileFirstLine, versionHeaderCommentPrefix)) 
{
+          String[] headerKeyValue = 
StringUtils.splitByWholeSeparator(fileFirstLine, VERSIONED_CONFIG_SEPARATOR, 2);
+          if (headerKeyValue.length == 2) {
+            versionValue = headerKeyValue[1];
+          }
+        }
+      } catch (IOException exception) {
+        throw new ConfigurationException(
+            "Error occurred while reading configuration file " + 
file.getName(), exception);
+      }
+    }
+    return versionValue;
+  }
+
+  // Returns the version header string based on the version header value 
provided.
+  // The return statement follow the pattern 'version = <value>'
+  static String getVersionHeaderString(String versionHeaderValue) {
+    return String.format("%s%s%s", VERSION_HEADER_IDENTIFIER, 
VERSIONED_CONFIG_SEPARATOR, versionHeaderValue);
+  }
 }
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyIOFactory.java
similarity index 94%
copy from 
pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
copy to 
pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyIOFactory.java
index 6de66bad7c..6dfa2b87da 100644
--- 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
+++ 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyIOFactory.java
@@ -23,7 +23,7 @@ import 
org.apache.commons.configuration2.PropertiesConfiguration.DefaultIOFactor
 import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesReader;
 
 
-public class ConfigFilePropertyReaderFactory extends DefaultIOFactory {
+public class ConfigFilePropertyIOFactory extends DefaultIOFactory {
   @Override
   public PropertiesReader createPropertiesReader(Reader in) {
     return new ConfigFilePropertyReader(in);
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/PinotConfiguration.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/PinotConfiguration.java
index 0516ee6b41..72be975544 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/env/PinotConfiguration.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/env/PinotConfiguration.java
@@ -213,9 +213,11 @@ public class PinotConfiguration {
       PropertiesConfiguration propertiesConfiguration;
       if (configPath.startsWith("classpath:")) {
         propertiesConfiguration = CommonsConfigurationUtils.fromInputStream(
-            
PinotConfiguration.class.getResourceAsStream(configPath.substring("classpath:".length())),
 true, true);
+            
PinotConfiguration.class.getResourceAsStream(configPath.substring("classpath:".length())),
 true,
+            PropertyIOFactoryKind.ConfigFileIOFactory);
       } else {
-        propertiesConfiguration = 
CommonsConfigurationUtils.fromPath(configPath, true, true);
+        propertiesConfiguration = 
CommonsConfigurationUtils.fromPath(configPath, true,
+            PropertyIOFactoryKind.ConfigFileIOFactory);
       }
       return propertiesConfiguration;
     } catch (ConfigurationException e) {
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
 b/pinot-spi/src/main/java/org/apache/pinot/spi/env/PropertyIOFactoryKind.java
similarity index 53%
copy from 
pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
copy to 
pinot-spi/src/main/java/org/apache/pinot/spi/env/PropertyIOFactoryKind.java
index 6de66bad7c..bef441de3b 100644
--- 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
+++ 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/PropertyIOFactoryKind.java
@@ -18,14 +18,38 @@
  */
 package org.apache.pinot.spi.env;
 
-import java.io.Reader;
-import 
org.apache.commons.configuration2.PropertiesConfiguration.DefaultIOFactory;
-import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesReader;
+import org.apache.commons.configuration2.PropertiesConfiguration;
 
+public enum PropertyIOFactoryKind {
+  ConfigFileIOFactory {
+    public String toString() {
+      return "ConfigFile";
+    }
 
-public class ConfigFilePropertyReaderFactory extends DefaultIOFactory {
-  @Override
-  public PropertiesReader createPropertiesReader(Reader in) {
-    return new ConfigFilePropertyReader(in);
-  }
+    @Override
+    public ConfigFilePropertyIOFactory getInstance() {
+      return new ConfigFilePropertyIOFactory();
+    }
+  },
+  VersionedIOFactory {
+    public String toString() {
+      return "Versioned";
+    }
+    @Override
+    public VersionedIOFactory getInstance() {
+      return new VersionedIOFactory();
+    }
+  },
+  DefaultIOFactory {
+    public String toString() {
+      return "Default";
+    }
+    @Override
+    public PropertiesConfiguration.DefaultIOFactory getInstance() {
+      return new PropertiesConfiguration.DefaultIOFactory();
+    }
+  };
+
+  // get the instance of the IO factory.
+  public abstract PropertiesConfiguration.DefaultIOFactory getInstance();
 }
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
 b/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedIOFactory.java
similarity index 60%
copy from 
pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
copy to pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedIOFactory.java
index 6de66bad7c..3ba7105357 100644
--- 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedIOFactory.java
@@ -19,13 +19,26 @@
 package org.apache.pinot.spi.env;
 
 import java.io.Reader;
+import java.io.Writer;
 import 
org.apache.commons.configuration2.PropertiesConfiguration.DefaultIOFactory;
 import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesReader;
+import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesWriter;
+import org.apache.commons.configuration2.convert.ListDelimiterHandler;
 
 
-public class ConfigFilePropertyReaderFactory extends DefaultIOFactory {
+/**
+ * VersionedIOFactory extends the DefaultIOFactory
+ * <p>
+ * Purpose: factory class for creating the custom versioned property 
configuration reader and writer.
+ */
+class VersionedIOFactory extends DefaultIOFactory {
+  @Override
+  public PropertiesReader createPropertiesReader(Reader reader) {
+    return new VersionedPropertyReader(reader);
+  }
+
   @Override
-  public PropertiesReader createPropertiesReader(Reader in) {
-    return new ConfigFilePropertyReader(in);
+  public PropertiesWriter createPropertiesWriter(Writer out, 
ListDelimiterHandler handler) {
+    return new VersionedPropertyWriter(out, handler);
   }
 }
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedPropertyReader.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedPropertyReader.java
new file mode 100644
index 0000000000..c108bfebcc
--- /dev/null
+++ 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedPropertyReader.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.spi.env;
+
+import com.google.common.base.Preconditions;
+import java.io.Reader;
+import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesReader;
+import org.apache.commons.lang3.StringUtils;
+
+
+/**
+ * VersionedPropertyReader extends the PropertiesReader
+ * <p>
+ * Purpose: loads the segment metadata faster
+ *  - by skipping the unescaping of key and
+ *  - parsing the line by splitting based on first occurrence of separator
+ */
+class VersionedPropertyReader extends PropertiesReader {
+
+  public VersionedPropertyReader(Reader reader) {
+    super(reader);
+  }
+
+  @Override
+  protected void parseProperty(final String line) {
+    // skip the regex based parsing of the line content and splitting the 
content based on first occurrence of separator
+    // getPropertySeparator(), in general returns the PropertiesConfiguration 
`DEFAULT_SEPARATOR` value i.e. ' = '.
+    String separator = getPropertySeparator();
+    
Preconditions.checkArgument(CommonsConfigurationUtils.VERSIONED_CONFIG_SEPARATOR.equals(separator),
+        String.format("Versioned property configuration separator '%s' should 
be equal to '%s'",
+            separator, CommonsConfigurationUtils.VERSIONED_CONFIG_SEPARATOR));
+
+    String[] keyValue = StringUtils.splitByWholeSeparator(line, separator, 2);
+    Preconditions.checkArgument(keyValue.length == 2, "property content split 
should result in key and value");
+    initPropertyName(keyValue[0]);
+    initPropertyValue(keyValue[1]);
+    initPropertySeparator(separator);
+  }
+
+  @Override
+  protected String unescapePropertyName(final String name) {
+    // skip the unescaping of the propertyName(key)
+    return name;
+  }
+}
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
 b/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedPropertyWriter.java
similarity index 61%
rename from 
pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
rename to 
pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedPropertyWriter.java
index 6de66bad7c..86dbbb95f1 100644
--- 
a/pinot-spi/src/main/java/org/apache/pinot/spi/env/ConfigFilePropertyReaderFactory.java
+++ 
b/pinot-spi/src/main/java/org/apache/pinot/spi/env/VersionedPropertyWriter.java
@@ -18,14 +18,25 @@
  */
 package org.apache.pinot.spi.env;
 
-import java.io.Reader;
-import 
org.apache.commons.configuration2.PropertiesConfiguration.DefaultIOFactory;
-import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesReader;
+import java.io.Writer;
+import 
org.apache.commons.configuration2.PropertiesConfiguration.PropertiesWriter;
+import org.apache.commons.configuration2.convert.ListDelimiterHandler;
 
 
-public class ConfigFilePropertyReaderFactory extends DefaultIOFactory {
+/**
+ * SegmentMetadataPropertyWriter extends the PropertiesWriter
+ * <p>
+ * Purpose: custom property writer for writing the segment metadata faster by 
skipping the escaping of key.
+ */
+public class VersionedPropertyWriter extends PropertiesWriter {
+
+  public VersionedPropertyWriter(final Writer writer, ListDelimiterHandler 
handler) {
+    super(writer, handler);
+  }
+
   @Override
-  public PropertiesReader createPropertiesReader(Reader in) {
-    return new ConfigFilePropertyReader(in);
+  protected String escapeKey(final String key) {
+    // skip the escapeKey functionality,
+    return key;
   }
 }
diff --git 
a/pinot-spi/src/test/java/org/apache/pinot/spi/env/CommonsConfigurationUtilsTest.java
 
b/pinot-spi/src/test/java/org/apache/pinot/spi/env/CommonsConfigurationUtilsTest.java
index 06174ed212..19a7e83b2f 100644
--- 
a/pinot-spi/src/test/java/org/apache/pinot/spi/env/CommonsConfigurationUtilsTest.java
+++ 
b/pinot-spi/src/test/java/org/apache/pinot/spi/env/CommonsConfigurationUtilsTest.java
@@ -27,6 +27,7 @@ import 
org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -39,6 +40,7 @@ import static org.testng.Assert.assertTrue;
 public class CommonsConfigurationUtilsTest {
   private static final File TEMP_DIR = new File(FileUtils.getTempDirectory(), 
"CommonsConfigurationUtilsTest");
   private static final File CONFIG_FILE = new File(TEMP_DIR, "config");
+  private static final File SEGMENT_METADATA_CONFIG_FILE = new File(TEMP_DIR, 
"segmentMetadataConfig");
   private static final String PROPERTY_KEY = "testKey";
   private static final int NUM_ROUNDS = 10000;
 
@@ -54,6 +56,34 @@ public class CommonsConfigurationUtilsTest {
     FileUtils.deleteDirectory(TEMP_DIR);
   }
 
+  @Test
+  public void testSegmentMetadataFromFile() {
+    // load the existing config and check the properties config instance
+    try {
+      PropertiesConfiguration config = CommonsConfigurationUtils
+          .getSegmentMetadataFromFile(SEGMENT_METADATA_CONFIG_FILE, true);
+      assertNotNull(config);
+
+      config.setProperty("testKey", "testValue");
+
+      // add the segment version header to the file and read it again
+      CommonsConfigurationUtils.saveSegmentMetadataToFile(config, CONFIG_FILE,
+          CommonsConfigurationUtils.PROPERTIES_CONFIGURATION_HEADER_VERSION_2);
+
+      // reading the property with header.
+      config = 
CommonsConfigurationUtils.getSegmentMetadataFromFile(CONFIG_FILE, true);
+      assertNotNull(config);
+      assertEquals(config.getHeader(), "# version = 2");
+    } catch (Exception ex) {
+      Assert.fail(String.format("should not throw ConfigurationException 
exception with valid file, %s",
+          ex.getMessage()));
+    }
+
+    // load the non-existing file and expect the exception
+    Assert.expectThrows(NullPointerException.class,
+        () -> CommonsConfigurationUtils.getSegmentMetadataFromFile(null, 
true));
+  }
+
   @Test
   public void testPropertyValueWithSpecialCharacters()
       throws Exception {
@@ -111,14 +141,16 @@ public class CommonsConfigurationUtilsTest {
       return;
     }
 
-    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromFile(CONFIG_FILE, false, true);
+    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromFile(CONFIG_FILE, true,
+        PropertyIOFactoryKind.DefaultIOFactory);
     configuration.setProperty(PROPERTY_KEY, replacedValue);
     String recoveredValue = 
CommonsConfigurationUtils.recoverSpecialCharacterInPropertyValue(
         (String) configuration.getProperty(PROPERTY_KEY));
     assertEquals(recoveredValue, value);
 
     CommonsConfigurationUtils.saveToFile(configuration, CONFIG_FILE);
-    configuration = CommonsConfigurationUtils.fromFile(CONFIG_FILE, false, 
true);
+    configuration = CommonsConfigurationUtils.fromFile(CONFIG_FILE, true,
+        PropertyIOFactoryKind.DefaultIOFactory);
     recoveredValue = 
CommonsConfigurationUtils.recoverSpecialCharacterInPropertyValue(
         (String) configuration.getProperty(PROPERTY_KEY));
     assertEquals(recoveredValue, value);
@@ -127,12 +159,12 @@ public class CommonsConfigurationUtilsTest {
   @Test
   public void testPropertiesConfigurationFromFile()
       throws ConfigurationException {
-    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromFile(null, false, true);
+    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromFile(null, false, null);
     assertNotNull(configuration);
     configuration.setProperty("Test Key", "Test Value");
     CommonsConfigurationUtils.saveToFile(configuration, CONFIG_FILE);
 
-    configuration = CommonsConfigurationUtils.fromFile(CONFIG_FILE, false, 
true);
+    configuration = CommonsConfigurationUtils.fromFile(CONFIG_FILE, false, 
null);
     assertNotNull(configuration);
     assertEquals(configuration.getProperty("Test Key"), "Test Value");
   }
@@ -140,12 +172,12 @@ public class CommonsConfigurationUtilsTest {
   @Test
   public void testPropertiesConfigurationFromPath()
       throws ConfigurationException {
-    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromPath(null, false, true);
+    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromPath(null, false, null);
     assertNotNull(configuration);
     configuration.setProperty("Test Key", "Test Value");
     CommonsConfigurationUtils.saveToFile(configuration, CONFIG_FILE);
 
-    configuration = CommonsConfigurationUtils.fromPath(CONFIG_FILE.getPath(), 
false, true);
+    configuration = CommonsConfigurationUtils.fromPath(CONFIG_FILE.getPath(), 
false, null);
     assertNotNull(configuration);
     assertEquals(configuration.getProperty("Test Key"), "Test Value");
   }
@@ -153,13 +185,13 @@ public class CommonsConfigurationUtilsTest {
   @Test
   public void testPropertiesConfigurationFromInputStream()
       throws ConfigurationException, FileNotFoundException {
-    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromInputStream(null, false, true);
+    PropertiesConfiguration configuration = 
CommonsConfigurationUtils.fromInputStream(null, false, null);
     assertNotNull(configuration);
     configuration.setProperty("Test Key", "Test Value");
     CommonsConfigurationUtils.saveToFile(configuration, CONFIG_FILE);
 
     FileInputStream inputStream = new FileInputStream(CONFIG_FILE);
-    configuration = CommonsConfigurationUtils.fromInputStream(inputStream, 
false, true);
+    configuration = CommonsConfigurationUtils.fromInputStream(inputStream, 
false, null);
     assertNotNull(configuration);
     assertEquals(configuration.getProperty("Test Key"), "Test Value");
   }
diff --git 
a/pinot-spi/src/test/java/org/apache/pinot/spi/env/PinotConfigurationTest.java 
b/pinot-spi/src/test/java/org/apache/pinot/spi/env/PinotConfigurationTest.java
index a7c1f0783e..1c810dc6ef 100644
--- 
a/pinot-spi/src/test/java/org/apache/pinot/spi/env/PinotConfigurationTest.java
+++ 
b/pinot-spi/src/test/java/org/apache/pinot/spi/env/PinotConfigurationTest.java
@@ -200,8 +200,8 @@ public class PinotConfigurationTest {
   public void assertPropertiesFromBaseConfiguration()
       throws ConfigurationException {
     PropertiesConfiguration propertiesConfiguration = 
CommonsConfigurationUtils.fromPath(
-        
PropertiesConfiguration.class.getClassLoader().getResource("pinot-configuration-1.properties").getFile(),
 true,
-        true);
+        
PropertiesConfiguration.class.getClassLoader().getResource("pinot-configuration-1.properties").getFile(),
+        true, PropertyIOFactoryKind.ConfigFileIOFactory);
 
     PinotConfiguration config = new 
PinotConfiguration(propertiesConfiguration);
 
diff --git 
a/pinot-spi/src/test/java/org/apache/pinot/spi/env/VersionedPropertyConfigTest.java
 
b/pinot-spi/src/test/java/org/apache/pinot/spi/env/VersionedPropertyConfigTest.java
new file mode 100644
index 0000000000..8bf07f3f46
--- /dev/null
+++ 
b/pinot-spi/src/test/java/org/apache/pinot/spi/env/VersionedPropertyConfigTest.java
@@ -0,0 +1,223 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.spi.env;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+
+public class VersionedPropertyConfigTest {
+
+  private static final String COLON_SEPARATOR = ":";
+  private static final File TEMP_DIR = new File(FileUtils.getTempDirectory(), 
"VersionedPropertyConfigTest");
+  private static final File CONFIG_FILE = new File(TEMP_DIR, "config");
+  private static final String[] TEST_PROPERTY_KEY = { "test1", "test2_key", 
"test3_key_",
+      "test4_key_1234", "test-1", "test.1" };
+  private static final String[] TEST_PROPERTY_KEY_WITH_SPECIAL_CHAR = { 
"test:1", "test2=key",
+      "test3,key_", "test4:=._key_1234", "test5-1=" };
+
+  @BeforeClass
+  public void setUp()
+      throws IOException {
+    FileUtils.deleteDirectory(TEMP_DIR);
+  }
+
+  @AfterClass
+  @AfterMethod
+  public void tearDown()
+      throws IOException {
+    FileUtils.deleteDirectory(TEMP_DIR);
+  }
+
+  @Test
+  public void testVersionedPropertyConfiguration()
+      throws ConfigurationException {
+    testVersionedPropertiesConfiguration(null, TEST_PROPERTY_KEY, false);
+  }
+
+  @Test
+  public void testVersionedPropertyConfigurationWithDefaultHeaderVersion()
+      throws ConfigurationException {
+    testVersionedPropertiesConfiguration(
+        
CommonsConfigurationUtils.DEFAULT_PROPERTIES_CONFIGURATION_HEADER_VERSION, 
TEST_PROPERTY_KEY, false);
+  }
+
+  @Test
+  public void testVersionedPropertyConfigurationWithHeaderVersion2()
+      throws ConfigurationException {
+    
testVersionedPropertiesConfiguration(CommonsConfigurationUtils.PROPERTIES_CONFIGURATION_HEADER_VERSION_2,
+        TEST_PROPERTY_KEY, false);
+  }
+
+  @Test
+  public void testVersionedReaderWithSpecialCharsPropertyKeys()
+      throws ConfigurationException {
+    testVersionedPropertiesConfiguration(null, 
TEST_PROPERTY_KEY_WITH_SPECIAL_CHAR, false);
+  }
+
+  @Test
+  public void 
testVersionedReaderWithSpecialCharsPropertyKeysWithDefaultHeader()
+      throws ConfigurationException {
+    
testVersionedPropertiesConfiguration(CommonsConfigurationUtils.DEFAULT_PROPERTIES_CONFIGURATION_HEADER_VERSION,
+        TEST_PROPERTY_KEY_WITH_SPECIAL_CHAR, false);
+  }
+
+  @Test
+  public void 
testVersionedReaderWithSpecialCharsPropertyKeysWithHeaderVersion2()
+      throws ConfigurationException {
+    
testVersionedPropertiesConfiguration(CommonsConfigurationUtils.PROPERTIES_CONFIGURATION_HEADER_VERSION_2,
+        TEST_PROPERTY_KEY_WITH_SPECIAL_CHAR, false);
+  }
+
+  @Test
+  public void testVersionedReaderWithDifferentSeparator() throws 
ConfigurationException {
+    
testVersionedPropertiesConfiguration(CommonsConfigurationUtils.PROPERTIES_CONFIGURATION_HEADER_VERSION_2,
+        TEST_PROPERTY_KEY, true);
+  }
+
+  @Test
+  //Test requires 'segment-metadata-without-version-header.properties' sample 
segment metadata file in resources folder
+  public void testOldSegmentMetadataBackwardCompatability()
+      throws ConfigurationException {
+    File oldSegmentProperties = new File(
+        Objects.requireNonNull(
+            PropertiesConfiguration.class.getClassLoader()
+                
.getResource("segment-metadata-without-version-header.properties")).getFile());
+    PropertiesConfiguration configuration =
+        
CommonsConfigurationUtils.getSegmentMetadataFromFile(oldSegmentProperties, 
true);
+
+    // assert that Header is null for the config.
+    assertNull(configuration.getHeader());
+
+    // assert that configuration has DefaultIOFactory
+    assertEquals(configuration.getIOFactory().getClass(), 
PropertiesConfiguration.DefaultIOFactory.class);
+
+    testSegmentMetadataContent(configuration);
+
+    // asserting escaped value ('column-ProductId-maxValue')
+    String productIDMaxValue = 
configuration.getString("column-ProductId-maxValue");
+    assertNotNull(productIDMaxValue);
+    assertEquals(productIDMaxValue, "B009,WVB40S");
+  }
+
+  @Test
+  //Test requires 'segment-metadata-with-version-header.properties' sample 
segment metadata file in resources folder
+  public void testSegmentMetadataWithVersionHeader()
+      throws ConfigurationException {
+    File oldSegmentProperties = new File(
+        Objects.requireNonNull(
+            PropertiesConfiguration.class.getClassLoader()
+                
.getResource("segment-metadata-with-version-header.properties")).getFile());
+    PropertiesConfiguration configuration =
+        
CommonsConfigurationUtils.getSegmentMetadataFromFile(oldSegmentProperties, 
true);
+
+    // assert that Header is equals to '# version = 2'
+    assertEquals(configuration.getHeader(), "# version = 2");
+
+    // assert that configuration has SegmentMetadataPropertyIOFactory
+    assertEquals(configuration.getIOFactory().getClass(), 
VersionedIOFactory.class);
+
+    testSegmentMetadataContent(configuration);
+  }
+
+  private static void testSegmentMetadataContent(PropertiesConfiguration 
configuration) {
+    // getting all the keys, length of the list should be equal to the number 
of lines in the segment metadata
+    List<String> keys = CommonsConfigurationUtils.getKeys(configuration);
+    assertEquals(keys.size(), 123);
+
+    // asserting table name property from segment metadata
+    String tableName = configuration.getString("segment.table.name");
+    assertEquals(tableName, "fineFoodReviews");
+
+    // asserting table name property from segment metadata
+    String segmentName = configuration.getString("segment.name");
+    assertEquals(segmentName, "fineFoodReviews_OFFLINE_0");
+
+    // asserting segment dimension column names from segment metadata
+    String[] segmentDimensionColumnNames = 
configuration.getStringArray("segment.dimension.column.names");
+    assertEquals(segmentDimensionColumnNames.length, 8);
+    assertEquals(String.join(",", segmentDimensionColumnNames),
+        "ProductId,Score,Summary,Text,UserId,combined,embedding,n_tokens");
+
+    // asserting segment.index.version
+    String segmentIndexVersion = 
configuration.getString("segment.index.version");
+    assertEquals(segmentIndexVersion, "v3");
+  }
+
+  private static void testVersionedPropertiesConfiguration(String 
versionHeader, String[] keysArray,
+      boolean setDifferentSeparator)
+      throws ConfigurationException {
+    PropertiesConfiguration configuration =
+        CommonsConfigurationUtils.getSegmentMetadataFromFile(CONFIG_FILE, 
true);
+
+    // setting the random value of the test keys
+    for (String key: keysArray) {
+      configuration.setProperty(key, RandomStringUtils.randomAscii(5));
+
+      // setting it at the key level as well for testing
+      if (setDifferentSeparator) {
+        configuration.getLayout().setSeparator(key, COLON_SEPARATOR);
+      }
+    }
+
+    // set the different separator, other than '='
+    if (setDifferentSeparator) {
+      configuration.getLayout().setGlobalSeparator(COLON_SEPARATOR);
+    }
+
+    // recovered keys from the configuration.
+    List<String> recoveredKeys = 
CommonsConfigurationUtils.getKeys(configuration);
+    testPropertyKeys(recoveredKeys, keysArray);
+
+    // save the configuration.
+    CommonsConfigurationUtils.saveSegmentMetadataToFile(configuration, 
CONFIG_FILE, versionHeader);
+
+    if (versionHeader != null) {
+      String expectedHeader = 
CommonsConfigurationUtils.getVersionHeaderString(versionHeader);
+      assertEquals(configuration.getHeader(), expectedHeader);
+    }
+
+    // reading the configuration from saved file.
+    configuration = 
CommonsConfigurationUtils.getSegmentMetadataFromFile(CONFIG_FILE, true);
+    recoveredKeys = CommonsConfigurationUtils.getKeys(configuration);
+    testPropertyKeys(recoveredKeys, keysArray);
+  }
+
+  private static void testPropertyKeys(List<String> recoveredKeys, String[] 
actualKeys) {
+    assertEquals(recoveredKeys.size(), actualKeys.length);
+    for (int i = 0; i < recoveredKeys.size(); i++) {
+      String recoveredValue = recoveredKeys.get(i);
+      assertEquals(recoveredValue, actualKeys[i]);
+    }
+  }
+}
diff --git 
a/pinot-spi/src/test/resources/segment-metadata-with-version-header.properties 
b/pinot-spi/src/test/resources/segment-metadata-with-version-header.properties
new file mode 100644
index 0000000000..b01085a673
--- /dev/null
+++ 
b/pinot-spi/src/test/resources/segment-metadata-with-version-header.properties
@@ -0,0 +1,125 @@
+# version = 2
+
+segment.padding.character = \u0000
+segment.name = fineFoodReviews_OFFLINE_0
+segment.table.name = fineFoodReviews
+segment.dimension.column.names = 
ProductId,Score,Summary,Text,UserId,combined,embedding,n_tokens
+segment.total.docs = 1000
+custom.input.data.file.uri = 
~/examples/batch/fineFoodReviews/rawdata/fine_food_reviews_with_embeddings_1k.parquet.gzip
+column.ProductId.cardinality = 868
+column.ProductId.totalDocs = 1000
+column.ProductId.dataType = STRING
+column.ProductId.bitsPerElement = 10
+column.ProductId.lengthOfEachEntry = 10
+column.ProductId.columnType = DIMENSION
+column.ProductId.isSorted = false
+column.ProductId.hasDictionary = true
+column.ProductId.isSingleValues = true
+column.ProductId.maxNumberOfMultiValues = 0
+column.ProductId.totalNumberOfEntries = 1000
+column.ProductId.isAutoGenerated = false
+column.ProductId.minValue = 7310172001
+column.ProductId.maxValue = B009WVB40S
+column.ProductId.defaultNullValue = null
+column.Score.cardinality = 5
+column.Score.totalDocs = 1000
+column.Score.dataType = INT
+column.Score.bitsPerElement = 3
+column.Score.lengthOfEachEntry = 0
+column.Score.columnType = DIMENSION
+column.Score.isSorted = false
+column.Score.hasDictionary = true
+column.Score.isSingleValues = true
+column.Score.maxNumberOfMultiValues = 0
+column.Score.totalNumberOfEntries = 1000
+column.Score.isAutoGenerated = false
+column.Score.minValue = 1
+column.Score.maxValue = 5
+column.Score.defaultNullValue = -2147483648
+column.Summary.cardinality = 721
+column.Summary.totalDocs = 1000
+column.Summary.dataType = STRING
+column.Summary.bitsPerElement = 10
+column.Summary.lengthOfEachEntry = 125
+column.Summary.columnType = DIMENSION
+column.Summary.isSorted = false
+column.Summary.hasDictionary = true
+column.Summary.isSingleValues = true
+column.Summary.maxNumberOfMultiValues = 0
+column.Summary.totalNumberOfEntries = 1000
+column.Summary.isAutoGenerated = false
+column.Summary.minValue = 34 unique and one duplicate
+column.Summary.maxValue = yummy low fat snacks
+column.Summary.defaultNullValue = null
+column.Text.cardinality = 761
+column.Text.totalDocs = 1000
+column.Text.dataType = STRING
+column.Text.bitsPerElement = 10
+column.Text.lengthOfEachEntry = 0
+column.Text.columnType = DIMENSION
+column.Text.isSorted = false
+column.Text.hasDictionary = false
+column.Text.isSingleValues = true
+column.Text.maxNumberOfMultiValues = 0
+column.Text.totalNumberOfEntries = 1000
+column.Text.isAutoGenerated = false
+column.Text.defaultNullValue = null
+column.UserId.cardinality = 708
+column.UserId.totalDocs = 1000
+column.UserId.dataType = STRING
+column.UserId.bitsPerElement = 10
+column.UserId.lengthOfEachEntry = 21
+column.UserId.columnType = DIMENSION
+column.UserId.isSorted = false
+column.UserId.hasDictionary = true
+column.UserId.isSingleValues = true
+column.UserId.maxNumberOfMultiValues = 0
+column.UserId.totalNumberOfEntries = 1000
+column.UserId.isAutoGenerated = false
+column.UserId.minValue = A06364072LBY1F3ING9XN
+column.UserId.maxValue = AZUCLRMHEBUG0
+column.UserId.defaultNullValue = null
+column.combined.cardinality = 762
+column.combined.totalDocs = 1000
+column.combined.dataType = STRING
+column.combined.bitsPerElement = 10
+column.combined.lengthOfEachEntry = 512
+column.combined.columnType = DIMENSION
+column.combined.isSorted = false
+column.combined.hasDictionary = true
+column.combined.isSingleValues = true
+column.combined.maxNumberOfMultiValues = 0
+column.combined.totalNumberOfEntries = 1000
+column.combined.isAutoGenerated = false
+column.combined.defaultNullValue = null
+column.embedding.cardinality = 1158749
+column.embedding.totalDocs = 1000
+column.embedding.dataType = FLOAT
+column.embedding.bitsPerElement = 21
+column.embedding.lengthOfEachEntry = 0
+column.embedding.columnType = DIMENSION
+column.embedding.isSorted = false
+column.embedding.hasDictionary = true
+column.embedding.isSingleValues = false
+column.embedding.maxNumberOfMultiValues = 1536
+column.embedding.totalNumberOfEntries = 1536000
+column.embedding.isAutoGenerated = false
+column.embedding.minValue = -0.66914773
+column.embedding.maxValue = 0.23317827
+column.embedding.defaultNullValue = -Infinity
+column.n_tokens.cardinality = 201
+column.n_tokens.totalDocs = 1000
+column.n_tokens.dataType = INT
+column.n_tokens.bitsPerElement = 8
+column.n_tokens.lengthOfEachEntry = 0
+column.n_tokens.columnType = DIMENSION
+column.n_tokens.isSorted = false
+column.n_tokens.hasDictionary = true
+column.n_tokens.isSingleValues = true
+column.n_tokens.maxNumberOfMultiValues = 0
+column.n_tokens.totalNumberOfEntries = 1000
+column.n_tokens.isAutoGenerated = false
+column.n_tokens.minValue = 28
+column.n_tokens.maxValue = 645
+column.n_tokens.defaultNullValue = -2147483648
+segment.index.version = v3
diff --git 
a/pinot-spi/src/test/resources/segment-metadata-without-version-header.properties
 
b/pinot-spi/src/test/resources/segment-metadata-without-version-header.properties
new file mode 100644
index 0000000000..09d0334582
--- /dev/null
+++ 
b/pinot-spi/src/test/resources/segment-metadata-without-version-header.properties
@@ -0,0 +1,123 @@
+segment.padding.character = \u0000
+segment.name = fineFoodReviews_OFFLINE_0
+segment.table.name = fineFoodReviews
+segment.dimension.column.names = 
ProductId,Score,Summary,Text,UserId,combined,embedding,n_tokens
+segment.total.docs = 1000
+custom.input.data.file.uri = 
~/examples/batch/fineFoodReviews/rawdata/fine_food_reviews_with_embeddings_1k.parquet.gzip
+column.ProductId.cardinality = 868
+column.ProductId.totalDocs = 1000
+column.ProductId.dataType = STRING
+column.ProductId.bitsPerElement = 10
+column.ProductId.lengthOfEachEntry = 10
+column.ProductId.columnType = DIMENSION
+column.ProductId.isSorted = false
+column.ProductId.hasDictionary = true
+column.ProductId.isSingleValues = true
+column.ProductId.maxNumberOfMultiValues = 0
+column.ProductId.totalNumberOfEntries = 1000
+column.ProductId.isAutoGenerated = false
+column.ProductId.minValue = 7310172001
+column-ProductId-maxValue = B009\\,WVB40S
+column.ProductId.defaultNullValue = null
+column.Score.cardinality = 5
+column.Score.totalDocs = 1000
+column.Score.dataType = INT
+column.Score.bitsPerElement = 3
+column.Score.lengthOfEachEntry = 0
+column.Score.columnType = DIMENSION
+column.Score.isSorted = false
+column.Score.hasDictionary = true
+column.Score.isSingleValues = true
+column.Score.maxNumberOfMultiValues = 0
+column.Score.totalNumberOfEntries = 1000
+column.Score.isAutoGenerated = false
+column.Score.minValue = 1
+column.Score.maxValue = 5
+column.Score.defaultNullValue = -2147483648
+column.Summary.cardinality = 721
+column.Summary.totalDocs = 1000
+column.Summary.dataType = STRING
+column.Summary.bitsPerElement = 10
+column.Summary.lengthOfEachEntry = 125
+column.Summary.columnType = DIMENSION
+column.Summary.isSorted = false
+column.Summary.hasDictionary = true
+column.Summary.isSingleValues = true
+column.Summary.maxNumberOfMultiValues = 0
+column.Summary.totalNumberOfEntries = 1000
+column.Summary.isAutoGenerated = false
+column.Summary.minValue = 34 unique and one duplicate
+column.Summary.maxValue = yummy low fat snacks
+column.Summary.defaultNullValue = null
+column.Text.cardinality = 761
+column.Text.totalDocs = 1000
+column.Text.dataType = STRING
+column.Text.bitsPerElement = 10
+column.Text.lengthOfEachEntry = 0
+column.Text.columnType = DIMENSION
+column.Text.isSorted = false
+column.Text.hasDictionary = false
+column.Text.isSingleValues = true
+column.Text.maxNumberOfMultiValues = 0
+column.Text.totalNumberOfEntries = 1000
+column.Text.isAutoGenerated = false
+column.Text.defaultNullValue = null
+column.UserId.cardinality = 708
+column.UserId.totalDocs = 1000
+column.UserId.dataType = STRING
+column.UserId.bitsPerElement = 10
+column.UserId.lengthOfEachEntry = 21
+column.UserId.columnType = DIMENSION
+column.UserId.isSorted = false
+column.UserId.hasDictionary = true
+column.UserId.isSingleValues = true
+column.UserId.maxNumberOfMultiValues = 0
+column.UserId.totalNumberOfEntries = 1000
+column.UserId.isAutoGenerated = false
+column.UserId.minValue = A06364072LBY1F3ING9XN
+column.UserId.maxValue = AZUCLRMHEBUG0
+column.UserId.defaultNullValue = null
+column.combined.cardinality = 762
+column.combined.totalDocs = 1000
+column.combined.dataType = STRING
+column.combined.bitsPerElement = 10
+column.combined.lengthOfEachEntry = 512
+column.combined.columnType = DIMENSION
+column.combined.isSorted = false
+column.combined.hasDictionary = true
+column.combined.isSingleValues = true
+column.combined.maxNumberOfMultiValues = 0
+column.combined.totalNumberOfEntries = 1000
+column.combined.isAutoGenerated = false
+column.combined.defaultNullValue = null
+column.embedding.cardinality = 1158749
+column.embedding.totalDocs = 1000
+column.embedding.dataType = FLOAT
+column.embedding.bitsPerElement = 21
+column.embedding.lengthOfEachEntry = 0
+column.embedding.columnType = DIMENSION
+column.embedding.isSorted = false
+column.embedding.hasDictionary = true
+column.embedding.isSingleValues = false
+column.embedding.maxNumberOfMultiValues = 1536
+column.embedding.totalNumberOfEntries = 1536000
+column.embedding.isAutoGenerated = false
+column.embedding.minValue = -0.66914773
+column.embedding.maxValue = 0.23317827
+column.embedding.defaultNullValue = -Infinity
+column.n_tokens.cardinality = 201
+column.n_tokens.totalDocs = 1000
+column.n_tokens.dataType = INT
+column.n_tokens.bitsPerElement = 8
+column.n_tokens.lengthOfEachEntry = 0
+column.n_tokens.columnType = DIMENSION
+column.n_tokens.isSorted = false
+column.n_tokens.hasDictionary = true
+column.n_tokens.isSingleValues = true
+column.n_tokens.maxNumberOfMultiValues = 0
+column.n_tokens.totalNumberOfEntries = 1000
+column.n_tokens.isAutoGenerated = false
+column.n_tokens.minValue = 28
+column.n_tokens.maxValue = 645
+column.n_tokens.defaultNullValue = -2147483648
+segment.index.version = v3
diff --git a/pom.xml b/pom.xml
index aaac77a9dc..6e71442f6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2115,6 +2115,9 @@
                 <exclude>**/.project</exclude>
                 <exclude>**/.classpath</exclude>
                 <exclude>.externalToolBuilders/**</exclude>
+
+                <!-- specific files -->
+                
<exclude>**/src/test/resources/*version-header.properties</exclude>
               </excludes>
             </licenseSet>
           </licenseSets>
@@ -2240,6 +2243,9 @@
 
             <!-- MISC -->
             <exclude>**/.factorypath</exclude>
+
+            <!-- specific files -->
+            <exclude>**/src/test/resources/*version-header.properties</exclude>
           </excludes>
         </configuration>
       </plugin>


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to