0012028: Tinebase Filesystem - deleting applications clean up
authorPaul Mehrer <p.mehrer@metaways.de>
Thu, 30 Jun 2016 14:53:46 +0000 (16:53 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Mon, 11 Jul 2016 11:09:01 +0000 (13:09 +0200)
on deleting an application, filesystem artifacts will now be
cleaned up

also FS <-> DB sync utility now iterates over the file objects
in DB instead of fetching all at once due to OOM issue

https://forge.tine20.org/view.php?id=12028

Change-Id: Ia595d4cf721610528b23d4a1f58c952f0f13bd03
Reviewed-on: http://gerrit.tine20.com/customers/3293
Tested-by: Jenkins CI (http://ci.tine20.com/)
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
tine20/Tinebase/Application.php
tine20/Tinebase/FileSystem.php
tine20/Tinebase/Model/Tree/FileObject.php
tine20/Tinebase/Model/Tree/FileObjectFilter.php [new file with mode: 0644]

index 92e0799..a2f8b98 100644 (file)
@@ -489,6 +489,12 @@ class Tinebase_Application
      */
     public function removeApplicationData(Tinebase_Model_Application $_application)
     {
+        try {
+            Tinebase_FileSystem::getInstance()->rmdir($_application->getId(), true);
+        } catch (Tinebase_Exception_NotFound $tenf) {
+            // nothing to do
+        }
+
         $dataToDelete = array(
             'container'     => array('tablename' => ''),
             'config'        => array('tablename' => ''),
@@ -513,9 +519,9 @@ class Tinebase_Application
                 case 'config':
                     $count = Tinebase_Config::getInstance()->deleteConfigByApplicationId($_application->getId());
                     break;
-                  case 'customfield':
-                      $count = Tinebase_CustomField::getInstance()->deleteCustomFieldsForApplication($_application->getId());
-                      break;
+                case 'customfield':
+                    $count = Tinebase_CustomField::getInstance()->deleteCustomFieldsForApplication($_application->getId());
+                    break;
                 default:
                     if ((isset($info['tablename']) || array_key_exists('tablename', $info)) && ! empty($info['tablename'])) {
                         try {
index 4b4834b..9d5f6c6 100644 (file)
@@ -1204,15 +1204,29 @@ class Tinebase_FileSystem implements Tinebase_Controller_Interface
     {
         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
             . ' Scanning database for deleted files ...');
-        
+
         // get all file objects from db and check filesystem existance
+        $filter = new Tinebase_Model_Tree_FileObjectFilter();
+        $start = 0;
+        $limit = 500;
         $toDeleteIds = array();
-        $fileObjects = $this->_fileObjectBackend->getAll();
-        foreach ($fileObjects as $fileObject) {
-            if ($fileObject->type == Tinebase_Model_Tree_FileObject::TYPE_FILE && $fileObject->hash && ! file_exists($fileObject->getFilesystemPath())) {
-                $toDeleteIds[] = $fileObject->getId();
+
+        do {
+            $pagination = new Tinebase_Model_Pagination(array(
+                'start' => $start,
+                'limit' => $limit,
+                'sort' => 'id',
+            ));
+
+            $fileObjects = $this->_fileObjectBackend->search($filter, $pagination);
+            foreach ($fileObjects as $fileObject) {
+                if ($fileObject->type == Tinebase_Model_Tree_FileObject::TYPE_FILE && $fileObject->hash && !file_exists($fileObject->getFilesystemPath())) {
+                    $toDeleteIds[] = $fileObject->getId();
+                }
             }
-        }
+
+            $start += $limit;
+        } while ($fileObjects->count() >= $limit);
         
         $nodeIdsToDelete = $this->_treeNodeBackend->search(new Tinebase_Model_Tree_Node_Filter(array(array(
             'field'     => 'object_id',
index 54eef9f..15a4ed3 100644 (file)
@@ -94,6 +94,18 @@ class Tinebase_Model_Tree_FileObject extends Tinebase_Record_Abstract
         'last_modified_time',
         'deleted_time'
     );
+
+    protected static $_i = 0;
+
+    public function __construct($_data = NULL, $_bypassFilters = false, $_convertDates = true)
+    {
+        static::$_i += 1;
+
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
+                    . ' ' . $this->_i);
+
+        parent::__construct($_data, $_bypassFilters, $_convertDates);
+    }
     
     /**
      * converts a string or Addressbook_Model_List to a list id
diff --git a/tine20/Tinebase/Model/Tree/FileObjectFilter.php b/tine20/Tinebase/Model/Tree/FileObjectFilter.php
new file mode 100644 (file)
index 0000000..7843d2c
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Tinebase
+ * @subpackage  Filter
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Paul Mehrer <p.mehrer@metaways.de>
+ * @copyright   Copyright (c) 2016 Metaways Infosystems GmbH (http://www.metaways.de)
+ *
+ */
+
+/**
+ *  file object filter class
+ *
+ * @package     Tinebase
+ * @subpackage  Filter
+ */
+class Tinebase_Model_Tree_FileObjectFilter extends Tinebase_Model_Filter_FilterGroup
+{
+    /**
+     * @var string application of this filter group
+     */
+    protected $_applicationName = 'Tinebase';
+
+    /**
+     * @var string name of model this filter group is designed for
+     */
+    protected $_modelName = 'Tinebase_Model_Tree_FileObject';
+
+    /**
+     * @var string class name of this filter group
+     *      this is needed to overcome the static late binding
+     *      limitation in php < 5.3
+     */
+    protected $_className = 'Tinebase_Model_Tree_FileObjectFilter';
+
+    /**
+     * @var array filter model fieldName => definition
+     */
+    protected $_filterModel = array(
+    );
+}