Jump to content

glendean

Members
  • Posts

    18
  • Joined

  • Last visited

Everything posted by glendean

  1. From my novice point of view I see unigui as the graphical interface and delphi as the engine so if I was having stability issues I'd try trap any errors within delphi exceptions blocks. Else use TApplication.OnException to try trap application errors and write them to a log. Its also possible that external application calls are being delayed (database in deadlock for example) causing thread timeouts in unigui. So connection timeouts should be adjusted as not to cause timeouts in unigui etc.
  2. If anyone is planning to roll their own connection pooler on servermodule the following code using the zeos library completes over 12,000 sql requests a second from postgresql. In my case reducing the unigui app exe size, without bde, by a third. Data is temporarily stored in a array of array of variant (aka TUniDBData) which can be accessed from a tquery like replacement residing on forms or the mainmodule. Performance across the web is excellent as long as you instigate a request for data from clientevents. Please advise if I have goofed anywhere. Function TUniDBConnection.ExecuteQuery (Const Sql: String; var fData: TUniDBData; var ErrorMessage: String; Const NoResult: Boolean): Boolean; Var ConnectionID,Colind,rowind: Integer; begin Result := False; if Length(fConnections) = 0 then begin ErrorMessage := 'System is not connected to a database. Operation aborted.'; Exit; end; ConnectionID := -1; // Stress tested with 400 threads executing over 6 miilion sql request in total through 20 connections. // Throughput with 20 connections was 15,000 sql requests per second. // Typical average responce in real world should be 1-25 ms with 10 connections depending on load (10 conn = ~13,000 requests second) Try EnterCriticalSection(fGate); while ConnectionID = -1 do begin ConnectionID := SelectFreeConnection; If ConnectionID = -1 then begin resetevent(fWaitSignal); WaitForSingleObject(fWaitSignal, 10); end; end; InterlockedIncrement(fQueueBusy[ConnectionID]); //atomic operation. Finally LeaveCriticalSection(fGate); End; Try Try if NoResult = True then Result := fStatements[ConnectionID].Execute(SQL) Else begin fResultSets[ConnectionID] := fStatements[ConnectionID].ExecuteQuery(SQL); if Assigned(fResultSets[ConnectionID]) then begin Result := True; SetLength(fdata,fResultSets[ConnectionID].GetMetadata.GetColumnCount, 2); for ColInd := 1 to fResultSets[ConnectionID].GetMetadata.GetColumnCount do begin fdata[Colind-1, 0] := fResultSets[ConnectionID].GetMetadata.GetColumnLabel(Colind); fdata[Colind-1, 1] := fResultSets[ConnectionID].GetMetadata.GetColumnType(Colind); end; rowind :=1; while fResultSets[ConnectionID].Next do begin inc(rowind); SetLength(fdata,Length(fData), rowind + 1); for ColInd := 1 to fResultSets[ConnectionID].GetMetadata.GetColumnCount do begin case fResultSets[ConnectionID].GetMetadata.GetColumnType(ColInd) of stBoolean: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetBoolean(ColInd); stByte: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetByte(ColInd); stShort: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetShort(ColInd); stInteger: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetInt(ColInd); stLong: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetLong(ColInd); stFloat: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetFloat(ColInd); stDouble: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetDouble(ColInd); stBigDecimal: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetBigDecimal(ColInd); stBytes, stBinaryStream: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetBlob(ColInd).GetString; stDate: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetDate(ColInd); stTime: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetTime(ColInd); stTimeStamp: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetTimeStamp(ColInd); stAsciiStream, stUnicodeStream: fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetBlob(ColInd).GetString; else fdata[ColInd-1,RowInd] := fResultSets[ConnectionID].GetString(ColInd); end; end; end; end; end; Except on E: EzSQLException do begin SetLength(fdata,0, 0); ErrorMessage := 'Sql Error ' + Inttostr(E.ErrorCode) + ' : ' + E.Message; Result := False; end; End; Finally Interlockeddecrement(fQueueBusy[ConnectionID]); // atomic operation. SetEvent(fWaitSignal); // atomic operation. End; End; Function TUniDBConnection.SelectFreeConnection: Integer; var i: integer; begin Result := -1; for I := 0 to Length(fConnections) - 1 do begin if fQueueBusy = 0 Then begin Result := i; Break; end; End; end;
  3. Thanks Rafashad for the reassurance and headsup, Cheers, Glen
  4. I am wanting lightweight access to postgresql without the bde layer (I am not using data controls). I looked at mORMmot but found it too complexing and restrictive so instead created a thread safe connection class with an Array of zeos IZConnections that I plan to place on servermodule. The clientclass which sits on mainmodule passes the sql request and a pointer to its array (dataset) to a threadsafe class of IZConnections on servermodule. Thanks to the performance of zeos, under test in a delphi app, it completed 12,000 sql requests a second to 500 threads via 20 connections to postgresql (24 sql request per second per thread) in an oracle vm. My thoughts are that 10 or so IZConnections placed on servermodule should easily serve 500+ unigui sessions. Thus saving valuable resources (no Data.DB). I name form tconrols with a similar name to database fields so can update forms with one function call.... DBSetFormControls(self, SQL) etc. so don't need no dammed bde So my question is this. Is placing a class of zeos IZConnections on servermodule a bad idea for any reason? Note.... Speed of unigui through the www (via vpn prozy) using zeos IZConnections without bde is simply outstanding. Saving my bickies so I can rid myself of the unigui trial banner soon.
  5. I just recompiled an old unigui test project I did under an older version of unigui from year back that previously worked successfully under isapi. Seems to work ok in chrome. IE just continually shows a blue spinning wheel and loading..., but Mozilla firefox displays one record in the unidbgrid then displays an Ajax error box , K.Caller is null, ssz_(O0,1920,950);_ssz_(O73,1920,51);_ssz_(O11,1920,899);_ssz_(O31,1920,416);O31.setPosition(0,483);_ssz_(O39,1781,410);_ssz_(O19,1920,483);O8.setWidth(1920);O8.setHeight(950); I am not going to report this as a bug until I go through my code to see if its data related or not. If I cannot find error in my code I will try create test case as per new bug rules. Suggest you open yours in firefox to see if it displays ajax error. Glen
  6. Yes clearly Unigui will aid many that have better things to do than waste time developing a user interface for the web so think its good investment and considering its prepayment for the future purchase, I don't mind assisting at all. Glen
  7. If no-one has any better idea's you might want look at using TUniUrlFrame to open documents using javascript There is example at http://www.kavoir.com/2009/01/using-javascript-to-open-excel-and-word-files-in-html.html but it uses activex so restricts functionality to IE Glen <script type="text/javascript"> function openWord(strFilePath) { var yourSite = "http://www.yoursite.com"; openWordDocPath(yourSite + strFilePath); } function openWordDocPath(strLocation) { var objWord; objWord = new ActiveXObject("Word.Application"); objWord.Visible = true; objWord.Documents.Open(strLocation); } </script>
  8. I have been testing speed of UniStringGrid by loading 300 rows,10 columns of data. Its slow and I am guessing that's because of communication overhead between client and server. If it were possible to add rows in one hit... .Rows[x].CommaText:= '"","","","","","" ' I'm guessing it will reduce communication overhead, improving performance 10 fold for a 10 column grid. UniStringGrid aside, I see unigui as a very usable platform for providing web apps to public. Congratulations on a fine product. Glen
  9. For newbies like myself.... The windowless demo was modified so all controls reside on mainpanel with visible=false; The MainForm calls a login form with callback to allow setting of mainpanel.visible to true; A cookie records UserID. WindowlessLoginExample.zip
  10. Be simpler to.... procedure TMainForm.UniFormShow(Sender: TObject); if WebMode then LogonForm.Show; end; And set LogonForm.WindowSate to wsMaximized so Mainform isn't view-able. If they fail logon ...unisession.TerminateAfterSecs(0) and then show another form saying .... "Session Has Ended" with option to restart If they logon ... LogonForm.close; Glen
  11. did you try.... unit Main; ........... implementation {$R *.dfm} uses UniGUIVars, MainModule, Unit1; var aflag: boolean;
  12. Hi Alberto I have modified the master detail which should be placed in your uniGUI\Demos folder to get the data files. I have been testing unigui with absolute database controls, when looking up a secondary 20,000 record table using SQL (ABSSquery) it displays in tuniHtmlFrame near instantaneously. Glen MasterDetailHTML.zip
  13. ahh...Tdatasource.OnDataChange seems to fill my needs. unihtmlframe is proving dramatically faster than using a second UniDBGrid to display details of the master table... practically instantaneous.
  14. Can someone assist with a problem I have. I started with Windowless demo and added Master Grid to Main (form) linked to abs data controls in MainModule (form). I have added an unihtmlframe in Main (form) to display read only data by calling function in MainModule when user clicks on various selection buttons (using AjaxEvent). It works nicely except I also want the data in unihtmlframe to update when user scrolls the master grid in Main. Is there anyway to fire an event in Main from a MainModule datacontrol afterscroll event. Glen
  15. Simple Accordion Menu that displays in UniHTMLFrame Note... Most of the HTML code is from switchonthecode.com/tutorials/javascript-and-css-tutorial-accordion-menus so if you use please give their site a visit. To sample add a TUniLabel to MainForm called PCInfoLabel (case sensitive) Create a UniHTMLFrame and add the following code to UniHTMLFrame.HTML <!DOCTYPE html> <html> <head> <script> var ContentHeight = 200; var TimeToSlide = 250.0; var openAccordion = ''; function PCInformation(PCValue) { MainForm.PCInfoLabel.setText(PCValue); } function runAccordion(index) { var nID = "Accordion" + index + "Content"; if(openAccordion == nID) nID = ''; setTimeout("animate(" + new Date().getTime() + "," + TimeToSlide + ",'" + openAccordion + "','" + nID + "')", 33); openAccordion = nID; } window.onload=runAccordion(1); function animate(lastTick, timeLeft, closingId, openingId) { var curTick = new Date().getTime(); var elapsedTicks = curTick - lastTick; var opening = (openingId == '') ? null : document.getElementById(openingId); var closing = (closingId == '') ? null : document.getElementById(closingId); if(timeLeft <= elapsedTicks) { if(opening != null) opening.style.height = ContentHeight + 'px'; if(closing != null) { closing.style.display = 'none'; closing.style.height = '0px'; } return; } timeLeft -= elapsedTicks; var newClosedHeight = Math.round((timeLeft/TimeToSlide) * ContentHeight); if(opening != null) { if(opening.style.display != 'block') opening.style.display = 'block'; opening.style.height = (ContentHeight - newClosedHeight) + 'px'; } if(closing != null) closing.style.height = newClosedHeight + 'px'; setTimeout("animate(" + curTick + "," + timeLeft + ",'" + closingId + "','" + openingId + "')", 33); } </script> <style> .AccordionTitle, .AccordionContent, .AccordionContainer { position:relative; width:150px; } .AccordionTitle { display: block; background-color: #FF9927; font-weight: bold; text-align:center; font-family:Arial; font-size:8pt; font-weight:bold; vertical-align:middle; margin: 1px; cursor: pointer; padding: 5 5 5 7px; list-style: circle; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } .AccordionContent { text-align:center; overflow:auto; line-height:180%; overflow: hidden; display:none; } .AccordionContainer { border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; } </STYLE> </head> <body> <div id="AccordionContainer" class="AccordionContainer"> <div onclick="runAccordion(1);"> <div class="AccordionTitle" onselectstart="return false;"> PC Information </div> </div> <div id="Accordion1Content" class="AccordionContent"> <a href="javascript:PCInformation('Summary')">Summary</a> <BR> <a href="javascript:PCInformation('Services')">Services</a> <BR> <a href="javascript:PCInformation('Drives')">Drives</a> <BR> <a href="javascript:PCInformation('Network')">Network</a> </div> <div onclick="runAccordion(2);"> <div class="AccordionTitle" onselectstart="return false;"> Reports </div> </div> <div id="Accordion2Content" class="AccordionContent"> <a href="javascript:PCInformation('Report1')">Report1</a> </div> <div onclick="runAccordion(3);"> <div class="AccordionTitle" onselectstart="return false;"> System </div> </div> <div id="Accordion3Content" class="AccordionContent"> <a href="javascript:PCInformation('System1')">System1</a> </div> </div> </body> </html>
×
×
  • Create New...