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

workOnFood

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

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

Однако я понял что все далеко не так просто как я себе представлял.
Буду читать ссылки которые мне здесь дали и мотать на ус. И спасибо тебе лично за все советы и замечания, и за то что в отличие от некоторых комментаторов прочитал код.
 

vovanium

Новичок
По простой логике запись одной и той же строки в базу в три раза медленнее чем в файл...
Почему именно в 3, а не в 2,5 или 4, ты проводил тестирование? Плюс основная проблема тех кто пишет свои бд на файлах, они практически всегда тестируют свои скрипты на локалке из браузера (потому, косяки с одновременным доступом проявятся уже на рабочем серваке, и будут большим сюрпризом) + тестируется это всё на очень мельких размерах. Попробуй залить в свои файлы, ну хотя бы метров 50 данных, и аналогично в MySQL и SQLite и потом уже сравнивай

PHP:
$fp = fopen($this->dirOfBase.'groups/'.$gr.'/gr.fb','a');
        fseek($fp,filesize($this->dirOfBase.'groups/'.$gr.'/gr.fb'));
Ну и нафига нужна строка с fseek? Когда стоит режим "a", и так указатель в конец ставится.

PHP:
fputs($fp,$id."\t".time()."\t".$pos."\n");
индексный файл в таком формате это фигня, нужно как минимум делать его бинарным с постоянным размером записи, тогда ты сможешь считывать нужные элементы индекса, не читая весь файл индекса в массив.

Ну и конечно при реально большой нагрузке будет куча глюков из-за отсутствия блокировки файлов.
 

workOnFood

Новичок
Харе зубоскалить, заняться нечем?

Почему именно в 3, а не в 2,5 или 4, ты проводил тестирование?
Согласен, есть такой косяк, навреняка при больших размерах, начнутся проблемы. Тем не менее чтобы мне получить мои пусть будет 100 баксов, придется дописать этот скрипт. Раз уж платят неахти хоть научусь чему-нибудь.

Ну и нафига нужна строка с fseek? Когда стоит режим "a", и так указатель в конец ставится.
Как не странно нет. Ума не приложу с чем это связано.

индексный файл в таком формате это фигня, нужно как минимум делать его бинарным
А вот насчет этого спасибо, я уже пробелы хотел добавлять в конец).

Действительно потестил функцию startGroup через Apache Benchmark, она пишет гдето 5 -10 групп - диалогов, а остальное ошибки.
Происходит так потому что у меня в файле maxgr.fb храниться номер последней созданной группы и имя следующей созданной группы будет этот номер +1.

Переписал таким образом -
PHP:
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));
		$fp = fopen($this->dirOfBase.'groups/maxgr.fb','r');
		flock($fp,LOCK_EX);
		$gr_id = fgets($fp)+1;
		fclose($fp);
		$fp = fopen($this->dirOfBase.'groups/maxgr.fb','w');
		flock($fp,LOCK_EX);
		fputs($fp,$gr_id);
		fclose($fp);
		$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);
	}
Ничего не изменилось. Запускаю на локалке Денвер.
 

vovanium

Новичок
Тем не менее чтобы мне получить мои пусть будет 100 баксов, придется дописать этот скрипт.
Так никто не говорит переписывать весь скрипт, достаточно переписать класс работы с базой на SQLite.
Как не странно нет. Ума не приложу с чем это связано.
Ты что-то путаешь, у меня все логи так пишутся :) "a" это вообще от слова append, т.е. добавить в конец.
Ничего не изменилось. Запускаю на локалке Денвер.
ты видимо плохо разобрался с flock и зачем это вообще нужно, для примера возьмем эти две строчки
PHP:
$pos = ftell($fp);
fputs($fp,$my_mes."\n");
Когда несколько скриптов запускаются одновременно, довольно часто может возникнуть ситация когда, между этими двумя строками в файл что-то запишет параллельно работающий скрипт и в итоге ты получишь кривой индекс
PHP:
//скрипт А запомнил позицию для индекса
$pos = ftell($fp);
//скрипт Б (запущенный на долю секунды позже) запомнил позицию для индекса
$pos = ftell($fp);
// на данном этапе оба скрипта ссылаются на одну и ту же позицию в файле
// скрипт А добавил строку в файл
fputs($fp,$my_mes."\n");
// скрипт Б добавил строку в файл
fputs($fp,$my_mes."\n");
// потом скрипты записывают в индекс ссылки на 2 записи но с одинаковым смещением, хотя смещения должны быть разными
Для того и нужны блокировки файлов, чтобы скрипт который запущен вторым, подождал пока первый закончит работу с файлами.
 

workOnFood

Новичок
Так никто не говорит переписывать весь скрипт, достаточно переписать класс работы с базой на SQLite.
Так "главный программист" заказчика считает что на файлах будет быстрее.

Ты что-то путаешь, у меня все логи так пишутся :) "a" это вообще от слова append, т.е. добавить в конец.
Неа, не путаю, сейчас еще раз перепроверил, без fseek позиция равна 0, интересно было бы узнать почему.

ты видимо плохо разобрался с flock и зачем это вообще нужно, для примера возьмем эти две строчки
Да действительно немного недопонимал работу flock(), спасибо что объяснил, переписал вот так -

PHP:
$fp = fopen($this->dirOfBase.'groups/maxgr.fb','r+/w+');
		flock($fp,LOCK_EX);
		$gr_id = fgets($fp);
		fseek($fp,0);
		fputs($fp,++$gr_id);
		fclose($fp);
Все работает.
 

