Olen jatkanut tutustumista NoSQL-tietokantoihin (tai vaihtoehtoisesti "AltDB" -- tämä nimi ei ole vielä oikein ottanut tuulta). Eräs yksinkertaisimmista ja tehokkaimmista on Tokyo Tyrant, joka muodostuu oikeastaan kahdesta palasesta:

Tokyo Cabinet vastaa idealtaan Berkeley DB -kirjastoa, jonka voi niinikään upottaa omaan sovellukseensa. Tokyo Cabinet on tiettävästi äärimmäisen tehokas, pystyen yli miljoonaan operaatioon sekunnissa.

Tokyo Tyrant lisää Cabinetin päälle verkkokerroksen, joten se on luonnollisesti hitaampi. Kehittäjän oman esityksen mukaan Tyrant pystyy noin 58000 operaatioon sekunnissa. Nämä luvut riippuvat tietysti palvelinraudasta.

Tokyo Cabinet on pohjimmiltaan samanlainen key-value-store kuin esimerkiksi Memcached. Jokaista yksilöivää avainta vastaa tasan yksi arvo. Arvo voi olla esimerkiksi JSON-objekti, joka on koodattu merkkijonoksi. Avain puolestaan on useimmiten UUID, johon on kenties lisätty prefiksi, jonka avulla kannasta voi tarvittaessa seuloa esiin tietyn tyyppisiä rivejä.

Rivien seulominen esiin avainprefiksien avulla ei ole kuitenkaan tehokasta. Key-value-tietokantojen ideana on rakentaa relaatiot ennemmin niin, että yhden avaimen alta löytyy lista toisista avaimista. Esimerkkinä voisi olla tällainen rakenne:

User:kennu
b714dc6fe2304e8d9160b5f389959a8a
UserInfo:b714dc6fe2304e8d9160b5f389959a8a
{ "realname":"Kenneth Falck" }
UserBlogs:b714dc6fe2304e8d9160b5f389959a8a
Blog:eded0f3009174fbcaa2da50c42c7468d Blog:51d49d44f4b64fe4827edc9caba0a619
Blog:eded0f3009174fbcaa2da50c42c7468d
{ "name": "Tekniikkablogi" }
Blog: 51d49d44f4b64fe4827edc9caba0a619
{ "name": "Hupiblogi" }

Tässä mallissa käyttäjätietoja lähdetään selvittämään etsimällä ensin avain User:(tunnus), joka kertoo käyttäjän UUID:n. Sillä voidaan sitten etsiä UserInfo:(uuid), josta saadaan käyttäjän perustiedot, sekä UserBlogs:(uuid), josta löytyy luettelo käyttäjän blogien UUID:istä välilyönneillä eroteltuna. Lopuksi noudetaan vielä kunkin blogin tarkemmat tiedot avaimella Blog:(uuid).

Haaste tällaisessa relaatiomallissa on säilyttää integriteetti UserBlogs- ja Blog-entiteettien välillä. Kun näitä kenttiä muokataan, muutosten tulisi olla atomisia, jotta tietokantaan ei jää roikkumaan Blog-rivejä, joihin ei enää viitata UserBlogs-kentistä tai toisin päin. Näin voi käydä, jos verkkoyhteys katkeaa sopivassa kohdassa tai sovelluksessa tapahtuu jokin muu virhe operaatioiden välillä.

Tokyo Tyrantissa atomiset operaatiot voi toteuttaa Lua-laajennuksilla. Palvelimelle annetaan käynnistyksen yhteydessä Lua-tiedosto, jossa määritellään laajennusoperaatiot funktioina. Blogiesimerkin tapauksessa laajennus voisi olla tällainen:

-- key: Blog key
-- value: User key + '|' + Blog value
function addblog(key, value)
  -- Split value into userkey and blogvalue
  parts = _split(value, '|')
  userkey = parts[1]
  blogvalue = parts[2]
  -- Create the Blog
  if not _put(key, blogvalue) then
    return nil
  end
  -- Add Blog's key to UserBlogs of owner
  akey = key
  if _vsiz(userkey) > 0 then
    akey = ' ' .. akey
  end
  if not _putcat(userkey, akey) then
    _out(key)
    return nil
  end
  return value
end

Laajennuskoodi on ehkä vähän sekavan tuntuista, mutta se hoitaa asiansa. Nyt sovellus voi kutsua addblog-laajennusta, joka luo ensin blogin ja lisää sitten sen avaimen käyttäjän blogiluetteloon välilyönnillä eroteltuna. Virhetilanteessa blogi poistetaan (_out), jottei se jää roikkumaan tietokantaan.

Vastaavasti olisi suhteellisen helppoa koodata deleteblog-laajennus, joka poistaa blogin sekä sen avaimen käyttäjän blogiluettelosta. Oikeassa sovelluksessa erottimena voisi olla mieluummin esimerkiksi NUL-merkki eikä '|'. Lisäksi operaation ympärille pitäisi lisätä _lock()- ja _unlock()-kutsut, joilla lukitaan sekä key että userkey koko operaation ajaksi.