diff --git a/core/DataTable.php b/core/DataTable.php
index b697fad2c97f20c5d2d8d0b4dbb0a354426a217a..322300af63a623d2429f6d3a0a6de13956de3cb4 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -244,11 +244,19 @@ class Piwik_DataTable
 	 * @var array
 	 */
 	protected $metadata = array();
-
+	
+	/**
+	 * Maximum number of rows allowed in this datatable (including the summary row).
+	 * If adding more rows is attempted, the extra rows get summed to the summary row.
+	 * 
+	 * @var int
+	 */
+	protected $maximumAllowedRows = 0;
+	
 	const ID_SUMMARY_ROW = -1;
 	const LABEL_SUMMARY_ROW = -1;
 	const ID_PARENTS = -2;
-
+	
 	/**
 	 * Builds the DataTable, registers itself to the manager
 	 *
@@ -595,6 +603,25 @@ class Piwik_DataTable
 	 */
 	public function addRow( Piwik_DataTable_Row $row )
 	{
+		// if there is a upper limit on the number of allowed rows and the table is full,
+		// add the new row to the summary row
+		if ($this->maximumAllowedRows > 0
+			&& $this->getRowsCount() >= $this->maximumAllowedRows - 1)
+		{
+			if ($this->summaryRow === null) // create the summary row if necessary
+			{
+				$this->addSummaryRow(new Piwik_DataTable_Row(array(
+					Piwik_DataTable_Row::COLUMNS => $row->getColumns()
+				)));
+				$this->summaryRow->setColumn('label', self::LABEL_SUMMARY_ROW);
+			}
+			else
+			{
+				$this->summaryRow->sumRow($row);
+			}
+			return $this->summaryRow;
+		}
+		
 		$this->rows[] = $row;
 		if(!$this->indexNotUpToDate
 			&& $this->rebuildIndexContinuously)
@@ -606,16 +633,19 @@ class Piwik_DataTable
 			}
 			$this->indexNotUpToDate = false;
 		}
+		return $row;
 	}
 
 	/**
 	 * Sets the summary row (a dataTable can have only one summary row)
 	 *
 	 * @param Piwik_DataTable_Row  $row
+	 * @return Piwik_DataTable_Row Returns $row.
 	 */
 	public function addSummaryRow( Piwik_DataTable_Row $row )
 	{
 		$this->summaryRow = $row;
+		return $row;
 	}
 
 	/**
@@ -1350,4 +1380,89 @@ class Piwik_DataTable
 	{
 		$this->metadata[$name] = $value;
 	}
+	
+	/**
+	 * Sets the maximum number of rows allowed in this datatable (including the summary
+	 * row). If adding more then the allowed number of rows is attempted, the extra
+	 * rows are added to the summary row.
+	 * 
+	 * @param int|null $maximumAllowedRows
+	 */
+	public function setMaximumAllowedRows( $maximumAllowedRows )
+	{
+		$this->maximumAllowedRows = $maximumAllowedRows;
+	}
+	
+	/**
+	 * Traverses a DataTable tree using an array of labels and returns the row
+	 * it finds or false if it cannot find one, and the number of segments of
+	 * the path successfully walked.
+	 * 
+	 * If $missingRowColumns is supplied, the specified path is created. When
+	 * a subtable is encountered w/o the queried label, a new row is created
+	 * with the label, and a subtable is added to the row.
+	 * 
+	 * @param array $path The path to walk. An array of label values.
+	 * @param array|false $missingRowColumns
+	 *						The default columns to use when creating new arrays.
+	 * 						If this parameter is supplied, new rows will be
+	 * 						created if labels cannot be found.
+	 * @param int $maxSubtableRows The maximum number of allowed rows in new
+	 *                             subtables.
+	 * @return array First element is the found row or false. Second element is
+	 *               the number of path segments walked. If a row is found, this
+	 *               will be == to count($path). Otherwise, it will be the index
+	 *               of the path segment that we could not find.
+	 */
+	public function walkPath( $path, $missingRowColumns = false, $maxSubtableRows = 0 )
+	{
+		$pathLength = count($path);
+		
+		$table = $this;
+		$next = false;
+		for ($i = 0; $i < $pathLength; ++$i)
+		{
+			$segment = $path[$i];
+			
+			$next = $table->getRowFromLabel($segment);
+			if ($next === false)
+			{
+				// if there is no table to advance to, and we're not adding missing rows, return false
+				if ($missingRowColumns === false)
+				{
+					return array(false, $i);
+				}
+				else // if we're adding missing rows, add a new row
+				{
+					$row = new Piwik_DataTable_Row_DataTableSummary();
+					$row->setColumns(array('label' => $segment) + $missingRowColumns);
+					
+					$next = $table->addRow($row);
+					if ($next !== $row) // if the row wasn't added, the table is full
+					{
+						return array($next, $i);
+					}
+				}
+			}
+			
+			$table = $next->getSubtable();
+			if ($table === false)
+			{
+				// if the row has no table (and thus no child rows), and we're not adding
+				// missing rows, return false
+				if ($missingRowColumns === false)
+				{
+					return array(false, $i);
+				}
+				else if ($i != $pathLength - 1) // create subtable if missing, but only if not on the last segment
+				{
+					$table = new Piwik_DataTable();
+					$table->setMaximumAllowedRows($maxSubtableRows);
+					$next->setSubtable($table);
+				}
+			}
+		}
+		
+		return array($next, $i);
+	}
 }
diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php
index caa8135b33ed448c9a362d98c519fb48d02eca05..c03dbdf595f53bf8ae17481493dd0c04df7f1c81 100644
--- a/core/DataTable/Row.php
+++ b/core/DataTable/Row.php
@@ -250,6 +250,20 @@ class Piwik_DataTable_Row
 				: null;
 	}
 	
+	/**
+	 * Returns the associated subtable, if one exists.
+	 * 
+	 * @return Piwik_DataTable|false
+	 */
+	public function getSubtable()
+	{
+		if ($this->isSubtableLoaded())
+		{
+			return Piwik_DataTable_Manager::getInstance()->getTable($this->getIdSubDataTable());
+		}
+		return false;
+	}
+	
 	/**
 	 * Sums a DataTable to this row subDataTable.
 	 * If this row doesn't have a SubDataTable yet, we create a new one.
@@ -262,7 +276,7 @@ class Piwik_DataTable_Row
 	{
 		if($this->isSubtableLoaded())
 		{
-			$thisSubTable = Piwik_DataTable_Manager::getInstance()->getTable( $this->getIdSubDataTable() );
+			$thisSubTable = $this->getSubtable();
 		}
 		else
 		{
@@ -278,8 +292,8 @@ class Piwik_DataTable_Row
 	 * If the row already has a DataTable associated to it, throws an Exception.
 	 * 
 	 * @param Piwik_DataTable  $subTable  DataTable to associate to this row
+	 * @return Piwik_DataTable Returns $subTable.
 	 * @throws Exception 
-	 * 
 	 */
 	public function addSubtable(Piwik_DataTable $subTable)
 	{
@@ -287,7 +301,7 @@ class Piwik_DataTable_Row
 		{
 			throw new Exception("Adding a subtable to the row, but it already has a subtable associated.");
 		}
-		$this->setSubtable($subTable);
+		return $this->setSubtable($subTable);
 	}
 	
 	/**
@@ -295,12 +309,14 @@ class Piwik_DataTable_Row
 	 * a DataTable associated, it is simply overwritten.
 	 * 
 	 * @param Piwik_DataTable  $subTable  DataTable to associate to this row
+	 * @return Piwik_DataTable Returns $subTable.
 	 */
 	public function setSubtable(Piwik_DataTable $subTable)
 	{
 		// Hacking -1 to ensure value is negative, so we know the table was loaded
 		// @see isSubtableLoaded()
 		$this->c[self::DATATABLE_ASSOCIATED] = -1 * $subTable->getId();
+		return $subTable;
 	}
 	
 	/**
@@ -592,8 +608,8 @@ class Piwik_DataTable_Row
 			)
 		)
 		{
-			$subtable1 = Piwik_DataTable_Manager::getInstance()->getTable($row1->getIdSubDataTable());
-			$subtable2 = Piwik_DataTable_Manager::getInstance()->getTable($row2->getIdSubDataTable());
+			$subtable1 = $row1->getSubtable();
+			$subtable2 = $row2->getSubtable();
 			if(!Piwik_DataTable::isEqual($subtable1, $subtable2))
 			{
 				return false;
diff --git a/core/DataTable/Row/DataTableSummary.php b/core/DataTable/Row/DataTableSummary.php
index 17af9ecfd2b7adfb461e28c96f353f21a3769971..bf648a04849be25048a3a8ca2d412ab97001db84 100644
--- a/core/DataTable/Row/DataTableSummary.php
+++ b/core/DataTable/Row/DataTableSummary.php
@@ -26,10 +26,37 @@ class Piwik_DataTable_Row_DataTableSummary extends Piwik_DataTable_Row
 	/**
 	 * @param Piwik_DataTable  $subTable
 	 */
