DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Data Engineering
  3. Data
  4. ADO.NET as Ignite.NET Cache Store

ADO.NET as Ignite.NET Cache Store

Learn about implementing an efficient Ignite.NET persistent store with ADO.NET and SQL Server, continuing from a previous article on the entity framework cache store.

Pavel Tupitsyn user avatar by
Pavel Tupitsyn
·
May. 31, 17 · Tutorial
Like (4)
Save
Tweet
Share
3.99K Views

Join the DZone community and get the full member experience.

Join For Free

The previous article, Entity Framework as Ignite.NET Cache Store, describes a way to persist Ignite in-memory data in a SQL Server using the entity framework. The code is nice and elegant, but not efficient (as mentioned on Reddit) because converting object operations to SQL queries introduces overhead.

Today, we are going to cut out all the middlemen and:

  • Work with SQL directly to read and write data.
  • Use binary mode in Ignite to avoid serialization costs.

Ignite 2.0 Generic Cache Store

The cache store interface has been reworked in Ignite.NET 2.0 to operate on generic arguments. This reduces casting and boxing, making code nicer and faster:

// Ignite 1.x
class MyStore : ICacheStore
{
    public object Load(object key) => db.Find((int) key);
}

// Ignite 2.x
class MyStore : ICacheStore<int, string>
{
    public string Load(int key) => db.Find(key);
}

Ignite Binary Mode

By default, Ignite works with user-defined objects and types, serializing/deserializing them as needed. While this serialization is very efficient, it is still not free.

To squeeze every bit of performance, there is a binary mode where we work with objects in serialized form, retrieving and modifying individual fields.

We are going to use this binary mode both on the cache side and the cache store side.

Code

The full source code is here under the AdoNetCacheStore folder.

The project is self-sufficient. You can download the sources and run it without setting anything up. It uses SQL Server Compact (via NuGet) and creates a database in the BIN folder when needed.

Data Model

Our model will be defined in SQL server like this:

CREATE TABLE Cars (ID int, Name NVARCHAR(200), Power int) 

In Ignite, this can be represented with ICache<int, Car> where Car class has Name and Power fields. However, we are going to use binary mode where classes are not needed:

// Retrieve cache and switch to binary mode.
ICache<int, IBinaryObject> cars = ignite.GetCache<int, object>("cars")
    .WithKeepBinary<int, IBinaryObject>();

// Create new value with binary builder.
IBinaryObject car = ignite.GetBinary()
    .GetBuilder("Car")
    .SetStringField("Name", "Honda NSX")
    .SetIntField("Power", 600)
    .Build();

// Put to cache, this causes ICacheStore.Write call (when store is configured and write-through).
cars[1] = car;

Of course, you can mix and match binary and non-binary modes (store can work with binary objects while cache operations are with classes, and vice versa).

Cache Store Configuration

Configuration is almost the same as in the entity framework store, but with an important difference: KeepBinaryInStore is true.

var cacheCfg = new CacheConfiguration
{
    Name = "cars",
    CacheStoreFactory = new AdoNetCacheStoreFactory(),
    KeepBinaryInStore = true,
    ReadThrough = true,
    WriteThrough = true
};

This way, cache store implementation receives IBinaryObject instances directly without any deserialization.

Implementing Cache Store

Let’s look at the Write method first, which is called under the hood of cache.Put:

public class AdoNetCacheStore : ICacheStore<int, IBinaryObject>
{
    // Notice that method arguments correspond to ICache<int, IBinaryObject> above.
    public void Write(int key, IBinaryObject val)
    {
        using (var conn = new SqlCeConnection(ConnectionString))
        {
            using (var cmd = new SqlCeCommand(@"INSERT INTO Cars (ID, name, Power) VALUES (@id, @name, @power)", conn))
            {
                cmd.Parameters.AddWithValue("@id", key);

                // Transfer data directly from binary object to SQL query.
                cmd.Parameters.AddWithValue("@name", val.GetField<string>("Name"));
                cmd.Parameters.AddWithValue("@power", val.GetField<int>("Power"));

                conn.Open();
                cmd.ExecuteNonQuery();
            }
        }
    }

    ...
}

There are no intermediate objects; we operate on raw field values here, which is as efficient as it gets.

The read method is in a similar fashion:

public IBinaryObject Load(int key)
{
    using (var conn = new SqlCeConnection(ConnectionString))
    {
        using (var cmd = new SqlCeCommand(@"SELECT Name, Power FROM Cars WHERE Id = @id", conn))
        {
            cmd.Parameters.AddWithValue("@id", key);

            conn.Open();

            foreach (IDataRecord row in cmd.ExecuteReader())
            {
                // Return first record.
                return Ignite.GetBinary()
                    .GetBuilder("Car")
                    .SetStringField("Name", row.GetString(0))
                    .SetIntField("Power", row.GetInt32(1))
                    .Build();
            }

            return null;
        }
    }
}

Again, we create serialized object directly from the data reader, keeping allocations and overhead to a minimum.

Running The Example

Download the code, open AdoNetCacheStore\AdoNetCacheStore.sln, and run.

I recommend setting breakpoints on cache operations and cache store methods to see it all in action.

ICacheStore.Delete is not implemented, by the way. I leave it up to the readers to implement it and test by calling cache.Remove(1).

Cache (computing) ADO.NET Database

Published at DZone with permission of Pavel Tupitsyn. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • A Beginner’s Guide To Styling CSS Forms
  • Configure Kubernetes Health Checks
  • Detecting Network Anomalies Using Apache Spark
  • Host Hack Attempt Detection Using ELK

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: