From 5eb9e8678ddc58a01929a9f340a01048836b47d3 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sat, 19 Jan 2013 16:59:39 +0100 Subject: Indexer: Added page and meta value rename functions With these functions that search index can be updated after page moves or mass metadata updates without the need to reindex the whole page/wiki. These functions will be used by the new pagemove plugin. --- inc/indexer.php | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'inc') diff --git a/inc/indexer.php b/inc/indexer.php index 7a62345bf..70eac035b 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -338,6 +338,106 @@ class Doku_Indexer { return true; } + /** + * Rename a page in the search index without changing the indexed content + * + * @param string $oldpage The old page name + * @param string $newpage The new page name + * @return string|bool If the page was successfully renamed, can be a message in the case of an error + */ + public function renamePage($oldpage, $newpage) { + if (!$this->lock()) return 'locked'; + + $pages = $this->getPages(); + + $id = array_search($oldpage, $pages); + if ($id === false) { + $this->unlock(); + return 'page is not in index'; + } + + $new_id = array_search($newpage, $pages); + if ($new_id !== false) { + $this->unlock(); + // make sure the page is not in the index anymore + $this->deletePage($newpage); + if (!$this->lock()) return 'locked'; + + $pages[$new_id] = 'deleted:'.time().rand(0, 9999); + } + + $pages[$id] = $newpage; + + // update index + if (!$this->saveIndex('page', '', $pages)) { + $this->unlock(); + return false; + } + + // reset the pid cache + $this->pidCache = array(); + + $this->unlock(); + return true; + } + + /** + * Renames a meta value in the index. This doesn't change the meta value in the pages, it assumes that all pages + * will be updated. + * + * @param string $key The metadata key of which a value shall be changed + * @param string $oldvalue The old value that shall be renamed + * @param string $newvalue The new value to which the old value shall be renamed, can exist (then values will be merged) + * @return bool|string If renaming the value has been successful, false or error message on error. + */ + public function renameMetaValue($key, $oldvalue, $newvalue) { + if (!$this->lock()) return 'locked'; + + // change the relation references index + $metavalues = $this->getIndex($key, '_w'); + $oldid = array_search($oldvalue, $metavalues); + if ($oldid !== false) { + $newid = array_search($newvalue, $metavalues); + if ($newid !== false) { + // free memory + unset ($metavalues); + + // okay, now we have two entries for the same value. we need to merge them. + $indexline = $this->getIndexKey($key, '_i', $oldid); + if ($indexline != '') { + $newindexline = $this->getIndexKey($key, '_i', $newid); + $pagekeys = $this->getIndex($key, '_p'); + $parts = explode(':', $indexline); + foreach ($parts as $part) { + list($id, $count) = explode('*', $part); + $newindexline = $this->updateTuple($newindexline, $id, $count); + + $keyline = explode(':', $pagekeys[$id]); + // remove old meta value + $keyline = array_diff($keyline, array($oldid)); + // add new meta value when not already present + if (!in_array($newid, $keyline)) { + array_push($keyline, $newid); + } + $pagekeys[$id] = implode(':', $keyline); + } + $this->saveIndex($key, '_p', $pagekeys); + unset($pagekeys); + $this->saveIndexKey($key, '_i', $oldid, ''); + $this->saveIndexKey($key, '_i', $newid, $newindexline); + } + } else { + $metavalues[$oldid] = $newvalue; + if (!$this->saveIndex($key, '_w', $metavalues)) { + $this->unlock(); + return false; + } + } + } + + $this->unlock(); + return true; + } /** * Remove a page from the index * -- cgit v1.2.3 From af73bba62fb11d7872a8b108b156d451302695bd Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sat, 26 Jan 2013 11:17:59 +0100 Subject: Clarified the behavior of the Doku_Indexer::renamePage method --- inc/indexer.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'inc') diff --git a/inc/indexer.php b/inc/indexer.php index 70eac035b..37ca92055 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -339,7 +339,9 @@ class Doku_Indexer { } /** - * Rename a page in the search index without changing the indexed content + * Rename a page in the search index without changing the indexed content. This function doesn't check if the + * old or new name exists in the filesystem. It returns an error if the old page isn't in the page list of the + * indexer and it deletes all previously indexed content of the new page. * * @param string $oldpage The old page name * @param string $newpage The new page name -- cgit v1.2.3 From 25adeb91ff207452ebd6275707b8a0cc3121db6c Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sat, 26 Jan 2013 11:18:52 +0100 Subject: Indexer: added internal deletePageNoLock method The new deletePageNoLock method is used by renamePage and avoids that the index needs to be unlocked and locked again for deleting the page. --- inc/indexer.php | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'inc') diff --git a/inc/indexer.php b/inc/indexer.php index 37ca92055..c08e438bf 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -360,10 +360,8 @@ class Doku_Indexer { $new_id = array_search($newpage, $pages); if ($new_id !== false) { - $this->unlock(); // make sure the page is not in the index anymore - $this->deletePage($newpage); - if (!$this->lock()) return 'locked'; + $this->deletePageNoLock($newpage); $pages[$new_id] = 'deleted:'.time().rand(0, 9999); } @@ -440,6 +438,7 @@ class Doku_Indexer { $this->unlock(); return true; } + /** * Remove a page from the index * @@ -453,10 +452,26 @@ class Doku_Indexer { if (!$this->lock()) return "locked"; + $result = $this->deletePageNoLock($page); + + $this->unlock(); + + return $result; + } + + /** + * Remove a page from the index without locking the index, only use this function if the index is already locked + * + * Erases entries in all known indexes. + * + * @param string $page a page name + * @return boolean the function completed successfully + * @author Tom N Harris + */ + protected function deletePageNoLock($page) { // load known documents $pid = $this->getPIDNoLock($page); if ($pid === false) { - $this->unlock(); return false; } @@ -482,7 +497,6 @@ class Doku_Indexer { } // Save the reverse index if (!$this->saveIndexKey('pageword', '', $pid, "")) { - $this->unlock(); return false; } @@ -499,7 +513,6 @@ class Doku_Indexer { $this->saveIndexKey($metaname.'_p', '', $pid, ''); } - $this->unlock(); return true; } -- cgit v1.2.3 From bc27f3e28790e9a25e9428ed275624578b3e9a2d Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Sat, 26 Jan 2013 11:22:52 +0100 Subject: Indexer: abort page rename if deletion of new id fails --- inc/indexer.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'inc') diff --git a/inc/indexer.php b/inc/indexer.php index c08e438bf..e518907d7 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -361,7 +361,9 @@ class Doku_Indexer { $new_id = array_search($newpage, $pages); if ($new_id !== false) { // make sure the page is not in the index anymore - $this->deletePageNoLock($newpage); + if ($this->deletePageNoLock($newpage) !== true) { + return false; + } $pages[$new_id] = 'deleted:'.time().rand(0, 9999); } -- cgit v1.2.3