Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,590
|
Comments: 51,223
Privacy Policy · Terms
filter by tags archive
time to read 19 min | 3673 words

Since it appears to be customary, I decided that I need to make a few posts for April 1st. Here is the first of them.

private IEnumerator<int> SendInternal(AsyncEnumerator ae)
{
    try
    {
        using (var client = new TcpClient())
        {
            try
            {
                client.BeginConnect(Destination.Host, Destination.Port,
                                    ae.End(),
                                    null);
            }
            catch (Exception exception)
            {
                logger.WarnFormat("Failed to connect to {0} because {1}", Destination, exception);
                Failure(exception);
                yield break;
            }

            yield return 1;

            try
            {
                client.EndConnect(ae.DequeueAsyncResult());
            }
            catch (Exception exception)
            {
                logger.WarnFormat("Failed to connect to {0} because {1}", Destination, exception);
                Failure(exception);
                yield break;
            }

            logger.DebugFormat("Successfully connected to {0}", Destination);

            using (var stream = client.GetStream())
            {
                var buffer = Messages.Serialize();

                var bufferLenInBytes = BitConverter.GetBytes(buffer.Length);

                logger.DebugFormat("Writing length of {0} bytes to {1}", buffer.Length, Destination);

                try
                {
                    stream.BeginWrite(bufferLenInBytes, 0, bufferLenInBytes.Length, ae.End(), null);
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }
            
                yield return 1;

                try
                {
                    stream.EndWrite(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                logger.DebugFormat("Writing {0} bytes to {1}", buffer.Length, Destination);

                try
                {
                    stream.BeginWrite(buffer, 0, buffer.Length, ae.End(), null);
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                    exception);
                    Failure(exception);
                    yield break;
                }
            
                yield return 1;

                try
                {
                    stream.EndWrite(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not write to {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                logger.DebugFormat("Successfully wrote to {0}", Destination);

                var recieveBuffer = new byte[ProtocolConstants.RecievedBuffer.Length];
                var readConfirmationEnumerator = new AsyncEnumerator();

                try
                {
                    readConfirmationEnumerator.BeginExecute(
                        StreamUtil.ReadBytes(recieveBuffer, stream, readConfirmationEnumerator, "recieve confirmation"), ae.End());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not read confirmation from {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                yield return 1;

                try
                {
                    readConfirmationEnumerator.EndExecute(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Could not read confirmation from {0} because {1}", Destination,
                                      exception);
                    Failure(exception);
                    yield break;
                }

                var recieveRespone = Encoding.Unicode.GetString(recieveBuffer);
                if (recieveRespone == ProtocolConstants.QueueDoesNotExists)
                {
                    logger.WarnFormat(
                        "Response from reciever {0} is that queue does not exists",
                        Destination);
                    Failure(new QueueDoesNotExistsException());
                    yield break;
                }
                else if(recieveRespone!=ProtocolConstants.Recieved)
                {
                    logger.WarnFormat(
                        "Response from reciever {0} is not the expected one, unexpected response was: {1}",
                        Destination, recieveRespone);
                    Failure(null);
                    yield break;
                }

                try
                {
                    stream.BeginWrite(ProtocolConstants.AcknowledgedBuffer, 0,
                                      ProtocolConstants.AcknowledgedBuffer.Length, ae.End(), null);
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Failed to write acknowledgement to reciever {0} because {1}",
                                      Destination, exception);
                    Failure(exception);
                    yield break;
                }

                yield return 1;

                try
                {
                    stream.EndWrite(ae.DequeueAsyncResult());
                }
                catch (Exception exception)
                {
                    logger.WarnFormat("Failed to write acknowledgement to reciever {0} because {1}",
                                      Destination, exception);
                    Failure(exception);
                    yield break;
                }
                Success();

                buffer = new byte[ProtocolConstants.RevertBuffer.Length];
                var readRevertMessage = new AsyncEnumerator(ae.ToString());
                readRevertMessage.BeginExecute(
                    StreamUtil.ReadBytes(buffer, stream, readRevertMessage, "revert"), ae.End());
                yield return 1;
                try
                {
                    readRevertMessage.EndExecute(ae.DequeueAsyncResult());
                    var revert = Encoding.Unicode.GetString(buffer);
                    if (revert == ProtocolConstants.Revert)
                    {
                        Failure(null);
                    }
                }
                catch (Exception)
                {
                    // expected, there is nothing to do here, the
                    // reciever didn't report anything for us
                }

            }
        }
    }
    finally
    {
        var completed = SendCompleted;
        if (completed != null)
            completed();
    }
}

And yes, it is from real code, and it is going to production soon.

time to read 1 min | 197 words

After running into a spate of problems with MSMQ, and following my previous decision, I decided that I might as well bite the bullet and do what I usually do, write my own. I have looked into other queuing systems, and all of them has something in them that precluded me from using them. And not, that something wasn’t “I didn’t write them”, whatever some people may think.

I have the advantage of writing Rhino Queues 5 times already, but this time I am setting up with a set of new goals. I intend to unveil my creation soon, but for now, I thought it would be a good idea to talk a bit about the features that I intend to build.

Rhino Queues is a queuing system that is:

  • XCopy deployable
  • Zero configuration
  • Durable
  • Supports System.Transactions
  • Works well with Load Balancing hardware
  • Supports sub queues
  • Support arbitrarily large messages

I’ll talk about this in more details when I can actually show working code (which would be in a bit)…

time to read 2 min | 293 words

I have been doing Open Source stuff for five years plus now, you could say that it defines a lot of what I do. Increasingly, but for a long time, I have been feeling uncomfortable in my position as an Open Source developer that works on a proprietary operating system and proprietary platform.

I have been spending more and more time investigating alternative technologies, as you probably noticed, and by now I think that I have accumulated enough knowledge to deal with the shift without causing too much pain for me.

I am writing this post on my new machine, a Linux box running Debian. This seems like a good match for my position, since Debian doesn't allow non free software on their distribution. I repaved my Macs as well. OS X has started life as free software, but is it no longer free.

I had some issues along the way, but nothing that was truly serious. Now, to the development environment. I considered moving to Java, since it is now truly Open Source and is very similar to .Net. However, its roots are non Free, and I would like to make a clean break from non Free software. I considered Ruby as well, but I don't like it very much. Nothing specific beyond the it is too much of a buzzward.

Combining both personal preference and political stance, I decided to go with Erlang, which is Free and Open Source for over a decade. I have been digging in CouchDB's code lately, and it is very interesting.

That is all for now.

Oh, and you might experience some problems with the blog. I am moving it from Subtext (which is OSS, but running on non OSS platform) to Drupal on Linux.

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. RavenDB 7.1 (7):
    11 Jul 2025 - The Gen AI release
  2. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  3. Webinar (7):
    05 Jun 2025 - Think inside the database
  4. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  5. RavenDB News (2):
    02 May 2025 - May 2025
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}