added multi process support to Calendar_Frontend_Cli
authorPaul Mehrer <p.mehrer@metaways.de>
Mon, 11 Aug 2014 14:04:14 +0000 (16:04 +0200)
committerPhilipp Schüle <p.schuele@metaways.de>
Thu, 4 Sep 2014 09:26:40 +0000 (11:26 +0200)
Change-Id: I1ae7eb1d200b3b4bc57ba8b1f5030d9f832a814b
Reviewed-on: http://gerrit.tine20.com/customers/963
Tested-by: Jenkins CI (http://ci.tine20.com/)
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
tine20/Calendar/Frontend/Cli.php
tine20/Calendar/Import/CalDav/Client.php

index e531aad..0b50841 100644 (file)
@@ -154,7 +154,7 @@ class Calendar_Frontend_Cli extends Tinebase_Frontend_Cli_Abstract
     }
     
     /**
-     * import calendar/events from a CalDav source
+     * import calendars from a CalDav source
      * 
      * param Zend_Console_Getopt $_opts
      */
@@ -175,7 +175,7 @@ class Calendar_Frontend_Cli extends Tinebase_Frontend_Cli_Abstract
     }
     
     /**
-     * import calendar/events from a CalDav source
+     * import calendar events from a CalDav source
      * 
      * param Zend_Console_Getopt $_opts
      */
