CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Steve Hebert's Development Blog

Steve's Blog - From .Net to dotMath and everything in between.

March 2005 - Posts

  • CLR/SqlServer Integration editorial on SSWUG

    Joe Celko has an editorial on CLR integration with Sql Server 2005 on the SSWUG site titled "CLR: Threat or Menace".

    On one hand, I absolutely agree with Mr. Celko on the fact that a bad developer will bring the database to its knees.  This is regardless of the presence of the CLR.  Project planning on a Sql Server 2005 project that utilizes CLR code must be extremely aware of the people they are dedicating to that task.  I certainly agree that a bad programmer will ignore the optimizations that can be made by the set-based processing of the SQL engine and decide to muscle processing through row-based processes.  However I think this is where Joe's argument starts to go flat.  The argument starts pointing at developers as the prototypical “unwashed masses” and supports CLR exclusion by campaigning under the basic idea of “a cork for every fork.”

    Here are a few points I found questionable…

    • “What do the CLR languages do with NULLs?  They do not have null, so the programmers will have to catch them and make up their own rules for stored procedures or constraints.“  Note to Joe, it’s all in the Sytem.Data.SqlTypes namespace…
    • “When programmers write CLR code inside the database, they will use cursors, explicitly or implicitly inside objects. Go to any SQL Newsgroup and look at the postings. The newbies confuse rows and records, columns and field, and think that tables have an ordering.”  I believe Mr. Celko is arguing that developers fail to see the set-based orientation of SQL and will inevitably misuse the tool. As I recall there was a time when SQL was viewed as a way to kill database performance by hiding the technical details from the users – just because I can do it in SQL doesn’t mean I always should.  Let’s face it, Mr. Celko’s long-running SQL coding exercises would’ve had SQL’s opponents pointing to these as reasons SQL is evil.  SQL’s early venomous detractors have largely disappeared, and I suspect CLR integration detractors will largely go the same route. 
    • “No good Sql programmer would code at the level of bits and bytes.”  -  Without an understanding of how the bits and bytes operate, can you really develop more than a regurgitative understanding of how the database optimizes joins and set selection?
    • “Will Johnny write a trigger or stored procedure with the functions from his favorite CLR?”  I have not heard any Microsoft type state that triggers should be written in CLR code.  This is due, in large part, to the overhead and latency of executing CLR code. 
    • Mr. Celko points out the SQL/PSM role, an ANSI/ISO standard for putting procedural code into the schema. Does the world really need yet another language to solve a simple task?  A real programmer is not excited by languages, but by the problems at hand and how to solve them.  Languages are nothing more than a tool – why create more when you can utilitize tools that have a larger audience?
    • Mr. Celko points out the need for a strict division between the database people and applications people and never the two shall meet. If any talent pool was more diluted by the boom cycle of the ‘90s it’s the DBA.  It’s easy to argue that most DBA’s are nothing more than operations people with over-hyped titles.
    Added Note:  While I'm being critical of Mr. Celko's approach to the .Net issues, I do own his "Joe Celko's Trees and Hierarchies in SQL for Smarties" book and find it a tremendous reference.
  • design pattern search

    I've been looking for a design pattern, but I'm not seeing it yet. 

    Given an application where application state is fully contained in memory, the database is merely a stateserver for restore purposes and integration with the application is handled through staging tables,  I'm looking for a pattern that discusses a LazyWrite that incorporates a Unit of Work pattern where transactions cancel the staging record and update the state database simulataneously.  Being a lazy write on the Unit of Work objects, it uses a background thread to perform the actual write to allow the in-memory server to continue responding to application-level interactions regardless of the database load.  The goal of the pattern is two-fold - keeping the data in a known state where no transactions are lost in the event of a power failure and performance of the in-memory server is not impacted by database performance.  If incoming transactions are not saved in the time between processing and a power-outage, restarting the server merely performs these transactions again once the in-memory state is restored.

    I have a feeling this may be a new pattern and there are several combinations of patterns that work nicely in this type of application. Perhaps I'll have to start writing about these and sharing.

  • Time limit testing with NUnit

    Here is a series of classes I use to test elapsed times within NUnit test.  While I use these functions very rarely, they come in handy when necessary.  This gives me the ability to directly monitor performance changes caused by inefficient code in a bug fix or feature addition.  Please note I've trimmed out pieces in the AppTimer that deal with runtime performance logging and I'm throwing an exception rather than performing an 'Assert.IsTrue(...)' function call.  The runtime performance logging is dropped to shorten the discussion and the Assert class is ignored for the sake of not wanting to bind to the NUnit.Framework in some conditions.

    The code below shows an 'AppTimer' class that grabs the tick count upon instantiation.  The client code can then call 'BoundedTimeTest()' to declare the maximum time allowed for the test.  If the elapsed time (measured in milliseconds) is greater than the requested maximum, then an AppTimerException is raised. As noted earlier, I am throwing an AppTimerException which is used so the test can rely upon [ExpectedException] attribute on the test function.


    public class AppTimerException : System.Exception

    {

       public AppTimerException()

       {

       }

     

       public AppTimerException(string Message) : base(Message)

       {

       }

     

       public AppTimerException(string Message, Exception innerException) : base(Message, innerException)

       {

       }

    }

     

    public class AppTimer

    {

       int _StartTick;

     

       public AppTimer()

       {

          _StartTick = Environment.TickCount;

       }

     

       private int GetElapsedTime()

       {

          return Environment.TickCount - _StartTick;

       }

     

       public void BoundedTimeTest( int TimeLimit )

       {

          int ElapsedTime = GetElapsedTime();

     

          if( TimeLimit

          {

             string Message = string.Format("Elapsed time of {0} ms exceeded limit of {1} ms", ElapsedTime, TimeLimit );

             throw new AppTimerException(Message);

          }

       }

    }

     


     The last bit of code involves the bounded time checking for the test in question.  Note that the initial Load functionality is not timed because this test only concerns itself with structural feasability.


     

    CoreTest ct = new CoreTest();

    Engine ime = ct.LoadIME();

     

    AppTimer appTimer = new AppTimer();

     

    foreach( BomHeader bomHeader in ime.bomEngine.bomHeaders.Values )

       Assert.IsTrue(bomHeader.IsFeasable);


    appTimer.BoundedTimeTest(500);  // exception thrown if code takes longer than 500 milliseconds to process

     


    Keep in mind that timespan testing is used very rarely in a test suite (at least mine), but these classes make implementation very easy.

     

  • WebGrid.Net and working with OnTheFlyPostback

    This post relates to using the Intersoft WebGrid.Net grid object.  This web-based grid is extremely flexible, but currently requires Internet Explorer to run.  Intersoft is in the process of rolling out their products to support the Gecko engine.  I'm blogging this ability because it was not immediately apparent in the product documentation.

    The WebGrid.Net tool supports what they term "OnTheFlyPostback".  When you are working within the grid, things like edits, sorts and incremental row gets are handled by posting only the necessary information for the task at hand.  While the functionality is very cool, it circumvents some behaviors you expect on a PostBack.  Namely, if I have a seperate filter textbox control on the webpage and a postback occurs within the grid, the textbox control is always empty. Why? Because the textbox information was not posted back to the server.

    When you want send extra information back to the server in the case of a postback (such as the contents of a TextBox control), you can register the information using the AddInput(name, value) function.  This is a client-side script function that can be run at any time.  Any postback will send this information to the browser when a light-weight postback function occurs - and at the server you can access the values with Request.Form(key). 

    I've built a functions around the script and server-side code to automate this process on web user controls and it works quite nicely.

     

  • Non-code post: Microsoft to Buy Groove Networks

    I just read on the Wall Street Journal that Microsoft has announced it's buying Groove Networks.  I thought Microsoft was trying to build their own competing product.  I only blog this because I had a run-in with Groove's marketing department back in October of 2004.

    It'll be interesting to see what Microsoft does with this product.

  • SQL Server 2000 Self-Tuning - Myth or Reality?

    Here's a question that's bothered me for a long time.  I remember hearing from marketing types and even Microsoft partners early in the SQL 2000 product cycle that the product is self tuning.  I distinctly remember a situation thrown around with DBA types saying that they would delete all the indexes and run the server for 24 hours and the server's processor would be pegged at 100% utilization for this time-period.  SQL Server would then miraculously self-tune itself and processor utilization would drop to 25%.  Obviously these numbers are app specific, but I've never seen this 'self-tuning' aspect. 

    Now I guess if you count running a SQL Profiler Trace and then run the index tuning wizard against the result, then you could say the database is capable of tuning itself.  But 'self-tuning' is a pretty loaded phrase.  After all, when did the DBA become considered part of the database?  I'd love to see an example of how to get SQL Server 2000 to be self-tuning, but I can't find this anywhere outside the marketing docs.

  • Protecting SQL script execution from SQL TRACE peeking (MSSQL 2000)

    I've run into a situation where I want to prevent a SQL TRACE from capturing my SQL script execution.  Encryption/decryption of the script is a separate process not discussed here.

    I'm checking the trace status of SQL server after every other script bit (a somewhat arbitrary decision) that's been sent to the server.  If I run into an active trace, I stop running the script and raise an error message stating this condition.  The server is checked every 4 seconds until the user clears the trace or cancels the process.  The code below is from a class that implements threaded processing of the script - this way multiple servers can be upgraded at the same time.  The class is responsible for tracking runtime messages and providing updated progress percentages that are displayed by the UI running on a separate thread (the UI thread periodically queries the object for updated messages and all message processing has been made thread-safe). I'm leaving out the UI pieces and related messaging components of the class because it's just not pertinent to the problem. 

    The larger script is broken into pieces by delimiting based on "\ngo\n".

    public bool IsTraceRunning(SqlConnection sqlConn)
    {
       SqlCommand sqlComm =
    new SqlCommand("select count(*) from :: fn_trace_getinfo(default)", sqlConn );
       object oObj = sqlComm.ExecuteScalar();
       Int32 iCount = (Int32) sqlComm.ExecuteScalar();
       return iCount > 0;
    }

    public void ThreadProc()
    {
       using( SqlConnection sqlConn = new SqlConnection( _ProcessData.ConnectionString ))
       {
          _ProcessData.AddMessage("Connection string accepted.");
          try
          {
             sqlConn.Open();
             _ProcessData.AddMessage("Connection Opened.");
          }
          catch( Exception ex )
          {
             _ProcessData.AddMessage(
    string.Format("FATAL ERROR: {0}", ex.ToString()) );
             _ProcessData.FatalError =
    true;
             return;
          }
          int iPos = 0;
          ArrayList asScriptBits = _ProcessData.UpgradeScripts;
          _ProcessData.AddMessage("Performing Update Scripts...");

          bool bWaitingOnTrace = false;

          while( iPos < asScriptBits.Count && ! _ProcessData.Abort)
          {
             if( iPos % 2 == 0 )
             {
                if( IsTraceRunning(sqlConn))
                {
                   if( ! bWaitingOnTrace )
                      _ProcessData.AddMessage("UPGRADE PAUSED! Please terminate all traces against this database to continue.");

                   bWaitingOnTrace = true;
                   Thread.Sleep(4000);
    // wait 4 seconds before trying again.
                   continue;
                }
             }


             if( bWaitingOnTrace )
             {
                _ProcessData.AddMessage("Trace terminated. Continuing upgrade process.");
                bWaitingOnTrace =
    false;
             }

             using( SqlCommand sqlComm = new SqlCommand(asScriptBits[iPos] sqlConn ))
             {

                try
                {
                   sqlComm.ExecuteNonQuery();
                }
                catch( Exception ex )
                {
                   string sErrorCount = string.Format("({0} of {1}): {2}", iPos, asScriptBits.Count, ex.ToString() );
                   _ProcessData.AddMessage( ex.ToString() );
                   _ProcessData.AddError((
    string)asScriptBits[iPos], sErrorCount );
                }
             }
             _ProcessData.ProgressCount = iPos + 1;
             iPos++;
          }

          _ProcessData.Finished = true;

          if( _ProcessData.Abort )
             _ProcessData.AddMessage("Process aborted successfully. Upgrade is not complete!");
          else
             _ProcessData.AddMessage("Update Complete.");
       }
    }

  • DHTML Lemmings game

    Here's a DHTML Lemmings game. I remember when this game was a compelling reason to buy a Commodore Amiga.

     

    Posted Mar 08 2005, 06:39 AM by shebert
    Filed under:
  • Recycling the ASP.NET worker process at set intervals

    Many ASP.NET developers are not aware of the ability to restart the ASP.NET worker process at given intervals in code.  While IIS6.0 makes a number of these features available through the UI, most of the features can be used in IIS5 and 5.1 as well.  I've found this useful for rogue components that are consuming memory and this provides a bandaid fix until the root problem is identified.
     
    The <processModel> model configuration setting allows you to set limits that any given running ASPNET_WP process will operate under until it's recycled.  For instance, if I set requestLimit="10000", a given ASPNET_WP process will run until 10000 requests have been serviced.  At that time, a new ASPNET_WP service will start and requests will be directed at it.  The old ASPNET_WP process will then be shut down.
     
    This setting can be made in the machine.config file and affects all processes .Net processes on that machine.  The related MSDN article can be found here.
     
  • Garbage Collection articles

    I've run into the need for these articles on the .Net garbage collector a couple of times in the past month - I thought I'd blog them so I know where they are.  The first two were written prior to .Net's release by Jeffrey Richter. The third article is a nice discussion on the impact of design choices related to the garbage collector.

    http://msdn.microsoft.com/msdnmag/issues/1100/GCI/TOC.ASP?frame=true
    http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/TOC.ASP?frame=true

    http://msdn.microsoft.com/library/en-us/dndotnet/html/dotnetgcbasics.asp?frame=true

  • Extending Javascript functions with respect to web user controls

    I've run into a number of situations where I want to provide overridable client-side functionality on objects running within a 'web user control'. I was talking to another developer and we were talking about this functionality, so I thought I'd take a second and blog it. 

    As an example, I'm working with a 3rd party grid and I've wrapped my right-click, context menu functionality entirely within the user control.  In the case of the application, this makes a great deal of sense.  However, in one or two cases I want to override some of the handling of the right-click creation on a page-by-page basis. 

    To address this problem, I'm using function pointers in javascript.  While function pointers in javascript aren't as nice as their c++ counterparts, they serve this function quite well.  Given a function called HandleContextMenus(...), I added the final bit of code to check for the existance of an 'agreed upon function' and execute it if it's defined.

    function HandleRowContextMenu( gridId, rowType, rowEl, rowMenu )
    {
       // normal 99% functionality happens here...
       
       var refFunction;
       try
       {
          refFunction = HandleRowContextMenu_Override;
       }
       catch(e)
       {
          refFunction = null; // just to be sure...
       }

       if( refFunction != null )
          refFunction( gridId, rowType, rowEl, rowMenu );
    }

    Given this functionality, I can run all my existing pages without modification.  For the pages that do require the functionality, I can simply provide a javascript function named "HandleRowContextMenu_Override" on the hosting page. 

    <script language=javascript>
    function HandleRowContextMenu_Override( gridId, rowType, rowEl, rowMenu )
    {
       // do something useful here
    }
    </script>

    I like the implementation and use it in other contexts as well.  The only piece I don't like is native to Javascript - the inability to tell if the user defined the override function with the proper signature. If anyone knows a way to handle this situation, I'd love to hear it.

  • Sql Server 2005 Pricing announced

    Microsoft announced pricing for Sql  Server 2005.  While they've upped the price of the enterprise and standard editions, they have introduced a workgroup edition and driven several operational features that were Enterprise-only down into the cheaper versions. 

    Given the role of .net in this release, I'm sure I'll be doing a lot of coding around this engine.

More Posts

Our Sponsors

Free Tech Publications