Skip to content
This repository has been archived by the owner on May 16, 2022. It is now read-only.

Commit

Permalink
Add mapper concept and AsymmetricKeyHashTable
Browse files Browse the repository at this point in the history
  • Loading branch information
neuecc committed Aug 15, 2017
1 parent 48e9612 commit 6a6c29b
Show file tree
Hide file tree
Showing 13 changed files with 1,405 additions and 19 deletions.
10 changes: 10 additions & 0 deletions sandbox/ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MySqlSharp;
using MySqlSharp.Mapper;
using MySqlSharp.Data;
using MySqlSharp.Protocol;
using System;
Expand All @@ -21,9 +22,18 @@ static void Main(string[] args)
UserId = "",
Password = "",
};




var driver = new MySqlDriver(option);
driver.Open();

var reader = driver.Query<long>($"select 1543535353 as aaa, 1234213, 21313");






//var nextReader = reader.CreateNextReader();
Expand Down
57 changes: 47 additions & 10 deletions src/MySqlSharp/Data/MySqlDataReader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using MySqlSharp.Protocol;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
Expand All @@ -8,13 +9,41 @@ namespace MySqlSharp.Data
{
public class MySqlDataReader : DbDataReader
{
public override object this[int ordinal] => throw new NotImplementedException();
readonly TextResultSet resultSet;
Dictionary<string, int> __ordinalLookup;

// TODO:test
public MySqlDataReader(TextResultSet resultSet)
{
this.resultSet = resultSet;
}

Dictionary<string, int> OrdinalLookup
{
get
{
if (__ordinalLookup == null)
{
__ordinalLookup = new Dictionary<string, int>(resultSet.ColumnDefinitions.Length);

for (int i = 0; i < resultSet.ColumnDefinitions.Length; i++)
{
__ordinalLookup.Add(resultSet.ColumnDefinitions[i].Column, i);
}
}

return __ordinalLookup;
}
}

public override object this[string name] => throw new NotImplementedException();

public override int Depth => throw new NotImplementedException();
public override object this[int ordinal] => resultSet.GetValue(ordinal);

public override int FieldCount => throw new NotImplementedException();
public override object this[string name] => resultSet.GetValue(GetOrdinal(name));

public override int Depth => throw new NotSupportedException();

public override int FieldCount => resultSet.ColumnCount;

public override bool HasRows => throw new NotImplementedException();

Expand Down Expand Up @@ -69,7 +98,15 @@ public override double GetDouble(int ordinal)

public override IEnumerator GetEnumerator()
{
throw new NotImplementedException();
while (resultSet.Read())
{
var xs = new object[resultSet.ColumnCount];
for (int i = 0; i < xs.Length; i++)
{
xs[i] = resultSet.GetValue(i);
}
yield return xs;
}
}

public override Type GetFieldType(int ordinal)
Expand Down Expand Up @@ -104,12 +141,12 @@ public override long GetInt64(int ordinal)

public override string GetName(int ordinal)
{
throw new NotImplementedException();
return resultSet.ColumnDefinitions[ordinal].Column;
}

public override int GetOrdinal(string name)
{
throw new NotImplementedException();
return OrdinalLookup[name];
}

public override string GetString(int ordinal)
Expand All @@ -119,7 +156,7 @@ public override string GetString(int ordinal)

public override object GetValue(int ordinal)
{
throw new NotImplementedException();
return resultSet.GetValue(ordinal);
}

public override int GetValues(object[] values)
Expand All @@ -139,7 +176,7 @@ public override bool NextResult()

public override bool Read()
{
throw new NotImplementedException();
return resultSet.Read();
}
}
}
17 changes: 15 additions & 2 deletions src/MySqlSharp/Data/MySqlTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,31 @@ namespace MySqlSharp.Data
{
public class MySqlTransaction : DbTransaction
{
readonly MySqlConnection conn;
readonly TransactionController controller;

public override IsolationLevel IsolationLevel => throw new NotImplementedException();

protected override DbConnection DbConnection => throw new NotImplementedException();

public MySqlTransaction(MySqlConnection conn, TransactionController controller)
{
//TODO:...
}

public override void Commit()
{
throw new NotImplementedException();
controller.Commit();
}

public override void Rollback()
{
throw new NotImplementedException();
controller.Rollback();
}

protected override void Dispose(bool disposing)
{
controller.Dispose();
}
}
}
226 changes: 226 additions & 0 deletions src/MySqlSharp/Internal/AsymmetricKeyHashTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
using System;

