[lvm-devel] master - lib: avoid reparsing same metadata

Zdenek Kabelac zkabelac at fedoraproject.org
Fri Mar 6 13:31:40 UTC 2015


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=7e7411966afc4309cdd91bfed4846720b308c84d
Commit:        7e7411966afc4309cdd91bfed4846720b308c84d
Parent:        6a2ae250ffc52c7620ec837cb10eb7b9ca44a121
Author:        Zdenek Kabelac <zkabelac at redhat.com>
AuthorDate:    Mon Mar 26 13:35:26 2012 +0200
Committer:     Zdenek Kabelac <zkabelac at redhat.com>
CommitterDate: Fri Mar 6 13:53:12 2015 +0100

lib: avoid reparsing same metadata

When reading VG mda from multiple PVs - do all the validation only
when mda is seen for the first time and  when mda checksum and length
is same just return already existing VG pointer.

(i.e. using 300PVs for a VG would lead to create and destroy 300 config trees....)
---
 WHATS_NEW                        |    1 +
 lib/config/config.c              |   18 +++++++++++++-----
 lib/config/config.h              |    3 ++-
 lib/format_text/import.c         |   24 ++++++++++++++++++++++--
 lib/metadata/metadata-exported.h |    5 +++++
 lib/metadata/metadata.c          |    1 +
 6 files changed, 44 insertions(+), 8 deletions(-)

diff --git a/WHATS_NEW b/WHATS_NEW
index b62a632..ef5abcd 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
 Version 2.02.118 - 
 =================================
+  Avoid reparsing same metadata when reading same metadata from multiple PVs.
   Save extra device open/close when scanning device for size.
   Fix seg_monitor field to report status also for mirrors and thick snapshots.
 
diff --git a/lib/config/config.c b/lib/config/config.c
index effe93d..5de6df6 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -478,9 +478,15 @@ int override_config_tree_from_profile(struct cmd_context *cmd,
 	return 0;
 }
 
+/*
+ * When skip_parse is set, the checksum of buffer is only matched
+ * and function avoids parsing of mda into config tree which
+ * remains unmodified and should not be used.
+ */
 int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
 			off_t offset, size_t size, off_t offset2, size_t size2,
-			checksum_fn_t checksum_fn, uint32_t checksum)
+			checksum_fn_t checksum_fn, uint32_t checksum,
+			int skip_parse)
 {
 	char *fb, *fe;
 	int r = 0;
@@ -529,9 +535,11 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
 		goto out;
 	}
 
-	fe = fb + size + size2;
-	if (!dm_config_parse(cft, fb, fe))
-		goto_out;
+	if (!skip_parse) {
+		fe = fb + size + size2;
+		if (!dm_config_parse(cft, fb, fe))
+			goto_out;
+	}
 
 	r = 1;
 
@@ -575,7 +583,7 @@ int config_file_read(struct dm_config_tree *cft)
 	}
 
 	r = config_file_read_fd(cft, cf->dev, 0, (size_t) info.st_size, 0, 0,
-				(checksum_fn_t) NULL, 0);
+				(checksum_fn_t) NULL, 0, 0);
 
 	if (!cf->keep_open) {
 		if (!dev_close(cf->dev))
diff --git a/lib/config/config.h b/lib/config/config.h
index ba34354..50ea361 100644
--- a/lib/config/config.h
+++ b/lib/config/config.h
@@ -205,7 +205,8 @@ typedef uint32_t (*checksum_fn_t) (uint32_t initial, const uint8_t *buf, uint32_
 struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open);
 int config_file_read_fd(struct dm_config_tree *cft, struct device *dev,
 			off_t offset, size_t size, off_t offset2, size_t size2,
-			checksum_fn_t checksum_fn, uint32_t checksum);
+			checksum_fn_t checksum_fn, uint32_t checksum,
+			int skip_parse);
 int config_file_read(struct dm_config_tree *cft);
 struct dm_config_tree *config_file_open_and_read(const char *config_file, config_source_t source,
 						 struct cmd_context *cmd);
diff --git a/lib/format_text/import.c b/lib/format_text/import.c
index fe19dd7..8a1771a 100644
--- a/lib/format_text/import.c
+++ b/lib/format_text/import.c
@@ -51,7 +51,7 @@ const char *text_vgname_import(const struct format_type *fmt,
 
 	if ((!dev && !config_file_read(cft)) ||
 	    (dev && !config_file_read_fd(cft, dev, offset, size,
-					 offset2, size2, checksum_fn, checksum))) {
+					 offset2, size2, checksum_fn, checksum, 0))) {
 		log_error("Couldn't read volume group metadata.");
 		goto out;
 	}
@@ -88,6 +88,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
 	struct volume_group *vg = NULL;
 	struct dm_config_tree *cft;
 	struct text_vg_version_ops **vsn;
+	int skip_parse;
 
 	_init_text_import();
 
@@ -97,11 +98,20 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
 	if (!(cft = config_open(CONFIG_FILE_SPECIAL, file, 0)))
 		return_NULL;
 
+	skip_parse = fid->vg && (fid->mda_checksum == checksum) &&
+		(fid->mda_size == (size + size2));
+
 	if ((!dev && !config_file_read(cft)) ||
 	    (dev && !config_file_read_fd(cft, dev, offset, size,
-					 offset2, size2, checksum_fn, checksum)))
+					 offset2, size2, checksum_fn, checksum,
+					 skip_parse)))
 		goto_out;
 
+	if (skip_parse) {
+		vg = fid->vg;
+		goto out;
+	}
+
 	/*
 	 * Find a set of version functions that can read this file
 	 */
@@ -116,6 +126,16 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
 		break;
 	}
 
+	if (vg && (!fid->vg || (vg->seqno > fid->vg->seqno))) {
+		/*
+		 * Remember vg pointer to newest VG for reuse.
+		 * NOTE: _vg_read() will not release same VG
+		 */
+		fid->vg = vg;
+		fid->mda_size = (size + size2);
+		fid->mda_checksum = checksum;
+	}
+
       out:
 	config_destroy(cft);
 	return vg;
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 8c081d9..b5ab1f2 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -324,6 +324,11 @@ struct format_instance {
 	struct dm_list metadata_areas_ignored;
 	struct dm_hash_table *metadata_areas_index;
 
+	/* Remember last vg to avoid parsing same mda content for multiple PVs */
+	struct volume_group *vg;
+	uint32_t mda_checksum;
+	size_t mda_size;
+
 	void *private;
 };
 
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 7e440a4..57066a5 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3365,6 +3365,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
 		}
 
 		if (vg != correct_vg)
+			/* NOTE: tied to fid->vg logic in text_vg_import_fd() */
 			release_vg(vg);
 	}
 	fid->ref_count--;




More information about the lvm-devel mailing list