-	function __construct($subTable)
+	function __construct($subTable = null)
 	{
 		parent::__construct();
-		foreach($subTable->getRows() as $row)
+		
+		if ($subTable !== null)
+		{
+			$this->sumTable($subTable);
+		}
+	}
+	
+	/**
+	 * Reset this row to an empty one and sum the associated subtable again.
+	 */
+	public function recalculate()
+	{
+		$id = $this->getIdSubDataTable();
+		if ($id !== null)
+		{
+			$subtable = Piwik_DataTable_Manager::getInstance()->getTable($id);
+			$this->sumTable($subtable);
+		}
+	}
+	
+	/**
+	 * Sums a tables row with this one.
+	 * 
+	 * @param Piwik_DataTable $table
+	 */
+	private function sumTable( $table )
+	{
+		foreach($table->getRows() as $row)
 		{
 			$this->sumRow($row);
 		}
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index cae4d15401892868b286b880f5f4f83e4df0d31b..8fe996d92784939b4d51cefa147783eef893e66b 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -430,7 +430,7 @@ class Piwik_Actions extends Piwik_Plugin
 		$actionsArchiving = new Piwik_Actions_Archiving;
 		return $actionsArchiving->archivePeriod($archiveProcessing);
 	}
-	
+		
 	/**
 	 * Compute all the actions along with their hierarchies.
 	 *
diff --git a/plugins/Actions/Archiving.php b/plugins/Actions/Archiving.php
index 728685b15fe83587040740124fe759d9fd12def5..e98c61657b2b14a753acebedc55488f067b80bc2 100644
--- a/plugins/Actions/Archiving.php
+++ b/plugins/Actions/Archiving.php
@@ -17,13 +17,14 @@
  */
 class Piwik_Actions_Archiving
 {
-	protected $actionsTablesByType = array(
-						Piwik_Tracker_Action::TYPE_ACTION_URL => array(),
-						Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
-						Piwik_Tracker_Action::TYPE_OUTLINK => array(),
-						Piwik_Tracker_Action::TYPE_ACTION_NAME => array(),
-	);
+	protected $actionsTablesByType = null;
 
+	public static $actionTypes = array(
+		Piwik_Tracker_Action::TYPE_ACTION_URL,
+		Piwik_Tracker_Action::TYPE_OUTLINK,
+		Piwik_Tracker_Action::TYPE_DOWNLOAD,
+		Piwik_Tracker_Action::TYPE_ACTION_NAME,
+	);
 
 	static protected $invalidSummedColumnNameToRenamedNameFromPeriodArchive = array(
 		Piwik_Archive::INDEX_NB_UNIQ_VISITORS => Piwik_Archive::INDEX_SUM_DAILY_NB_UNIQ_VISITORS,
@@ -80,6 +81,7 @@ class Piwik_Actions_Archiving
 		$rankingQueryLimit = self::getRankingQueryLimit();
 		Piwik_Actions_ArchivingHelper::reloadConfig();
 
+		$this->initActionsTables();
 		$this->archiveDayActions($archiveProcessing, $rankingQueryLimit);
 		$this->archiveDayEntryActions($archiveProcessing, $rankingQueryLimit);
 		$this->archiveDayExitActions($archiveProcessing, $rankingQueryLimit);
@@ -297,7 +299,7 @@ class Piwik_Actions_Archiving
 	{
 		Piwik_Actions_ArchivingHelper::clearActionsCache();
 
-		$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_URL]);
+		$dataTable = $this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_URL];
 		self::deleteInvalidSummedColumnsFromDataTable($dataTable);
 		$s = $dataTable->getSerialized( Piwik_Actions_ArchivingHelper::$maximumRowsInDataTableLevelZero, Piwik_Actions_ArchivingHelper::$maximumRowsInSubDataTable, Piwik_Actions_ArchivingHelper::$columnToSortByBeforeTruncation );
 		$archiveProcessing->insertBlobRecord('Actions_actions_url', $s);
@@ -305,7 +307,7 @@ class Piwik_Actions_Archiving
 		$archiveProcessing->insertNumericRecord('Actions_nb_uniq_pageviews', array_sum($dataTable->getColumn(Piwik_Archive::INDEX_NB_VISITS)));
 		destroy($dataTable);
 
