Решение.
1. Делаем в папке с заявками файл lock.
2. Убеждаемся, что генератор случайных чисел сеется. Я сею его на основе выбранного порта и системного времени. Подозреваю, в windows может не работать, если там time-of-day возвращается с точностью до секунды, а не до миллисекунды.
(seed (div (time-of-day) (int (env "REMOTE_PORT")) 0.000001))
3. Вот собственно процедура получения номера. Суть простая. Пишем через append в файл "lock" номер, который мы хотим занять и подписываем его случайным числом. Проверяем, что никто не успел вклиниться перед нами. Если мы опоздали (номер уже занят), повторяем попытку.
(define (occupy-number) (local (id num res)
(set 'id (rand-string))
(set 'num (last (or (sort (map int (directory "." "txt$"))) '(0))))
(do-until (= (or (find (s-a num ":" id) res 0) "no") (find (s-a num ":.*") res 0))
(inc num)
(append-file "lock" (s-a num ":" id "\n"))
(set 'res (read-tail "lock" 100)))
num))
Я тестировал на одновременных 100 подключениях. Работало с двойным запасом.
4. Вот воспомогательные процедуры:
(define (string-append) (apply append (map string (args))))
(set 's-a string-append)
; В Windows реальный rand (насколько я помню) имеет диапазон в 32768,
; поэтому я его для надёжности "утроил".
(define (rand-string)
(join (map string (list (rand 65536) (rand 65536) (rand 65536))) "_"))
; Возвращает последние 'lines строк файла в виде списка.
; Работает, по понятным причинам, только под *nix
(define (read-tail fname (lines 10))
(exec (append "tail " fname " -n " (string lines))))
5. Замечания.
5.1. Лог может сильно разрастись, надо как-то его стирать изредка.
5.2. Если мы стёрли файл, а в lock он остался, в нумерации будут пропуски. Это скорее фича, но тем не менее.
5.3. Процедура блокировки файлов для изменения не проработана. Если мы хотим обезопаситься ещё и от изменения, нужно думать дальше.
5.4. Схема "велосипедна". То есть, лучше бы, вообще, пользоваться базами данных.
Комментариев нет:
Отправить комментарий