After some time of investigation and thanks to two delayed flights I came up 
with the following solution that fixes the natbib slowness problem for me and 
makes LyX 1.4 usable again.

What it does is:
- store the timestamp of any bibfile in the buffer
- in insetcite, store the timestamp of the files at the time when the 
bibliographies were scanned for the last time
- now only scan the files again if the timestamp of a file has changed or if a 
file is new.

Opinions?

Jürgen
Index: src/insets/insetbibtex.C
===================================================================
--- src/insets/insetbibtex.C	(Revision 13663)
+++ src/insets/insetbibtex.C	(Arbeitskopie)
@@ -89,6 +89,7 @@ void InsetBibtex::doDispatch(LCursor & c
 			setParams(p);
 		else
 			cur.noUpdate();
+		cur.buffer().updateBibfilesCache();
 		break;
 	}
 
@@ -283,6 +284,17 @@ vector<string> const InsetBibtex::getFil
 }
 
 
+void InsetBibtex::getFiles(Buffer const & buffer,
+	std::vector<std::string> & bibfiles) const
+{
+	vector<string> const files = getFiles(buffer);
+	for (vector<string>::const_iterator it = files.begin();
+	     it != files.end(); ++ it) {
+		bibfiles.push_back(it->c_str());
+	}
+}
+
+
 // This method returns a comma separated list of Bibtex entries
 void InsetBibtex::fillWithBibKeys(Buffer const & buffer,
 				  std::vector<std::pair<string, string> > & keys) const
Index: src/insets/insetbibtex.h
===================================================================
--- src/insets/insetbibtex.h	(Revision 13663)
+++ src/insets/insetbibtex.h	(Arbeitskopie)
@@ -39,6 +39,9 @@ public:
 	///
 	std::vector<std::string> const getFiles(Buffer const &) const;
 	///
+	void getFiles(Buffer const & buffer,
+		std::vector<std::string> & bibfiles) const;
+	///
 	bool addDatabase(std::string const &);
 	///
 	bool delDatabase(std::string const &);
Index: src/insets/insetcite.C
===================================================================
--- src/insets/insetcite.C	(Revision 13663)
+++ src/insets/insetcite.C	(Arbeitskopie)
@@ -24,6 +24,8 @@
 
 #include "support/lstrings.h"
 
+#include <boost/filesystem/operations.hpp>
+
 using lyx::support::ascii_lowercase;
 using lyx::support::contains;
 using lyx::support::getVectorFromString;
@@ -37,6 +39,7 @@ using std::vector;
 using std::map;
 
 namespace biblio = lyx::biblio;
+namespace fs = boost::filesystem;
 
 
 namespace {
@@ -50,26 +53,51 @@ string const getNatbibLabel(Buffer const
 	if (!buffer.fully_loaded())
 		return string();
 
+	// Cache the labels
 	typedef std::map<Buffer const *, biblio::InfoMap> CachedMap;
 	static CachedMap cached_keys;
 
-	// build the keylist
-	typedef vector<std::pair<string, string> > InfoType;
-	InfoType bibkeys;
-	buffer.fillWithBibKeys(bibkeys);
-
-	InfoType::const_iterator bit  = bibkeys.begin();
-	InfoType::const_iterator bend = bibkeys.end();
+	// and cache the timestamp of the bibliography files.
+	static std::map<string, time_t> bibfileStatus;
 
 	biblio::InfoMap infomap;
-	for (; bit != bend; ++bit) {
-		infomap[bit->first] = bit->second;
+
+	if (buffer.getBibfilesCache().empty())
+		buffer.updateBibfilesCache();
+	vector<string> bibfilesCache = buffer.getBibfilesCache();
+	// compare the cached timestamps with the actual ones.
+	bool changed = false;
+	for (vector<string>::const_iterator it = bibfilesCache.begin();
+			it != bibfilesCache.end(); ++ it) {
+		string const f = it->c_str();
+		if (bibfileStatus[f] != fs::last_write_time(f)) {
+			changed = true;
+			bibfileStatus[f] = fs::last_write_time(f);
+		}
 	}
+
+	// build the keylist only if the bibfiles have been changed
+	if (cached_keys.empty() || bibfileStatus.empty() || changed) {
+		typedef vector<std::pair<string, string> > InfoType;
+		InfoType bibkeys;
+		buffer.fillWithBibKeys(bibkeys);
+	
+		InfoType::const_iterator bit  = bibkeys.begin();
+		InfoType::const_iterator bend = bibkeys.end();
+	
+		
+		for (; bit != bend; ++bit) {
+			infomap[bit->first] = bit->second;
+		}
+	
+		cached_keys[&buffer] = infomap;
+	} else
+		// use the cached keys
+		infomap = cached_keys[&buffer];
+
 	if (infomap.empty())
 		return string();
 
-	cached_keys[&buffer] = infomap;
-
 	// the natbib citation-styles
 	// CITET:	author (year)
 	// CITEP:	(author,year)
Index: src/BufferView_pimpl.C
===================================================================
--- src/BufferView_pimpl.C	(Revision 13663)
+++ src/BufferView_pimpl.C	(Arbeitskopie)
@@ -1290,8 +1290,10 @@ bool BufferView::Pimpl::dispatch(FuncReq
 		bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false);
 		InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
 						InsetBase::BIBTEX_CODE);
-		if (inset)
-			inset->addDatabase(cmd.argument);
+		if (inset) {
+			if (inset->addDatabase(cmd.argument))
+				buffer_->updateBibfilesCache();
+		}
 		break;
 	}
 
@@ -1300,8 +1302,10 @@ bool BufferView::Pimpl::dispatch(FuncReq
 		bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false);
 		InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
 						InsetBase::BIBTEX_CODE);