namespace MySqlSharp.Internal
{
// Safe for multiple-read, single-write.

// Add and Get Key is asymmetric.

internal interface IAsymmetricEqualityComparer<TKey1, TKey2>
{
int GetHashCode(TKey1 key1);
int GetHashCode(TKey2 key2);
bool Equals(TKey1 x, TKey1 y); // when used rehash
bool Equals(TKey1 x, TKey2 y); // when used get
}

internal sealed class AsymmetricKeyHashTable<TKey1, TKey2, TValue>
{
Entry[] buckets;
int size; // only use in writer lock

readonly object writerLock = new object();
readonly float loadFactor;
readonly IAsymmetricEqualityComparer<TKey1, TKey2> comparer;

public AsymmetricKeyHashTable(IAsymmetricEqualityComparer<TKey1, TKey2> comparer)
: this(4, 0.72f, comparer)
{
}

public AsymmetricKeyHashTable(int capacity, float loadFactor, IAsymmetricEqualityComparer<TKey1, TKey2> comparer)
{
var tableSize = CalculateCapacity(capacity, loadFactor);
this.buckets = new Entry[tableSize];
this.loadFactor = loadFactor;
this.comparer = comparer;
}

public TValue AddOrGet(TKey1 key1, Func<TKey1, TValue> valueFactory)
{
TValue v;
TryAddInternal(key1, valueFactory, out v);
return v;
}

public bool TryAdd(TKey1 key, Func<TKey1, TValue> valueFactory)
{
TValue _;
return TryAddInternal(key, valueFactory, out _);
}

bool TryAddInternal(TKey1 key, Func<TKey1, TValue> valueFactory, out TValue resultingValue)
{
lock (writerLock)
{
var nextCapacity = CalculateCapacity(size + 1, loadFactor);

if (buckets.Length < nextCapacity)
{
// rehash
var nextBucket = new Entry[nextCapacity];
for (int i = 0; i < buckets.Length; i++)
{
var e = buckets[i];
while (e != null)
{
var newEntry = new Entry { Key = e.Key, Value = e.Value, Hash = e.Hash };
AddToBuckets(nextBucket, key, newEntry, null, out resultingValue);
e = e.Next;
}
}

// add entry(if failed to add, only do resize)
var successAdd = AddToBuckets(nextBucket, key, null, valueFactory, out resultingValue);

// replace field(threadsafe for read)
VolatileWrite(ref buckets, nextBucket);

if (successAdd) size++;
return successAdd;
}
else
{
// add entry(insert last is thread safe for read)
var successAdd = AddToBuckets(buckets, key, null, valueFactory, out resultingValue);
if (successAdd) size++;
return successAdd;
}
}
}

bool AddToBuckets(Entry[] buckets, TKey1 newKey, Entry newEntryOrNull, Func<TKey1, TValue> valueFactory, out TValue resultingValue)
{
var h = (newEntryOrNull != null) ? newEntryOrNull.Hash : comparer.GetHashCode(newKey);
if (buckets[h & (buckets.Length - 1)] == null)
{
if (newEntryOrNull != null)
{
resultingValue = newEntryOrNull.Value;
VolatileWrite(ref buckets[h & (buckets.Length - 1)], newEntryOrNull);
}
else
{
resultingValue = valueFactory(newKey);
VolatileWrite(ref buckets[h & (buckets.Length - 1)], new Entry { Key = newKey, Value = resultingValue, Hash = h });
}
}
else
{
var searchLastEntry = buckets[h & (buckets.Length - 1)];
while (true)
{
if (comparer.Equals(searchLastEntry.Key, newKey))
{
resultingValue = searchLastEntry.Value;
return false;
}

if (searchLastEntry.Next == null)
{
if (newEntryOrNull != null)
{
resultingValue = newEntryOrNull.Value;
VolatileWrite(ref searchLastEntry.Next, newEntryOrNull);
}
else
{
resultingValue = valueFactory(newKey);
VolatileWrite(ref searchLastEntry.Next, new Entry { Key = newKey, Value = resultingValue, Hash = h });
}
break;
}
searchLastEntry = searchLastEntry.Next;
}
}

return true;
}

public bool TryGetValue(TKey2 key, out TValue value)
{
var table = buckets;
var hash = comparer.GetHashCode(key);
var entry = table[hash & table.Length - 1];

if (entry == null) goto NOT_FOUND;

if (comparer.Equals(entry.Key, key))
{
value = entry.Value;
return true;
}

var next = entry.Next;
while (next != null)
{
if (comparer.Equals(next.Key, key))
{
value = next.Value;
return true;
}
next = next.Next;
}

NOT_FOUND:
value = default(TValue);
return false;
}

static int CalculateCapacity(int collectionSize, float loadFactor)
{
var initialCapacity = (int)(((float)collectionSize) / loadFactor);
var capacity = 1;
while (capacity < initialCapacity)
{
capacity <<= 1;
}

if (capacity < 8)
{
return 8;
}

return capacity;
}

static void VolatileWrite(ref Entry location, Entry value)
{
System.Threading.Volatile.Write(ref location, value);
}

static void VolatileWrite(ref Entry[] location, Entry[] value)
{
System.Threading.Volatile.Write(ref location, value);
}

class Entry
{
public TKey1 Key;
public TValue Value;
public int Hash;
public Entry Next;

// from debugger only
public override string ToString()
{
return "Count:" + Count;
}

internal int Count
{
get
{
var count = 1;
var n = this;
while (n.Next != null)
{
count++;
n = n.Next;
}
return count;
}
}
}
}
}
Loading

0 comments on commit 6a6c29b

Please sign in to comment.