|
|
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Задача проста, нужно выполнить запрос вначале на удаленном сервере и если он не доступен, то на локальном. Я написал extended stored procedures, которая выполняет запрос на удаленном сервере. Но самое проблематичное то, что нужно четко выдержать время запроса (не более 5 секунд). По истечении данного времени, нужно уже тянуть данные с локального сервера. Я создал OLEDB класс и выполняю хронимку в отдельном треде, ожидая его завершения в течении 5 секунд. Выставить таймауты на соединение и выполнение команды не составляет труда, трудности возникают при обрыве канала. В этом случае время ожидания достигает уже нескольких минут. Если я завершаю работу треда, то получаю зависшие конекшены на серваке. Может, кто уже решал такую же задачу? Спасибо! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 12:06 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Напрашиваеться работа в отдельном потоке с БД. И связь с основным через синхро обьекты. Ожидание на синхро обьекте может быть регламентирована "временем ожидания". вроде то что пришло на ум. (круглый) ЗЫ На мой взгляд - в консерватории проблемы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 12:42 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Обнаружение разрыва соединения зависит целиком от используемых сетевых библиотек (TCP/IP, IPX/SPX и т.д.). Например, в TCP есть специально настраиваемый time-out, после достижения которого соединение считается разорванным. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 13:04 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Ну вот выдержки из кода: Вызывающая функция: RETCODE __declspec(dllexport) xp_mirCheckForNewCardinOffice(SRV_PROC *srvproc) { try { ExecProc pProc(srvproc); return(pProc.Run()); } catch(...) { DBCHAR ErrorMsg[255]; DBINT ErrorID; ErrorID = SQL_EXEC_ERROR; sprintf(ErrorMsg, "Error executing procedure: Error executing procedure."); srv_paramsetoutput(srvproc, 8, (BYTE*)&ErrorID, sizeof(DBINT), FALSE); srv_paramsetoutput(srvproc, 9, (BYTE*)ErrorMsg, 255, FALSE); srv_senddone(srvproc, SRV_DONE_MORE | SRV_DONE_COUNT, (DBUSMALLINT)0, (DBINT)0); } return XP_NOERROR; } Рабочий сласс: public: Csp_mirCheckForNewCardInOffice m_CheckForNew; RETCODE ExecProc::Run() { unsigned threadID; hTh = (HANDLE)_beginthreadex( NULL, 0, &Start, this, 0, &threadID ); switch (dw) { case WAIT_OBJECT_0: // процесс завершается if(this->ErrorID != XP_NOERROR && srvproc != NULL) err_handler(ErrorID, ErrorMsg, srvproc); else { ReturnResult(); } break; case WAIT_TIMEOUT: // процесс не завершился в течение TimeOut // TerminateThread(hTh, 0); ErrorID = TIME_OUT_EXPIRED; sprintf(ErrorMsg, "Error executing procedure: Time out expired. Function break."); err_handler(ErrorID, ErrorMsg, srvproc); break; case WAIT_FAILED: // неправильный вызов функции (неверный описатель?) ErrorID = ERROR_PROC_EXEC; sprintf(ErrorMsg, "Error executing procedure: Error start extended stored procedure."); err_handler(ErrorID, ErrorMsg, srvproc); break; } } } ExecProc::~ExecProc(void) { if(hTh != NULL) { WaitForSingleObject(hTh, INFINITE); CloseHandle(hTh); this->m_CheckForNew.CloseAll(); } } unsigned __stdcall Start(void *arg) { ExecProc* _this = static_cast<ExecProc*>(arg); try { HRESULT hr = _this->m_CheckForNew.OpenAll(); if (FAILED(hr)) { _this->ErrorID = _this->m_CheckForNew.ErrorId; sprintf(_this->ErrorMsg, _this->m_CheckForNew.ErrorMsg.c_str()); } } catch(...) { _this->ErrorID = SQL_EXEC_ERROR; sprintf(_this->ErrorMsg, "Error executing procedure: Error executing procedure."); } _endthreadex(0); return 0; } Класс БД(После визарда, почти ничего не менял): class Csp_mirCheckForNewCardInOffice : public CCommand<CAccessor<Csp_mirCheckForNewCardInOfficeAccessor>, CNoRowset > { public: std::string ErrorMsg; long ErrorId; Csp_mirCheckForNewCardInOffice() { ErrorMsg = ""; ErrorId = 0; } public: HRESULT OpenAll() { HRESULT hr; hr = OpenDataSource(); if (FAILED(hr)) { this->CheckOLEDBError(hr); return hr; } __if_exists(GetRowsetProperties) { CDBPropSet propset(DBPROPSET_ROWSET); __if_exists(HasBookmark) { propset.AddProperty(DBPROP_IRowsetLocate, true); } GetRowsetProperties(&propset); return OpenRowset(&propset); } __if_not_exists(GetRowsetProperties) { __if_exists(HasBookmark) { CDBPropSet propset(DBPROPSET_ROWSET); propset.AddProperty(DBPROP_IRowsetLocate, true); return OpenRowset(&propset); } } return OpenRowset(); } HRESULT OpenRowset(DBPROPSET *pPropSet = NULL) { try { HRESULT hr = Open(m_session, NULL, pPropSet); if(FAILED(hr)) this->CheckOLEDBError(hr); return hr; } catch(CAtlException &ex) { ErrorId = 60017; ErrorMsg = "Error executing procedure: Error executing procedure."; return ex.m_hr; } catch(...) { ErrorId = 60017; ErrorMsg = "Error executing procedure: Error executing procedure."; return FAIL; } } void CloseAll() { Close(); ReleaseCommand(); CloseDataSource(); } void CheckOLEDBError(HRESULT hr) { try { CDBErrorInfo myErrorInfo; ULONG numRec = 0; BSTR myErrStr,mySource; ISQLErrorInfo *pISQLErrorInfo = NULL; LCID lcLocale = GetSystemDefaultLCID(); myErrorInfo.GetErrorRecords(&numRec); // ERRORINFO* ErrINFO; if (numRec) { myErrorInfo.GetAllErrorInfo(0,lcLocale,&myErrStr,&mySource); // myErrorInfo.GetBasicErrorInfo(0, ErrINFO); ErrorMsg = (_bstr_t)(myErrStr); if(ErrorMsg.find("Timeout expired") != std::string::npos) ErrorId = 60016; if(ErrorId == 0) ErrorId = 60017; if(ErrorMsg.length() > 7998) ErrorMsg = ErrorMsg.substr(0, 7998); } } catch(...) { ErrorId = 60017; ErrorMsg = "Error executing procedure: Error executing procedure."; } } }; ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 13:04 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
MasterZivОбнаружение разрыва соединения зависит целиком от используемых сетевых библиотек (TCP/IP, IPX/SPX и т.д.). Например, в TCP есть специально настраиваемый time-out, после достижения которого соединение считается разорванным. Так в MSDN я об этом читал... Только данный таймаут установить можно только на все соединения, а это в даннос случае не годиться, таймаут нужно настроить только для выполнения одного запроса и для определенного удаленного сервера, чего сделань нельзя, или я ошибаюсь...? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 13:08 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Slava SolovievТак в MSDN я об этом читал... Только данный таймаут установить можно только на все соединения, а это в даннос случае не годиться, таймаут нужно настроить только для выполнения одного запроса и для определенного удаленного сервера, чего сделань нельзя, или я ошибаюсь...? Почему нельзя? Можно. Но это зависит от сервера. Если ты рвешь связь с сервером БД - мало прибить клиентский поток сделавший запрос. Надо послать на сервер команду отмены (причем не все сервера БД такую команду имеют). Потом закрыть коннект, и только потом прибивать поток. После того как ты скомандуешь серверу отменить запрос - сервер начнет делать rollback и в зависимости от сложности запроса информация о коннекте будет еще некоторое время висеть в списке коннектов на сервере. А вот если ты все это учтешь - задача станет действительно очень простой :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 18:32 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
White Owl Slava SolovievТак в MSDN я об этом читал... Только данный таймаут установить можно только на все соединения, а это в даннос случае не годиться, таймаут нужно настроить только для выполнения одного запроса и для определенного удаленного сервера, чего сделань нельзя, или я ошибаюсь...? Почему нельзя? Можно. Но это зависит от сервера. Если ты рвешь связь с сервером БД - мало прибить клиентский поток сделавший запрос. Надо послать на сервер команду отмены (причем не все сервера БД такую команду имеют). Потом закрыть коннект, и только потом прибивать поток. После того как ты скомандуешь серверу отменить запрос - сервер начнет делать rollback и в зависимости от сложности запроса информация о коннекте будет еще некоторое время висеть в списке коннектов на сервере. А вот если ты все это учтешь - задача станет действительно очень простой :) Я не смог найти команду отмены запроса в OLEDB... Не подскажешь ??? Использую MSSQL2000. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 18:42 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Да и еще забыл сказать, как я пошлю команду отмены, если канала нет ??? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 18:43 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
не понятно что такое switch(dw) откуда прибежал ? если это Вы делаете в цикле - 100% проца Вам обеспечено. И ещё... 1) Нет контроля (возможно опущен) подьёма нитки. Фаза СИНХРОННАЯ и должна контролироваться. В противном случае при ударной нагрузке может выполняться не в той последовательности, чем при спокойном режиме. 2) Между потоком и основной ниткой заводите синхро обьект. Либо ждёте на хэндлере самого потока (возможно так и есть - не вижу просто) определённое время. 3) Выше уже подсказали механизацию "убийств" со стороны сервака. Думаю Вам придёться открывать для этого ышо один коннект. Это в случае когда сервак жив. 4) Думаю если сервак труп - то молчать будут и другие службы. Например ICMP. удачи вам (круглый) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 19:23 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Slava SolovievЯ не смог найти команду отмены запроса в OLEDB... Не подскажешь ??? ICommand::Cancel() наверное, ни разу в жизни не работал с OLE DB из С, так что могу и ошибиться :) В ODBC есть функция SQLCancel(), в ADO у объектов делающих запросы есть метод Cancel(). Slava SolovievИспользую MSSQL2000. Значит идешь в форум где тусуются любители MSSQL2000 и спрашиваешь у них как сервер ведет себя при отмене последней недовыполненой команды. Как он ведет себя при закрытии коннекта к серверу без отмены недовыполненной команды. Как он ведет себя в случае довыполнения команды, но обрывом связи клиентом без коммита. Это все вопросы первоочередной важности. Их надо знать на зубок. Slava SolovievДа и еще забыл сказать, как я пошлю команду отмены, если канала нет ??? Если канала уже нет, то никак конечно же. Тогда только молится что сервер правильно обработает пропадание клиента. Но по хорошему, ты все же сначала должен скомандовать серверу отмену, потом закрыть коннект, и только потом убивать процесс. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.07.2005, 20:06 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
после вырубания клиента (напр. по 3 клавишам) на сервере начинается откат транзакции до полного его завершения. 2. Непонятна постановка: - если сервер не доступен то это проверяется простой процедурой SELECT CONNECT. - не доступен из-за загрузки его - не определишь. ============ Тогда в чём проблема? ============ ЗЫ. поиск по KILL на форуме сиквела http://www.sql.ru/forum/actualtopics.aspx?search=kill+&bid=1 ______________________________________________ Вы имеете право хранить молчание! Всё что Вы скажете может быть использовано против Вас в суде! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.07.2005, 11:12 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
kolobok0не понятно что такое switch(dw) откуда прибежал ? если это Вы делаете в цикле - 100% проца Вам обеспечено. И ещё... 1) Нет контроля (возможно опущен) подьёма нитки. Фаза СИНХРОННАЯ и должна контролироваться. В противном случае при ударной нагрузке может выполняться не в той последовательности, чем при спокойном режиме. 2) Между потоком и основной ниткой заводите синхро обьект. Либо ждёте на хэндлере самого потока (возможно так и есть - не вижу просто) определённое время. 3) Выше уже подсказали механизацию "убийств" со стороны сервака. Думаю Вам придёться открывать для этого ышо один коннект. Это в случае когда сервак жив. 4) Думаю если сервак труп - то молчать будут и другие службы. Например ICMP. удачи вам (круглый) ой, пардон, забыл :) switch(dw) Вобщем читать так : unsigned threadID; hTh = (HANDLE)_beginthreadex( NULL, 0, &Start, this, 0, &threadID ); DWORD dw = WaitForSingleObject(hTh, this->TimeOut * 1000); switch(dw) { case WAIT_OBJECT_0: // процесс завершается case WAIT_TIMEOUT: // процесс не завершился в течение TimeOut case WAIT_FAILED: // неправильный вызов функции (неверный описатель?) } Это ожидание завершение процесса.... по пункту 3 - Видимо да, хотя не очень бы хотелось... по пункту 4 - Если не сложно, то может у вас есть класс дя пинга по ICMP... Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.07.2005, 12:42 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Petro123 - если сервер не доступен то это проверяется простой процедурой SELECT CONNECT. А можно об этом поподробнее... Спасибо. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.07.2005, 12:54 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
Slava Soloviev Petro123 - если сервер не доступен то это проверяется простой процедурой SELECT CONNECT. А можно об этом поподробнее... Спасибо. даёшь запрос: Код: plaintext - послать по мылу сообщение. - материться матом на уборщицу за швабру. - запустить таймер на реконнект всех открытых таблиц. - .......... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.07.2005, 13:06 |
|
||
|
Время исполненя процедуры.
|
|||
|---|---|---|---|
|
#18+
pkarklin ............Ну, если автоматом делать реконнект, то можно и так. У меня просто м меню Сервис есть пункт Восстановить подключение, которое и выбирает пользователь, если коннект разорвался, а такое бывает редко. ______________________________________________ Вы имеете право хранить молчание! Всё что Вы скажете может быть использовано против Вас в суде! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 13.07.2005, 13:08 |
|
||
|
|

start [/forum/topic.php?fid=57&msg=33160947&tid=2033038]: |
0ms |
get settings: |
8ms |
get forum list: |
11ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
52ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
38ms |
get tp. blocked users: |
1ms |
| others: | 214ms |
| total: | 338ms |

| 0 / 0 |
