[blivet:master 3/3] Add a method that determines whether a number is an exact power of 2.

mulhern amulhern at redhat.com
Fri Oct 31 15:31:59 UTC 2014


Taking the log to determine whether a number is an exact power of 2 does
not always work, because log computes w/ floats, somehow. It usually works,
because base 2 works well w/ binary floating point representation.

Decimal does not actually have a log function. You can use change of base
to get log base 2, but you do not get an exact result.

Use method in is_valid_pool_chunk_size().

Signed-off-by: mulhern <amulhern at redhat.com>
---
 blivet/devicelibs/lvm.py |  3 +--
 blivet/util.py           | 28 ++++++++++++++++++++++++++++
 tests/util_test.py       | 22 ++++++++++++++++++++++
 3 files changed, 51 insertions(+), 2 deletions(-)
 create mode 100644 tests/util_test.py

diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
index cf21902..958b974 100644
--- a/blivet/devicelibs/lvm.py
+++ b/blivet/devicelibs/lvm.py
@@ -20,7 +20,6 @@
 # Author(s): Dave Lehman <dlehman at redhat.com>
 #
 
-import math
 from decimal import Decimal
 from collections import namedtuple
 
@@ -212,7 +211,7 @@ def is_valid_thin_pool_chunk_size(size, discard=False):
         return False
 
     if discard:
-        return (math.log(size, 2) % 1.0 == 0)
+        return util.power_of_two(int(size))
     else:
         return (size % LVM_THINP_MIN_CHUNK_SIZE == Size(0))
 
diff --git a/blivet/util.py b/blivet/util.py
index a69b694..e045a32 100644
--- a/blivet/util.py
+++ b/blivet/util.py
@@ -524,3 +524,31 @@ def variable_copy(obj, memo, omit=None, shallow=None, duplicate=None):
 def get_current_entropy():
     with open("/proc/sys/kernel/random/entropy_avail", "r") as fobj:
         return int(fobj.readline())
+
+def power_of_two(value):
+    """ Checks whether value is a power of 2 greater than 1.
+
+        :param any value: a value
+        :returns: True if the value is a power of 2
+        :rtype: bool
+    """
+    try:
+        int_value = int(value)
+    except (ValueError, TypeError):
+        return False
+
+    if int_value != value:
+        return False
+
+    value = int_value
+
+    if value < 2:
+        return False
+
+    (q, r) = (value, 0)
+    while q != 0:
+        if r != 0:
+            return False
+        (q, r) = q.__divmod__(2)
+
+    return True
diff --git a/tests/util_test.py b/tests/util_test.py
new file mode 100644
index 0000000..13b8d06
--- /dev/null
+++ b/tests/util_test.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+import unittest
+from decimal import Decimal
+
+from blivet import util
+
+class MiscTest(unittest.TestCase):
+
+    longMessage = True
+
+    def test_power_of_two(self):
+        self.assertFalse(util.power_of_two(None))
+        self.assertFalse(util.power_of_two("not a number"))
+        self.assertFalse(util.power_of_two(Decimal(2.2)))
+        self.assertFalse(util.power_of_two(-1))
+        self.assertFalse(util.power_of_two(0))
+        self.assertFalse(util.power_of_two(1))
+        for i in range(1, 60, 5):
+            self.assertTrue(util.power_of_two(2 ** i), msg=i)
+            self.assertFalse(util.power_of_two(2 ** i + 1), msg=i)
+            self.assertFalse(util.power_of_two(2 ** i - 1), msg=i)
-- 
1.9.3



More information about the anaconda-patches mailing list