Как реализовать семафоры в PHP без семафора PHP?

Вопрос:

Как реализовать переменную разделяемой памяти в PHP без пакета семафоров (http://php.net/manual/en/function.shm-get-var.php) ?

Контекст

  • У меня есть простое веб-приложение (фактически плагин для WordPress)
  • это получает URL
  • затем это проверяет базу данных, если этот URL-адрес уже существует
  • если нет, то он выходит и выполняет некоторые операции
  • а затем записывает запись в базу данных с URL-адресом как уникальную запись

На самом деле происходит то, что 4,5,6... сеансы одновременно запрашивают URL-адрес, и я получаю до 9 повторяющихся записей в базе данных URL-адреса.. (возможно, 9, потому что время обработки и запись в базу данных первая запись занимает достаточно времени, чтобы пропустить 9 других запросов). После этого все запросы читают правильную запись о том, что запись уже существует, так что это хорошо.

Поскольку это плагин WordPress, будет много пользователей на всех типах платформ общего хостинга с переменными компиляциями/настройками PHP.

Поэтому я ищу более универсальное решение. Я не могу использовать запись в базу данных или текстовый файл, так как это будет слишком медленно. пока я пишу в БД, следующая сессия уже пройдет.

к вашему сведению: код базы данных: http://plugins.svn.wordpress.org/wp-favicons/trunk/includes/server/plugins/metadata_favicon/inc/class-favicon.php

обновить

Использование уникального ключа для нового хэша md5 uri вместе с try catch вокруг него, кажется, работает.

Я нашел 1 повторяющуюся запись с

SELECT uri, COUNT( uri ) AS NumOccurrences
FROM edl40_21_wpfavicons_1
GROUP BY uri
HAVING (
COUNT( uri ) >1
)
LIMIT 0 , 30

Поэтому я думал, что это не сработало, но это было потому, что они были:

http://en.wikipedia.org/wiki/Book_of_the_dead
http://en.wikipedia.org/wiki/Book_of_the_Dead

(столицы ухмыляются)


person edelwater    schedule 07.03.2011    source источник


Ответы (2)


Это может быть достигнуто с помощью MySQL.

Вы можете сделать это явно, заблокировав доступ к таблице для чтения. Это предотвратит любой доступ для чтения из всей таблицы, поэтому может быть нежелательным. http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html

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

Как обсуждалось в комментариях, поскольку длина URL-адреса может быть очень длинной, уникальный хэш фиксированной длины может помочь решить эту проблему.

person Jacob    schedule 07.03.2011
comment
Это большое дополнительное хранилище, но, может быть, вместо этого вы могли бы использовать уникальный хэш? - person Jacob; 08.03.2011
comment
блокировка всей таблицы немного сурова, во время 1 блокировки у меня, вероятно, около N процессов не могут писать (из разных uris). Невозможно сделать uri уникальным: для уникальных полей существует максимальная длина. уникальный хэш интересен, может быть, это то, что делает вкусный. здесь вы видите смешанные запросы к базе данных: leau .co/wp-content/blogs.dir/21/files/wp-favicons/cache/ - person edelwater; 08.03.2011
comment
поскольку я не знаю, существует ли запись uri, она, вероятно, выглядит так: (A) обновить БЛОКИРОВКУ в записи, где uri_hash=md5(uri) попытаться поймать (B) прочитать, если она существует (C), если она существует, отпустить A (D), если не существует, сделайте обработку, напишите и отпустите A - дайте мне попробовать :) - person edelwater; 08.03.2011
comment
Да, блокировка задержит любые дальнейшие запросы. Я бы попробовал уникальный хеш-подход и позволил MySQL предотвратить добавление дубликатов. Интересная проблема. - person Jacob; 08.03.2011
comment
проблема с stackoverflow.com/questions/5109825/ заключается в том, что во время чтения результатом является то, что запись не существует. если он не существует, блокировать нечего, и N сеансов начинают обрабатывать все желающие писать, но это можно решить, установив уникальный хэш. но у меня все еще есть n процессов. Возможно, я могу предотвратить это, всегда пытаясь вставить с попыткой поймать. а в catch обработать логику php и установить логическое значение ... нужно подумать об этом, лол. - person edelwater; 08.03.2011
comment
Я бы даже не заморачивался с блокировкой... Обработка будет одинаковой для каждого уникального URI, поэтому сначала проверьте, если его нет, обработайте и попробуйте добавить. Если за это время он был добавлен, вы обрабатываете ошибку mysql. - person Jacob; 08.03.2011
comment
хм... все еще не будет работать немного сложно... uri может иметь уникальный uri favicon... но если другой uri имеет тот же uri favicon, он указывает на исходный uri, чтобы предотвратить дублирование... ЕСЛИ этот исходный uri не существует (пока) у меня будет несколько уникальных uri, но дублируются URL-адреса favicon .... GRIN argh. и uri фавикона известен только во время обработки, так как это может быть много вещей. надо еще подумать над этим. - person edelwater; 08.03.2011
comment
но это другая проблема/транзакции шаблона здесь не будут работать. Я думаю, мне нужна промежуточная таблица с временными метками, которая через некоторое время обрабатывается в другую таблицу. - person edelwater; 08.03.2011

В PHP есть и другие модули с общей памятью (shmop или APC), но я думаю, что вы говорите, что существует проблема, связанная с нестандартными/не предустановленными библиотеками.

Мое предложение состоит в том, что, прежде чем вы пойдете и выполните «другие операции», вам нужно сделать запись в базе данных, возможно, со статусом «компиляция» (или что-то в этом роде), чтобы вы знали, что она все еще недоступна. Таким образом, вы не столкнетесь с проблемами при получении нескольких записей. Я также был бы уверен, что вы используете транзакции, когда они доступны, поэтому ваши коммиты являются атомарными.

Затем, когда вы выполните «другие операции», обновите запись базы данных до «доступной» и сделайте все, что вам нужно.

person Kevin Peno    schedule 07.03.2011