Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

Authors

Search

XML Feeds

Google Ads

« Go ahead and click it! I triple dog dare you!!!How to search for all words inclusive without using Full Text search »
comments
Rate Post:
submit to reddit Digg!FacebookDotnetkicks

A few days ago I had a situation in which I needed to get backups for one of my DBs off to the hot site for disaster/recovery purposes. The primary goal was for me to again remove the need to rely on tape backups from my recovery plans. I already have Quests Litespeed in place and with that have the ability to retain a month of backups on a disk array attached to the instance that this DB resides on. That alone has me feeling comfortable but as most DBAs will agree, we never really get into a comfort zone and always feel the need to better protect out data from disasters. So compressed my backups for this DB are running around 15GB and the Differentials are around 6GB. Of course you can't just log in daily and drag'n'drop these files over the WAN. First the file may not get over there by the time you leave and you end up cancelling it. Second if you have something like RDP or VNC, the chances of the copy failing are 50\50 and then the file is useless for restore on the other side. This leads me to my theory of DBAs and the need for them to have basic development skills. I don't mean for DBAs to run out and become hard core developers. I'm talking about having the ability to go above and beyond the simplistic batch files and windows task manager. In the scenario I was faced with this time, I felt a windows service was idea to get the job done. This way I can use my backup schedules to my advantage and do copy tasks during those off peak hours. Basically my thought process was to grab the file once it was available in the backup directory. Once it was found based on the naming conventions of the files, I then start the copy over to the DR site. This happens through the night and then once the copy succeeds or fails use the event log to capture the events. Now I can simply browse the event viewer on the server the windows service is installed to see how my backups copied over. I can also test my backups by restoring them on that offsite instance either manually or through jobs. Testing your backups by restoring them is of course the best way to know if they will actually save you.

I'll be the first to admit that over the years I have lost some of my development skills. It's like anything else in technology really. If you don't use it for awhile, you need to work a bit harder to get the job done when you want to jump back on it. Being a DBA, development tasks are nowhere near a daily job. I do utilize SQLCLR and my knowledge of programming often but you can only use those skills to work as a DBA so often while retaining the, "use the right object for the task at hand" mentality. With that I thought posting the service and how to install it would be helpful to others. I'm still going through some additional error handling with the code and adding more logging but this is the shell of things.

First warning of this entire process is to find a server that you won't directly affect by the task. File operations cause high OS paging and a number of other issues with the servers resources. So don't go throwing this onto your primary database servers unless you want to have issues during copy times. I recommend to all DBAs to fight for a job server. Everyone should have an instance set aside and configured for jobs that perform tasks that put pressure on the database servers. Last thing you want to do is affect performance by trying to better secure your data. No matter what that task is.

The code for this type of task is pretty simple. In the OnStart of your windows service you initiate the timer and the call to the method in which you perform your tasks.

  1. protected override void OnStart(string[] args)
  2.         {
  3.             TimerCallback tmrCallBack = new TimerCallback(MoveBackup);
  4.             oTimer = new Timer(tmrCallBack);
  5.             oTimer.Change(new TimeSpan(0, 0, 1), new TimeSpan(0, 1, 0));
  6.         }

Then in our main method we need to first grab some config values. In this case we need the source and destination directory and we want this to be easily changed so hence the app.config usage. Once we have those values we grab all the files in the directories and then start running through them finding the files that are designated Full and Diff. In most cases log shipping will be going on or some other means so the log backups are unwanted for this operation. The last step in validation is to make sure we don't try copying files we already have on the destination. You do that by simply searching the array we filled up with file names. And of course after all this is done we simply copy it over. To better this you can throttle it up by chopping the file up and sending it across in small pieces similar to bringing down large files from HTTP sources. For this case I have the schedules for backups on off peak hours and a few hours of time in which I can do the copy without concern to flooding the pipe. The network is also setup to throw the copy to the back of network traffic so it will not take priority over other things.

