Sitting in a Car, Listening to a Song

Last update 21 Aug 2014.

You are sitting in a car travelling at 120 km/hour, listening to a song that lasts for 5 minutes. At the end of the song you would have moved TEN KILOMETERS from the start!

How far is your office from your home? My office is almost 30 km from my home. So in that 5 minutes I have taken a third of the total distance between my office to my home.

The miracle of modern civilization :)

So how come on average I need 1.5 hours to get to office? <clue>rhetoric</clue>

Comments


Winter is Coming

Last update 20 Oct 2013.

Lahir di negara tropis, sampai umur 38 hidup di negara tropis, dan November 2013 nanti mau berkunjung ke negara subtropis untuk pertama kalinya, dan di sana sedang musim dingin :)

Menurut catatan cuaca November tahun lalu, di Belfast temperatur bawah rata-rata 5°C dan temperatur atas rata-rata 9°C, dengan kelembaban bawah rata-rata 76% dan kelembaban atas rata-rata 95%. Bandingkan dengan kondisi Jakarta November 2012 yang temperatur rata-rata bawah 26°C atas 33°C, kelembaban rata-rata bawah 62% atas 89%.

Sesudah cari-cari informasi di internet, strategi yang banyak dianjurkan untuk tetap nyaman pada suhu seperti itu adalah memakai thermal underwear dan memakai beberapa lapis pakaian. Saya beli tiga thermal underwear dari sumber yang berbeda:

Bulan Desember akan saya update thermal underwear mana yang paling bagus dan yang tidak efektif.

Stay tuned!

UPDATE 8 DESEMBER 2013

Saya sudah balik!

Beberapa temuan menarik:

Comments


Operator Precedence of ??

Last update 19 Aug 2013.

This bit me today:

public string stringemup(string a, string b)
{
    var result = a ?? "c" + b ?? "d";
    return result;
}

What do you expect to get when you call stringemup(null, null)? If you say cd then you, like me, forgot that the operator precedence of ?? is very low. It is almost at the bottom of the list.

So the evaluation flow is like this:

  1. a is null, so evaluate "c" + b ?? "d"
  2. "c" + b evaluates to “c”, so return “c”

To make the script work as originally intended, I need to add some parentheses:

var result = (a ?? "c") + (b ?? "d");

Extra: did you know that

?null + ""
""
?"" + null
""
?"a" + null + "b"
"ab"
?null + "a" + null + "b"
"ab"

Comments


Generating Insert Statements from MYSQL to be Run on SQL Server

Last update 01 Aug 2013.

I need to copy data from a table in a MYSQL database to a table with the same structure in a SQL Server database. Looks like my best bet to do it is to use MYSQLDUMP to generate insert statements, then run those insert statements in SQL Server.

MYSQLDUMP has a LOT of parameters. So after perusing 6 pages of parameter documentations and some trial and errors, this is the set of parameters that produced insert statements that can be readily run in SQL Server (MYSQL version 5.6.10):

mysqldump -hMYSQLHOST -uMYSQLUSERNAME -pMYSQLPASSWORD --no-create-info --complete-insert --skip-extended-insert --skip-quote-names --compact MYSQLDBNAME MYSQLTABLENAME

--no-create-info tells MYSQL that I don’t need create table statements.

--complete-insert tells MYSQL to include column names in the insert statements.

--skip-extended-insert tells MYSQL to add INSERT INTO ... for each row instead of MYSQL style of one INSERT INTO ... followed by multiple values.

--skip-quote-names tells MYSQL to not put backticks around table and column names.

--compact tells MYSQL to not write locking statements, comments, character set statements, etc. around the insert statements.

Example of output:

INSERT INTO MYSQLTABLENAME (COL1, COL2) VALUES ('1',3);
INSERT INTO MYSQLTABLENAME (COL1, COL2) VALUES ('8',3);

BUT! If your data has some string and the string contains single quote ', it is converted to backslash quote \' instead of the SQL standard two single quotes ''.

I haven’t found an easy solution for that except mass replacing:

  1. \r\n with real carriage return line feed
  2. \" with "
  3. \' with ''
  4. \\ with \

