Skip to content

VoltDB csharp wireprotocol and client implementation

License

Notifications You must be signed in to change notification settings

giansalex/voltdb-client-csharp

 
 

Repository files navigation

VoltDB C# Client Library

The VoltDB client library implements the native VoltDB wire protocol. You can use the library to connect to a VoltDB cluster, invoke stored procedures and read responses.

For an introduction to using the C# library: Introducting VoltDB.NET: C# Library for Your VoltDB Applications

New Features in V6.0

Fixes for VoltDecimal where some of the Decimal values were transmitted incorrectly over the wire.

Getting Started

Download the driver:

VoltDB.NET in a nutshell

The .NET/C# client library for VoltDB is extremely flexible and allows you to develop WinForms, Console and Web applications and services much as you would leveraging any other back-end data service or database.

  • Connect with a customized connectionstring in your app/web.config.
  • Perform Synchronous or Asynchronous data operations using standard .NET design patterns.
  • Consume and filter data results using LINQ.
  • Leverage native, strongly-typed, data access and type casting, as well as late-bound operations.
  • Monitor performance and manage a database cluster.

Key considerations:

  • All access is thread-safe
    • Safe for multi-threaded application
    • Safe as shared connections for a website/service
    • OK to mix asynchronous and synchronous calls
    • OK to have long-running callbacks (they are Thread-Pooled)
  • Resilience
    • Connect to multiple nodes
  • Performance
    • Share: multi-threading on a single connection is faster
    • Production: No Tracing (ever) or Statistics (unless needed)
    • Avoid usage of IAsync WaitHandles: they are slow!

Connecting to VoltDB

Read the section "Creating a Database Connection" of blog post: Introducting VoltDB.NET: C# Library for Your VoltDB Applications.

Key Connection Options:

  • Port – default: 21212
  • MaxOutstandingTransaction (txnq) – default: 3,000
  • Statistics (stats) – default: false
  • CommandTimeout – default: 5,000(ms)
  • AllowSystemCalls (system) – default: false
  • AllowAdHocQueries (adhoc) – default: false

Synchronous and Asynchronous Calls

Synchronous = Do nothing until you get the answer

  • Good: ‘Procedural’ model easier to understand/work with
  • Bad: Limits your throughput
  • Redeeming: For this thread only

Asynchronous = Call me when you get the answer

  • Good: No bottlenecks on wait operations
  • Bad: ‘Disjointed’ model harder to work with/error prone
  • Redeeming: Known ‘Best Practice’ patterns

VoltDB.NET implements:

  • Sync: .Execute
  • Async: .Begin/.Cancel/.End with IAsyncResult

Example Code

Calling Procedures

Define Callback for Asynchronous call

void MyDelegate(Response<Table[]> response) {
  if (response.Status == ResponseStatus.Success) {// Send response to client, update UI, etc.
  }
  else {// Deal with error
  }
}

Create Strongly-typed Wrappers

var my = conn.Procedures.Wrap<Table[],int,string>("MyProcedure", MyDelegate);

Supported Data Types:

  • Result:
    • Table[], Table
    • SingleRowTable[], SingleRowTable
    • int[], long[], string[], double[], … (and nullable types)
    • int, long, … (and nullable types)
  • Parameters:
    • int[], long[], string[], double[], …
    • int, long, …

Execute the procedure

Response<Table[]> r = myProc.Execute(1, "test");

IAsyncResult h = my.BeginExecute(1, "test");
IAsyncResult h = my.BeginExecute(1, "test", state);

Cancel Async Execution

myProc.ExecuteCancelAsync(h);

Get Async results (if not using callback)

Response<Table[]> r = myProc.EndExecute(h);

Wrapper Rules:

  • Up to 35 input parameters
  • Types must be compatible with core VoltDB types
  • Types can be single-values or arrays
    • sbyte, short, int, long, double, VoltDecimal, DateTime, string
    • sbyte?, short?, int?, …
    • sbyte[], sbyte?[], short[], short?[], …

Another option is to use Runtime Wrappers, but the type of runtime values must still be compatible.

conn.Procedures.Wrap<Table[],object,,object>();

Per-execution callback delegate/closures

IAsyncResult h = my.BeginExecute(1, "test", MyDelegate);

// or...

h = my.BeginExecute( 1, "test", (r) => MyClosureFunction(r,) );

Re-use Wrappers across connections (of course, executions still occur in the initiating context/connection).

my.SetConnection(otherVoltConnection);

Consuming Results

Access data directly...

double? value = response.Result
                        .GetValue<double?>(col, row);

double? Value = response.Result
                        .Rows
                        .ElementAt(row)
                        .GetValue<double?>(col);

...or through Strongly-typed Table Wrappers

var myTable = response.Result.Wrap<int?,,double?>();

double? value = myTable.Column7[row];

Wrapper Rules:

  • Up to 35 columns
  • Types must be compatible with core VoltDB types and flagged as Nullable => use int? (not int)
    • sbyte?, short?, int?, long?, double?, VoltDecimal?, DateTime? and string

Results are LINQ-friendly:

// On a strongly-typed VoltDB data table
myTable.Rows.Where(r => r.Column2 == "Books")
            .Select(r => new { Title = r.Column2, Price = r.Column7 })
            .OrderBy(p => p.Price);

// On a raw VoltDB data table
raw.Rows.Where(r => r.GetValue<string>(1) == "Books")
        .Select(r => new { Title = r. GetValue<string>(1), Price = r. GetValue<double>(6) })
        .OrderBy(p => p.Price);

Access metadata:

int count = myTable.RowCount;
bool check = myTable.HasData;

string name = raw.GetColumnName(idx);
short idx = raw.GetColumnIndex(name);

Type type = raw.GetColumnType(idx);
DBType type = raw.GetColumnDBType(idx);

int?[] column1Data = raw.GetColumnData<int?>(0);
object[] column1Data = raw.GetColumnData(0);

Fill a (System.Data.)DataTable

Table raw = procedureWrapper.Execute().Result;
DataTable dt = new DataTable("Result");
for(short i = 0; i < raw.ColumnCount; i++)
    dt.Columns.Add( raw.GetColumnName(i), raw.GetColumnType(i));
object[] values = new object[raw.ColumnCount];
foreach (Row row in raw.Rows) {
    for (short i = 0; i < raw.ColumnCount; i++)
        values[i] = row.GetValue(i);
    dt.Rows.Add(values);
}

Fill a (System.Windows.Forms.)DataGridView

view.Columns.Clear();
view.DataSource = null;
for (short i = 0; i &lt; raw.ColumnCount; i++)
    view.Columns.Add(raw.GetColumnName(i), raw.GetColumnName(i));
foreach (Row row in raw.Rows) {
    int n = view.Rows.Add();
    for (short i = 0; i < row.ColumnCount; i++) {
        view.Rows[n].Cells[i].Value = row.GetValue(i);
        view.Rows[n].Cells[i].ValueType = row.GetColumnType(i);
    }
} 

About

VoltDB csharp wireprotocol and client implementation

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%