AmdY

Пью пиво
Команда форума
workOnFood
во первых, не называй того дядьку программистом. во вторых используй готовое решение - максимально близкое - dba. но лучше mysql или какое-нить nosql решение.

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

workOnFood

Новичок
workOnFood
во первых, не называй того дядьку программистом. во вторых используй готовое решение - максимально близкое - dba. но лучше mysql или какое-нить nosql решение.

а ещё доложи заказчику, что у него какой-то дядька изображает из себя программиста, если не хочет завалить проект, нужно срочно принять меры.
Ну не знаю, они долго работают вместе, кого он послушает вопрос. И я же написал в кавычках "главный программист"=)

Я то впринципе не в претензии, не мне потом мучаться, а этому самому дядьке) А я попрактикуюсь в работе с файлами.

Ты лучше скажи почему у меня ftell() возвращает 0, когда я открываю файл со вторым параметром "а" ?
 

AmdY

Пью пиво
Команда форума
workOnFood
он так работает, если файл не пустой. посмотри ман http://php.net/ftell
When opening a file to append via fopen('file','ab') the file pointer should be at the end of the file. However ftell() returns int(0) even if the file is not empty and even after writing some text into the file.
 

vovanium

Новичок
Так "главный программист" заказчика считает что на файлах будет быстрее.
Ну формально SQLite это всего один файл с базой.
Неа, не путаю, сейчас еще раз перепроверил, без fseek позиция равна 0
а ну ты же ftell юзаешь, а он не предназначен для режима "a". в твоем случае он как бы не нужен, т.к. твою конструкцию
PHP:
fseek($fp,filesize($this->dirOfBase.'groups/'.$gr_id.'/gr.fb'));
$pos = ftell($fp);
можно заменить просто
PHP:
$pos = filesize($this->dirOfBase.'groups/'.$gr_id.'/gr.fb');
Чисто любопытно, зачем было написано 'r+/w+'
 

workOnFood

Новичок
а ну ты же ftell юзаешь, а он не предназначен для режима "a". в твоем случае он как бы не нужен, т.к. твою конструкцию
Да спасибо, так будет правильнее.

Чисто любопытно, зачем было написано 'r+/w+'
Сказывается мое незнание функций работы с файлами, где-то увидел такую запись, использовал - заработало, так и запомнил.
Заменил на r+
 

iceman

говнокодер
вот именнннннннннннноооооооооооо - НЕЗНАНИЕ!!!!!!!!!!!!!!
ТЫ с начало узнай, потом делай.
 

workOnFood

Новичок
вот именнннннннннннноооооооооооо - НЕЗНАНИЕ!!!!!!!!!!!!!!
ТЫ с начало узнай, потом делай.
Да ну?=) А ты наверное сразу взял учебник, все выучил от корки до корки, и начал писать без ошибок=) Не смеши мои тапочки. Как еще учиться если не напрактике!?))

P.S. Ненавижу такие бессмысленные эгоцентричные посты.
 

Absinthe

жожо
workOnFood ты прямо так уверен, что он как начал писать, так стал считать себя умнее всех? Или все же делал велосипеды только после того, как детально исследовал область?
А что делать тебе уже сказали: ab на скрипт свой натрави и посмотри, что будет.

От себя я бы посоветовал попробовать MongoDB для данной задачи, но через несколько лет.
 

grigori

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

workOnFood

Новичок
workOnFood ты прямо так уверен, что он как начал писать, так стал считать себя умнее всех? Или все же делал велосипеды только после того, как детально исследовал область?
А что делать тебе уже сказали: ab на скрипт свой натрави и посмотри, что будет.

От себя я бы посоветовал попробовать MongoDB для данной задачи, но через несколько лет.
Ты тоже походу ни код не читал не предидущие сообщения.

vovanium

Блин, что-то я не соображу как сделать индекс в бинарнике, в общих чертах это звучало так просто, а как взялся за реализацию подзалип.
Встает вопрос как писать данные строками заданной длины, в голову снова не приходит ничего лучше чем добавлять пробелы в конец, и вообще помоему я не совсем то делаю -
PHP:
$str = '1 12341231 123';
for($i=strlen($str);$i<50;$i++){
	$str.=' ';
}
$fp = fopen('data.bin','ab');
flock($fp,LOCK_EX);
fputs($fp,$str);
fclose($fp);
По моему у меня получается обычный текстовый файл. Я понимаю что любой будь то текстовый или еще какой файл является бинарным, но вроде он не должен нормально отображаться в редакторе, как текстовый.
Напишите плиз для примера как мне записать эту строку в бинарном виде, или все же у меня все правильно?
 

workOnFood

Новичок
так оно и было - я сначала взял мануал по php, прочел все основные разделы, потом начал писать
и сейчас я сначала читаю мануал, потом пишу
если не получается - гуглю, а если не нахожу - спрашиваю :)
И что? Когда прочитал мануал и начал писать, сразу писал как бог?=) Без глупых синтаксических ошибок и говнокода?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
без глупых вопросов и "гениальных" идей
8 лет назад понятия говнокода в php не было в силу объективных причин :)
но как только я прочитал стандарты кодирования - я стал им следовать
 

craz

Нестандартное звание
workOnFood
Ты не вкуриваешь что тебе пишут даже, а лезишь базы на файлах строить. Тебе говорят одно: мы все учились учимся и будем учиться, а ты пишешь. Есть разница? Да когда мы учимся мы тоже пишем, но мы не пишем а) за бабло б) не посмотрев примеров и других реализаций.
 
Сверху