Monday, June 3, 2013

DataBus Compression

We have a requirement to be a bit conservative about our network traffic.  We are using the DataBus to move larger data elements to distributed locations.  My first attempt was to implement a transport message mutator to perform some compression, but it did not compress the DataBus properties.

Come to find out, those are stripped after the file is written to disc, so the compression never hits.  What I found to be the simplest thing to do is to just override the IDataBus/FileShareDataBus altogether.  IDataBus has a couple of simple methods, Get and Put to override.  I used the existing FileShareDataBus as a model and just injected some simple compression.  Let's start with Put:

        public string Put(Stream stream, TimeSpan timeToBeReceived)
        {
            var key = GenerateKey(timeToBeReceived);

            var filePath = Path.Combine(basePath, key);

            Directory.CreateDirectory(Path.GetDirectoryName(filePath));

            var outStream = new FileStream(filePath, FileMode.CreateNew);

            using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
            {
                var buffer = new byte[32 * 1024];
                Int32 read = 0;

                while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    tinyStream.Write(buffer, 0, read);
                }
            }

            return key;
        }

Note that all I really did was slip in the GZipStream. Now for Get:
        public Stream Get(String key)
        {
            var bigStreamOut = new MemoryStream();

            using (var bigStream = new GZipStream(File.OpenRead(Path.Combine(this.basePath, key)), CompressionMode.Decompress))
            {
                bigStream.CopyTo(bigStreamOut);
            }

            bigStreamOut.Position = 0;

            return bigStreamOut;
        }

Lastly all we need is a little bit of configuration magic:
    public static class ConfigureCompressedFileShareDataBus
    {
        public static Configure CompressedFileShareDataBus(this Configure config, String basePath)
        {
            var bus = new CompressedFileShareDataBus(basePath);

            config.Configurer.RegisterSingleton<IDataBus>(bus);

            return config;
        }
    }

Now we have a heck of a lot less data on the network...enjoy!