Изменения в mongo-cl-driver
После длительного перерыва снова взялся за mongo-cl-driver и основательно его переделал.
Адаптеры
Для начала выкинул iolib. При чём, не могу сказать о ней ничего плохого, но... Во-первых, до сих пор я использовал mongo-cl-driver только в блокирующем режиме, мои надежды на то, что iolib откроет двери в мир асинхронного программирования не оправдываются - просто никто ничего такого не пишет, никакого веб-сервера и т.п. на iolib до сих пор не появилось. А между тем, Andrew Lyon активно пилит платформу на базе libevent: cl-libevent2, cl-async, drakma-async и даже асинхронный веб-сервер wookie (это при том, что кое-какой веб-сервер есть в самой libevent). Кстати, libevent отлично работает на винде.
В итоге, под впечатлением от pika добавил в mongo-cl-driver поддержку адаптеров и сейчас есть два работающих адаптера: на базе usocket и cl-async. Вернуть адаптер для iolib несложно, но пока не понятно что с ним вообще делать то.
Futures
Долго не мог решить, как же совместить в одной библиотеке синхронный и асинхронный интерфейс. Идти по пути node.js, где каждая функция представлена в двух вариантах (например, fs.readFile и fs.readFileSync) мне не хотелось. Как сделано в pika (каждый адаптер предоставляет свой набор классов) мне тоже не нравится. В итоге остановился на использовании futures : никакого разделения API на синхронный и асинхронный нет, но при использовании асинхронного адаптера возвращается не результат, а future. Сейчас мне кажется, что это очень удачный вариант, за одним но... Я пока не придумал, как нормально организовать обработку ошибок в таком варианте. cl-async-future (по моей просьбе автор выделил её в отдельную библиотеку) предоставляет API и набор макросов. Эти макросы работают просто замечательно если ошибок нет. А вот когда есть ошибки, случается что-то мутное. Пока план в том, что бы взять API и реализовать на его основе аналог Step, но этого я ещё не сделал. Собственно, поэтому пользоваться cl-async адаптером пока не стоит, но можно с ним экспериментировать.
MongoClient
Другим направлением работы было приведение драйвера в соответствии с официальными рекомендациями. В первую очередь, добавлен класс mongo:mongo-client, при создании которого указывается параметры сервера (класс mongo:server-config) и уровень Write Concern (класс mongo:write-concern).
Адаптеры наследуют от mongo:mongo-client и поэтому для создания клиента следует использовать функцию mongo:create-mongo-client:
- (mongo:with-client (client (mongo:create-mongo-client :usocket
- :server config
- :write-concern w))
- (print (mongo:$count (mongo:collection (make-instance 'mongo:database
- :client client
- :name "blog"))
- "posts"))))
Для упрощения задания Write Concern предопределены следующие константы:
mongo:+write-concern-normal+
mongo:+write-concern-fsync+
mongo:+write-concern-replicas+
mongo:+write-concern-journal+
mongo:+write-concern-fast+
mongo:+write-concern-crazy+
Другие изменения
У функций
mongo:update-op
mongo:insert-op
mongo:delete-op
опциональный параметры превращены в keys для того, что бы добавить key-параметр :write-concern.
Функция mongo:collection-count переименована в mongo:$count. Плюс добавленная функция mongo:$distinct, очень удобная, например, все тэги в этом блоге с её помощью я получаю так:
- (mongo:$distinct posts "tags")
Добавил функцию mongo:eval-js:
- (mongo:with-client (client (mongo:create-mongo-client :usocket))
- (mongo:eval-js (make-instance 'mongo:database :mongo-client client :name "test")
- "function (x, y) { return x * y; }"
- :args #(2 3)))
- 6.0d0
Ну и ещё наверное есть пара небольших изменений, о которых сейчас не помню.