@@ -196,6 +196,199 @@ class Calendar_Frontend_Cli extends Tinebase_Frontend_Cli_Abstract
     }
     
     /**
+     * import calendars and calendar events from a CalDav source using multiple parallel processes
+     * 
+     * param Zend_Console_Getopt $_opts
+     */
+    public function importCalDavMultiProc(Zend_Console_Getopt $_opts)
+    {
+        $args = $this->_parseArgs($_opts, array('url', 'caldavuserfile', 'numProc'));
+        
+        $numProc = intval($args['numProc']);
+        if ($numProc < 1) {
+            throw new Exception('numProc: ' . $numProc . ' needs to be at least 1');
+        }
+        if ($numProc > 32) {
+            throw new Exception('numProc: ' . $numProc . ' needs to be lower than 33');
+        }
+        
+        $opts = Tinebase_Core::get('opts');
+        if (empty($opts->passwordfile)) {
+            throw new Exception('Passwordfile requried for this method');
+        }
+        
+        $writer = new Zend_Log_Writer_Stream('php://output');
+        $writer->addFilter(new Zend_Log_Filter_Priority(4));
+        Tinebase_Core::getLogger()->addWriter($writer);
+        
+        $users = $this->_readCalDavUserFile($args['caldavuserfile']);
+        
+        //first import the calendars, serial sadly
+        $client = new Calendar_Import_CalDav_Client(array('baseUri' => $args['url']), 'MacOSX');
+        $client->setVerifyPeer(false);
+        
+        $client->importAllCalendarsForUsers($users);
+        
+        //then do multiprocess part, no system resources may be used as of here, like file handles, db resources... see pcntl_fork man page!
+        for ($run = 1; $run < 3; ++$run)
+        {
+            $processes = array();
+            $line = 0;
+            foreach ($users as $user => $pwd)
+            {
+                ++$line;
+                if (count($processes) >= $numProc) {
+                    $pid = pcntl_wait($status);
+                    if (!isset($processes[$pid])) {
+                        exit('pcntl_wait return value was not found in process list: ' . $pid . ' status: ' . $status . PHP_EOL);
+                    }
+                    unset($processes[$pid]);
+                }
+                
+                $pid = pcntl_fork();
+                if ($pid == -1) {
+                     exit('could not fork' . PHP_EOL);
+                } else if ($pid) {
+                     // we are the parent
+                     $processes[$pid] = true;
+                } else {
+                    // we are the child
+                    exec('./tine20.php --username ' . $opts->username . ' --passwordfile ' . $opts->passwordfile . ' --method Calendar.importCalDavDataForUser url="https://ical.familienservice.de:8443" caldavuserfile=caldavuserfile.csv run=' . $run . ' line=' . $line);
+                    exit();
+                }
+            }
+            //wait for childs to finish
+            while (count($processes) > 0) {
+                $pid = pcntl_wait($status);
+                if (!isset($processes[$pid])) {
+                    exit('pcntl_wait return value was not found in process list: ' . $pid . ' status: ' . $status . PHP_EOL);
+                }
+                unset($processes[$pid]);
+            }
+        }
+    }
+    
+    /**
+     * update calendar events from a CalDav source using multiple parallel processes
+     * 
+     * param Zend_Console_Getopt $_opts
+     */
+    public function updateCalDavMultiProc(Zend_Console_Getopt $_opts)
+    {
+        $args = $this->_parseArgs($_opts, array('url', 'caldavuserfile', 'numProc'));
+        
+        $numProc = intval($args['numProc']);
+        if ($numProc < 1) {
+            throw new Exception('numProc: ' . $numProc . ' needs to be at least 1');
+        }
+        if ($numProc > 32) {
+            throw new Exception('numProc: ' . $numProc . ' needs to be lower than 33');
+        }
+        
+        $opts = Tinebase_Core::get('opts');
+        if (empty($opts->passwordfile)) {
+            throw new Exception('Passwordfile requried for this method');
+        }
+        
+        $writer = new Zend_Log_Writer_Stream('php://output');
+        $writer->addFilter(new Zend_Log_Filter_Priority(4));
+        Tinebase_Core::getLogger()->addWriter($writer);
+        
+        $users = $this->_readCalDavUserFile($args['caldavuserfile']);
+        
+        //do multiprocess part, no system resources may be used as of here, like file handles, db resources... see pcntl_fork man page!
+        for ($run = 1; $run < 3; ++$run)
+        {
+            $processes = array();
+            $line = 0;
+            foreach ($users as $user => $pwd)
+            {
+                ++$line;
+                if (count($processes) >= $numProc) {
+                    $pid = pcntl_wait($status);
+                    if (!isset($processes[$pid])) {
+                        exit('pcntl_wait return value was not found in process list: ' . $pid . ' status: ' . $status . PHP_EOL);
+                    }
+                    unset($processes[$pid]);
+                }
+                
+                $pid = pcntl_fork();
+                if ($pid == -1) {
+                     exit('could not fork' . PHP_EOL);
+                } else if ($pid) {
+                     // we are the parent
+                     $processes[$pid] = true;
+                } else {
+                    // we are the child
+                    exec('./tine20.php --username ' . $opts->username . ' --passwordfile ' . $opts->passwordfile . ' --method Calendar.updateCalDavDataForUser url="https://ical.familienservice.de:8443" caldavuserfile=caldavuserfile.csv run=' . $run . ' line=' . $line);
+                    exit();
+                }
+            }
+            //wait for childs to finish
+            while (count($processes) > 0) {
+                $pid = pcntl_wait($status);
+                if (!isset($processes[$pid])) {
+                    exit('pcntl_wait return value was not found in process list: ' . $pid . ' status: ' . $status . PHP_EOL);
+                }
+                unset($processes[$pid]);
+            }
+        }
+    }
+    
+    /**
+     * import calendar events from a CalDav source for one user
+     * 
+     * param Zend_Console_Getopt $_opts
+     */
+    public function importCalDavDataForUser(Zend_Console_Getopt $_opts)
+    {
+        $args = $this->_parseArgs($_opts, array('url', 'caldavuserfile', 'line', 'run'));
+        
+        $writer = new Zend_Log_Writer_Stream('php://output');
+        $writer->addFilter(new Zend_Log_Filter_Priority(4));
+        Tinebase_Core::getLogger()->addWriter($writer);
+        
+        if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
+            Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' in importCalDavDataForUser');
+        
+        $user = $this->_readCalDavUserFile($args['caldavuserfile'], $args['line']);
+        
+        $client = new Calendar_Import_CalDav_Client(array(
+                'baseUri' => $args['url'],
+                'userName' => $user['username'],
+                'password' => $user['password'],
+                ), 'MacOSX');
+        $client->setVerifyPeer(false);
+        
+        $client->importAllCalendarData($args['run']==1?true:false);
+    }
+    
+    /**
+     * update calendar/events from a CalDav source using etags for one user
+     * 
+     * param Zend_Console_Getopt $_opts
+     */
+    public function updateCalDavDataForUser(Zend_Console_Getopt $_opts)
+    {
+        $args = $this->_parseArgs($_opts, array('url', 'caldavuserfile', 'line', 'run'));
+        
+        $writer = new Zend_Log_Writer_Stream('php://output');
+        $writer->addFilter(new Zend_Log_Filter_Priority(4));
+        Tinebase_Core::getLogger()->addWriter($writer);
+        
+        $user = $this->_readCalDavUserFile($args['caldavuserfile'], $args['line']);
+        
+        $client = new Calendar_Import_CalDav_Client(array(
+                'baseUri' => $args['url'],
+                'userName' => $user['username'],
+                'password' => $user['password'],
+                ), 'MacOSX');
+        $client->setVerifyPeer(false);
+        
+        $client->updateAllCalendarData($args['run']==1?true:false);
+    }
+    
+    /**
      * update calendar/events from a CalDav source using etags
      * 
      * param Zend_Console_Getopt $_opts
@@ -226,23 +419,29 @@ class Calendar_Frontend_Cli extends Tinebase_Frontend_Cli_Abstract
      * @param string $file
      * @throws Exception
      */
