Skip to content

Commit

Permalink
Use cache for options for #214
Browse files Browse the repository at this point in the history
  • Loading branch information
lvps committed Jan 9, 2022
1 parent d4d0095 commit dc13e1d
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 81 deletions.
10 changes: 10 additions & 0 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Database
private $treeDAO = null;
private $productDAO = null;
private $bulkDAO = null;
private $optionDAO = null;
private $username;
private $password;
private $dsn;
Expand Down Expand Up @@ -141,6 +142,15 @@ public function bulkDAO(): BulkDAO
return $this->bulkDAO;
}

public function optionDAO(): OptionDAO
{
if ($this->optionDAO === null) {
$this->optionDAO = new OptionDAO($this, $this->callback);
}

return $this->optionDAO;
}

public function updater()
{
return new Updater($this, $this->callback);
Expand Down
68 changes: 68 additions & 0 deletions src/Database/OptionDAO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace WEEEOpen\Tarallo\Database;

class OptionDAO extends DAO
{
private function getAllOptions(): array
{
$query = "SELECT `Key`, Value FROM Configuration";

$options = [];
$statement = $this->getPDO()->prepare($query);

try {
$success = $statement->execute();
assert($success, 'get all options');
while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
$options[$row['Key']] = $row['Value'];
}
} finally {
$statement->closeCursor();
}
return $options;
}

private function apcuGenerator($key)
{
return $this->getAllOptions();
}

public function getOptionValue(string $key)
{
if (Database::hasApcu()) {
$success = null;
$options = apcu_fetch('options', $success);
if (!$success) {
$options = apcu_entry('options', [$this, 'apcuGenerator']);
}
} else {
$options = $this->getAllOptions();
}

return $options[$key] ?? null;
}

public function setOptionValue(string $key, string $value)
{
$pdo = $this->getPDO();
$query = "INSERT INTO Configuration (`Key`, Value) VALUES (:k, :v) ON DUPLICATE KEY UPDATE Value = :v2";

$statement = $pdo->prepare($query);
$statement->bindValue(':k', $key);
$statement->bindValue(':v', $value);
$statement->bindValue(':v2', $value);

$success = false;
try {
$success = $statement->execute();
assert($success, 'new option');
} finally {
$statement->closeCursor();
}
if (Database::hasApcu() && $success) {
// Key will be generated on next read via apcu_entry which uses a big global lock
$options = apcu_delete('options');
}
}
}
84 changes: 16 additions & 68 deletions src/Database/StatsDAO.php
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,8 @@ public function getItemsForEachValue(
if ($filter === null) {
$featureFilter = '';
} else {
$featureFilter = /** @lang MySQL */ 'AND `Code` IN (
$featureFilter = /** @lang MySQL */
'AND `Code` IN (
SELECT `Code`
FROM ProductItemFeatureUnified
WHERE Feature = ' . $pdo->quote($filter->name) . ' AND COALESCE(`Value`, ValueText, ValueEnum, ValueDouble) = ' . $pdo->quote($filter->value) . '
Expand Down Expand Up @@ -682,7 +683,8 @@ public function getAllProducts(?string $brand, ?string $model): array
$where = '';
}

$statement = $this->getPDO()->prepare(<<<EOQ
$statement = $this->getPDO()->prepare(
<<<EOQ
SELECT Product.Brand, Product.Model, Product.Variant, pfManufacturer.ValueText AS Manufacturer, pfFamily.ValueText AS Family, pfInternal.ValueText AS Internal, COUNT(Code) AS Items
FROM Item
NATURAL RIGHT JOIN Product
Expand Down Expand Up @@ -724,7 +726,8 @@ public function getAllProducts(?string $brand, ?string $model): array
*/
public function getAllBrands(): array
{
$statement = $this->getPDO()->prepare(<<<EOQ
$statement = $this->getPDO()->prepare(
<<<EOQ
SELECT Brand, COUNT(*) AS Products
FROM Product
GROUP BY Brand
Expand All @@ -742,7 +745,8 @@ public function getAllBrands(): array

public function getAllItemsOfProduct(ProductCode $product): array
{
$statement = $this->getPDO()->prepare(<<<EOQ
$statement = $this->getPDO()->prepare(
<<<EOQ
SELECT Code
FROM Item
WHERE Brand = ? AND Model = ? AND Variant = ?
Expand Down Expand Up @@ -880,7 +884,7 @@ public function getStatsByType(
foreach ($dict as $featureName => $value) {
BaseFeature::validateFeatureName($featureName);
if ($value === null) {
$notInCondition .= "OR Feature = " . $pdo->quote($featureName);
$notInCondition .= "OR Feature = " . $pdo->quote($featureName);
} else {
$inCondition .= "OR (Feature = " . $pdo->quote($featureName) .
" AND COALESCE(`Value`, ValueText, ValueEnum, ValueDouble) = " . $pdo->quote($value) . ")";
Expand All @@ -906,7 +910,7 @@ public function getStatsByType(
WHERE ' . $inCondition . ')';
}

$condition .= ' ' . $this->filterLocation($location);
$condition .= ' ' . $this->filterLocation($location);
$deletedFilter = $deleted ? '' : $this->filterDeletedLost();

$query = "SELECT " . $select . "
Expand Down Expand Up @@ -947,12 +951,12 @@ public function getUsersStats(string $change = '', ?int $limit = 5): array
}
$change = strtoupper($change);
$pdo = $this->getPDO();
$where = $change ? " WHERE `Change` = " . $pdo->quote($change) : '';
$where = $change ? " WHERE `Change` = " . $pdo->quote($change) : '';
/** @noinspection SqlResolve */
$query = "SELECT User, COUNT(*) as Count
FROM Audit" .
$where
. " GROUP BY User
. " GROUP BY User
ORDER BY Count DESC
LIMIT " . $limit;

Expand Down Expand Up @@ -996,33 +1000,12 @@ public function getLastAudit(?bool $productAudit = false, ?int $limit = 10): arr
return $array;
}

public function getDefaultLocations(): array
{
//this will cause a massive bug later lmao
$query = "SELECT `Key`, Value
FROM Configuration C
WHERE `Key` != 'DataVersion' AND
`Key` != 'SchemaVersion'";

$array = [];
$statement = $this->getPDO()->prepare($query);

try {
$success = $statement->execute();
assert($success, 'Default location');
while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
$array[$row['Key']] = $row['Value'];
}
} finally {
$statement->closeCursor();
}
return $array;
}

/**
* get the total and average capacity of hdds or rams
*
* @param array $hddsOrRams must have property 'quantity' for each item
* @param string $propertyToSum must be 'capacity-decibyte' or 'capacity-byte'
*
* @return array
*/
public function getTotalAndAverageCapacity(array $hddsOrRams, string $propertyToSum): array
Expand All @@ -1037,12 +1020,12 @@ public function getTotalAndAverageCapacity(array $hddsOrRams, string $propertyTo
if (!$item[$propertyToSum]) {
continue;
}
$sumOfCapacity += ( $item[$propertyToSum] * $item['Quantity'] );
$sumOfCapacity += ($item[$propertyToSum] * $item['Quantity']);
$numberOfItems += $item['Quantity'];
}
return [
'totalCapacity' => $sumOfCapacity,
'averageCapacity' => ( $sumOfCapacity / $numberOfItems )
'averageCapacity' => ($sumOfCapacity / $numberOfItems)
];
}

Expand Down Expand Up @@ -1095,39 +1078,4 @@ public function countItemsByTypeThatHaveSerialNumber(): array

return $array;
}

public function setDefaultLocation(string $key, string $value)
{
$pdo = $this->getPDO();
if (isset($this->getDefaultLocations()[$key])) {
$query = "UPDATE Configuration
SET Value = :v
WHERE `Key` = :k";

$statement = $pdo->prepare($query);
$statement->bindValue(':v', $value);
$statement->bindValue(':k', $key);
try {
$success = $statement->execute();
assert($success, 'Set location');
} finally {
$statement->closeCursor();
}
} else {
//$pdo = $this->getPDO();
$query = "
INSERT INTO Configuration (`Key`, Value) VALUES (:k, :v)";

$statement = $pdo->prepare($query);
$statement->bindValue(':v', $value);
$statement->bindValue(':k', $key);

try {
$success = $statement->execute();
assert($success, 'New location');
} finally {
$statement->closeCursor();
}
}
}
}
40 changes: 27 additions & 13 deletions src/SSRv1/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,12 @@ public static function options(ServerRequestInterface $request, RequestHandlerIn

$error = null;
$token = null;
$editable = [
'DefaultHddLocation',
'DefaultCpuLocation',
'DefaultTodosLocation',
];

if ($body !== null && count($body) > 0) {
try {
if (isset($body['delete']) && isset($body['token'])) {
Expand All @@ -371,7 +377,10 @@ public static function options(ServerRequestInterface $request, RequestHandlerIn
$db->sessionDAO()->setDataForToken($token, $data);
} elseif (isset($body['location']) && isset($body['default'])) {
if ($user->getLevel() === $user::AUTH_LEVEL_ADMIN) {
$db->statsDAO()->setDefaultLocation($body['default'], $body['location']);
if (!in_array($body['default'], $editable, true)) {
throw new AuthorizationException('Not even admins can edit that');
}
$db->statsDAO()->setOptionValue($body['default'], $body['location']);
} else {
throw new AuthorizationException('Only admins can do that');
}
Expand All @@ -381,13 +390,18 @@ public static function options(ServerRequestInterface $request, RequestHandlerIn
}
}

$optionsForTemplate = [];
foreach ($editable as $optionKey) {
$optionsForTemplate[$optionKey] = $db->statsDAO()->getOptionValue($optionKey);
}

$request = $request->withAttribute('Template', 'options');
$request = $request->withAttribute(
'TemplateParameters',
[
'tokens' => $db->sessionDAO()->getUserTokens($user->uid),
'newToken' => $token,
'defaultLocations' => $db->statsDAO()->getDefaultLocations(),
'defaultLocations' => $optionsForTemplate,
'apcuEnabled' => $db->hasApcu(),
'error' => $error
]
Expand All @@ -400,13 +414,13 @@ public static function getHome(ServerRequestInterface $request, RequestHandlerIn
/** @var Database $db */
$db = $request->getAttribute('Database');

$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultHddLocation'] ?? null;
$locationDefault = $db->optionDAO()->getOptionValue('DefaultHddLocation');
$location = Validation::validateOptionalString($request->getQueryParams(), 'where', $locationDefault, null);
$location = $location === null ? null : new ItemCode($location);

$templateParameters = [
'todos' => $db->statsDAO()->getItemsForEachValue('todo', null, $db->statsDAO()->getDefaultLocations()['DefaultTodosLocation'] ?? null),
'checks' => $db->statsDAO()->getItemsForEachValue('check', null, $db->statsDAO()->getDefaultLocations()['DefaultTodosLocation'] ?? null),
'todos' => $db->statsDAO()->getItemsForEachValue('todo', null, $db->optionDAO()->getOptionValue('DefaultTodosLocation'),
'checks' => $db->statsDAO()->getItemsForEachValue('check', null, $db->optionDAO()->getOptionValue('DefaultTodosLocation'),
'toTest' => self::getToTest($db),
'missingSmartOrSurfaceScan' => $db->statsDAO()->getStatsByType(
false,
Expand Down Expand Up @@ -472,7 +486,7 @@ public static function getStats(ServerRequestInterface $request, RequestHandlerI
break;

case 'cases':
$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultCaseLocation'] ?? null;
$locationDefault = $db->optionDAO()->getOptionValue('DefaultCaseLocation');
$location = Validation::validateOptionalString($query, 'where', $locationDefault, null);
$locationSet = $location !== $locationDefault;
$location = $location === null ? null : new ItemCode($location);
Expand Down Expand Up @@ -508,7 +522,7 @@ public static function getStats(ServerRequestInterface $request, RequestHandlerI
break;

case 'rams':
$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultRamLocation'] ?? null;
$locationDefault = $db->optionDAO()->getOptionValue('DefaultRamLocation');
$location = Validation::validateOptionalString($query, 'where', $locationDefault, null);
$locationSet = $location !== $locationDefault;
$location = $location === null ? null : new ItemCode($location);
Expand Down Expand Up @@ -567,7 +581,7 @@ public static function getStats(ServerRequestInterface $request, RequestHandlerI
);
break;
case 'cpus':
$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultCpuLocation'] ?? null;
$locationDefault = $db->optionDAO()->getOptionValue('DefaultCpuLocation');
$location = Validation::validateOptionalString($query, 'where', $locationDefault, null);
$locationSet = $location !== $locationDefault;
$location = $location === null ? null : new ItemCode($location);
Expand All @@ -593,7 +607,7 @@ public static function getStats(ServerRequestInterface $request, RequestHandlerI
);
break;
case 'hdds':
$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultHddLocation'] ?? null;
$locationDefault = $db->optionDAO()->getOptionValue('DefaultHddLocation');
$location = Validation::validateOptionalString($query, 'where', $locationDefault, null);
$locationSet = $location !== $locationDefault;
$location = $location === null ? null : new ItemCode($location);
Expand Down Expand Up @@ -676,7 +690,7 @@ public static function getStats(ServerRequestInterface $request, RequestHandlerI
);
break;
case 'cool':
$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultCpuLocation'] ?? null;
$locationDefault = $db->optionDAO()->getOptionValue('DefaultCpuLocation');
$location = Validation::validateOptionalString($query, 'where', $locationDefault, null);
$location = $location === null ? null : new ItemCode($location);
$request = $request->withAttribute('Template', 'stats::cool')->withAttribute(
Expand Down Expand Up @@ -1299,13 +1313,13 @@ public static function infoTodo(ServerRequestInterface $request, RequestHandlerI
/** @var Database $db */
$db = $request->getAttribute('Database');

$locationDefault = $db->statsDAO()->getDefaultLocations()['DefaultHddLocation'] ?? null;
$locationDefault = $db->statsDAO()->getOptionValue('DefaultHddLocation');
$location = Validation::validateOptionalString($request->getQueryParams(), 'where', $locationDefault, null);
$location = $location === null ? null : new ItemCode($location);

$templateParameters = [
'checks' => $db->statsDAO()->getItemsForEachValue('check', null, $db->statsDAO()->getDefaultLocations()['DefaultTodosLocation'] ?? null),
'todos' => $db->statsDAO()->getItemsForEachValue('todo', null, $db->statsDAO()->getDefaultLocations()['DefaultTodosLocation'] ?? null),
'checks' => $db->statsDAO()->getItemsForEachValue('check', null, $db->statsDAO()->getOptionValue('DefaultTodosLocation'),
'todos' => $db->statsDAO()->getItemsForEachValue('todo', null, $db->statsDAO()->getOptionValue('DefaultTodosLocation'),
'toTest' => self::getToTest($db),
'missingSmartOrSurfaceScan' => $db->statsDAO()->getStatsByType(
false,
Expand Down
1 change: 1 addition & 0 deletions tests/Database/DatabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public function setUp(): void {
$pdo->exec(/** @lang MariaDB */ "SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE Product; SET FOREIGN_KEY_CHECKS = 1;");
$pdo->exec(/** @lang MariaDB */ "SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE SearchResult; SET FOREIGN_KEY_CHECKS = 1;");
$pdo->exec(/** @lang MariaDB */ "SET FOREIGN_KEY_CHECKS = 0; TRUNCATE TABLE Search; SET FOREIGN_KEY_CHECKS = 1;");
$pdo->exec(/** @lang MariaDB */ "DELETE FROM Configuration WHERE `Key` NOT IN ('SchemaVersion', 'DataVersion');");
$pdo->exec(/** @lang MariaDB */ "INSERT INTO Prefixes(Prefix, `Integer`) VALUES ('M', 10), ('T', 75), ('', 60);");
}

Expand Down
Loading

0 comments on commit dc13e1d

Please sign in to comment.