Disable isset, optimize getInstance, concurrent offsetSet

This commit is contained in:
Alexander Pankratov 2020-06-11 00:23:35 +03:00
parent ca03bc662a
commit 321787f718
3 changed files with 53 additions and 24 deletions

View File

@ -8,10 +8,21 @@ use Amp\Promise;
interface DbArray extends DbType, \ArrayAccess, \Countable
{
public function getArrayCopy(): Promise;
public function offsetExists($offset): Promise;
public function isset($key): Promise;
public function offsetGet($offset): Promise;
public function offsetSet($offset, $value);
public function offsetUnset($offset): Promise;
public function count(): Promise;
public function getIterator(): Producer;
/**
* @deprecated
* @internal
* @see DbArray::isset();
*
* @param mixed $offset
*
* @return bool
*/
public function offsetExists($offset);
}

View File

@ -28,9 +28,14 @@ class MemoryArray extends \ArrayIterator implements DbArray
});
}
public function offsetExists($offset): Promise
public function offsetExists($offset)
{
return call(fn() => parent::offsetExists($offset));
throw new \RuntimeException('Native isset not support promises. Use isset method');
}
public function isset($key): Promise
{
return call(fn() => parent::offsetExists($key));
}
public function offsetGet($offset): Promise

View File

@ -2,14 +2,12 @@
namespace danog\MadelineProto\Db;
use Amp\Loop;
use Amp\Mysql\Pool;
use Amp\Producer;
use Amp\Promise;
use Amp\Sql\ResultSet;
use danog\MadelineProto\Logger;
use function Amp\call;
use function Amp\Promise\wait;
class MysqlArray implements DbArray
{
@ -50,9 +48,14 @@ class MysqlArray implements DbArray
*/
public static function getInstance(string $name, $value = null, string $tablePrefix = '', array $settings = []): Promise
{
$tableName = "{$tablePrefix}_{$name}";
if ($value instanceof self && $value->table === $tableName) {
$instance = &$value;
} else {
$instance = new static();
$instance->table = $tableName;
}
$instance->table = "{$tablePrefix}_{$name}";
$instance->settings = $settings;
$instance->db = static::getDbConnection($settings);
$instance->ttl = $settings['cache_ttl'] ?? $instance->ttl;
@ -60,9 +63,13 @@ class MysqlArray implements DbArray
$instance->startCacheCleanupLoop();
return call(static function() use($instance, $value) {
yield from static::renameTmpTable($instance, $value);
yield from $instance->prepareTable();
//Skip migrations if its same object
if ($instance !== $value) {
yield from static::renameTmpTable($instance, $value);
yield from static::migrateDataToDb($instance, $value);
}
return $instance;
});
@ -109,7 +116,7 @@ class MysqlArray implements DbArray
$total = count($value);
foreach ($value as $key => $item) {
$counter++;
if ($counter % 100 === 0) {
if ($counter % 500 === 0) {
yield $instance->offsetSet($key, $item);
Logger::log("Loading data to table {$instance->table}: $counter/$total", Logger::WARNING);
} else {
@ -121,21 +128,21 @@ class MysqlArray implements DbArray
}
}
public function offsetExists($index): bool
{
throw new \RuntimeException('Native isset not support promises. Use isset method');
}
/**
* Check if offset exists
* Check if key isset
*
* @link https://php.net/manual/en/arrayiterator.offsetexists.php
*
* @param string $index <p>
* The offset being checked.
* </p>
* @param $key
*
* @return Promise<bool> true if the offset exists, otherwise false
* @throws \Throwable
*/
public function offsetExists($index): Promise
public function isset($key): Promise
{
return call(fn() => yield $this->offsetGet($index) !== null);
return call(fn() => yield $this->offsetGet($key) !== null);
}
@ -177,9 +184,10 @@ class MysqlArray implements DbArray
if ($this->getCache($index) === $value) {
return call(fn()=>null);
}
$this->setCache($index, $value);
return $this->request("
$request = $this->request("
INSERT INTO `{$this->table}`
SET `key` = :index, `value` = :value
ON DUPLICATE KEY UPDATE `value` = :value
@ -189,6 +197,11 @@ class MysqlArray implements DbArray
'value' => serialize($value),
]
);
//Ensure that cache is synced with latest insert in case of concurrent requests.
$request->onResolve(fn() => $this->setCache($index, $value));
return $request;
}
/**