Comments


Optimistic Concurrency in RavenDB

Last update 30 Jun 2013.

This post is my digest of this article.

Suppose I have a table called sales:

create table sales (
    ID              bigint identity constraint PK_SALES primary key,
    ...
    Version         bigint not null     -- this column for optimistic concurrency
)

To implement poor man optimistic concurrency with SQL, in an update statement I would include the version in the where clause so in case someone else has modified the row, this statement would not modify any rows. I would also increment the version number to not let my update get overwritten by someone else:

update sales set ... , version = 2 where id = 1 and version = 1

I was planning to do the same with RavenDB, but it turned out RavenDB implements optimistic concurrency differently. RavenDB follows HTTP ETag mechanism.

To activate optimistic concurrency, first set the session object’s Advanced.UseOptimisticConcurrency property to true:

var session = store.OpenSession();
session.Advanced.UseOptimisticConcurrency = true;

RavenDB session will remember the ETag of each entity whenever it loads the entity from database.

Next add a property to the entity class to store the ETag. If you don’t want to persist this property, attach JsonIgnore attribute to it:

public class Sales
{
    public long Id { get; set; }
    ...
    [Raven.Imports.Newtonsoft.Json.JsonIgnore]
    public Guid? Etag { get; set; }
    ...
}

Next create an implementation of IDocumentConversionListener that fills the entity’s ETag property during load:

public class EtagConversionListener : Raven.Client.Listeners.IDocumentConversionListener
{
    public void DocumentToEntity(string key, object entity, Raven.Json.Linq.RavenJObject document, Raven.Json.Linq.RavenJObject metadata)
    {
        var prop = entity.GetType().GetProperty("Etag");
        if (prop != null)
        {
            prop.SetValue(entity, metadata.Value<Guid>("@etag"), null);
        }
    }

    public void EntityToDocument(string key, object entity, Raven.Json.Linq.RavenJObject document, Raven.Json.Linq.RavenJObject metadata)
    {
        return;
    }
}

Next create an implementation of IDocumentStoreListener that fills the entity’s ETag property after a successful save:

public class EtagStoreListener : Raven.Client.Listeners.IDocumentStoreListener
{
    public void AfterStore(string key, object entityInstance, Raven.Json.Linq.RavenJObject metadata)
    {
        var prop = entityInstance.GetType().GetProperty("Etag");
        if (prop != null)
        {
            prop.SetValue(entityInstance, metadata.Value<Guid>("@etag"), null);
        }
    }

    public bool BeforeStore(string key, object entityInstance, Raven.Json.Linq.RavenJObject metadata, Raven.Json.Linq.RavenJObject original)
    {
        return false;
    }
}

In my project’s client server scenario, the flow of data modification is like this:

  1. Server loads document 1.
  2. Server creates viewmodel A from document 1.
  3. Server sends viewmodel A to browser.
  4. Browser modifies viewmodel A.
  5. Browser sends viewmodel A to server.
  6. Server loads document 1 by using viewmodel A’s ID.
  7. Server modifies document 1 according to viewmodel A.
  8. Server save document 1.

Concurrency check needs to be done at point 6 and 8. It may take several minutes or longer from point 1 to point 6. During that time the document may have been modified by someone else. This is why we need to attach the ETag to viewmodel A. Before we proceed with step 7 we will compare viewmodel A’s ETag with document 1’s ETag that is retrieved from server at point 6:

vmA.Amount = 33000;

using (var session = store.OpenSession())
{
    session.Advanced.UseOptimisticConcurrency = true;

    var doc1 = session.Query<Sales>().Where(e => e.Code == vmA.Code).FirstOrDefault();

    // if the ETag do not match, reject changes
    if (vmA.Etag != doc1.Etag)
    {
        throw new ArgumentException("somebody modified");
    }

    doc1.Amount = vmA.Amount;

    session.SaveChanges();
}

There is also a (much smaller) possibility that someone else has modified document 1 between point 6 and point 8. We can rely on RavenDB session to check that the ETags still match before it commits the changes to the database. If the ETags do not match, session.SaveChanges(); will throw a concurrency error.

Comments