Hi
I am wondering whether the Postgres implementation in Purebasic is thread safe? I created a ISAPI extension using Purebasic and compiled it with the "Create Thread safe" flag set but I get errors from time to time such as "extraneous data in "T" message" or "insufficient data in "T" message
". I believe this maybe due to the fact that my ISAPI extension is running in a multithreaded environment.
Perhaps I should open a new connection HttpExtensionProc instead of opening the database connection in AttachProcess.
Thanks,
Simon
Is Postgres Implementation Thread Safe?
Is Postgres Implementation Thread Safe?
Simon White
dCipher Computing
dCipher Computing
Re: Is Postgres Implementation Thread Safe?
It should be, the lib is compiled is compiled with ENABLE_THREAD_SAFETY define, and the PB lib is threadsafe.
Re: Is Postgres Implementation Thread Safe?
Okay thank-you for that information. I will change the way I handle connections and see if my problem goes away.
Simon
Simon
Simon White
dCipher Computing
dCipher Computing
Re: Is Postgres Implementation Thread Safe?
I changed my code to open a new connection on each ISAPI request and I stopped getting the Postgres error messages. I installed pgBouncer for connection polling so I do not have to have the cost of creating a new connection on every request. So far things are working smoothly.
Thanks,
Simon
Thanks,
Simon
Simon White
dCipher Computing
dCipher Computing
Re: Is Postgres Implementation Thread Safe?
Nice to hear !
Re: Is Postgres Implementation Thread Safe?
Hi
It appears I may have spoken too soon. I get many less errors now but I do get some like the following:
Which occurred immediately after successfully creating the connection to the database.
or
Line 947 is
It appears I may have spoken too soon. I get many less errors now but I do get some like the following:
Code: Select all
select pid,site from dcfusnsrvc.khsite where siteid='BVDCORN55400' failed due To error: no connection to the server
or
Code: Select all
Error : C0000005 on line 947 in C:\Business\dCipherComputing\Applications\FusionPro\PB_Windows\dCFusionREST.pb
Code: Select all
ProcedureReturn #HSE_STATUS_SUCCESS
Code: Select all
; This is the main function that is called for each client request
; *pECB contains all needed data
;
ProcedureDLL HttpExtensionProc(*pECB._EXTENSION_CONTROL_BLOCK)
Define lcJSON.s,lnSize.i,lnBytes.i,lnLen.i,*Ascii,*Header,*Status,lcTrn.s,lcHTM.s
Define Header._HSE_SEND_HEADER_EX_INFO
;
; Send the response header with the ServerSupportFunction() callback
;
Header._HSE_SEND_HEADER_EX_INFO
*Status = AllocateMemory(100)
*Header = AllocateMemory(100)
PokeS(*Status, "200 OK", 6, #PB_Ascii)
PokeS(*Header, "Content-type: application/json" + #CRLF$ + #CRLF$, 34, #PB_Ascii)
Header\pszStatus = *Status
Header\pszHeader = *Header
Header\cchStatus = 6 ; Length of Status
Header\cchHeader = 34 ; Length of Header
Header\fKeepConn = 0
goParam\Sec = ElapsedMilliseconds()
goParam\Rcvd = ReplaceString(RemoveString(GetRestData(*pECB),Chr(13)),Chr(39),Chr(34)) ; PB expects JSON to use double quotes
goParam\URL = LCase(ServerVariable(*pECB,"HTTP_URL"))
goParam\Port=ServerVariable(*pECB,"SERVER_PORT")
goParam\Auth=ServerVariable(*pECB,"HTTP_AUTHENTICATION")
goParam\SiteID=ServerVariable(*pECB,"QUERY_STRING")
goParam\Method=ServerVariable(*pECB,"REQUEST_METHOD")
goParam\dBNo=OpenDatabase(#PB_Any,goParam\dBName,goParam\dBUser,goParam\dBPwd,#PB_Database_PostgreSQL)
If Not goParam\dBNo
goParam\dBNo=OpenDatabase(#PB_Any,goParam\dBName,goParam\dBUser,goParam\dBPwd,#PB_Database_PostgreSQL)
EndIf
If Not goParam\dBNo
WriteToLog("**ERROR HTTPExtensionProc("+goParam\dBName+" uid="+goParam\dBUser+" pwd="+goParam\dBPwd+") failed To open connection.")
ElseIf Not IsAuthenticated(@goParam)
PokeS(*Status, goParam\Msg,StringByteLength(goParam\Msg,#PB_Ascii), #PB_Ascii)
Header\cchStatus = 16
lcJSON = ~"{\"msg\":\"401 Unauthorized - "+goParam\Method+goParam\URL+~"\"}"
ElseIf goParam\Method+goParam\URL = "POST/rest/prices.fusion?"+LCase(goParam\SiteID)
WriteToLog(goParam\SiteID+" "+goParam\Rcvd)
SavePrices(goParam)
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\"}"
ElseIf goParam\Method+goParam\URL = "POST/rest/transactions.fusion?"+LCase(goParam\SiteID)
WriteToLog(goParam\SiteID+" "+goParam\Rcvd)
lcTrn = GetTransactions(goParam)
If lcTrn = ""
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\",\"transactions\":[]}" ; Javascript does not expect the array without quotation marks.
Else
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\",\"transactions\":"+lcTrn+"}" ; Javascript does not expect the array without quotation marks.
EndIf
ElseIf goParam\Method+goParam\URL = "POST/rest/transactionexport.fusion?"+LCase(goParam\SiteID)
WriteToLog(goParam\SiteID+" "+goParam\Rcvd)
lcTrn = GetTransactionExport(goParam)
If lcTrn = ""
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\",\"transactions\":[]}" ; Javascript does not expect the array without quotation marks.
Else
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\",\"transactions\":"+lcTrn+"}" ; Javascript does not expect the array without quotation marks.
EndIf
ElseIf goParam\Method+goParam\URL = "POST/rest/receipt.fusion?"+LCase(goParam\SiteID)
WriteToLog(goParam\SiteID+" "+goParam\Rcvd)
lcHTM = PrintReceipt(goParam)
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\",\"receipt\":\""+lcHTM+~"\"}"
ElseIf goParam\Method+goParam\URL = "POST/rest/register.fusion?"+LCase(goParam\SiteID)
WriteToLog(goParam\SiteID+" "+goParam\Rcvd)
If StrExtract(goParam\Rcvd,~"\"validate\":\"",#DQUOTE$) = "email"
SendeMsg(goParam)
Else
SendTextMsg(goParam)
EndIf
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\"}"
ElseIf goParam\Method+goParam\URL = "POST/rest/register_post.fusion?"+LCase(goParam\SiteID)
WriteToLog(goParam\SiteID+" "+goParam\Rcvd)
goParam\CCAcctNo = Trim(StrExtract(goParam\Rcvd,#dCCCAcctNo,","))
goParam\HostKey1 = Trim(StrExtract(goParam\Rcvd,#dCHostKey1,","))
goParam\HostKey2 = Trim(StrExtract(goParam\Rcvd,#dCHostKey2,","))
goParam\CCNo = Trim(StrExtract(goParam\Rcvd,#dCCCNo,","))
goParam\CCExpiry = Trim(StrExtract(goParam\Rcvd,#dCCCExpiry,","))
goParam\CCName = Trim(StrExtract(goParam\Rcvd,#dCCCName,","))
goParam\CCCVV = Trim(StrExtract(goParam\Rcvd,#dCCCVV,","))
CC_CardVerify(@goParam)
lcJSON = ~"{\"msg\":\""+goParam\Msg+~"\",\"cctoken\":\""+goParam\CCToken+~"\",\"fuelcard\":\""+goParam\FuelCard+~"\"}"
Else
WriteToLog("**ERROR Bad Request("+goParam\Method+goParam\URL+")")
PokeS(*Status, "400 Bad Request", 13, #PB_Ascii)
Header\cchStatus = 15
lcJSON = ~"{\"msg\":\"Bad Request - "+goParam\Method+goParam\URL+~"\"}"
EndIf
*pECB\ServerSupportFunction(*pECB\ConnID, #HSE_REQ_SEND_RESPONSE_HEADER_EX, @Header, 0, 0)
;
; Send the html data with the WriteClient() callback:
;
lnLen = StringByteLength(lcJSON,#PB_Ascii)
*Ascii = Ascii(lcJSON)
*pECB\WriteClient(*pECB\ConnID,*Ascii, @lnLen, 0)
FreeMemory(*Ascii)
FreeMemory(*Header)
FreeMemory(*Status)
If #dCTestMode And lnLen <= 2048
WriteToLog(lcJSON)
ElseIf #dCTestMode
WriteToLog(Left(lcJSON,2048)+"...")
EndIf
If IsDatabase(goParam\dBNo)
CloseDatabase(goParam\dBNo)
EndIf
;
; Check log size once a day and clear if appropriate
;
If goParam\Day <> Day(Date())
goParam\Day = Day(Date())
ClearLog()
EndIf
ProcedureReturn #HSE_STATUS_SUCCESS
EndProcedure
ProcedureDLL AttachProcess(Instance)
OnErrorCall(@EHandler())
goParam\Day = Day(Date())
UseSHA2Fingerprint()
UsePostgreSQLDatabase()
SetCurrentDirectory(GetPathPart(ProgramFilename()))
goParam\StartIn = GetCurrentDirectory()
ClearLog()
If Not OpenPreferences(goParam\Startin+"dcMain.ini") Or Not PreferenceGroup("DATA")
WriteToLog("**ERROR '[Data]' section missing in dcMain.ini")
RaiseError(#ERROR_DLL_INIT_FAILED)
Else
If ExaminePreferenceKeys()
While NextPreferenceKey()
If PreferenceKeyName()="CONNECTIONSTRING"
goParam\dBCStr = PreferenceKeyValue()
Break
EndIf
Wend
EndIf
ClosePreferences()
goParam\dBName = "host=127.0.0.1 port="+StrExtract(goParam\dBCStr,"PORT=",";")+" dbname="+StrExtract(goParam\dBCStr,"DATABASE=",";")
goParam\dBPwd = StrExtract(goParam\dBCStr,"PWD=",";")
goParam\dBUser = StrExtract(goParam\dBCStr,"UID=",";")
EndIf
WriteToLog("AttachProcess("+goParam\StartIn+"dCFusionREST.dll ver. "+FormatDate("%yyyy.%mm.%dd.%hh.%ii",#PB_Compiler_Date)+" loaded successfully.)")
EndProcedure
Simon White
dCipher Computing
dCipher Computing