[gparted] Cache results from querying all LVM2 PVs (#160787)
- From: Curtis Gedak <gedakc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gparted] Cache results from querying all LVM2 PVs (#160787)
- Date: Fri, 3 Feb 2012 19:04:49 +0000 (UTC)
commit 608d992e822a6ea0a8b5612c134ab76ca5a394d9
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date: Sat Jan 28 14:25:31 2012 +0000
Cache results from querying all LVM2 PVs (#160787)
Cache results from querying all LVM2 PVs in one go to minimise the
number of times lvm commands are executed. Take inspiration from
caching performed by FS_Info and Proc_Partitions_Info.
Bug #160787 - lvm support
include/LVM2_PV_Info.h | 57 +++++++++++++++
include/Makefile.am | 1 +
include/Utils.h | 3 +
po/POTFILES.in | 1 +
src/GParted_Core.cc | 2 +
src/LVM2_PV_Info.cc | 184 ++++++++++++++++++++++++++++++++++++++++++++++++
src/Makefile.am | 1 +
src/Utils.cc | 24 ++++++
src/lvm2_pv.cc | 21 ++----
9 files changed, 280 insertions(+), 14 deletions(-)
---
diff --git a/include/LVM2_PV_Info.h b/include/LVM2_PV_Info.h
new file mode 100644
index 0000000..9a03ddf
--- /dev/null
+++ b/include/LVM2_PV_Info.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2012 Mike Fleetwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+/* LVM2_PV_Info
+ *
+ * A persistent cache of information about LVM2 PVs that helps to
+ * minimize the number of executions of lvm commands used to query
+ * their attributes.
+ */
+
+#ifndef LVM2_PV_INFO_H_
+#define LVM2_PV_INFO_H_
+
+#include "../include/Utils.h"
+
+namespace GParted
+{
+
+class LVM2_PV_Info
+{
+public:
+ LVM2_PV_Info() ;
+ LVM2_PV_Info( bool do_refresh ) ;
+ ~LVM2_PV_Info() ;
+ bool is_lvm2_pv_supported() ;
+ Glib::ustring get_vg_name( const Glib::ustring & path ) ;
+ Byte_Value get_free_bytes( const Glib::ustring & path ) ;
+ bool has_active_lvs( const Glib::ustring & path ) ;
+private:
+ void set_commands_found() ;
+ void load_lvm2_pv_info_cache() ;
+ Glib::ustring get_pv_attr( const Glib::ustring & path, unsigned int entry ) ;
+ static bool lvm2_pv_info_cache_initialized ;
+ static bool lvm_found ;
+ static bool dmsetup_found ;
+ static std::vector<Glib::ustring> lvm2_pv_cache ;
+ static Glib::ustring dmsetup_info_cache ;
+};
+
+}//GParted
+
+#endif /*LVM2_PV_INFO_H_*/
diff --git a/include/Makefile.am b/include/Makefile.am
index 0544fec..31eab07 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -21,6 +21,7 @@ EXTRA_DIST = \
FS_Info.h \
GParted_Core.h \
HBoxOperations.h \
+ LVM2_PV_Info.h \
Operation.h \
OperationCopy.h \
OperationCheck.h \
diff --git a/include/Utils.h b/include/Utils.h
index 6bcca41..e472526 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -166,6 +166,9 @@ public:
static void tokenize( const Glib::ustring& str,
std::vector<Glib::ustring>& tokens,
const Glib::ustring& delimiters ) ;
+ static void split( const Glib::ustring& str,
+ std::vector<Glib::ustring>& result,
+ const Glib::ustring& delimiters ) ;
static int convert_to_int(const Glib::ustring & src);
static Glib::ustring generate_uuid(void);
};
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 35cd984..21b2ec3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -16,6 +16,7 @@ src/DMRaid.cc
src/FileSystem.cc
src/GParted_Core.cc
src/HBoxOperations.cc
+src/LVM2_PV_Info.cc
src/OperationChangeUUID.cc
src/OperationCopy.cc
src/OperationCheck.cc
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index d740ae4..8b3ebfe 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -21,6 +21,7 @@
#include "../include/DMRaid.h"
#include "../include/SWRaid.h"
#include "../include/FS_Info.h"
+#include "../include/LVM2_PV_Info.h"
#include "../include/OperationCopy.h"
#include "../include/OperationCreate.h"
#include "../include/OperationDelete.h"
@@ -172,6 +173,7 @@ void GParted_Core::set_devices( std::vector<Device> & devices )
FS_Info fs_info( true ) ; //Refresh cache of file system information
DMRaid dmraid( true ) ; //Refresh cache of dmraid device information
SWRaid swraid( true ) ; //Refresh cache of swraid device information
+ LVM2_PV_Info lvm2_pv_info( true ) ; //Refresh cache of LVM2 PV information
init_maps() ;
diff --git a/src/LVM2_PV_Info.cc b/src/LVM2_PV_Info.cc
new file mode 100644
index 0000000..28ef858
--- /dev/null
+++ b/src/LVM2_PV_Info.cc
@@ -0,0 +1,184 @@
+/* Copyright (C) 2012 Mike Fleetwood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "../include/LVM2_PV_Info.h"
+
+namespace GParted
+{
+
+enum PV_ATTRIBUTE
+{
+ PVATTR_PV_NAME = 0,
+ PVATTR_VG_NAME = 1,
+ PVATTR_PV_FREE = 2
+} ;
+
+//Data model:
+// lvm2_pv_info_cache_initialized
+// - Has the cache been loaded let?
+// lvm_found - Is the "lvm" command available?
+// dmsetup_found - Is the "dmsetup" command available?
+// lvm2_pv_cache - String vector storing attributes of a PV.
+// Attributes are: pv_name,vg_name,pv_free.
+// Pv_free is the number of free bytes.
+// E.g.
+// ["/dev/sda6,vg_test,4022337536",
+// "/dev/sda8,vg_test2,5087690752",
+// "/dev/sda10,,2147483648"]
+// dmsetup_info_cache - String storing active LVs. E.g.
+// "vg_test-lvol1\nvg_test-lvol0\nvg_test2-lvol0\n"
+
+//Initialize static data elements
+bool LVM2_PV_Info::lvm2_pv_info_cache_initialized = false ;
+bool LVM2_PV_Info::lvm_found = false ;
+bool LVM2_PV_Info::dmsetup_found = false ;
+std::vector<Glib::ustring> LVM2_PV_Info::lvm2_pv_cache ;
+Glib::ustring LVM2_PV_Info::dmsetup_info_cache = "" ;
+
+LVM2_PV_Info::LVM2_PV_Info()
+{
+ //Ensure that cache has been loaded at least once
+ if ( ! lvm2_pv_info_cache_initialized )
+ {
+ lvm2_pv_info_cache_initialized = true ;
+ set_commands_found() ;
+ load_lvm2_pv_info_cache() ;
+ }
+}
+
+LVM2_PV_Info::LVM2_PV_Info( bool do_refresh )
+{
+ //Ensure that cache has been loaded at least once
+ if ( ! lvm2_pv_info_cache_initialized )
+ {
+ lvm2_pv_info_cache_initialized = true ;
+ set_commands_found() ;
+ if ( do_refresh == false )
+ load_lvm2_pv_info_cache() ;
+ }
+
+ if ( do_refresh )
+ load_lvm2_pv_info_cache() ;
+}
+
+LVM2_PV_Info::~LVM2_PV_Info()
+{
+}
+
+bool LVM2_PV_Info::is_lvm2_pv_supported()
+{
+ return ( lvm_found && dmsetup_found ) ;
+}
+
+Glib::ustring LVM2_PV_Info::get_vg_name( const Glib::ustring & path )
+{
+ return get_pv_attr( path, PVATTR_VG_NAME ) ;
+}
+
+//Return number of free bytes in the PV, or -1 for error.
+Byte_Value LVM2_PV_Info::get_free_bytes( const Glib::ustring & path )
+{
+ Byte_Value free_bytes = -1 ;
+ Glib::ustring fb_str = get_pv_attr( path, PVATTR_PV_FREE ) ;
+ if ( fb_str != "" )
+ {
+ gchar * suffix ;
+ free_bytes = (Byte_Value) g_ascii_strtoll( fb_str .c_str(), & suffix, 10 ) ;
+ if ( free_bytes < 0 || ( free_bytes == 0 && suffix == fb_str ) )
+ //Negative number or conversion failed
+ free_bytes = -1 ;
+ }
+ return free_bytes ;
+}
+
+//Report if any LVs are active in the VG stored in the PV.
+bool LVM2_PV_Info::has_active_lvs( const Glib::ustring & path )
+{
+ Glib::ustring vgname = get_pv_attr( path, PVATTR_VG_NAME ) ;
+ if ( vgname == "" )
+ //PV not yet included in any VG
+ return false ;
+
+ Glib::ustring regexp = "^(" + vgname + ")-" ;
+ Glib::ustring match = Utils::regexp_label( dmsetup_info_cache, regexp ) ;
+ return ( match == vgname ) ;
+}
+
+//Private methods
+
+void LVM2_PV_Info::set_commands_found()
+{
+ //Set status of commands found
+ lvm_found = ( ! Glib::find_program_in_path( "lvm" ) .empty() ) ;
+ dmsetup_found = ( ! Glib::find_program_in_path( "dmsetup" ) .empty() ) ;
+}
+
+void LVM2_PV_Info::load_lvm2_pv_info_cache()
+{
+ Glib::ustring output, error ;
+
+ //Load LVM2 PV attribute cache
+ lvm2_pv_cache .clear() ;
+ if ( lvm_found )
+ {
+ //The OS is expected to fully enable LVM, this scan does
+ // not do the full job. It is included incase anything
+ // is changed not using lvm commands.
+ Utils::execute_command( "lvm vgscan", output, error, true ) ;
+ //Output PV attributes, in PV_ATTRIBUTE order
+ if ( ! Utils::execute_command( "lvm pvs --config \"log{command_names=0}\" --nosuffix --noheadings --separator , --units b -o pv_name,vg_name,pv_free", output, error, true ) )
+ {
+ if ( output != "" )
+ Utils::tokenize( output, lvm2_pv_cache, " \n" ) ;
+ }
+ }
+
+ //Load dmsetup info cache. This is a list of active LV names as
+ //reported by the kernel's device-mapper driver.
+ dmsetup_info_cache = "" ;
+ if ( dmsetup_found )
+ {
+ if ( ! Utils::execute_command( "dmsetup info --columns --noheadings --separator , -o name", output, error, true ) )
+ {
+ Glib::ustring match = Utils::regexp_label( output, "^(No devices found).*" ) ;
+ if ( match != "No devices found" )
+ dmsetup_info_cache = output ;
+ }
+ }
+}
+
+//Return PV's nth attribute. Attributes are numbered 0 upwards for:
+// pv_name,vg_name,pv_free
+Glib::ustring LVM2_PV_Info::get_pv_attr( const Glib::ustring & path, unsigned int entry )
+{
+ for ( unsigned int i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
+ {
+ std::vector<Glib::ustring> pv_attrs ;
+ Utils::split( lvm2_pv_cache [i], pv_attrs, "," ) ;
+ if ( path == pv_attrs [PVATTR_PV_NAME] )
+ {
+ if ( entry < pv_attrs .size() )
+ return pv_attrs [entry] ;
+ else
+ break ;
+ }
+ }
+
+ return "" ;
+}
+
+}//GParted
diff --git a/src/Makefile.am b/src/Makefile.am
index 66a8e53..5fe75fb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,6 +31,7 @@ gpartedbin_SOURCES = \
FS_Info.cc \
GParted_Core.cc \
HBoxOperations.cc \
+ LVM2_PV_Info.cc \
Operation.cc \
OperationChangeUUID.cc \
OperationCopy.cc \
diff --git a/src/Utils.cc b/src/Utils.cc
index 8a14802..c778974 100644
--- a/src/Utils.cc
+++ b/src/Utils.cc
@@ -544,6 +544,30 @@ void Utils::tokenize( const Glib::ustring& str,
}
}
+//Split string on every delimiter, appending to the vector. Inspired by:
+// http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c/3616605#3616605
+// E.g. using Utils::split(str, result, ":") for str -> result
+// "" -> [] "a" -> ["a"] "::" -> ["","",""] ":a::bb" -> ["","a","","bb"]
+void Utils::split( const Glib::ustring& str,
+ std::vector<Glib::ustring>& result,
+ const Glib::ustring& delimiters )
+{
+ //Special case zero length string to empty vector
+ if ( str == "" )
+ return ;
+ Glib::ustring::size_type fromPos = 0 ;
+ Glib::ustring::size_type delimPos = str.find_first_of( delimiters );
+ while ( Glib::ustring::npos != delimPos )
+ {
+ Glib::ustring word( str, fromPos, delimPos - fromPos ) ;
+ result .push_back( word ) ;
+ fromPos = delimPos + 1 ;
+ delimPos = str.find_first_of( delimiters, fromPos ) ;
+ }
+ Glib::ustring word( str, fromPos ) ;
+ result. push_back( word ) ;
+}
+
// Converts a Glib::ustring into a int
int Utils::convert_to_int(const Glib::ustring & src)
{
diff --git a/src/lvm2_pv.cc b/src/lvm2_pv.cc
index f022145..8bd2d84 100644
--- a/src/lvm2_pv.cc
+++ b/src/lvm2_pv.cc
@@ -16,6 +16,7 @@
*/
+#include "../include/LVM2_PV_Info.h"
#include "../include/lvm2_pv.h"
namespace GParted
@@ -26,7 +27,8 @@ FS lvm2_pv::get_filesystem_support()
FS fs ;
fs .filesystem = GParted::FS_LVM2_PV ;
- if ( ! Glib::find_program_in_path( "lvm" ) .empty() )
+ LVM2_PV_Info lvm2_pv_info ;
+ if ( lvm2_pv_info .is_lvm2_pv_supported() )
{
fs .read = GParted::FS::EXTERNAL ;
}
@@ -36,19 +38,10 @@ FS lvm2_pv::get_filesystem_support()
void lvm2_pv::set_used_sectors( Partition & partition )
{
- if ( ! Utils::execute_command( "lvm pvs --units b --noheadings --nosuffix -o pv_free " + partition .get_path(), output, error, true ) )
- {
- gdouble free_bytes = g_ascii_strtod( output .c_str(), NULL ) ;
- partition .Set_Unused( Utils::round( free_bytes / double(partition .sector_size) ) ) ;
- }
- else
- {
- if ( ! output .empty() )
- partition .messages .push_back( output ) ;
-
- if ( ! error .empty() )
- partition .messages .push_back( error ) ;
- }
+ LVM2_PV_Info lvm2_pv_info ;
+ Byte_Value free_bytes = lvm2_pv_info .get_free_bytes( partition .get_path() ) ;
+ if ( free_bytes >= 0 )
+ partition .Set_Unused( Utils::round( double(free_bytes) / double(partition .sector_size) ) ) ;
}
void lvm2_pv::read_label( Partition & partition )
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]