Быстрая база на файлах для узких целей

workOnFood

Новичок
Всем доброго дня. Пишу систему сообщений которая будет работать с использованием аякса и предполагается что она будет довольно сильно нагружена поэтому нужно чтобы все работало максимально быстро. Ввиду этих обстоятельств решил вместо использования mySql написать свое подобие базы с функционалом заточенным исключительно под нужды приложения на файлах. Хотелось бы узнать ваше мнение по поводу структуры, а также по поводу самого кода. Заранее извиняюсь если увидите откровенный говнокод, я пока еще только учусь. Кода не много поэтому выкладываю сюда, а также архивчик со структурой базы.

PHP:
class Filebase{
	protected $dirOfBase;
	protected $basedir;
	function __construct($path_to_filebase){
		$this->dirOfBase = $path_to_filebase;
	}
	function sys_getUserArr($id){
		return $arr = array('Vasia','img/avatar.png');
	}
	function sys_addUserIfNotEx($id,$gr_id){
		if(file_exists($this->dirOfBase.'users/'.$id.'.fb')){
				$fp = fopen($this->dirOfBase.'users/'.$id.'.fb','a');
				fputs($fp,$new_group."\t");
				fclose($fp);
			}else{
				$user = $this->sys_getUserArr($id);
				file_put_contents($this->dirOfBase.'users/'.$id.'.fb',$id."\t".$user[0]."\t".$user[1]."\t".$gr_id."\t");
			}
	}
	function startGroup($my_id,$other_id,$my_mes,$title){
		$my_mes = preg_replace("/\n/s",'<br/>',htmlspecialchars($my_mes));
		$title = preg_replace("/\n/s",' ',htmlspecialchars($title));
		$gr_id = file_get_contents($this->dirOfBase.'groups/maxgr.fb')+1;
		file_put_contents($this->dirOfBase.'groups/maxgr.fb',$gr_id);
		$new_group = $my_id.'|1 '.$other_id.'|0 ';
		foreach(array($my_id,$other_id) as $id){
			$this->sys_addUserIfNotEx($id,$gr_id);
		}
		mkdir($this->dirOfBase.'groups/'.$gr_id);
		$fp = fopen($this->dirOfBase.'groups/'.$gr_id.'/gr.fb','a');
		fseek($fp,filesize($this->dirOfBase.'groups/'.$gr_id.'/gr.fb'));
		$pos = ftell($fp);
		fputs($fp,$my_mes."\n");
		fclose($fp);
		$fp = fopen($this->dirOfBase.'groups/'.$gr_id.'/m_index.fb','a');
		fputs($fp,$my_id."\t".time()."\t".$pos."\n");
		fclose($fp);
		file_put_contents($this->dirOfBase.'groups/'.$gr_id.'/users.fb',$new_group);
		file_put_contents($this->dirOfBase.'groups/'.$gr_id.'/title.fb',$title);
	}
	function inviteUser($id,$gr){
		$this->sys_addUserIfNotEx($id,$gr);
		$fp = fopen($this->dirOfBase.'groups/'.$gr.'/users.fb','a');
		fputs($fp,$id.'|0 ');
		fclose($fp);
	}
	function writeMessage($id,$gr,$mes){
		$mes = preg_replace("/\n/s",'<br/>',htmlspecialchars($mes));
		$fp = fopen($this->dirOfBase.'groups/'.$gr.'/gr.fb','a');
		fseek($fp,filesize($this->dirOfBase.'groups/'.$gr.'/gr.fb'));
		$pos = ftell($fp);
		fputs($fp,$mes."\n");
		fclose($fp);
		$fp = fopen($this->dirOfBase.'groups/'.$gr.'/m_index.fb','a');
		fputs($fp,$id."\t".time()."\t".$pos."\n");
		fclose($fp);
	}
	function getDialogArr($gr,$from=0,$howmany=0,$rev=true){
		$index_arr = file($this->dirOfBase.'groups/'.$gr.'/m_index.fb');
		if($from>0){
			if($howmany>0){
				$index_arr = array_slice($index_arr,($rev?0-$from:$from),$howmany);
			}else{
				$index_arr = array_slice($index_arr,($rev?0-$from:$from));
			}
		}
		foreach($index_arr as $mes_x){
			$mes_x = explode("\t",$mes_x);
			$fp =fopen($this->dirOfBase.'groups/'.$gr.'/gr.fb','r');
			fseek($fp,$mes_x[2]);
			$mes = fgets($fp);
			fclose($fp);
			if(date("j",$mes_x[1])<date("j"))$df = "d.m.Y H:i";
			else $df = "H:i";
			$user = file_get_contents($this->dirOfBase.'users/'.$mes_x[0].'.fb');
			$user = explode("\t",$user);
			$disp_arr[] = array($user[1],$user[2],date($df,$mes_x[1]),$mes);
		}
		return $disp_arr;
	}
	function groupDelUser($id,$gr){
		$gr_users = file_get_contents($this->dirOfBase.'groups/'.$gr.'/users.fb');
		$gr_users = explode(" ",$gr_users);
		foreach($gr_users as $user){
			$u_arr = explode('|',$user);
			if($u_arr[0]!=$id  && $u_arr[0]!=''){
				$allowed.=$user.' ';
			}
		}
		file_put_contents($this->dirOfBase.'groups/'.$gr.'/users.fb',$allowed);
		$user = file_get_contents($this->dirOfBase.'users/'.$id.'.fb');
		$user = explode("\t",$user);
		$allowed = $user[0]."\t".$user[1]."\t".$user[2]."\t";
		for($i=3;$i<count($user);$i++){
			if($user[$i]!=$gr && $user[$i]!=''){
				$allowed.=$user[$i]."\t";
			}
		}
		file_put_contents($this->dirOfBase.'users/'.$id.'.fb',$allowed);
	}
	function renameGroup($gr,$title){
		$title = preg_replace("/\n/s",' ',htmlspecialchars($title));
		file_put_contents($this->dirOfBase.'groups/'.$gr.'/title.fb',$title);
	}
}
 

