<?php
/*
Redis可真能坑爺,原先的設計用redis保存臨時數據,可到了實際應用(實際上也就是幾十我的同時用),老是出現莫名其妙的問題,最多見的就是讀不出數據來,調試了好多天,那問題仍是偶爾出現(也不是一直有,偶爾讀不到),幸虧這段時間接觸swoole,發現有swoole_table這麼個好東東,因而就先試試吧,下面的就是用於替換redis的。完了後再測,基本沒出什麼異常,也用了N個客戶端同時自動發送(比原先十幾我的手工發速度要快不少了),運行了十多分鐘,基本沒問題。
swoole_table還有些功能上的不足之處:
1,不能getAll,多是我沒找到方法吧,因而就另外建個表專門用於記錄鍵,雖然這樣應付不了多少數據,並且可能也很慢,但這是目前能想到的惟一的辦法。
2,可保存的數據類型只有:string,int,float,若是能加上數組就行了,或者在保存時,如果數組,自動轉換JSON,會好不少。
3,建立表時,有點麻煩,若是能象redis那樣容許直接一個字串就行了,雖然能夠建立只有一個列的表,可仍是以爲有點不方便;
下面的類是完整應用類,裏面的表結構需根據實際須要設置
調用:
$mem=new Mem_swoole();
而後就能夠按對象直接使用啦。
*/
class Mem_swoole
{
private $user;//數據表
private $client;//數據表
private $master;//數據表
private $index;//保存數據表的全部鍵
private $count;//計數器
private $temp;//測試表
public function __construct($conf = [])
{
$user = [];
$user[] = ['key' => 'ip', 'type' => 'string', 'len' => 15];
$user[] = ['key' => 'port', 'type' => 'int', 'len' => 4];
$user[] = ['key' => 'dns', 'type' => 'string', 'len' => 30];
$user[] = ['key' => 'pid', 'type' => 'int', 'len' => 4];
$user[] = ['key' => 'mode', 'type' => 'int', 'len' => 2];
$user[] = ['key' => 'screen', 'type' => 'string', 'len' => 10];
$user[] = ['key' => 'name', 'type' => 'string', 'len' => 30];
$client = [];
$client[] = ['key' => 'dns', 'type' => 'string', 'len' => 15];
$client[] = ['key' => 'client', 'type' => 'string', 'len' => 100];
$master = [];
$master[] = ['key' => 'id', 'type' => 'int', 'len' => 4];
$master[] = ['key' => 'dns', 'type' => 'string', 'len' => 15];
$master[] = ['key' => 'lv', 'type' => 'int', 'len' => 1];
$index = [];
$index[] = ['key' => 'keys', 'type' => 'string', 'len' => 65536];
$count = [];
$count[] = ['key' => 'send', 'type' => 'int', 'len' => 8];
$this->user = new swoole_table(1024);
$this->client = new swoole_table(1024);
$this->master = new swoole_table(1024);
$this->index = new swoole_table(8);
$this->count = new swoole_table(8);
$this->column($this->user, $user);
$this->column($this->client, $client);
$this->column($this->master, $master);
$this->column($this->index, $index);
$this->column($this->count, $count);
$this->user->create();
$this->client->create();
$this->master->create();
$this->index->create();
$this->count->create();
}
/**
* swoole_table的測試
* @param string $table
*/
public function test($table = 'temp')
{
$count = [];
$count[] = ['key' => 'name', 'type' => 'string', 'len' => 50];
$count[] = ['key' => 'title', 'type' => 'string', 'len' => 50];
$this->{$table} = new swoole_table(1024);
$allType = ['int' => swoole_table::TYPE_INT, 'string' => swoole_table::TYPE_STRING, 'float' => swoole_table::TYPE_FLOAT];
foreach ($count as $row) {
$this->{$table}->column($row['key'], $allType[$row['type']], $row['len']);
}
$this->{$table}->create();
foreach ([1, 2, 3] as $val) {
$value = ['title' => "這是第{$val}個標題"];
$this->{$table}->set("K_{$val}", $value);
$this->record($table, "K_{$val}");
}
foreach ([4, 5, 6] as $val) {
$value = ['name' => "這是第{$val}個名字"];
$this->{$table}->set("K_{$val}", $value);
$this->record($table, "K_{$val}");
}
foreach ([7, 8, 9] as $val) {
$value = ['name' => "這是第{$val}個名字", 'title' => "這是第{$val}個標題"];
$this->{$table}->set("K_{$val}", $value);
$this->record($table, "K_{$val}");
}
$value = [];
foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9] as $val) {
$value["K_{$val}"] = $this->{$table}->get("K_{$val}");
}
$key = $this->record($table);
$all = $this->getAll($table);
print_r($value);
print_r($key);
print_r($all);
}
/**
* 數據表定義
* @param $name
* @param $type
* @param int $len
*/
private function column(swoole_table $table, $arr)
{
$allType = ['int' => swoole_table::TYPE_INT, 'string' => swoole_table::TYPE_STRING, 'float' => swoole_table::TYPE_FLOAT];
foreach ($arr as $row) {
if (!isset($allType[$row['type']])) $row['type'] = 'string';
$table->column($row['key'], $allType[$row['type']], $row['len']);
}
}
/**
* 存入【指定表】【行鍵】【行值】
* @param $key
* @param array $array
* @return bool
*/
public function set($table, $key, array $array)
{
$this->{$table}->set($key, $this->checkArray($array));
$this->add($table, 1);
return $this->record($table, $key);
}
/**
* 存入數據時,遍歷數據,二維以上的內容轉換JSON
* @param array $array
* @return array
*/
private function checkArray(array $array)
{
$value = [];
foreach ($array as $key => $arr) {
$value[$key] = is_array($arr) ? json_encode($arr, 256) : $arr;
}
return $value;
}
/**
* 讀取【指定表】的【行鍵】數據
* @param $key
* @return array
*/
public function get($table, $key)
{
return $this->{$table}->get($key);
}
/**
* 讀取【指定表】全部行鍵值和記錄
* @param $table
* @return array
*/
public function getAll($table)
{
$recode = $this->record($table);
return $this->getKeyValue($table, $recode);
}
/**
* 讀取【指定表】【指定鍵值】的記錄
* @param $table
* @param $recode
* @return array
*/
public function getKeyValue($table, $recode)
{
$value = [];
foreach ($recode as $i => $key) {
$value[$key] = $this->get($table, $key);
}
return $value;
}
/**
* 讀取【指定表】的全部行鍵
* @param $table
* @return array
*/
public function getKey($table)
{
return $this->record($table);
}
/**
* 記錄【某個表】全部記錄的鍵值,或讀取【某個表】
* @param $table
* @param null $key 不指定爲讀取
* @param bool|true $add 加,或減
* @return array
*/
private function record($table, $key = null, $add = true)
{
$this->index->lock();
$oldVal = $this->index->get($table);
if (!$oldVal) {
$tmpArr = [];
} else {
$tmpArr = explode(',', $oldVal['keys']);
}
if ($key === null) {//讀取,直接返回
$this->index->unlock();
return $tmpArr;
}
if ($add === true) {//加
$tmpArr[] = $key;
$tmpArr = array_unique($tmpArr);//過濾重複
} else {//減
$tmpArr = array_flip($tmpArr);//交換鍵值
unset($tmpArr[$key]);
$tmpArr = array_flip($tmpArr);//交換回來
}
$this->index->set($table, ['keys' => implode(',', $tmpArr)]);
return $this->index->unlock();
}
/**
* 刪除key
* @param $key
* @return bool
*/
public function del($table, $key)
{
$this->{$table}->del($key);
$this->add($table, -1);
return $this->record($table, $key, false);
}
/**
* 原子自增操做,可用於整形或浮點型列
* @param string $TabKey 表名.鍵名,但這兒的鍵名要是預先定好義的
* @param int $incrby 能夠是正數、負數,或0,=0時爲讀取值
* @return bool
*/
public function add($TabKey = 'count.send', $incrby = 1)
{
if (is_int($TabKey)) list($incrby, $TabKey) = [$TabKey, 'count.send'];
list($table, $column, $tmp) = explode('.', $TabKey . '.send.');
if ($incrby >= 0) {
return $this->count->incr($table, $column, $incrby);
} else {
return $this->count->decr($table, $column, 0 - $incrby);
}
}
/**
* 某錶行數
* @param string $TabKey
* @return bool
*/
public function len($TabKey = 'count.send')
{
return $this->add($TabKey, 0);
}
/**
* 鎖定整個表
* @return bool
*/
public function lock($table)
{
return $this->{$table}->lock();
}
/**
* 釋放表鎖
* @return bool
*/
public function unlock($table)
{
return $this->{$table}->unlock();
}
}