-		$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]);
+		$dataTable = $this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD];
 		self::deleteInvalidSummedColumnsFromDataTable($dataTable);
 		$s = $dataTable->getSerialized(Piwik_Actions_ArchivingHelper::$maximumRowsInDataTableLevelZero, Piwik_Actions_ArchivingHelper::$maximumRowsInSubDataTable, Piwik_Actions_ArchivingHelper::$columnToSortByBeforeTruncation );
 		$archiveProcessing->insertBlobRecord('Actions_downloads', $s);
@@ -313,7 +315,7 @@ class Piwik_Actions_Archiving
 		$archiveProcessing->insertNumericRecord('Actions_nb_uniq_downloads', array_sum($dataTable->getColumn(Piwik_Archive::INDEX_NB_VISITS)));
 		destroy($dataTable);
 
-		$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
+		$dataTable = $this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK];
 		self::deleteInvalidSummedColumnsFromDataTable($dataTable);
 		$s = $dataTable->getSerialized( Piwik_Actions_ArchivingHelper::$maximumRowsInDataTableLevelZero, Piwik_Actions_ArchivingHelper::$maximumRowsInSubDataTable, Piwik_Actions_ArchivingHelper::$columnToSortByBeforeTruncation );
 		$archiveProcessing->insertBlobRecord('Actions_outlink', $s);
@@ -321,7 +323,7 @@ class Piwik_Actions_Archiving
 		$archiveProcessing->insertNumericRecord('Actions_nb_uniq_outlinks', array_sum($dataTable->getColumn(Piwik_Archive::INDEX_NB_VISITS)));
 		destroy($dataTable);
 
-		$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_NAME]);
+		$dataTable = $this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_NAME];
 		self::deleteInvalidSummedColumnsFromDataTable($dataTable);
 		$s = $dataTable->getSerialized( Piwik_Actions_ArchivingHelper::$maximumRowsInDataTableLevelZero, Piwik_Actions_ArchivingHelper::$maximumRowsInSubDataTable, Piwik_Actions_ArchivingHelper::$columnToSortByBeforeTruncation );
 		$archiveProcessing->insertBlobRecord('Actions_actions', $s);
@@ -408,18 +410,37 @@ class Piwik_Actions_Archiving
 			if(($idSubtable = $row->getIdSubDataTable()) !== null
 				|| $id === Piwik_DataTable::ID_SUMMARY_ROW)
 			{
-				foreach(self::$invalidSummedColumnNameToDeleteFromDayArchive as $name)
-				{
-					$row->deleteColumn($name);
-				}
-
 				if ($idSubtable !== null)
 				{
 					$subtable = Piwik_DataTable_Manager::getInstance()->getTable($idSubtable);
 					self::deleteInvalidSummedColumnsFromDataTable($subtable);
 				}
+				
+				if ($row instanceof Piwik_DataTable_Row_DataTableSummary)
+				{
+					$row->recalculate();
+				}
+				
+				foreach(self::$invalidSummedColumnNameToDeleteFromDayArchive as $name)
+				{
+					$row->deleteColumn($name);
+				}
 			}
 		}
 	}
 
+	/**
+	 * Initializes the DataTables created by the archiveDay function.
+	 */
+	private function initActionsTables()
+	{
+		$this->actionsTablesByType = array();
+		foreach (self::$actionTypes as $type)
+		{
+			$dataTable = new Piwik_DataTable();
+			$dataTable->setMaximumAllowedRows(Piwik_Actions_ArchivingHelper::$maximumRowsInDataTableLevelZero);
+			
+			$this->actionsTablesByType[$type] = $dataTable;
+		}
+	}
 }