-    protected function _readCalDavUserFile($file)
+    protected function _readCalDavUserFile($file, $line = 0)
     {
-        if (!($fh = fopen($file, 'r')))
-        {
-            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' couldn\'t open file: '.$file);
+        if (!($fh = fopen($file, 'r'))) {
+            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' Couldn\'t open file: '.$file);
             throw new Exception('Couldn\'t open file: '.$file);
         }
         $users = array();
+        $i = 0;
         while ($row = fgetcsv($fh, 2048, ';'))
         {
+            if ($line > 0 && ++$i == $line) {
+                return array('username' => $row[0], 'password' => $row[1]);
+            }
             $users[$row[0]] = $row[1];
         }
-        if (count($users) < 1)
-        {
-            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' no users found in: '.$file);
+        if (count($users) < 1) {
+            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' No users found in: '.$file);
             throw new Exception('No users found in: '.$file);
         }
+        if ($line > 0) {
+            Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' Line: '.$line. ' out of bounds');
+            throw new Exception('No user found, line: '.$line. ' out of bounds');
+        }
         return $users;
     }
 }
index 13358b4..f4a96ba 100644 (file)
@@ -1,7 +1,6 @@
 <?php
 //./tine20.php --username unittest --method Calendar.importCalDav url="https://osx-testfarm-mavericks-server.hh.metaways.de:8443" caldavuserfile=caldavuserfile.csv
 
-
 /**
  * Tine 2.0
  * 
@@ -10,8 +9,6 @@
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Paul Mehrer <p.mehrer@metaways.de>
  * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
- * 
- * @todo        
  */
 
 /**
@@ -19,7 +16,6 @@
  * 
  * @package     Calendar
  * @subpackage  Import
- * 
  */
 class Calendar_Import_CalDav_Client extends Tinebase_Import_CalDav_Client
 {
@@ -222,7 +218,7 @@ class Calendar_Import_CalDav_Client extends Tinebase_Import_CalDav_Client
         }
     }
     
-    public function updateAllCalendarData()
+    public function updateAllCalendarData($onlyCurrentUserOrganizer = false)
     {
         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs())
             return false;
@@ -268,7 +264,7 @@ class Calendar_Import_CalDav_Client extends Tinebase_Import_CalDav_Client
             if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' . $count . ' calendar(s) changed for: ' . $this->userName);
             $this->calendarICSs = $newICSs;
-            $this->importAllCalendarData();
+            $this->importAllCalendarData($onlyCurrentUserOrganizer);
         } else {
             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' no changes found for: ' . $this->userName);
@@ -446,9 +442,30 @@ class Calendar_Import_CalDav_Client extends Tinebase_Import_CalDav_Client
     
     public function updateAllCalendarDataForUsers(array $users)
     {
-        if (!$this->findCurrentUserPrincipalForUsers($users))
-            return false;
-        
+        // first only update/import events where the current user is also the organizer
+        $result = true;
+        foreach ($users as $username => $pwd) {
+            $this->clearCurrentUserCalendarData();
+            $this->userName = $username;
+            $this->password = $pwd;
+            if (!$this->updateAllCalendarData(true)) {
+                $result = false;
+            }
+        }
+        // then update all events again
+        foreach ($users as $username => $pwd) {
+            $this->clearCurrentUserCalendarData();
+            $this->userName = $username;
+            $this->password = $pwd;
+            if (!$this->updateAllCalendarData(false)) {
+                $result = false;
+            }
+        }
+        return $result;
+    }
+    
+    public function importAllCalendarDataForUsers(array $users)
+    {
         $result = true;
         foreach ($users as $username => $pwd) {
             $this->clearCurrentUserCalendarData();