You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

860 lines
27 KiB
C#

//#define WINDOWS_PHONE
//#define NET2
using System;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using iBoxDB.LocalServer;
using iBoxDB.LocalServer.IO;
using iBoxDB.LocalServer.Replication;
using iBoxDB.DBDebug;
/*
Copy to "static void Main(string[] args)"
iBoxDB.LocalServer.DB.Root("/tmp/");
var text = iBoxDB.NDB.RunALL();
Console.WriteLine(text);
*/
namespace iBoxDB
{
public class NDB
{
public static String RunALL(bool speedTest = false)
{
try
{
//DB.Root("/tmp/");
DBPlatform.SetStorage();
strout = new StringBuilder();
WriteLine("");
GettingStarted();
WriteLine("");
IsolatedSpace();
WriteLine("");
BeyondSQL();
WriteLine("");
MasterSlave();
WriteLine("");
MasterMaster();
if (speedTest)
{
GC.Collect();
WriteLine("");
SpeedTest(DBPlatform.Speed_ThreadCount);
GC.Collect();
WriteLine("");
ReplicationSpeed(DBPlatform.Replication_ThreadCount, DBPlatform.Replication_Time);
}
DBPlatform.DeleteDB();
return WriteLine("").ToString();
}
catch (Exception ex)
{
return ex.ToString();
}
}
public static void GettingStarted()
{
WriteLine("Getting Started");
DBPlatform.DeleteDB();
var db = new DB(1);
db.GetConfig().EnsureTable<Member>("Table", "ID");
var auto = db.Open();
long key = 1;
auto.Insert("Table", new Member { ID = key, Name = "Andy" });
var o1 = auto.Get<Member>("Table", key);
WriteLine(o1.Name);
o1.Name = "Kelly";
auto.Update("Table", o1);
o1 = null;
var o2 = auto.Get<Member>("Table", key);
WriteLine(o2.Name);
db.Dispose();
}
public static void IsolatedSpace()
{
WriteLine("Isolated Space");
DBPlatform.DeleteDB();
var db = new DB(1);
db.GetConfig().EnsureTable<Member>("Member", "ID");
// StringColumnName(Length) , default length is 32
db.GetConfig().EnsureIndex<Member>("Member", "Name(20)");
// Particular index for class MemberVIP.VIP
db.GetConfig().EnsureIndex<MemberVIP>("Member", "VIP");
// Composite Key Supported
db.GetConfig().EnsureTable<Product>("Product", "Type", "UID");
var auto = db.Open();
long andyId, kellyId;
//Creating Isolated Space, the Box.
using (var box = auto.Cube())
{
andyId = box.NewId();
kellyId = box.NewId();
// insert members, two different classes with different index setting.
box["Member"].Insert(new Member()
{
ID = andyId,
Name = "Andy",
RegTime = new DateTime(2013, 1, 2),
Tags = new string[] { "Nice", "Player" }
});
box["Member"].Insert(new MemberVIP()
{
ID = kellyId,
Name = "Kelly",
RegTime = new DateTime(2013, 1, 3),
Tags = new string[] { "Player" },
VIP = 3
});
Product game = new Product()
{
Type = 8,
UID = new Guid("{22222222-0000-0000-0000-000000000000}"),
Name = "MoonFlight"
};
// Dynamic Column
game["GameType"] = "ACT";
box["Product"].Insert(game);
var cr = box.Commit();
//cr.Equals(CommitResult.OK)
cr.Assert();
}
using (var box = auto.Cube())
{
// Query Object, SQL Style
// > < >= <= == !=
// & | ()
// []
foreach (var m in box.Select<MemberVIP>("from Member where VIP>? ", 1))
{
WriteLine("Member: " + m.Name + " RegTime: " + m.RegTime);
}
// Key-Value Style, Composite-Key Supported
var cs = box["Product", 8, new Guid("{22222222-0000-0000-0000-000000000000}")].Select<Product>();
WriteLine("Product: " + cs.Name + " Type: " + cs["GameType"]);
}
using (var box = auto.Cube())
{
var m = box["Member", kellyId].Select<MemberVIP>();
// Update Amount and Name
m.Name = "Kelly J";
m.Amount = 100;
box["Member", m.ID].Update(m);
box.Commit().Assert();
}
using (var box = auto.Cube())
{
foreach (var m in box.Select<Member>("from Member where Name==?", "Kelly J"))
{
WriteLine("Updated: " + m.Name + " Amount: " + m.Amount);
}
}
db.Dispose();
}
public static void BeyondSQL()
{
DBPlatform.DeleteDB();
var db = new DB(1);
db.GetConfig().EnsureTable<MemberInc>("MemberInc", "ID");
db.GetConfig().EnsureUpdateIncrementIndex<MemberInc>("MemberInc", "Version");
var auto = db.Open();
WriteLine("Update Increment");
Write("Number increasing: ");
MemberInc m = new MemberInc();
m.ID = 1;
m.Name = "Andy";
auto.Insert("MemberInc", m);
var mg = auto.Get<MemberInc>("MemberInc", 1L);
Write(mg.Version + ". ");
auto.Update("MemberInc", mg);
mg = auto.Get<MemberInc>("MemberInc", 1L);
Write(mg.Version + ". ");
auto.Update("MemberInc", mg);
mg = auto.Get<MemberInc>("MemberInc", 1L);
WriteLine(mg.Version + ". ");
WriteLine("Selecting Tracer");
using (var boxTracer = auto.Cube())
{
bool keepTrace = true;
Member tra = boxTracer["MemberInc", 1L].Select<Member>(keepTrace);
String currentName = tra.Name;
{
// another box changes the name
MemberInc mm = new MemberInc();
mm.ID = 1;
mm.Name = "Kelly";
auto.Update("MemberInc", mm.ID, mm);
}
// Change detected
if (!boxTracer.Commit().Equals(CommitResult.OK))
{
Write("Detected '" + currentName + "' has changed, ");
}
}
Member nm = auto.Get<Member>("MemberInc", 1L);
WriteLine("new name is '" + nm.Name + "'");
db.Dispose();
}
public static void MasterSlave()
{
DBPlatform.DeleteDB();
long MasterA_DBAddress = 10;
// negative number
long SlaveA_DBAddress = -10;
var db = new DB(MasterA_DBAddress);
db.GetConfig().EnsureTable<Member>("Member", "ID");
db.SetBoxRecycler(new MemoryBoxRecycler());
var auto = db.Open();
var db_slave = new DB(SlaveA_DBAddress);
var auto_slave = db_slave.Open();
WriteLine("MasterSlave Replication");
using (var box = auto.Cube())
{
for (var i = 0; i < 3; i++)
{
box["Member"].Insert(new Member()
{
ID = box.NewId(),
Name = "LN " + i
});
}
box.Commit().Assert();
}
// Database Serialization
var recycler = (MemoryBoxRecycler)auto.GetDatabase().GetBoxRecycler();
lock (recycler.Packages)
{
foreach (var p in recycler.Packages)
{
if (p.Socket.SourceAddress == MasterA_DBAddress)
{
(new BoxData(p.OutBox)).SlaveReplicate(auto_slave.GetDatabase()).Assert();
}
}
recycler.Packages.Clear();
}
WriteLine("Master Address: " + auto.GetDatabase().LocalAddress + ", Data:");
using (var box = auto.Cube())
{
foreach (var o in box.Select<Member>("from Member", null))
{
Write(o.Name + ". ");
}
}
WriteLine("");
WriteLine("Slave Address: " + auto_slave.GetDatabase().LocalAddress + ", Data:");
using (var box = auto_slave.Cube())
{
foreach (var o in box.Select<Member>("from Member", null))
{
Write(o.Name + ". ");
}
}
WriteLine("");
db.Dispose();
db_slave.Dispose();
}
public static void MasterMaster()
{
DBPlatform.DeleteDB();
long MasterA_DBAddress = 10;
long MasterB_DBAddress = 20;
var db_masterA = new DB(MasterA_DBAddress);
db_masterA.GetConfig().EnsureTable<Member>("Member", "ID");
db_masterA.SetBoxRecycler(new MemoryBoxRecycler());
//send to MasterB_Address
var auto_masterA = db_masterA.Open(MasterB_DBAddress);
var db_masterB = new DB(MasterB_DBAddress);
db_masterB.GetConfig().EnsureTable<Member>("Member", "ID");
db_masterB.SetBoxRecycler(new MemoryBoxRecycler());
// send to MasterA_Address
var auto_masterB = db_masterB.Open(MasterA_DBAddress);
WriteLine("MasterMaster Replication");
byte IncTableID = 1;
using (var box = auto_masterA.Cube())
{
for (var i = 0; i < 3; i++)
{
box["Member"].Insert(new Member()
{
ID = box.NewId(IncTableID, 1) * 1000 + MasterA_DBAddress,
Name = "A" + i
});
}
box.Commit().Assert();
}
using (var box = auto_masterB.Cube())
{
for (var i = 0; i < 3; i++)
{
box["Member"].Insert(new Member()
{
ID = box.NewId(IncTableID, 1) * 1000 + MasterB_DBAddress,
Name = "B" + i
});
}
box.Commit().Assert();
}
//Do Replication
List<Package> buffer;
var recycler = (MemoryBoxRecycler)auto_masterA.GetDatabase().GetBoxRecycler();
lock (recycler.Packages)
{
buffer = new List<Package>(recycler.Packages);
recycler.Packages.Clear();
}
recycler = (MemoryBoxRecycler)auto_masterB.GetDatabase().GetBoxRecycler();
lock (recycler.Packages)
{
buffer.AddRange(recycler.Packages);
recycler.Packages.Clear();
}
foreach (var p in buffer)
{
if (p.Socket.DestAddress == MasterA_DBAddress)
{
(new BoxData(p.OutBox)).MasterReplicate(auto_masterA.GetDatabase());
}
if (p.Socket.DestAddress == MasterB_DBAddress)
{
(new BoxData(p.OutBox)).MasterReplicate(auto_masterB.GetDatabase());
}
}
WriteLine("MasterA Address: " + auto_masterA.GetDatabase().LocalAddress);
using (var box = auto_masterA.Cube())
{
foreach (var o in box.Select<Member>("from Member", null))
{
Write(o.Name + ". ");
}
}
WriteLine("");
WriteLine("MasterB Address: " + auto_masterB.GetDatabase().LocalAddress);
using (var box = auto_masterB.Cube())
{
foreach (var o in box.Select<Member>("from Member", null))
{
Write(o.Name + ". ");
}
}
WriteLine("");
db_masterA.Dispose();
db_masterB.Dispose();
/* another replication config
Key = [ID,Address]
m.ID = box.NewId(IncTableID, 1) ;
m.Address = box.LocalAddress;
box.Bind("Member").Insert(m);
*/
}
public static void SpeedTest(int threadCount)
{
DBPlatform.DeleteDB();
var db = new DB(1);
db.GetConfig().EnsureTable<Member>("TSpeed", "ID");
var dbConfig = db.GetConfig().DBConfig;
//Cache
//dbConfig.CacheLength = dbConfig.MB(512);
//File
//dbConfig.FileIncSize = (int)dbConfig.MB(4);
//Thread
//dbConfig.ReadStreamCount = 8;
var auto = db.Open();
WriteLine("Speed");
var objectCount = 10;
WriteLine("Begin Insert " + (threadCount * objectCount).ToString("#,#"));
DDebug.StartWatch();
DBPlatform.For(0, threadCount, (i) =>
{
using (var box = auto.Cube())
{
for (var o = 0; o < objectCount; o++)
{
var m = new Member
{
ID = box.NewId(0, 1),
Name = i.ToString() + "_" + o.ToString(),
Age = 1
};
box["TSpeed"].Insert(m);
}
box.Commit().Assert();
}
});
var sec = DDebug.StopWatch().TotalSeconds;
var avg = (threadCount * objectCount) / sec;
WriteLine("Elapsed " + sec + "s, AVG Insert " + avg.ToString("#,#") + " o/sec");
DDebug.StartWatch();
DBPlatform.For(0, threadCount, (i) =>
{
using (var box = auto.Cube())
{
for (var o = 0; o < objectCount; o++)
{
long ID = i * objectCount + o + 1;
var mem = box["TSpeed", ID].Select<Member>();
if (mem.ID != ID) { throw new Exception(); }
}
}
});
sec = DDebug.StopWatch().TotalSeconds;
avg = (threadCount * objectCount) / sec;
WriteLine("Elapsed " + sec + "s, AVG Lookup " + avg.ToString("#,#") + " o/sec");
DDebug.StartWatch();
int count = 0;
DBPlatform.For(0, threadCount, (i) =>
{
using (var box = auto.Cube())
{
var tspeed = box.Select<Member>("from TSpeed where ID>=? & ID<=?",
(long)(i * objectCount + 1), (long)(i * objectCount + objectCount));
foreach (var m in tspeed)
{
// age == 1
Interlocked.Add(ref count, m.Age);
}
}
});
if (count != (threadCount * objectCount)) { throw new Exception(count.ToString()); }
sec = DDebug.StopWatch().TotalSeconds;
avg = count / sec;
WriteLine("Elapsed " + sec + "s, AVG Query " + avg.ToString("#,#") + " o/sec");
db.Dispose();
}
public static void ReplicationSpeed(int threadCount, int time)
{
DBPlatform.DeleteDB();
int MasterA_DBAddress = 10;
int MasterB_DBAddress = 20;
int SlaveA_DBAddress = -10;
var db_masterA = new DB(MasterA_DBAddress);
db_masterA.GetConfig().EnsureTable<Member>("TSpeed", "ID");
db_masterA.SetBoxRecycler(new MemoryBoxRecycler());
var auto_masterA = db_masterA.Open(MasterB_DBAddress);
var db_slave = new DB(SlaveA_DBAddress);
var auto_slave = db_slave.Open();
var db_masterB = new DB(MasterB_DBAddress);
db_masterB.GetConfig().EnsureTable<Member>("TSpeed", "ID");
var auto_masterB = db_masterB.Open();
var data = ((MemoryBoxRecycler)auto_masterA.GetDatabase().GetBoxRecycler()).AsBoxData();
BoxData.SlaveReplicate(auto_slave.GetDatabase(), data).Assert();
BoxData.MasterReplicate(auto_masterB.GetDatabase(), data).Assert();
var objectCount = 10;
double slaveSec = 0;
double masterSec = 0;
for (var t = 0; t < time; t++)
{
DBPlatform.For(0, threadCount, (i) =>
{
using (var box = auto_masterA.Cube())
{
for (var o = 0; o < objectCount; o++)
{
var m = new Member
{
ID = box.NewId(0, 1),
Name = i.ToString() + "_" + o.ToString(),
Age = 1
};
box["TSpeed"].Insert(m);
}
box.Commit().Assert();
}
});
data = ((MemoryBoxRecycler)auto_masterA.GetDatabase().GetBoxRecycler()).AsBoxData();
DDebug.StartWatch();
BoxData.SlaveReplicate(auto_slave.GetDatabase(), data).Assert();
slaveSec += DDebug.StopWatch().TotalSeconds;
DDebug.StartWatch();
BoxData.MasterReplicate(auto_masterB.GetDatabase(), data).Assert();
masterSec += DDebug.StopWatch().TotalSeconds;
}
WriteLine("Replicate " + (threadCount * time).ToString("#,#") + " transactions, totals " + (threadCount * objectCount * time).ToString("#,#") + " objects");
var avg = (threadCount * objectCount * time) / slaveSec;
WriteLine("SlaveSpeed " + slaveSec + "s, AVG " + avg.ToString("#,#") + " o/sec");
avg = (threadCount * objectCount * time) / masterSec;
WriteLine("MasterSpeed " + masterSec + "s, AVG " + avg.ToString("#,#") + " o/sec");
int count = 0;
DDebug.StartWatch();
for (var t = 0; t < time; t++)
{
DBPlatform.For(0, threadCount, (i) =>
{
for (var dbc = 0; dbc < 2; dbc++)
{
using (var box = dbc == 0 ? auto_slave.Cube() : auto_masterB.Cube())
{
for (var o = 0; o < objectCount; o++)
{
long ID = i * objectCount + o + 1;
ID += (t * threadCount * objectCount);
var mem = box["TSpeed", ID].Select<Member>();
if (mem.ID != ID) { throw new Exception(); }
Interlocked.Add(ref count, mem.Age);
}
}
}
});
}
if (count != (threadCount * objectCount * time * 2))
{
throw new Exception();
}
masterSec = DDebug.StopWatch().TotalSeconds;
avg = count / masterSec;
WriteLine("Lookup after replication " + masterSec + "s, AVG " + avg.ToString("#,#") + " o/sec");
auto_masterA.GetDatabase().Dispose();
auto_slave.GetDatabase().Dispose();
auto_masterB.GetDatabase().Dispose();
}
private static StringBuilder strout = new StringBuilder();
private static StringBuilder WriteLine(string str)
{
strout.Append(str + "\r\n");
return strout;
}
private static StringBuilder Write(string str)
{
strout.Append(str);
return strout;
}
public abstract class IDClass
{
public long ID;
}
public class Member : IDClass
{
public string Name;
public DateTime RegTime;
public string[] Tags;
public decimal Amount;
public int Age;
}
public class MemberVIP : Member
{
public int VIP;
}
public class MemberInc : Member
{
// UpdateIncrement, type is long
public long Version;
}
public class Product : Dictionary<string, object>
{
public int Type
{
get
{
return (int)this["Type"];
}
set
{
this["Type"] = value;
}
}
public Guid UID
{
get
{
return (Guid)this["UID"];
}
set
{
this["UID"] = value;
}
}
public string Name
{
get
{
return (string)this["Name"];
}
set
{
this["Name"] = value;
}
}
}
}
public class DBPlatform
{
public static void SetStorage()
{
//DB.Root(path); DB Files Path
#if (WINDOWS_PHONE || UNITY_WP8) && (!UNITY_EDITOR)
DB.Root(Windows.Storage.ApplicationData.Current.LocalFolder.Path);
#else
#if (NETFX_CORE || UNITY_METRO) && (!UNITY_EDITOR)
iBoxDB.WSDatabaseConfig.ResetStorage();
#else
Xamarin_IL2CPP_MakeSureClassesAreLinked();
#endif
#endif
}
public delegate void FRun(int i);
#if WINDOWS_PHONE || NET2 || UNITY_EDITOR || UNITY_WP8 || UNITY_ANDROID
public static void For(int start, int end, FRun run)
{
for (var i = start; i < end; i++)
{
run(i);
}
}
#else
public static void For(int start, int end, FRun run)
{
System.Threading.Tasks.Parallel.For(start, end,
(i) =>
{
run(i);
});
}
#endif
#if WINDOWS_PHONE || NET2 || UNITY_EDITOR || NETFX_CORE || UNITY_WP8 || UNITY_METRO || UNITY_ANDROID
public static int Speed_ThreadCount = 200;
public static int Replication_ThreadCount = 40;
public static int Replication_Time = 4;
#else
public static int Speed_ThreadCount = 20000;
public static int Replication_ThreadCount = 200;
public static int Replication_Time = 10;
#endif
public static void DeleteDB()
{
DDebug.DeleteDBFiles(new long[] { 1, 10, 20, -10 });
}
private static void Xamarin_IL2CPP_MakeSureClassesAreLinked()
{
#if !NETFX_CORE && !UNITY_METRO && !WINDOWS_PHONE && !UNITY_WP8 && !UNITY_EDITOR
if (Object.ReferenceEquals(1, 2))
{
//ensure the methods
new System.IO.FileStream("", System.IO.FileMode.OpenOrCreate,
System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite, 1);
System.IO.File.Exists("");
System.IO.File.Delete("");
}
#endif
}
}
public class Package
{
public Socket Socket;
public byte[] OutBox;
}
// recycle boxes
public class MemoryBoxRecycler : IBoxRecycler //,IBoxRecycler3
{
public List<Package> Packages = new List<Package>();
public MemoryBoxRecycler() { }
public MemoryBoxRecycler(long name, DatabaseConfig config) : this()
{
}
public void OnReceived(Socket socket, BoxData outBox, bool normal)
{
if (socket.DestAddress == long.MaxValue)
{
// default replicate address
return;
}
lock (Packages)
{
Packages.Add(new Package { Socket = socket, OutBox = outBox.ToBytes() });
}
}
public BoxData[] AsBoxData()
{
List<BoxData> list = new List<BoxData>();
lock (Packages)
{
foreach (var p in Packages)
{
list.Add(new BoxData(p.OutBox));
}
Packages.Clear();
}
return list.ToArray();
}
public void Dispose()
{
Packages = null;
}
}
//ALL in One Config, var server = new ApplicationServer();
public class ApplicationServer : LocalDatabaseServer
{
public class Config : BoxFileStreamConfig
{
public Config()
: base()
{
CacheLength = MB(512);
FileIncSize = (int)MB(4);
ReadStreamCount = 8;
}
}
class MyConfig : Config
{
public MyConfig()
: base()
{
EnsureTable<NDB.Member>("Member", "ID");
EnsureIndex<NDB.Member>("Member", "Name(20)");
EnsureIndex<NDB.Member>("Member", "VIP");
EnsureTable<NDB.Product>("Product", "Type", "UID");
EnsureTable<NDB.Member>("TSpeed", "ID");
EnsureTable<NDB.MemberInc>("MemberInc", "ID");
EnsureUpdateIncrementIndex<NDB.MemberInc>("MemberInc", "Version");
//KeyOnly Table, StartsWith '/', only read/write ID and Name
EnsureTable<NDB.Member>("/M", "ID", "Name");
}
}
public const int MasterA_DBAddress = 10;
public const int MasterB_DBAddress = 20;
public const int SlaveA_DBAddress = -10;
protected override DatabaseConfig BuildDatabaseConfig(long name)
{
if (name == MasterB_DBAddress || name == MasterA_DBAddress)
{
return new MyConfig();
}
if (name == SlaveA_DBAddress)
{
return new Config();
}
throw new NotImplementedException();
}
protected override IBoxRecycler BuildBoxRecycler(long name, DatabaseConfig config)
{
if (name == MasterA_DBAddress || name == MasterB_DBAddress)
{
return new MemoryBoxRecycler(name, config);
}
return base.BuildBoxRecycler(name, config);
}
}
}