So here is that method

  1. private void MoveBackup(object state)
  2.         {
  3.             string source = ConfigurationSettings.AppSettings["dirSource"];
  4.             string destination = ConfigurationSettings.AppSettings["dirDestination"];
  5.             string sSource;
  6.             string sLog;
  7.  
  8.  
  9.             sSource = "Full Backup Copy Service";
  10.             sLog = "Application";
  11.  
  12.             try
  13.             {
  14.                 oTimer.Change(Timeout.Infinite, Timeout.Infinite);
  15.  
  16.                 string[] files = Directory.GetFiles(source);
  17.                 string[] destfiles = Directory.GetFiles(destination);
  18.  
  19.                 for (int i = 0; i < files.Length; i++)
  20.                 {
  21.                     FileInfo f = new FileInfo(files[i]);
  22.  
  23.  
  24.                     if (((f.ToString().IndexOf("Full") > 0) || (f.ToString().IndexOf("Diff") > 0))
  25.                                     && (SearchArr(destfiles, f.Name.ToString()) == false)
  26.                                     && (f.CreationTime >= System.DateTime.Now.AddDays(-7)))
  27.                     {
  28.                         File.Copy(files[i], destination + f.Name);
  29.                         if (!EventLog.SourceExists(sSource))
  30.                             EventLog.CreateEventSource(sSource, sLog);
  31.  
  32.                         EventLog.WriteEntry(sSource, "Full backup file copy as " + destination + f.Name + " was successful at: " + System.DateTime.Now.ToString());
  33.                     }
  34.                 }
  35.                 oTimer.Change(new TimeSpan(0, 0, 1), new TimeSpan(0, 5, 0));
  36.             }
  37.             catch (Exception e)
  38.             {
  39.                 if (!EventLog.SourceExists(sSource))
  40.                     EventLog.CreateEventSource(sSource, sLog);
  41.  
  42.                     EventLog.WriteEntry(sSource, "Full backup file copy failure: " + e.Message.ToString(),EventLogEntryType.Warning, 234);
  43.                     oTimer.Change(new TimeSpan(0, 0, 1), new TimeSpan(0, 1, 0));
  44.             }
  45.            
  46.         }

And my supporting methods for searching arrays and grabbing the file names are

  1. private bool SearchArr(string[] arr, string search_string)
  2.         {
  3.             bool match = false;
  4.  
  5.             for (int i = 0; i < arr.Length; i++)
  6.             {
  7.                 if (GetFileName(arr[i].ToString()) == search_string)
  8.                 {
  9.                     match = true;
  10.                 }
  11.             }
  12.             return match;
  13.         }
  14.  
  15.         private string GetFileName(string filepath)
  16.         {
  17.             Regex r = new Regex(@"\w+[.]\w+$+");
  18.             return r.Match(filepath).Value;
  19.         }

These are nothing special and can be found online in hundreds of different forms.

After you have that all written this is how you install it if you have never done so.

Copy the debug or release folder form your project over to the server. Open command prompt and navigate to the .net framework version you have. in my case that is v2.0 so
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727

Using the InstallUtil.exe you install the service by simply calling the executable with the parm of your executable.
InstallUtil "C:\BackupCopy\CopyService.exe"

The installation is controlled by your installer you added to the project. The settings like user logon, start mode etc... are all set there. If you have a hard time with this I would use sites like code project and such to get you going on the fundamentals of writing windows services. They really are simple to get going. They are a pain to debug, but simple in comparison to other development tasks.

So there is my plea to all the DBAs to go out and have the motivation to learn some development skills. It can really make you an exceptional DBA and push you over that level of just another DBA monitoring index fragmentation. :)

About the Author

Ted Krueger has been working in development and database administration for 13+ years. Specialties range from High Availability and Disaster / Recovery setup and testing methods down to custom assembly development for SQL Server Reporting Services. Ted blogs and is also one of the founders of LessThanDot.com technology community. Some of the articles focused on are Backup / Recovery, Security, SSIS and working on SQL Server and using all of the SQL Server features available to create stable and scalable database services. Recent community contributions have been to organize SQL Saturday events in the Chicago-land to Milwaukee-land area for 2010 where he will also be speaking about various SQL Server topics. @onpnt
Social SitingsTwitterLinkedInLTD RSS Feed
1014 views
submit to reddit Digg!FacebookDotnetkicks

Comments and Feedback

4 comments

Comment from: AlexCuse [Member] Email
*****
Good read. One thing to note is that you don't need to roll your own method to get the file name.

System.IO.Path.GetFileName(string) will get you the same thing :)
09/07/09 @ 09:33
Comment from: onpnt [Member] Email
I think I did that strictly for speed. Grabbed code I wrote years ago though. Will check it out
09/07/09 @ 09:48
Comment from: SQLDenis [Member] Email
*****
Oh no onpnt is morphing, next he will start writing MDX queries :-)
09/07/09 @ 11:09
Comment from: Jerry Hung [Visitor] · http://www.SQLServerNewbie.com
I just use SyncBack Free, or there is also the freeware SQL Backup and FTP, which I don't know if is applicable to you or not
http://sqlbackupandftp.com/
09/07/09 @ 12:27

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)