-		if (inset)
-			inset->delDatabase(cmd.argument);
+		if (inset) {
+			if (inset->delDatabase(cmd.argument))
+				buffer_->updateBibfilesCache();
+		}
 		break;
 	}
 
Index: src/buffer.C
===================================================================
--- src/buffer.C	(Revision 13663)
+++ src/buffer.C	(Arbeitskopie)
@@ -150,6 +150,8 @@ int const LYX_FORMAT = 245;
 
 
 typedef std::map<string, bool> DepClean;
+vector<string> Buffer::bibfilesCache_;
+
 
 class Buffer::Impl
 {
@@ -1253,6 +1255,39 @@ void Buffer::fillWithBibKeys(vector<pair
 }
 
 
+void Buffer::updateBibfilesCache() const
+{
+	/// if this is a child document and the parent is already loaded
+	/// use the parent's list instead
+	Buffer const * tmp = getMasterBuffer();
+	BOOST_ASSERT(tmp);
+	if (tmp != this) {
+		tmp->updateBibfilesCache();
+		return;
+	}
+
+	bibfilesCache_.clear();
+	for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
+		if (it->lyxCode() == InsetBase::BIBTEX_CODE) {
+			InsetBibtex const & inset =
+				dynamic_cast<InsetBibtex const &>(*it);
+			vector<string> bibfiles;
+			inset.getFiles(*this, bibfiles);
+			for (vector<string>::const_iterator it = bibfiles.begin();
+				it != bibfiles.end(); ++ it) {
+				bibfilesCache_.push_back(it->c_str());
+			}
+		}
+	}
+}
+
+
+vector<string> const Buffer::getBibfilesCache() const
+{
+	return bibfilesCache_;
+}
+
+
 bool Buffer::isDepClean(string const & name) const
 {
 	DepClean::const_iterator const it = pimpl_->dep_clean.find(name);
Index: src/buffer.h
===================================================================
--- src/buffer.h	(Revision 13663)
+++ src/buffer.h	(Arbeitskopie)
@@ -24,6 +24,7 @@
 #include <boost/signal.hpp>
 
 #include <iosfwd>
+#include <string>
 #include <map>
 #include <utility>
 #include <vector>
@@ -249,6 +250,10 @@ public:
 
 	/// return all bibkeys from buffer and its childs
 	void fillWithBibKeys(std::vector<std::pair<std::string, std::string> > & keys) const;
+	/// update the cache with all bibfiles in use
+	void updateBibfilesCache() const;
+	/// return the cache with all bibfiles in use
+	std::vector<std::string> const Buffer::getBibfilesCache() const;
 	///
 	void getLabelList(std::vector<std::string> &) const;
 
@@ -352,6 +357,9 @@ private:
 	/// it's BufferView, this should be FIXED in future.
 	StableDocIterator cursor_;
 	StableDocIterator anchor_;
+	/// a cache for the bibfiles, needed for appropriate
+	/// update of natbib labels.
+	static std::vector<std::string> bibfilesCache_;
 };
 
 #endif

Reply via email to