Commit e6e8da1f authored by Sebastian Kummer's avatar Sebastian Kummer

Merge pull request #242 in ZP/z-push from...

Merge pull request #242 in ZP/z-push from feature/ZP-835-istatemachine-cleanstates-should-get to develop

* commit '1ad4e7c8':
  ZP-835 Added new parameter to the IStateMachine->CleanStates() that indicates if only the defined counter should be deleted, implemented new flag in file state machine and sql state machine, introduced Sql->returnNullified() to nullify false keys and Sql->getSQLOp() to have the operator determination at one place, added logging to the file->db migration script, changed ZPushAdmin->RemoveDevice() to use the new flag, Utils::PrintAsString() understands "null" now.
parents df6fc45e 1ad4e7c8
...@@ -178,12 +178,13 @@ class SqlStateMachine implements IStateMachine { ...@@ -178,12 +178,13 @@ class SqlStateMachine implements IStateMachine {
* @return mixed * @return mixed
* @throws StateNotFoundException, StateInvalidException, UnavailableException * @throws StateNotFoundException, StateInvalidException, UnavailableException
*/ */
public function GetState($devid, $type, $key = null, $counter = false, $cleanstates = true) { public function GetState($devid, $type, $key = false, $counter = false, $cleanstates = true) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SqlStateMachine->GetState(): devid:'%s' type:'%s' key:'%s' counter:'%s'", $devid, $type, ($key == null ? 'null' : $key), Utils::PrintAsString($counter), Utils::PrintAsString($cleanstates))); $key = $this->returnNullified($key);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SqlStateMachine->GetState(): devid:'%s' type:'%s' key:'%s' counter:'%s'", $devid, $type, Utils::PrintAsString($key), Utils::PrintAsString($counter), Utils::PrintAsString($cleanstates)));
if ($counter && $cleanstates) if ($counter && $cleanstates)
$this->CleanStates($devid, $type, $key, $counter); $this->CleanStates($devid, $type, $key, $counter);
$sql = "SELECT state_data FROM states WHERE device_id = :devid AND state_type = :type AND uuid ". (($key == null) ? " IS " : " = ") . ":key AND counter = :counter"; $sql = "SELECT state_data FROM states WHERE device_id = :devid AND state_type = :type AND uuid". $this->getSQLOp($key) .":key AND counter = :counter";
$params = $this->getParams($devid, $type, $key, $counter); $params = $this->getParams($devid, $type, $key, $counter);
$data = null; $data = null;
...@@ -232,10 +233,11 @@ class SqlStateMachine implements IStateMachine { ...@@ -232,10 +233,11 @@ class SqlStateMachine implements IStateMachine {
* @return boolean * @return boolean
* @throws StateInvalidException, UnavailableException * @throws StateInvalidException, UnavailableException
*/ */
public function SetState($state, $devid, $type, $key = null, $counter = false) { public function SetState($state, $devid, $type, $key = false, $counter = false) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SqlStateMachine->SetState(): devid:'%s' type:'%s' key:'%s' counter:'%s'", $devid, $type, ($key == null ? 'null' : $key), Utils::PrintAsString($counter))); $key = $this->returnNullified($key);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SqlStateMachine->SetState(): devid:'%s' type:'%s' key:'%s' counter:'%s'", $devid, $type, Utils::PrintAsString($key), Utils::PrintAsString($counter)));
$sql = "SELECT device_id FROM states WHERE device_id = :devid AND state_type = :type AND uuid ". (($key == null) ? " IS " : " = ") . ":key AND counter = :counter"; $sql = "SELECT device_id FROM states WHERE device_id = :devid AND state_type = :type AND uuid". $this->getSQLOp($key) .":key AND counter = :counter";
$params = $this->getParams($devid, $type, $key, $counter); $params = $this->getParams($devid, $type, $key, $counter);
$sth = null; $sth = null;
...@@ -256,7 +258,7 @@ class SqlStateMachine implements IStateMachine { ...@@ -256,7 +258,7 @@ class SqlStateMachine implements IStateMachine {
} }
else { else {
// Existing record, we update it // Existing record, we update it
$sql = "UPDATE states SET state_data = :data, updated_at = :updated_at WHERE device_id = :devid AND state_type = :type AND uuid " . (($key == null) ? " IS " : " = ") .":key AND counter = :counter"; $sql = "UPDATE states SET state_data = :data, updated_at = :updated_at WHERE device_id = :devid AND state_type = :type AND uuid ". $this->getSQLOp($key) .":key AND counter = :counter";
$sth = $this->getDbh()->prepare($sql); $sth = $this->getDbh()->prepare($sql);
} }
...@@ -288,27 +290,32 @@ class SqlStateMachine implements IStateMachine { ...@@ -288,27 +290,32 @@ class SqlStateMachine implements IStateMachine {
/** /**
* Cleans up all older states. * Cleans up all older states.
* If called with a $counter, all states previous state counter can be removed. * If called with a $counter, all states previous state counter can be removed.
* If additionally the $thisCounterOnly flag is true, only that specific counter will be removed.
* If called without $counter, all keys (independently from the counter) can be removed. * If called without $counter, all keys (independently from the counter) can be removed.
* *
* @param string $devid the device id * @param string $devid the device id
* @param string $type the state type * @param string $type the state type
* @param string $key * @param string $key
* @param string $counter (opt) * @param string $counter (opt)
* @param string $thisCounterOnly (opt) if provided, the exact counter only will be removed
* *
* @access public * @access public
* @return * @return
* @throws StateInvalidException * @throws StateInvalidException
*/ */
public function CleanStates($devid, $type, $key = null, $counter = false) { public function CleanStates($devid, $type, $key, $counter = false, $thisCounterOnly = false) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SqlStateMachine->CleanStates(): devid:'%s' type:'%s' key:'%s' counter:'%s'", $devid, $type, ($key == null ? 'null' : $key), Utils::PrintAsString($counter))); $key = $this->returnNullified($key);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SqlStateMachine->CleanStates(): devid:'%s' type:'%s' key:'%s' counter:'%s' thisCounterOnly:'%s'", $devid, $type, Utils::PrintAsString($key), Utils::PrintAsString($counter), Utils::PrintAsString($thisCounterOnly)));
if ($counter === false) { if ($counter === false) {
// Remove all the states. Counter are -1 or > 0, then deleting >= -1 deletes all // Remove all the states. Counter are 0 or >0, then deleting >= 0 deletes all
$sql = "DELETE FROM states WHERE device_id = :devid AND state_type = :type AND uuid = :key AND counter >= :counter"; $sql = "DELETE FROM states WHERE device_id = :devid AND state_type = :type AND uuid". $this->getSQLOp($key) .":key AND counter >= :counter";
}
else if ($counter !== false && $thisCounterOnly === true) {
$sql = "DELETE FROM states WHERE device_id = :devid AND state_type = :type AND uuid". $this->getSQLOp($key).":key AND counter = :counter";
} }
else { else {
$sql = "DELETE FROM states WHERE device_id = :devid AND state_type = :type AND uuid = :key AND counter < :counter"; $sql = "DELETE FROM states WHERE device_id = :devid AND state_type = :type AND uuid". $this->getSQLOp($key) .":key AND counter < :counter";
} }
$params = $this->getParams($devid, $type, $key, $counter); $params = $this->getParams($devid, $type, $key, $counter);
...@@ -636,6 +643,35 @@ class SqlStateMachine implements IStateMachine { ...@@ -636,6 +643,35 @@ class SqlStateMachine implements IStateMachine {
return array(":devid" => $devid, ":type" => $type, ":key" => $key, ":counter" => ($counter === false ? 0 : $counter) ); return array(":devid" => $devid, ":type" => $type, ":key" => $key, ":counter" => ($counter === false ? 0 : $counter) );
} }
/**
* Returns the SQL operator for the parameter.
* If the parameter is null then " IS " is returned, else " = ".
*
* @param mixed $param
*
* @access private
* @return string
*/
private function getSQLOp($param) {
if ($param == null) {
return " IS ";
}
return " = ";
}
/**
* Returns "null" if the parameter is false, else the parameter.
*
* @param mixed $param
* @return NULL|mixed
*/
private function returnNullified($param) {
if ($param === false) {
return null;
}
return $param;
}
/** /**
* Free PDO resources. * Free PDO resources.
* *
......
...@@ -162,37 +162,28 @@ class FileStateMachine implements IStateMachine { ...@@ -162,37 +162,28 @@ class FileStateMachine implements IStateMachine {
} }
/** /**
* Cleans up all older states * Cleans up all older states.
* If called with a $counter, all states previous state counter can be removed * If called with a $counter, all states previous state counter can be removed.
* If called without $counter, all keys (independently from the counter) can be removed * If additionally the $thisCounterOnly flag is true, only that specific counter will be removed.
* If called without $counter, all keys (independently from the counter) can be removed.
* *
* @param string $devid the device id * @param string $devid the device id
* @param string $type the state type * @param string $type the state type
* @param string $key * @param string $key
* @param string $counter (opt) * @param string $counter (opt)
* @param string $thisCounterOnly (opt) if provided, the exact counter only will be removed
* *
* @access public * @access public
* @return * @return
* @throws StateInvalidException * @throws StateInvalidException
*/ */
public function CleanStates($devid, $type, $key, $counter = false) { public function CleanStates($devid, $type, $key, $counter = false, $thisCounterOnly = false) {
// Remove permanent backend storage files
// TODO remove this block and implement it as described in ZP-835
if ($key === false && $type === IStateMachine::BACKENDSTORAGE) {
$file = $this->getFullFilePath($devid, $type, $key, $counter);
if (file_exists($file)) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("FileStateMachine->CleanStates(): Deleting 'bs' file: '%s'", $file));
unlink($file);
return;
}
}
$matching_files = glob($this->getFullFilePath($devid, $type, $key). "*", GLOB_NOSORT); $matching_files = glob($this->getFullFilePath($devid, $type, $key). "*", GLOB_NOSORT);
if (is_array($matching_files)) { if (is_array($matching_files)) {
foreach($matching_files as $state) { foreach($matching_files as $state) {
$file = false; $file = false;
if($counter !== false && preg_match('/([0-9]+)$/', $state, $matches)) { if($counter !== false && preg_match('/([0-9]+)$/', $state, $matches)) {
if($matches[1] < $counter) { if(($thisCounterOnly === false && $matches[1] < $counter) || ($thisCounterOnly === true && $matches[1] == $counter)) {
$candidate = $this->getFullFilePath($devid, $type, $key, (int)$matches[1]); $candidate = $this->getFullFilePath($devid, $type, $key, (int)$matches[1]);
if ($candidate == $state) if ($candidate == $state)
...@@ -410,8 +401,10 @@ class FileStateMachine implements IStateMachine { ...@@ -410,8 +401,10 @@ class FileStateMachine implements IStateMachine {
isset($parts[1]) && strlen($parts[1]) == 4 && isset($parts[1]) && strlen($parts[1]) == 4 &&
isset($parts[2]) && strlen($parts[2]) == 4 && isset($parts[2]) && strlen($parts[2]) == 4 &&
isset($parts[3]) && strlen($parts[3]) == 4 && isset($parts[3]) && strlen($parts[3]) == 4 &&
isset($parts[4]) && strlen($parts[4]) == 12) isset($parts[4]) && strlen($parts[4]) == 12) {
$state['uuid'] = $parts[0]."-".$parts[1]."-".$parts[2]."-".$parts[3]."-".$parts[4]; $state['uuid'] = $parts[0]."-".$parts[1]."-".$parts[2]."-".$parts[3]."-".$parts[4];
}
if (isset($parts[5]) && is_numeric($parts[5])) { if (isset($parts[5]) && is_numeric($parts[5])) {
$state['counter'] = $parts[5]; $state['counter'] = $parts[5];
...@@ -419,14 +412,20 @@ class FileStateMachine implements IStateMachine { ...@@ -419,14 +412,20 @@ class FileStateMachine implements IStateMachine {
} }
if (isset($parts[5])) { if (isset($parts[5])) {
if (is_int($parts[5])) if (is_int($parts[5])) {
$state['counter'] = $parts[5]; $state['counter'] = $parts[5];
}
else if (in_array($parts[5], $types)) else if (in_array($parts[5], $types)) {
$state['type'] = $parts[5]; $state['type'] = $parts[5];
}
} }
if (isset($parts[6]) && is_numeric($parts[6])) if (isset($parts[6]) && is_numeric($parts[6])) {
$state['counter'] = $parts[6]; $state['counter'] = $parts[6];
}
// Permanent BS are recognized here
if($state['counter'] == false && $state['uuid'] == false && isset($parts[1]) && is_numeric($parts[1])) {
$state['counter'] = $parts[1];
}
$out[] = $state; $out[] = $state;
} }
......
...@@ -119,20 +119,22 @@ interface IStateMachine { ...@@ -119,20 +119,22 @@ interface IStateMachine {
public function SetState($state, $devid, $type, $key = false, $counter = false); public function SetState($state, $devid, $type, $key = false, $counter = false);
/** /**
* Cleans up all older states * Cleans up all older states.
* If called with a $counter, all states previous state counter can be removed * If called with a $counter, all states previous state counter can be removed.
* If called without $counter, all keys (independently from the counter) can be removed * If additionally the $thisCounterOnly flag is true, only that specific counter will be removed.
* If called without $counter, all keys (independently from the counter) can be removed.
* *
* @param string $devid the device id * @param string $devid the device id
* @param string $type the state type * @param string $type the state type
* @param string $key * @param string $key
* @param string $counter (opt) * @param string $counter (opt)
* @param string $thisCounterOnly (opt) if provided, the exact counter only will be removed
* *
* @access public * @access public
* @return * @return
* @throws StateInvalidException * @throws StateInvalidException
*/ */
public function CleanStates($devid, $type, $key, $counter = false); public function CleanStates($devid, $type, $key, $counter = false, $thisCounterOnly = false);
/** /**
* Links a user to a device * Links a user to a device
......
...@@ -51,7 +51,7 @@ class Utils { ...@@ -51,7 +51,7 @@ class Utils {
* @return string * @return string
*/ */
static public function PrintAsString($var) { static public function PrintAsString($var) {
return ($var)?(($var===true)?'true':$var):(($var===false)?'false':(($var==='')?'empty':$var)); return ($var)?(($var===true)?'true':$var):(($var===false)?'false':(($var==='')?'empty':(($var == null) ? 'null':$var)));
//return ($var)?(($var===true)?'true':$var):'false'; //return ($var)?(($var===true)?'true':$var):'false';
} }
......
...@@ -282,7 +282,7 @@ class ZPushAdmin { ...@@ -282,7 +282,7 @@ class ZPushAdmin {
StateManager::UnLinkState($device, false); StateManager::UnLinkState($device, false);
// remove backend storage permanent data // remove backend storage permanent data
ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, false, $device->GetFirstSyncTime()); ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, false, $device->GetFirstSyncTime(), true);
// remove devicedata and unlink user from device // remove devicedata and unlink user from device
unset($devices[$user]); unset($devices[$user]);
......
...@@ -148,6 +148,7 @@ class StateMigratorFileToDB { ...@@ -148,6 +148,7 @@ class StateMigratorFileToDB {
printf("Processing device: %s with %s states\t", str_pad($devid,35), str_pad(count($allStates), 4, ' ',STR_PAD_LEFT)); printf("Processing device: %s with %s states\t", str_pad($devid,35), str_pad(count($allStates), 4, ' ',STR_PAD_LEFT));
$migrated = 0; $migrated = 0;
foreach ($allStates as $stateInfo) { foreach ($allStates as $stateInfo) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("StateMigratorFileToDB->DoMigration(): Migrating state type:'%s' uuid:'%s' counter:'%s'", Utils::PrintAsString($stateInfo['type']), Utils::PrintAsString($stateInfo['uuid']), Utils::PrintAsString($stateInfo['counter'])));
$state = $this->fsm->GetState($lowerDevid, $stateInfo['type'], $stateInfo['uuid'], (int) $stateInfo['counter'], false); $state = $this->fsm->GetState($lowerDevid, $stateInfo['type'], $stateInfo['uuid'], (int) $stateInfo['counter'], false);
$this->dbsm->SetState($state, $lowerDevid, $stateInfo['type'], (empty($stateInfo['uuid']) ? NULL : $stateInfo['uuid']), (int) $stateInfo['counter']); $this->dbsm->SetState($state, $lowerDevid, $stateInfo['type'], (empty($stateInfo['uuid']) ? NULL : $stateInfo['uuid']), (int) $stateInfo['counter']);
$migrated++; $migrated++;
...@@ -170,4 +171,4 @@ class StateMigratorFileToDB { ...@@ -170,4 +171,4 @@ class StateMigratorFileToDB {
$timeSpent = gmdate("H:i:s", time() - $starttime); $timeSpent = gmdate("H:i:s", time() - $starttime);
printf(PHP_EOL ."StateMigratorFileToDB->DoMigration(): Migration completed successfuly. Migrated %d devices with %d states in %s.".PHP_EOL.PHP_EOL, $deviceCount, $stateCount, $timeSpent); printf(PHP_EOL ."StateMigratorFileToDB->DoMigration(): Migration completed successfuly. Migrated %d devices with %d states in %s.".PHP_EOL.PHP_EOL, $deviceCount, $stateCount, $timeSpent);
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment