diff --git a/config/memcache_default.conf.php b/config/memcache_default.conf.php new file mode 100755 index 00000000..dceaea54 --- /dev/null +++ b/config/memcache_default.conf.php @@ -0,0 +1,30 @@ +addServer("some.ip", 11211); + // $memcache->addServer("other.ip", 11211); + } diff --git a/main/include/setup.inc.php b/main/include/setup.inc.php index 64d9d610..789ac583 100755 --- a/main/include/setup.inc.php +++ b/main/include/setup.inc.php @@ -74,6 +74,7 @@ 'action', 'database', 'id', + 'memcache', 'logging', 'recaptcha', 'authentication_setup', diff --git a/main/library/PluginManager/SeguePlugins/SeguePluginsAPI.interface.php b/main/library/PluginManager/SeguePlugins/SeguePluginsAPI.interface.php index ec9ab775..4c0fd2bb 100755 --- a/main/library/PluginManager/SeguePlugins/SeguePluginsAPI.interface.php +++ b/main/library/PluginManager/SeguePlugins/SeguePluginsAPI.interface.php @@ -123,7 +123,8 @@ public function initialize (); * as needed. * * @param array $request - * @return void + * @return boolean - TRUE if changes were made to the stored state of this plugin. + * This is used to control various caching mechanisms. * @access public * @since 1/12/06 */ diff --git a/main/library/PluginManager/SeguePlugins/SeguePluginsDriver.abstract.php b/main/library/PluginManager/SeguePlugins/SeguePluginsDriver.abstract.php index 71424ef4..644bffc5 100755 --- a/main/library/PluginManager/SeguePlugins/SeguePluginsDriver.abstract.php +++ b/main/library/PluginManager/SeguePlugins/SeguePluginsDriver.abstract.php @@ -13,6 +13,7 @@ require_once(MYDIR."/main/modules/media/MediaAsset.class.php"); require_once(MYDIR."/main/library/Wiki/WikiResolver.class.php"); require_once(MYDIR."/main/library/DiffEngine.php"); +require_once(MYDIR."/main/library/PublicSiteOutputCache.class.php"); require_once(dirname(__FILE__)."/SeguePluginsDriverAPI.interface.php"); require_once(dirname(__FILE__)."/SeguePluginsAPI.interface.php"); @@ -1380,6 +1381,7 @@ final private function setShowControls ($showControls) { */ public function executeAndGetMarkup ( $showControls = false, $extended = false ) { $obLevel = ob_get_level(); + $clearCache = false; try { $this->setShowControls($showControls); @@ -1395,7 +1397,12 @@ public function executeAndGetMarkup ( $showControls = false, $extended = false ) $this->_baseUrl = $harmoni->request->mkURL(); } - $this->update($this->_getRequestData()); + // update() returns TRUE when new data is saved to + // persistent storage. in that case, we + // probably need to clear the cache for this site. + if ($this->update($this->_getRequestData())) { + $clearCache = true; + } if ($extended) $markup = $this->getExtendedMarkup(); @@ -1423,6 +1430,11 @@ public function executeAndGetMarkup ( $showControls = false, $extended = false ) $markup = _("An Error has occured in the plugin with the following message: "); $markup .= $e->getMessage(); } + + if ($clearCache) { + PublicSiteOutputCache::invalidate(); + } + return $markup; } @@ -2066,4 +2078,4 @@ public function importVersion (DOMDocument $versionXml, Id $agentId, DateAndTime } } -?> \ No newline at end of file +?> diff --git a/main/library/PluginManager/SeguePlugins/SeguePluginsTemplate.abstract.php b/main/library/PluginManager/SeguePlugins/SeguePluginsTemplate.abstract.php index 87eabf7a..21dfd13a 100755 --- a/main/library/PluginManager/SeguePlugins/SeguePluginsTemplate.abstract.php +++ b/main/library/PluginManager/SeguePlugins/SeguePluginsTemplate.abstract.php @@ -132,12 +132,13 @@ public function initialize () { * as needed. * * @param array $request - * @return void + * @return boolean * @access public * @since 1/12/06 */ public function update ( $request ) { // Override as needed. + return false; } /** @@ -378,4 +379,4 @@ public function replaceIdsInVersion (array $idMap, DOMDocument $version) { } } -?> \ No newline at end of file +?> diff --git a/main/library/PublicSiteOutputCache.class.php b/main/library/PublicSiteOutputCache.class.php new file mode 100644 index 00000000..a591e57e --- /dev/null +++ b/main/library/PublicSiteOutputCache.class.php @@ -0,0 +1,119 @@ +request->startNamespace(null); + $site = $harmoni->request->get("site"); + $node = $harmoni->request->get("node"); + $harmoni->request->endNamespace(); + + if (!$site && !$node) { + $harmoni->request->startNamespace("plugin_manager"); + $pluginId = $harmoni->request->get("plugin_id"); + $harmoni->request->endNamespace(); + if ($pluginId) { + // trick the site dispatcher into thinking this is the + // current node (which it is...) + $harmoni->request->startNamespace(null); + $harmoni->request->set("node", $pluginId); + $harmoni->request->endNamespace(); + } else { + return; + } + } + + $siteNode = SiteDispatcher::getCurrentRootNode(); + + $hierarchy = $hierarchyManager->getHierarchy( + $idManager->getId("edu.middlebury.authorization.hierarchy")); + $infoList = $hierarchy->traverse( + $idManager->getId($siteNode->getId()), + Hierarchy::TRAVERSE_MODE_DEPTH_FIRST, + Hierarchy::TRAVERSE_DIRECTION_DOWN, + Hierarchy::TRAVERSE_LEVELS_ALL); + + while ($infoList->hasNext()) { + $info = $infoList->next(); + PersistentCache::remove(PublicSiteOutputCache::_getKeyFromParts("anonymous", $info->getNodeId())); + PersistentCache::remove(PublicSiteOutputCache::_getKeyFromParts("institute", $info->getNodeId())); + } + } + + function _getKeyFromParts($user, $node) { + return "siteCache:$user:$node"; + } + + function _getKey(Harmoni $harmoni) { + // check authn, and see if we are logged in as anybody + // specific. if so, we shouldn't cache it. + $valid = array( + "edu.middlebury.agents.anonymous" => false, + "edu.middlebury.institude" => false + ); + + $authN = Services::getService("AuthN"); + $authTypes = $authN->getAuthenticationTypes(); + while ($authTypes->hasNext()) { + $id = $authN->getUserId($authTypes->next()); + if (!in_array($id->getIdString(), array_keys($valid))) { + return null; + } + + $valid[$id->getIdString()] = true; + } + + $user = "anonymous"; + if ($valid["edu.middlebury.institute"]) { + $user = "institute"; + } + + if ($harmoni->getCurrentAction() == "view.html") { + $harmoni->request->startNamespace(null); + $site = $harmoni->request->get("site"); + $node = $harmoni->request->get("node"); + $harmoni->request->endNamespace(); + + if ($site) { + if (!$node) { + $harmoni->request->startNamespace(null); + $node = SiteDispatcher::getCurrentRootNode()->getNodeId(); + $harmoni->request->endNamespace(); + } + return PublicSiteOutputCache::_getKeyFromParts($user, $node); + } + } + + return null; + } + +} diff --git a/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetBlockSiteComponent.class.php b/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetBlockSiteComponent.class.php index 4538a640..d7cd52cf 100755 --- a/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetBlockSiteComponent.class.php +++ b/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetBlockSiteComponent.class.php @@ -112,6 +112,7 @@ function getDisplayName () { */ function updateDisplayName ( $displayName ) { $this->_asset->updateDisplayName(HtmlString::getSafeHtml($displayName)); + PublicSiteOutputCache::invalidate(); } /** @@ -135,6 +136,7 @@ function getDescription () { */ function updateDescription ( $description ) { $this->_asset->updateDescription(HtmlString::getSafeHtml($description)); + PublicSiteOutputCache::invalidate(); } /** @@ -230,6 +232,7 @@ function getContentMarkup () { function updateContentMarkup ( $contentMarkup ) { $content = Blob::fromString($contentMarkup); $this->_asset->updateContent($content); + PublicSiteOutputCache::invalidate(); } /** @@ -413,4 +416,4 @@ function _saveXml () { } -?> \ No newline at end of file +?> diff --git a/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetSiteComponent.class.php b/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetSiteComponent.class.php index 199fe5f2..d050facd 100755 --- a/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetSiteComponent.class.php +++ b/main/library/SiteDisplay/SiteComponents/AssetSiteComponents/AssetSiteComponent.class.php @@ -629,7 +629,11 @@ function _saveXml () { $element->ownerDocument->saveXMLWithWhitespace())); $this->clearDomCache(); + + // clear the public site output cache, since the structure + // of this site may have just changed. + PublicSiteOutputCache::invalidate(); } } -?> \ No newline at end of file +?> diff --git a/main/modules/view/html.act.php b/main/modules/view/html.act.php index 7b2fd224..4b77d5bd 100755 --- a/main/modules/view/html.act.php +++ b/main/modules/view/html.act.php @@ -45,6 +45,8 @@ class htmlAction extends displayAction { + + var $_outputCache; /** * AuthZ @@ -91,6 +93,8 @@ public function getUnauthorizedMessage () { */ function execute () { $harmoni = Harmoni::instance(); + + $this->_outputCache = new PublicSiteOutputCache(); /********************************************************* * Split sites based on their location-category @@ -155,34 +159,47 @@ function execute () { } catch (UnknownIdException $e) { // No slot for the site.... } - $authZ = Services::getService("AuthZ"); - $recordManager = Services::getService("RecordManager"); + // here, check if we have the content of this site cached yet. if so, + // we can use it + $shouldCache = false; + $content = null; + if ($this->_outputCache->shouldCache($harmoni)) { + $shouldCache = true; + $content = $this->_outputCache->fetch($harmoni); + } - // - // Begin Optimizations - // - // The code below queues up authorizations for all visible nodes, - // as well as pre-fetches all of the RecordSets that have data - // specific to the visible nodes. - $visibleComponents = SiteDispatcher::getSiteDirector()->getVisibleComponents(SiteDispatcher::getCurrentNodeId()); + $mainScreen = new Container(new YLayout, BLOCK, BACKGROUND_BLOCK); + $allWrapper = $this->addHeaderControls($mainScreen); - $preCacheIds = array(); - foreach ($visibleComponents as $component) { - $id = $component->getQualifierId(); - $authZ->getIsAuthorizedCache()->queueId($id); - $preCacheIds[] = $id->getIdString(); - } + if (!$content) { + $authZ = Services::getService("AuthZ"); + $recordManager = Services::getService("RecordManager"); - $recordManager->preCacheRecordsFromRecordSetIDs($preCacheIds); - // - // End Optimizations - // + // + // Begin Optimizations + // + // The code below queues up authorizations for all visible nodes, + // as well as pre-fetches all of the RecordSets that have data + // specific to the visible nodes. + $visibleComponents = SiteDispatcher::getSiteDirector()->getVisibleComponents(SiteDispatcher::getCurrentNodeId()); - $mainScreen = new Container(new YLayout, BLOCK, BACKGROUND_BLOCK); + $preCacheIds = array(); + foreach ($visibleComponents as $component) { + $id = $component->getQualifierId(); + $authZ->getIsAuthorizedCache()->queueId($id); + $preCacheIds[] = $id->getIdString(); + } + + $recordManager->preCacheRecordsFromRecordSetIDs($preCacheIds); + // + // End Optimizations + // + + $this->addSiteContent($mainScreen, $shouldCache); + } else { + $mainScreen->add(new UnstyledBlock($content)); + } - $allWrapper = $this->addHeaderControls($mainScreen); - - $this->addSiteContent($mainScreen); $this->addFooterControls($allWrapper); $this->mainScreen = $mainScreen; @@ -294,14 +311,24 @@ public function addHeaderControls (Component $mainScreen) { * @access public * @since 4/7/08 */ - public function addSiteContent (Component $mainScreen) { + public function addSiteContent (Component $mainScreen, $shouldCache) { $harmoni = Harmoni::instance(); if ($this->isAuthorizedToExecute()) { // :: Site :: $rootSiteComponent = SiteDispatcher::getCurrentRootNode(); $this->siteGuiComponent = $rootSiteComponent->acceptVisitor($this->getSiteVisitor()); - $mainScreen->add($this->siteGuiComponent); + if ($shouldCache) { + ob_start(); + $harmoni->getOutputHandler()->getCurrentTheme()->printPage($this->siteGuiComponent); + $content = ob_get_contents(); + ob_end_clean(); + + $this->_outputCache->store($harmoni, $content); + $mainScreen->add(new UnstyledBlock($content)); + } else { + $mainScreen->add($this->siteGuiComponent); + } } else { // Replace the title $outputHandler = $harmoni->getOutputHandler(); diff --git a/plugins-dist/SeguePlugins/edu.middlebury/Assignment/EduMiddleburyAssignmentPlugin.class.php b/plugins-dist/SeguePlugins/edu.middlebury/Assignment/EduMiddleburyAssignmentPlugin.class.php index f0cc478b..b442c3c2 100755 --- a/plugins-dist/SeguePlugins/edu.middlebury/Assignment/EduMiddleburyAssignmentPlugin.class.php +++ b/plugins-dist/SeguePlugins/edu.middlebury/Assignment/EduMiddleburyAssignmentPlugin.class.php @@ -42,7 +42,7 @@ function initialize () { * as needed. * * @param array $request - * @return void + * @return boolean * @access public * @since 1/12/06 */ @@ -52,7 +52,11 @@ function update ( $request ) { $this->updateDataArray(); $this->updateDataRecords(); + + return true; } + + return false; } function updateDataArray () { @@ -187,4 +191,4 @@ function getMarkup () { } -?> \ No newline at end of file +?> diff --git a/plugins-dist/SeguePlugins/edu.middlebury/AudioPlayer/EduMiddleburyAudioPlayerPlugin.class.php b/plugins-dist/SeguePlugins/edu.middlebury/AudioPlayer/EduMiddleburyAudioPlayerPlugin.class.php index bde57656..e3ac6369 100755 --- a/plugins-dist/SeguePlugins/edu.middlebury/AudioPlayer/EduMiddleburyAudioPlayerPlugin.class.php +++ b/plugins-dist/SeguePlugins/edu.middlebury/AudioPlayer/EduMiddleburyAudioPlayerPlugin.class.php @@ -105,7 +105,7 @@ function initialize () { * as needed. * * @param array $request - * @return void + * @return boolean * @access public * @since 1/12/06 */ @@ -115,7 +115,11 @@ function update ( $request ) { $this->setRawDescription($this->tokenizeLocalUrls($this->getFieldValue('description'))); $this->setShowDownloadLink(($this->getFieldValue('show_download_link') == 'true')?true:false); $this->logEvent('Modify Content', 'File for download updated'); + + return true; } + + return false; } /** diff --git a/plugins-dist/SeguePlugins/edu.middlebury/Download/EduMiddleburyDownloadPlugin.class.php b/plugins-dist/SeguePlugins/edu.middlebury/Download/EduMiddleburyDownloadPlugin.class.php index ac92f37e..b918e7ed 100755 --- a/plugins-dist/SeguePlugins/edu.middlebury/Download/EduMiddleburyDownloadPlugin.class.php +++ b/plugins-dist/SeguePlugins/edu.middlebury/Download/EduMiddleburyDownloadPlugin.class.php @@ -107,7 +107,7 @@ function initialize () { * as needed. * * @param array $request - * @return void + * @return boolean * @access public * @since 1/12/06 */ @@ -116,7 +116,11 @@ function update ( $request ) { $this->setContent($this->getFieldValue('file_id')); $this->setRawDescription($this->tokenizeLocalUrls($this->getFieldValue('description'))); $this->logEvent('Modify Content', 'File for download updated'); + + return true; } + + return false; } /** diff --git a/plugins-dist/SeguePlugins/edu.middlebury/RssFeed/EduMiddleburyRssFeedPlugin.class.php b/plugins-dist/SeguePlugins/edu.middlebury/RssFeed/EduMiddleburyRssFeedPlugin.class.php index 54f53865..e77d8528 100755 --- a/plugins-dist/SeguePlugins/edu.middlebury/RssFeed/EduMiddleburyRssFeedPlugin.class.php +++ b/plugins-dist/SeguePlugins/edu.middlebury/RssFeed/EduMiddleburyRssFeedPlugin.class.php @@ -124,7 +124,7 @@ public function initialize () { * as needed. * * @param array $request - * @return void + * @return boolean * @access public * @since 1/12/06 */ @@ -187,7 +187,10 @@ public function update ( $request ) { $this->_setMaxItems(intval($this->getFieldValue('max_items'))); $this->_setExtendedMaxItems(intval($this->getFieldValue('extended_max_items'))); + return true; } + + return false; } /** @@ -980,4 +983,4 @@ public function replaceIds (array $idMap) { } -?> \ No newline at end of file +?> diff --git a/plugins-dist/SeguePlugins/edu.middlebury/TextBlock/EduMiddleburyTextBlockPlugin.class.php b/plugins-dist/SeguePlugins/edu.middlebury/TextBlock/EduMiddleburyTextBlockPlugin.class.php index 3556f4ab..a637006f 100755 --- a/plugins-dist/SeguePlugins/edu.middlebury/TextBlock/EduMiddleburyTextBlockPlugin.class.php +++ b/plugins-dist/SeguePlugins/edu.middlebury/TextBlock/EduMiddleburyTextBlockPlugin.class.php @@ -118,7 +118,7 @@ function initialize () { * as needed. * * @param array $request - * @return void + * @return boolean * @access public * @since 1/12/06 */ @@ -136,6 +136,7 @@ function update ( $request ) { else $this->markVersion(); + return true; } else if ($this->getFieldValue('editor')) { $this->textEditor = $this->getFieldValue('editor'); UserData::instance()->setPreference('segue_text_editor', $this->textEditor);; @@ -144,8 +145,8 @@ function update ( $request ) { $this->workingContent = $this->cleanHTML($this->getFieldValue('content')); $this->workingAbstractLength = intval($this->getFieldValue('abstractLength')); } - - + + return false; } /**