Вложения

grigori

( ͡° ͜ʖ ͡°)
Команда форума
открой для себя sqlite )))
там уже есть и индексы, и полноценный sql, и не нужен сервер базы,
а с отключенным fsync-ом на коммитах и журналом в памяти он еще и на записи намного быстрее
 

fixxxer

К.О.
Партнер клуба
Запусти на код, использующий твою "базу", ab или подобную долбилку, и подивись, как красиво твоя "база" рушится.
 

lamozavrik

Новичок
открой для себя sqlite )))
там уже есть и индексы, и полноценный sql, и не нужен сервер базы,
а с отключенным fsync-ом на коммитах и журналом в памяти он еще и на записи намного быстрее
Поддерживаю! В твоем случае sqlite будет самым правильным решением! =)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
lamozavrik правильным для него будет понять, что довольно сильных нагрузок у него не будет ;)
и начать учиться
 

workOnFood

Новичок
открой для себя sqlite )))
там уже есть и индексы, и полноценный sql, и не нужен сервер базы,
а с отключенным fsync-ом на коммитах и журналом в памяти он еще и на записи намного быстрее
Открыл спасибо.
Sqlite возможно и было бы актуально использовать когда еще не написал это, но сейчас мой код и так раза в три быстрее MySql, а к тому же меньще sqLite, и в нем абсолютно прозрачная для меня структура, которую я могу совершенствовать до бесконечности.

Запусти на код, использующий твою "базу", ab или подобную долбилку, и подивись, как красиво твоя "база" рушится.
Можно поподробнее, что за ab? Первый раз слышу.
 

workOnFood

Новичок
Нда Яндексу пора на помойку, он по запросу долбилка ab выдает рекламу машинок для долбления асфальта(бетона).
 

iceman

говнокодер
есть же фейсбуковская бд, прочитай про нее, она быстрая и масштабируемая.
 

AmdY

Пью пиво
Команда форума
http://lmgtfy.com/?q=ab
а ещё бы потестил на разные объёмы данных, где у тебя будет реальный прогиб. потестил бы на выборку по фильтру, узнал бы зачем нужны индексы т.д. и т.п. кстати, flock тебе ни о чём не говорит?

аватарка у тебя очень подходящая, символизирующая что ждёт, когда чукча не читатель, чукча писатель
 

workOnFood

Новичок
http://lmgtfy.com/?q=ab
а ещё бы потестил на разные объёмы данных, где у тебя будет реальный прогиб. потестил бы на выборку по фильтру, узнал бы зачем нужны индексы т.д. и т.п. кстати, flock тебе ни о чём не говорит?

аватарка у тебя очень подходящая, символизирующая что ждёт, когда чукча не читатель, чукча писатель
На разные объемы обязательно потестирую. Фильтр никчему, так как я уже сказал что функционал сильно ограничен и выборка будет осуществляться только функцией getDialogArr, и никак иначе. Индексы? Вроде для хранения инфы о сообщениях у меня используются индексы m_index.fb. А вот про flock, как-то читал но ничего не понял, спасибо что обратил на нее мое внимание, обязательно почитаю.
 

AmdY

Пью пиво
Команда форума
$index_arr = file($this->dirOfBase.'groups/'.$gr.'/m_index.fb');

у тебя индекс каждый раз считывается из файла и загоняется в тяжёлый php-шный массив. о каком вообще сравнении по скорости с мускулом может быть речь. идея вообще никуда не годная.


теперь по коду:
1. правила именования у тебя просто отсутствуют, смесь верблюдов с нижним подчёркиванием sys_getUserArr, кстати, неужели так сложно дописать две буквы sys_getUserArray
2. слишком много магических строк, которые стоило бы вынести в константы класса.
3. отсутствие блокировок и понятия атомарности, пишешь за раз в несколько файлов, не задумываясь о том, что параллельно может этим заниматься другой процесс.
4. пренебрежение стандартными функциями php и придумывание своих форматов для хранения данных. вырызаешь кучу символов, экранируешь всё подрят
и т.д.
 

