01 января 2011

Асинхронное соединение с postgresql

Механизм неблокирующего создания соединения бывает полезен при создании списка подключений, а также при медленном соединении.
To begin a nonblocking connection request, call conn = PQconnectStart("connection_info_string"). If conn is null, then libpq has been unable to allocate a new PGconn structure. Otherwise, a valid PGconn pointer is returned (though not yet representing a valid connection to the database). On return from PQconnectStart, call status = PQstatus(conn). If status equals CONNECTION_BAD, PQconnectStart has failed. If PQconnectStart succeeds, the next stage is to poll libpq so that it can proceed with the connection sequence. Use PQsocket(conn) to obtain the descriptor of the socket underlying the database connection. Loop thus: If PQconnectPoll(conn) last returned PGRES_POLLING_READING, wait until the socket is ready to read (as indicated by select(), poll(), or similar system function). Then call PQconnectPoll(conn) again. Conversely, if PQconnectPoll(conn) last returned PGRES_POLLING_WRITING, wait until the socket is ready to write, then call PQconnectPoll(conn) again. If you have yet to call PQconnectPoll, i.e., just after the call to PQconnectStart, behave as if it last returned PGRES_POLLING_WRITING. Continue this loop until PQconnectPoll(conn) returns PGRES_POLLING_FAILED, indicating the connection procedure has failed, or PGRES_POLLING_OK, indicating the connection has been successfully made.
Вольный и неточный перевод:
Для создания неблокирующего запроса на подключение вызовите PQconnectStart("conn_info-string"). Если объект соединения нулевой, значит libpq не смогла выделить память для этого объекта. Иначе объект соединения корректен (однако само подключение к базе еще некорректно). После вызова PQconnectStart, узнайте статус с помощью функции PQstatus(conn). Если полученное значение CONNECTION_BAD, значит подключение к базе данных не удалось. Иначе необходимо подождать цикл подключения. Прежде всего получите дескриптор сокета с помощью функции PQsocket. Далее выполняйте в цикле:
Если PQconenctPoll(conn) вернула PGRES_POLLING_READING, подождите пока сокет будет готов к приему данных (используйте для этого фукнцию select(), poll(), или другую подходящую).  
Если PQconnectPoll(conn) вернула PGRES_POLLING_WRITING, подождите пока сокет будет готов к передаче данных. Далее снова вызовите PQconnectPoll(conn).
Повторяйте данные действия пока PQconnectPoll(conn) не вернет одно из двух значений: PGRES_POLLING_FAILED или PGRES_POLLING_OK. Значения отображают неуспешность или успешность установления соединения соответсвенно.
Сразу после вызова PQconnectStart можете без вызова PQconnectPoll считать что сокет подготавливается к записи (PGRES_POLLING_WRITING).
Код на языке python.

#
#    Waiting while libpq process connect
#
def wait_connect(conn):
    while 1:
        status = conn.status
        if status == CONNECTION_STARTED:
            print >> sys.stderr, 'Connecting...'
        elif status == CONNECTION_MADE:
            print >> sys.stderr, 'Connected to server...'
        elif status == CONNECTION_AWAITING_RESPONSE:
            print >> sys.stderr, 'Awaiting responce...'
        elif status == CONNECTION_AUTH_OK:
            print >> sys.stderr, 'Authentificated...'
        elif status == CONNECTION_SSL_STARTUP:
            print >> sys.stderr, 'SSL startup...'
        elif status == CONNECTION_SETENV:
            print >> sys.stderr, 'Negotiating environment-driven parameter settings.'
        else:
            print >> sys.stderr, 'Connecting error'
            break

        state = conn.poll()
        if state == PGRES_POLLING_OK:
            print >> sys.stderr, 'PGRES_POLLING_OK'
            break
        elif state == PGRES_POLLING_WRITING:
            print >> sys.stderr, 'PGRES_POLLING_WRITING'
            select.select([], [conn.socket], [])
        elif state == PGRES_POLLING_READING:
            print >> sys.stderr, 'PGRES_POLLING_READING'
            select.select([conn.socket], [], [])
        elif state == PGRES_POLLING_FAILED:
            print >> sys.stderr, 'PGRES_POLLING_FAILED'
            break
        else:
            print >> sys.stderr, state
            break
conn = PGConnection('dbname=postgres', 1)
if conn.status == CONNECTION_BAD:
    print >> sys.stderr, 'Connection to database failed: %s' % conn.error_message
else:
    wait_connect(conn)
    if conn.status != CONNECTION_BAD:
        print >> sys.stderr, 'Connection created'

Комментариев нет:

Отправить комментарий