ekaterinadimitrova2 commented on a change in pull request #1425:
URL: https://github.com/apache/cassandra/pull/1425#discussion_r793084537



##########
File path: src/java/org/apache/cassandra/config/DataStorageSpec.java
##########
@@ -0,0 +1,395 @@
+/*
+ * 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.cassandra.config;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import com.google.common.primitives.Ints;
+
+import org.apache.cassandra.exceptions.ConfigurationException;
+
+/**
+ * Represents an amount of data storage. Wrapper class for Cassandra 
configuration parameters, providing to the
+ * users the opportunity to be able to provide config with a unit of their 
choice in cassandra.yaml as per the available
+ * options. (CASSANDRA-15234)
+ */
+public final class DataStorageSpec
+{
+    /**
+     * The Regexp used to parse the storage provided as String.
+     */
+    private static final Pattern STORAGE_UNITS_PATTERN = 
Pattern.compile("^(\\d+)(GiB|MiB|KiB|B)$");
+
+    private final long quantity;
+
+    private final DataStorageUnit unit;
+
+    public DataStorageSpec(String value)
+    {
+        if (value == null || value.equals("null"))
+        {
+            quantity = 0;
+            unit = DataStorageUnit.MEBIBYTES; // the unit doesn't really 
matter as 0 is 0 in all units
+            return;
+        }
+
+        //parse the string field value
+        Matcher matcher = STORAGE_UNITS_PATTERN.matcher(value);
+
+        if (!matcher.find())
+        {
+            throw new ConfigurationException("Invalid data storage: " + value 
+ " Accepted units: B, KiB, MiB, GiB" +
+                                               " where case matters and only 
non-negative values are accepted");
+        }
+
+        quantity = Long.parseLong(matcher.group(1));
+        unit = DataStorageUnit.fromSymbol(matcher.group(2));
+    }
+
+    DataStorageSpec(long quantity, DataStorageUnit unit)
+    {
+        if (quantity < 0)
+            throw new ConfigurationException("Invalid data storage: value must 
be positive, but was " + quantity);
+
+        this.quantity = quantity;
+        this.unit = unit;
+    }
+
+    /**
+     * Creates a {@code DataStorageSpec} of the specified amount of bytes.
+     *
+     * @param bytes the amount of bytes
+     * @return a {@code DataStorageSpec}
+     */
+    public static DataStorageSpec inBytes(long bytes)
+    {
+        return new DataStorageSpec(bytes, DataStorageUnit.BYTES);
+    }
+
+    /**
+     * Creates a {@code DataStorageSpec} of the specified amount of kibibytes.
+     *
+     * @param kibibytes the amount of kibibytes
+     * @return a {@code DataStorageSpec}
+     */
+    public static DataStorageSpec inKibibytes(long kibibytes)
+    {
+        return new DataStorageSpec(kibibytes, DataStorageUnit.KIBIBYTES);
+    }
+
+    /**
+     * Creates a {@code DataStorageSpec} of the specified amount of mebibytes.
+     *
+     * @param mebibytes the amount of mebibytes
+     * @return a {@code DataStorageSpec}
+     */
+    public static DataStorageSpec inMebibytes(long mebibytes)
+    {
+        return new DataStorageSpec(mebibytes, DataStorageUnit.MEBIBYTES);
+    }
+
+    /**
+     * @return the data storage unit.
+     */
+    public DataStorageUnit getUnit()
+    {
+        return unit;
+    }
+
+    /**
+     * @return the amount of data storage in bytes
+     */
+    public long toBytes()
+    {
+        return unit.toBytes(quantity);
+    }
+
+    /**
+     * Returns the amount of data storage in bytes as an {@code int}
+     *
+     * @return the amount of data storage in bytes or {@code 
Integer.MAX_VALUE} if the number of bytes is too large.
+     */
+    public int toBytesAsInt()
+    {
+        return Ints.saturatedCast(toBytes());
+    }
+
+    /**
+     * @return the amount of data storage in kibibytes
+     */
+    public long toKibibytes()
+    {
+        return unit.toKibibytes(quantity);
+    }
+
+    /**
+     * Returns the amount of data storage in kibibytes as an {@code int}
+     *
+     * @return the amount of data storage in kibibytes or {@code 
Integer.MAX_VALUE} if the number of kibibytes is too large.
+     */
+    public int toKibibytesAsInt()
+    {
+        return Ints.saturatedCast(toKibibytes());
+    }
+
+    /**
+     * @return the amount of data storage in mebibytes
+     */
+    public long toMebibytes()
+    {
+        return unit.toMebibytes(quantity);
+    }
+
+    /**
+     * Returns the amount of data storage in mebibytes as an {@code int}
+     *
+     * @return the amount of data storage in mebibytes or {@code 
Integer.MAX_VALUE} if the number of mebibytes is too large.
+     */
+    public int toMebibytesAsInt()
+    {
+        return Ints.saturatedCast(toMebibytes());
+    }
+
+    /**
+     * @return the amount of data storage in gibibytes
+     */
+    public long toGibibytes()
+    {
+        return unit.toGibibytes(quantity);
+    }
+
+    /**
+     * Returns the amount of data storage in gibibytes as an {@code int}
+     *
+     * @return the amount of data storage in gibibytes or {@code 
Integer.MAX_VALUE} if the number of gibibytes is too large.
+     */
+    public int toGibibytesAsInt()
+    {
+        return Ints.saturatedCast(toGibibytes());
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return Objects.hash(unit.toKibibytes(quantity));
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+
+        if (!(obj instanceof DataStorageSpec))
+            return false;
+
+        DataStorageSpec other = (DataStorageSpec) obj;
+        if (unit == other.unit)
+            return quantity == other.quantity;
+
+        // Due to overflows we can only guarantee that the 2 storages are 
equal if we get the same results
+        // doing the convertion in both directions.
+        return unit.convert(other.quantity, other.unit) == quantity && 
other.unit.convert(quantity, unit) == other.quantity;
+    }
+
+    @Override
+    public String toString()
+    {
+        return quantity + unit.symbol;
+    }
+
+    public enum DataStorageUnit
+    {
+        BYTES("B")
+        {
+            public long toBytes(long d)
+            {
+                return d;
+            }
+
+            public long toKibibytes(long d)
+            {
+                return d / 1024;
+            }
+
+            public long toMebibytes(long d)
+            {
+                return d / (1024 * 1024);
+            }
+
+            public long toGibibytes(long d)
+            {
+                return d / (1024 * 1024 * 1024);
+            }
+
+            public long convert(long source, DataStorageUnit sourceUnit)
+            {
+                return sourceUnit.toBytes(source);
+            }
+        },
+        KIBIBYTES("KiB")
+        {
+            public long toBytes(long d)
+            {
+                return x(d, 1024, MAX / 1024);
+            }
+
+            public long toKibibytes(long d)
+            {
+                return d;
+            }
+
+            public long toMebibytes(long d)
+            {
+                return d / 1024;
+            }
+
+            public long toGibibytes(long d)
+            {
+                return d / (1024 * 1024);
+            }
+
+            public long convert(long source, DataStorageUnit sourceUnit)
+            {
+                return sourceUnit.toKibibytes(source);
+            }
+        },
+        MEBIBYTES("MiB")
+        {
+            public long toBytes(long d)
+            {
+                return x(d, 1024 * 1024, MAX / (1024 * 1024));
+            }
+
+            public long toKibibytes(long d)
+            {
+                return x(d, 1024, MAX / 1024);
+            }
+
+            public long toMebibytes(long d)
+            {
+                return d;
+            }
+
+            public long toGibibytes(long d)
+            {
+                return d / 1024;
+            }
+
+            public long convert(long source, DataStorageUnit sourceUnit)
+            {
+                return sourceUnit.toMebibytes(source);
+            }
+        },
+        GIBIBYTES("GiB")
+        {
+            public long toBytes(long d)
+            {
+                return x(d, 1024 * 1024 * 1024, MAX / (1024 * 1024 * 1024));
+            }
+
+            public long toKibibytes(long d)
+            {
+                return x(d, 1024 * 1024, MAX / 1024 * 1024);
+            }
+
+            public long toMebibytes(long d)
+            {
+                return x(d, 1024, MAX / 1024);
+            }
+
+            public long toGibibytes(long d)
+            {
+                return d;
+            }
+
+            public long convert(long source, DataStorageUnit sourceUnit)
+            {
+                return sourceUnit.toGibibytes(source);
+            }
+        };
+
+        /**
+         * Scale d by m, checking for overflow. This has a short name to make 
above code more readable.
+         */
+        static long x(long d, long m, long over)
+        {
+            if (d > over)
+                return Long.MAX_VALUE;
+            return d * m;

Review comment:
       I was about to commit this but over is used three times with specific 
constant, I don't think we need this. 




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to