Mols

Новичок
workOnFood
Вам тут уже 10 раз сказали. Возьмите или sqlite или mysql и пользуйтесь на здоровье.
Это именно тот совет, который Вы должны услышать.
Когда начнет тормозить - придёте ещё.
Лет 5 - 10 у Вас точно будет.
За это время может и подучитесь.
 

workOnFood

Новичок
$index_arr = file($this->dirOfBase.'groups/'.$gr.'/m_index.fb');

у тебя индекс каждый раз считывается из файла и загоняется в тяжёлый php-шный массив. о каком вообще сравнении по скорости с мускулом может быть речь. идея вообще никуда не годная.
Долго думал над этим куском, и мне он самому не очень нравиться, но что-то более адекватное так и не смог придумать, так как нужно выбирать определенные куски файла gr.fb, если есть идеи как это можно сделать более рационально, слушаю очень внимательно.

1. правила именования у тебя просто отсутствуют, смесь верблюдов с нижним подчёркиванием sys_getUserArr, кстати, неужели так сложно дописать две буквы sys_getUserArray
Это уже холивар - функции с префиксом sys являются как бэ системными т.е. не имеют отношения к используемуму функционалу класса, а служат для уменьшения количества кода.


2. слишком много магических строк, которые стоило бы вынести в константы класса.
Не понимаю что значит магические. Которые часто повторяются так чтоли?
Тогда впринципе согласен оптимизация кода будет не лишней.

3. отсутствие блокировок и понятия атомарности, пишешь за раз в несколько файлов, не задумываясь о том, что параллельно может этим заниматься другой процесс.
Я так понял это продолжение темы flock? Если нет то можно ссылочку?

4. пренебрежение стандартными функциями php и придумывание своих форматов для хранения данных. вырызаешь кучу символов, экранируешь всё подрят
и т.д.
Не понимаю чем плохо если формат будет .fb а не .txt или .hz по-моему от этого вообще ничего не зависит.

По поводу экранирования и вырезания - можно пример, по-моему там все к месту.
 

AmdY

Пью пиво
Команда форума
ОМГ. просто убегай с теперешней работы, пока не сгнил там. Но объяснить хотя бы половину твоих заблуждений на форуме не получится, здесь нужно просто поработать под руководством программиста.
 

workOnFood

Новичок
workOnFood
Вам тут уже 10 раз сказали. Возьмите или sqlite или mysql и пользуйтесь на здоровье.
Это именно тот совет, который Вы должны услышать.
Когда начнет тормозить - придёте ещё.
Лет 5 - 10 у Вас точно будет.
За это время может и подучитесь.
Если вы имеете ввиду, что нагрузка при которой начнет тормозить у меня появиться только через 5-10 лет, то вы тут ошибаетесь, я думал все кто читает эту тему уже поняли что я пишу не свой собственный проект а по заданию на фрилансе пишу приложение для уже существующего и раскрученного. Тем не менее при всей раскрученности проект пока не приносит особой прибыли и админ, будучи вкурсе об уровне моих знаний тем не менее нанял меня написать эту вешь, за не бог весть какие деньги конечно. Сделать этот функционал на файлах не моя идея, её ему предложил его главный программист, который вообще предлагал осуществлять выборку с использованием readdir, у меня хотябы в каждом файле содержится информация об относящемся к нему и получение инфы происходит напрямую через открытие пути.

Вообще если бы вы почитали код и то что я писал в топике, вы бы поняли что функционал настолько узок, что отказавшись от использования каккой-либо базы данных можно выиграть по скорости, что я и пытаюсь сделать.
 

Mols

Новичок
workOnFood
Я совершенно не сомневаюсь в том, что Вы искренно верите в то, что пишете.
Но как бы там ни было Вы пытаетесь сделать то, что делать не надо.
Не надо на ПХП писать свою СУБД. Тем более с расчетом "увеличить производительность" (особенно учитывая то, что даже ab - для Вас магическое слово)
Субд умеют кешировать ответ. Они подойдут намного лучше, будут намного быстрее и надёжнее.
При этом Вы всегда сможете использовать дополнительный кеш... это не запрещено)))
Код я конечно разбирать не буду... уж простите.
 

AmdY

Пью пиво
Команда форума
пожалуйсто, не называй того человека ни то что главным, но и вовсе программистом. посылаю ему луч презрения.

по сокрости ты ничего не выиграешь в сравнении с mysql или любым готовым nosql решением, даже древним dba. н у тебя появилась куча проблем с сохранностью, атомарностью и параллельными обращениями. и вообще, в php уже есть готовые решения для стороджей на файлах http://php.net/dba
 
Сверху