diff --git a/plugins/Actions/ArchivingHelper.php b/plugins/Actions/ArchivingHelper.php
index 8aa2baeb587f6a761a48e1691a3dd5b3ad64a56c..a7eaeba9bfdbb98af4e3aa1f1f9233539c44db10 100644
--- a/plugins/Actions/ArchivingHelper.php
+++ b/plugins/Actions/ArchivingHelper.php
@@ -21,7 +21,7 @@
 class Piwik_Actions_ArchivingHelper
 {
 	const OTHERS_ROW_KEY = '';
-
+	
 	/**
 	 * @param Zend_Db_Statement|PDOStatement $query
 	 * @param string|bool $fieldQueried
@@ -189,7 +189,8 @@ class Piwik_Actions_ArchivingHelper
 	 * @param array $actionsTablesByType
 	 * @return Piwik_DataTable
 	 */
-	protected function parseActionNameCategoriesInDataTable($actionName, $actionType, $urlPrefix=null, &$actionsTablesByType)
+	protected static function parseActionNameCategoriesInDataTable( 
+		$actionName, $actionType, $urlPrefix=null, &$actionsTablesByType )
 	{
 		// we work on the root table of the given TYPE (either ACTION_URL or DOWNLOAD or OUTLINK etc.)
 		$currentTable =& $actionsTablesByType[$actionType];
@@ -197,45 +198,33 @@ class Piwik_Actions_ArchivingHelper
 		// check for ranking query cut-off
 		if ($actionName == Piwik_DataTable::LABEL_SUMMARY_ROW)
 		{
-			return self::createOthersRow($currentTable, $actionType);
+			$summaryRow = $currentTable->getRowFromId(Piwik_DataTable::ID_SUMMARY_ROW);
+			if ($summaryRow === false)
+			{
+				$summaryRow = $currentTable->addSummaryRow(self::createSummaryRow());
+			}
+			return $summaryRow;
 		}
 
 		// go to the level of the subcategory
 		$actionExplodedNames = self::getActionExplodedNames($actionName, $actionType, $urlPrefix);
-		$end = count($actionExplodedNames)-1;
-		$maxRows = self::$maximumRowsInDataTableLevelZero;
-		for($level = 0 ; $level < $end; $level++)
+		list($row, $level) = $currentTable->walkPath(
+			$actionExplodedNames, self::getDefaultRowColumns(), self::$maximumRowsInSubDataTable);
+		
+		// if we didn't traverse the entire path, the table the action belongs to is full, so we
+		// found a summary row. we don't set metadata on that row.
+		if ($level != count($actionExplodedNames))
 		{
-			$actionCategory = $actionExplodedNames[$level];
-
-			$othersRow = self::getOthersRowIfTableFull($currentTable, $actionCategory, $actionType, $maxRows);
-			if ($othersRow)
-			{
-				return $othersRow;
-			}
-
-			$currentTable =& $currentTable[$actionCategory];
-			$maxRows = self::$maximumRowsInSubDataTable;
+			return $row;
 		}
-		$actionShortName = $actionExplodedNames[$end];
-
-		$othersRow = self::getOthersRowIfTableFull($currentTable, $actionShortName, $actionType, $maxRows);
-		if ($othersRow)
+		
+		// if the action type is a URL type, set the url as metadata
+		if ($actionType != Piwik_Tracker_Action::TYPE_ACTION_NAME)
 		{
-			return $othersRow;
+			$row->setMetadata('url', Piwik_Tracker_Action::reconstructNormalizedUrl((string)$actionName, $urlPrefix));
 		}
-
-		// currentTable is now the array element corresponding the the action
-		// at this point we may be for example at the 4th level of depth in the hierarchy
-		$currentTable =& $currentTable[$actionShortName];
-
-		// add the row to the matching sub category subtable
-		if(!($currentTable instanceof Piwik_DataTable_Row))
-		{
-			$currentTable = self::createActionsTableRow(
-				(string)$actionShortName, $actionType, $actionName, $urlPrefix);
-		}
-		return $currentTable;
+		
+		return $row;
 	}
 
 	/**
@@ -530,4 +519,29 @@ class Piwik_Actions_ArchivingHelper
 		self::$cacheParsedAction[$cacheLabel] = $actionRow;
 	}
 
+	/**
+	 * Returns the default columns for a row in an Actions DataTable.
+	 * 
+	 * @return array
+	 */
+	private static function getDefaultRowColumns()
+	{
+		return array(Piwik_Archive::INDEX_NB_VISITS => 0,
+					  Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 0,
+					  Piwik_Archive::INDEX_PAGE_NB_HITS => 0,
+					  Piwik_Archive::INDEX_PAGE_SUM_TIME_SPENT => 0);
+	}
+	
+	/**
+	 * Creates a summary row for an Actions DataTable.
+	 * 
+	 * @return array
+	 */
+	private static function createSummaryRow()
+	{
+		return new Piwik_DataTable_Row(array(
+			Piwik_DataTable_Row::COLUMNS => 
+				array('label' => Piwik_DataTable::LABEL_SUMMARY_ROW) + self::getDefaultRowColumns()
+		));
+	}
 }