Compare commits

...
Author SHA1 Message Date
Taha d9e4f9ff9e Fixing mangled merge 2023-09-30 12:18:23 -04:00
Taha e30a762969 Adding tests 2023-09-30 12:08:51 -04:00
Taha 83d016d46a Streams can be published across PubSub now 2023-09-30 12:07:10 -04:00
Taha 0039d08b5b PubSub is working now 2023-09-30 12:03:30 -04:00
Taha 74627f9a8a AsyncTCPCOnnection2 done 2023-09-30 12:01:58 -04:00
Taha 0b18e95a77 Both SImpleTCPClient and SimpleTCPServer use non async calls now 2023-09-30 12:01:58 -04:00
Taha 57c56f05c2 Merging, and adding test project 2023-09-30 12:01:05 -04:00
66 changed files with 3466 additions and 2119 deletions

No files matched your search

Submodule
+1
Submodule docker/linux added at 6537812262.
+1
Submodule docker/windows added at de7d40c09d.
@@ -1,72 +1,68 @@
using System;
using System.Collections;
using System.Collections.Generic;
using BCG.Utilities;
namespace BCG
{
namespace BCG {
/// <summary>
/// This class will be used by the clients to publish data to the pubsub
/// This class will be used by the clients to publish tabular data to the pubsub
/// </summary>
public class PubTableBroker
{
protected PublisherCore myPublisherCore;
protected IDictionary myPublisherMap = new Hashtable ();
protected IDictionary mySchemaMap = new Hashtable ();
public class PubTableBroker {
protected PublisherCore _publisher_core;
protected IDictionary<string, IPubTablePublisher> _publisher_map = new Dictionary<string, IPubTablePublisher>();
protected Dictionary<string, IBlueTableSchema> _schema_map = new Dictionary<string, IBlueTableSchema>();
protected bool myWaitingForFirstOp = false;
public PubTableBroker ()
: this (new PublisherCore())
{}
public PubTableBroker()
: this(new PublisherCore()) { }
public PubTableBroker (PublisherCore publisher)
{myPublisherCore = publisher;}
public PubTableBroker(PublisherCore publisher) { _publisher_core = publisher; }
public PubTableBroker (IBlueRowCollection[] tablesToPublish)
: this (new PublisherCore(), tablesToPublish)
{}
public PubTableBroker(IBlueRowCollection[] tablesToPublish)
: this(new PublisherCore(), tablesToPublish) { }
public PubTableBroker (PublisherCore publisher, IBlueRowCollection[] tablesToPublish)
{
myPublisherCore = publisher;
public PubTableBroker(PublisherCore publisher, IBlueRowCollection[] tablesToPublish) {
_publisher_core = publisher;
myPublisherCore.beginTransaction ();
_publisher_core.beginTransaction();
foreach (IBlueRowCollection table in tablesToPublish)
createTable (table);
myPublisherCore.commitTransaction ();
createTable(table);
_publisher_core.commitTransaction();
}
public void beginTransaction ()
{
public void beginTransaction() {
myWaitingForFirstOp = true;
}
public void commitTransaction ()
{
public void commitTransaction() {
bts.Log.Gen.info("PubTableBroker.commitTransaction");
if (myWaitingForFirstOp)
myWaitingForFirstOp = false;
else
myPublisherCore.commitTransaction ();
_publisher_core.commitTransaction();
}
public void rollbackTransaction ()
{
public void rollbackTransaction() {
bts.Log.Gen.info("PubTableBroker.rollbackTransaction");
if (myWaitingForFirstOp)
myWaitingForFirstOp = false;
else
myPublisherCore.abortTransaction ();
_publisher_core.abortTransaction();
}
public virtual void createTable (IBlueRowCollection newTable)
{
public virtual void createTable(IBlueRowCollection newTable) {
bts.Log.Gen.info($"PubTableBroker.createTable table: {newTable.schema.tableName}");
myCheckTransaction();
if (myPublisherMap [newTable.schema.tableName.ToLower()] == null)
{
myPublisherMap [newTable.schema.tableName.ToLower()] = myGetIPubTablePublisher ();
mySchemaMap [newTable.schema.tableName.ToLower()] = newTable.schema;
IPubTablePublisher table_publisher = null;
var name_key = newTable.schema.tableName.ToLower();
if (!_publisher_map.TryGetValue(name_key, out table_publisher)) {
table_publisher = _create_pubtable_publisher(name_key);
_publisher_map.Add(name_key, table_publisher);
_schema_map.Add(name_key, newTable.schema);
}
(myPublisherMap[newTable.schema.tableName.ToLower()] as IPubTablePublisher).createTable (newTable);
table_publisher.createTable(newTable);
}
/// <summary>
@@ -74,13 +70,14 @@ namespace BCG
/// will be thrown
/// </summary>
/// <param name="r"></param>
public virtual void addRow (IBlueRow r)
{
public virtual void addRow(IBlueRow r) {
myCheckTransaction();
if (myPublisherMap[r.schema.tableName.ToLower()] == null)
throw new ApplicationException ("Row can not be added, as the table that has not been created yet");
IPubTablePublisher table_publisher = null;
var name_key = r.schema.tableName.ToLower();
if (!_publisher_map.TryGetValue(name_key, out table_publisher))
throw new ApplicationException("Row can not be added, as the table that has not been created yet");
else
(myPublisherMap [r.schema.tableName.ToLower()] as IPubTablePublisher).addRow (r);
table_publisher.addRow(r);
}
/// <summary>
@@ -88,13 +85,14 @@ namespace BCG
/// will be thrown
/// </summary>
/// <param name="r"></param>
public virtual void deleteRow (IBlueRow r)
{
public virtual void deleteRow(IBlueRow r) {
myCheckTransaction();
if (myPublisherMap[r.schema.tableName.ToLower()] == null)
throw new ApplicationException ("Row can not be removed, as the table has not been created yet");
IPubTablePublisher table_publisher = null;
var name_key = r.schema.tableName.ToLower();
if (!_publisher_map.TryGetValue(name_key, out table_publisher))
throw new ApplicationException("Row can not be removed, as the table has not been created yet");
else
(myPublisherMap [r.schema.tableName.ToLower()] as IPubTablePublisher).deleteRow (r);
table_publisher.deleteRow(r);
}
/// <summary>
@@ -102,13 +100,14 @@ namespace BCG
/// will be thrown
/// </summary>
/// <param name="r"></param>
public virtual void changeRow (IBlueRow r)
{
public virtual void changeRow(IBlueRow r) {
myCheckTransaction();
if (myPublisherMap[r.schema.tableName.ToLower()] == null)
throw new ApplicationException ("Row can not be changed, as the table has not been created yet");
IPubTablePublisher table_publisher = null;
var name_key = r.schema.tableName.ToLower();
if (!_publisher_map.TryGetValue(name_key, out table_publisher))
throw new ApplicationException("Row can not be changed, as the table has not been created yet");
else
(myPublisherMap [r.schema.tableName.ToLower()] as IPubTablePublisher).changeRow (r);
table_publisher.changeRow(r);
}
/// <summary>
@@ -116,40 +115,37 @@ namespace BCG
/// will be thrown
/// </summary>
/// <param name="r"></param>
public virtual void makeBatchChanges (IBlueRowCollection newRows,
IBlueRowCollection deletedRows,
IBlueRowCollection addedRows)
{
public virtual void makeBatchChanges(IBlueRowCollection newRows,
IBlueRowCollection deletedRows,
IBlueRowCollection addedRows) {
myCheckTransaction();
if (myPublisherMap[newRows.schema.tableName.ToLower()] == null)
throw new ApplicationException ("Batch changes can not be made, as the table has not been created yet");
IPubTablePublisher table_publisher = null;
var name_key = newRows.schema.tableName.ToLower();
if (!_publisher_map.TryGetValue(name_key, out table_publisher))
throw new ApplicationException("Batch changes can not be made, as the table has not been created yet");
else
(myPublisherMap [newRows.schema.tableName.ToLower()] as IPubTablePublisher).batchRemoveAdd (deletedRows, addedRows);
table_publisher.batchRemoveAdd(deletedRows, addedRows);
}
public virtual void deleteTableRows (string tableName)
{
public virtual void deleteTableRows(string tableName) {
myCheckTransaction();
(myPublisherMap [tableName.ToLower()] as IPubTablePublisher).createTable (
new BlueTable (mySchemaMap[tableName.ToLower()] as IBlueTableSchema));
(_publisher_map[tableName.ToLower()] as IPubTablePublisher).createTable(
new BlueTable(_schema_map[tableName.ToLower()] as IBlueTableSchema));
}
public int getNumberOfWaitingMessages() { return myPublisherCore.getNumberOfWaitingMessages(); }
public void clearTable(string tableName)
{myPublisherCore.clearState(PubStreamPrefixer.prefix(tableName));}
public int getNumberOfWaitingMessages() { return _publisher_core.getNumberOfWaitingMessages(); }
protected void myCheckTransaction()
{
public void clearTable(string tableName) { _publisher_core.clearState(PubStreamPrefixer.prefix(tableName)); }
protected void myCheckTransaction() {
if (myWaitingForFirstOp)
myPublisherCore.beginTransaction ();
_publisher_core.beginTransaction();
myWaitingForFirstOp = false;
}
protected virtual IPubTablePublisher myGetIPubTablePublisher ()
{
return new PubTablePublisher (myPublisherCore);
protected virtual IPubTablePublisher _create_pubtable_publisher(string tag) {
return new PubTablePublisher(tag, _publisher_core);
}
}
}
}
@@ -4,62 +4,51 @@ using System.Data;
using BCG.Utilities;
namespace BCG
{
public class ViewPublisher : IDisposable
{
protected ViewPublisher () {}
namespace BCG {
public class ViewPublisher : IDisposable {
protected ViewPublisher() { }
/// If an name IsNullOrEmpty then it uses the name
/// in the schema (be careful with that because this
/// could lead to double publishes if the schema name
/// is not uniquely chosen)
public ViewPublisher(string name, PubTableBroker br, ViewStream vs)
{
public ViewPublisher(string name, PubTableBroker br, ViewStream vs) {
myName = name;
myView = new TableStream(name); // TODOds String.IsNullOrEmpty(name) ? vs : new ProjectStream(vs, "!", myName);
myView = vs;//String.IsNullOrEmpty(name) ? vs : new ProjectStream(vs, "!", myName);
myBroker = br;
myFirstTime = true;
myView.onChange += new DataStream.ChangeDelegate(myChangeHandler);
}
public void Dispose()
{
public void Dispose() {
myView.onChange -= new DataStream.ChangeDelegate(myChangeHandler);
if (!String.IsNullOrEmpty(myName))
myBroker.clearTable(myName);
}
private void myChangeHandler(object o)
{
DataPacket dp = (DataPacket) o;
if (myFirstTime)
{
private void myChangeHandler(object o) {
DataPacket dp = (DataPacket)o;
if (myFirstTime) {
myName = String.IsNullOrEmpty(myName) ? dp.schema.tableName : myName;
myLastRowCount = dp.newRows.Count;
myBroker.createTable(dp.newRows);
myFirstTime = false;
}
else
{
if (((dp.addedRows.Count + dp.deletedRows.Count) != 0))
{
myLastRowCount = dp.newRows.Count;
myBroker.makeBatchChanges(dp.newRows,dp.deletedRows, dp.addedRows);
} else {
if (((dp.addedRows.Count + dp.deletedRows.Count) != 0)) {
myLastRowCount = dp.newRows.Count;
myBroker.makeBatchChanges(dp.newRows, dp.deletedRows, dp.addedRows);
}
}
}
public int getLastRowPublishedCount()
{return myLastRowCount;}
public int getLastRowPublishedCount() { return myLastRowCount; }
public bool hasPublished()
{ return !myFirstTime; }
public bool hasPublished() { return !myFirstTime; }
private int myLastRowCount = -1;
private string myName;
private PubTableBroker myBroker;
protected ViewStream myView;
private bool myFirstTime;
}
}
}
@@ -112,6 +112,34 @@ namespace BCG
#endregion
public static void print_table(this IBlueRowCollection table, Func<string, int> get_col_width)
{
// Print column headers
Console.WriteLine($"{table.schema.tableName}______________________________________");
foreach (var col_name in table.schema.columnNames)
{
int col_width = get_col_width(col_name);
Console.Write($"{col_name.PadRight(col_width)} ");
}
Console.WriteLine();
Console.WriteLine("______________________________________");
// Print table data
foreach (IBlueRow row in table)
{
foreach (string col_name in table.schema.columnNames)
{
int col_width = get_col_width(col_name);
object row_val = row[col_name];
string row_val_str = row_val.ToString();
if (row_val != null)
{
Console.Write($"{row_val_str.PadRight(col_width)} ");
}
}
Console.WriteLine();
}
}
private static IReadOnlyDictionary<TypeCode, Type> _typecode_to_type = new Dictionary<TypeCode, Type>
{
{ TypeCode.Boolean, typeof(bool) },
@@ -895,12 +923,12 @@ namespace BCG
out IBlueRowCollection out_d_rows, out IBlueRowCollection out_a_rows)
{
Func<IBlueRow, IBlueRow, bool> rows_equal = (r1, r2) =>
{
foreach (int col_no in col_indices)
if (!(r1[col_no] ?? DBNull.Value).Equals(r2[col_no] ?? DBNull.Value))
return false;
return true;
};
{
foreach (int col_no in col_indices)
if (!(r1[col_no] ?? DBNull.Value).Equals(r2[col_no] ?? DBNull.Value))
return false;
return true;
};
BlueTable del_rows = new BlueTable(new_rows.schema), add_rows = new BlueTable(new_rows.schema);
// adds + changes
@@ -134,18 +134,17 @@ namespace BCG
/// <param name="row"></param>
public virtual void addRow(IBlueRow row)
{
object val = row["id"];
object id = row["id"];
if (val == null || val == DBNull.Value)
if (id == null || id == DBNull.Value)
throw new BlueDataException("The ID of the row being added is null/DNBull");
try
{
myIdIndex.Add(val, row);
myIdIndex.Add(id, row);
}
catch (ArgumentException)
{
throw new BlueDataException("ID already exists in the table " + mySchema.tableName +
" , duplication of field ID not allowed");
throw new BlueDataException($"ID {id} already exists in the table: {mySchema.tableName} , duplication of field ID not allowed");
}
}
+279 -279
View File
@@ -1,316 +1,316 @@
using System;
using System.Collections;
using System.Data;
using BCG.Utilities.General;
// using System;
// using System.Collections;
// using System.Data;
// using BCG.Utilities.General;
namespace BCG
{
[Serializable]
public class DataPacket : ICloneable, IDataPacket
{
public class BlueRowIdComparator
{
private string[] myIdColumns = new string[]{"id"};
// namespace BCG
// {
// [Serializable]
// public class DataPacket : ICloneable, IDataPacket
// {
// public class BlueRowIdComparator
// {
// private string[] myIdColumns = new string[]{"id"};
public BlueRowIdComparator(string[] idCols)
{
if ( idCols.Length != 0 )
{
myIdColumns = idCols;
}
}
public bool blueRowIdEqualEvaluator(object a, object b)
{
if ( a == null || b == null )
{
return false;
}
// public BlueRowIdComparator(string[] idCols)
// {
// if ( idCols.Length != 0 )
// {
// myIdColumns = idCols;
// }
// }
if ( !(a is IBlueRow) || !(b is IBlueRow) )
{
return false;
}
// public bool blueRowIdEqualEvaluator(object a, object b)
// {
// if ( a == null || b == null )
// {
// return false;
// }
IBlueRow lhs = (IBlueRow)a;
IBlueRow rhs = (IBlueRow)b;
bool result = true;
foreach(string idColumn in myIdColumns)
{
result = result && lhs[idColumn].Equals(rhs[idColumn]);
if ( !result )
break;
}
// if ( !(a is IBlueRow) || !(b is IBlueRow) )
// {
// return false;
// }
return result;
}
}
// IBlueRow lhs = (IBlueRow)a;
// IBlueRow rhs = (IBlueRow)b;
public IBlueRowCollection newRows, addedRows, deletedRows;
public DataPacket () {}
public DataPacket (IBlueRowCollection newRows, IBlueRowCollection addedRows, IBlueRowCollection deletedRows)
{
this.newRows = newRows;
this.addedRows = addedRows;
this.deletedRows = deletedRows;
}
// bool result = true;
// foreach(string idColumn in myIdColumns)
// {
// result = result && lhs[idColumn].Equals(rhs[idColumn]);
// if ( !result )
// break;
// }
public void get_new_added_deleted(out ICollection new_rows, out ICollection added_rows, out ICollection deleted_rows)
{
new_rows = newRows;
added_rows = addedRows;
deleted_rows = deletedRows;
}
// return result;
// }
// }
public IBlueRowCollection getTrulyAddedRows(params string[] idColumns)
{
BlueTable truly = new BlueTable(addedRows.schema);
BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
// public IBlueRowCollection newRows, addedRows, deletedRows;
// public DataPacket () {}
// public DataPacket (IBlueRowCollection newRows, IBlueRowCollection addedRows, IBlueRowCollection deletedRows)
// {
// this.newRows = newRows;
// this.addedRows = addedRows;
// this.deletedRows = deletedRows;
// }
CollectionHelpers.EqualDelegate ed =
new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
// public void get_new_added_deleted(out ICollection new_rows, out ICollection added_rows, out ICollection deleted_rows)
// {
// new_rows = newRows;
// added_rows = addedRows;
// deleted_rows = deletedRows;
// }
ICollection ta = CollectionHelpers.difference(addedRows, deletedRows, ed);
foreach(IBlueRow r in ta)
{
truly.addRow(r);
}
return truly;
}
// public IBlueRowCollection getTrulyAddedRows(params string[] idColumns)
// {
// BlueTable truly = new BlueTable(addedRows.schema);
// BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
public virtual IBlueRowCollection getTrulyAddedRows ()
{
BlueTable retVal = new BlueTable (schema);
foreach (IBlueRow r in addedRows)
if (!deletedRows.containsID ((int)r["id"]))
retVal.addRow (r);
return retVal;
}
// CollectionHelpers.EqualDelegate ed =
// new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
public virtual IBlueRowCollection getTrulyDeletedRows ()
{
BlueTable retVal = new BlueTable (schema);
foreach (IBlueRow r in deletedRows)
if (!addedRows.containsID ((int)r["id"]))
retVal.addRow (r);
return retVal;
}
// ICollection ta = CollectionHelpers.difference(addedRows, deletedRows, ed);
public virtual IBlueRowCollection getTrulyChangedRows ()
{
BlueTable retVal = new BlueTable (schema);
foreach (IBlueRow r in addedRows)
if (deletedRows.containsID ((int)r["id"]))
retVal.addRow (r);
return retVal;
}
// foreach(IBlueRow r in ta)
// {
// truly.addRow(r);
// }
public IBlueRowCollection getTrulyDeletedRows(params string[] idColumns)
{
BlueTable truly = new BlueTable(deletedRows.schema);
BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
// return truly;
CollectionHelpers.EqualDelegate ed =
new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
// }
ICollection td = CollectionHelpers.difference(deletedRows, addedRows, ed);
foreach(IBlueRow r in td)
{
truly.addRow(r);
}
// public virtual IBlueRowCollection getTrulyAddedRows ()
// {
// BlueTable retVal = new BlueTable (schema);
// foreach (IBlueRow r in addedRows)
// if (!deletedRows.containsID ((int)r["id"]))
// retVal.addRow (r);
// return retVal;
// }
return truly;
}
public IBlueRowCollection getTrulyChangedRows(params string[] idColumns)
{
BlueTable truly = new BlueTable(addedRows.schema);
BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
// public virtual IBlueRowCollection getTrulyDeletedRows ()
// {
// BlueTable retVal = new BlueTable (schema);
// foreach (IBlueRow r in deletedRows)
// if (!addedRows.containsID ((int)r["id"]))
// retVal.addRow (r);
// return retVal;
// }
CollectionHelpers.EqualDelegate ed =
new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
// public virtual IBlueRowCollection getTrulyChangedRows ()
// {
// BlueTable retVal = new BlueTable (schema);
// foreach (IBlueRow r in addedRows)
// if (deletedRows.containsID ((int)r["id"]))
// retVal.addRow (r);
// return retVal;
// }
ICollection ta = CollectionHelpers.difference(addedRows, deletedRows, ed);
ICollection tc = CollectionHelpers.difference(addedRows, ta, ed);
foreach(IBlueRow r in tc)
{
truly.addRow(r);
}
return truly;
}
public IBlueRowCollection getTrulyChangedOldRows(params string[] idColumns)
{
BlueTable truly = new BlueTable(deletedRows.schema);
BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
CollectionHelpers.EqualDelegate ed =
new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
// public IBlueRowCollection getTrulyDeletedRows(params string[] idColumns)
// {
// BlueTable truly = new BlueTable(deletedRows.schema);
// BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
ICollection td = CollectionHelpers.difference(deletedRows, addedRows, ed);
ICollection tco = CollectionHelpers.difference(deletedRows, td, ed);
foreach(IBlueRow r in tco)
{
truly.addRow(r);
}
// CollectionHelpers.EqualDelegate ed =
// new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
return truly;
}
public TablePacket toTablePacket ()
{
return new TablePacket (BlueDataUtility.toDataTable (newRows), BlueDataUtility.toDataTable (addedRows),
BlueDataUtility.toDataTable (deletedRows));
}
// ICollection td = CollectionHelpers.difference(deletedRows, addedRows, ed);
public IBlueTableSchema schema
{
get
{
IBlueTableSchema retVal = newRows.schema != null ? newRows.schema :
addedRows.schema != null ? addedRows.schema : deletedRows.schema;
return retVal;
}
}
// foreach(IBlueRow r in td)
// {
// truly.addRow(r);
// }
/*
status D total A total D this A This D' total A' Total
x 0 0 0 0 0 0
0 0 0 1 1 this+
0 0 1 0 1this
0 0 1 1 1 this 1 this+
x 0 1 0 0
error 0 1 0 1
0 1 1 0 1 total-
0 1 1 1 1 total-, 1 this +
x 1 0 0 0
1 0 0 1 1 this+
error 1 0 1 0
error 1 0 1 1
x 1 1 0 0
error 1 1 0 1
1 1 1 0 1 total -1 keep the old delete and remove the old add
1 1 1 1 1 total-, 1 this +
d' = dthis - (dthis intersect a) + d // keep the old delete
a' = a - (dthis intersect a) + athis // keep the new add
* */
public static DataPacket combineWithIds(ICollection packets, string[] idColumns)
{
if ( packets.Count == 0 )
{
return new DataPacket(
new BlueTable(new DataTable()),
new BlueTable(new DataTable()),
new BlueTable(new DataTable()));
}
// return truly;
// }
DataPacket.BlueRowIdComparator c = new DataPacket.BlueRowIdComparator(idColumns);
CollectionHelpers.EqualDelegate ed =
new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
// public IBlueRowCollection getTrulyChangedRows(params string[] idColumns)
// {
ArrayList added = new ArrayList();
ArrayList deleted = new ArrayList();
BlueTable dt = null;
BlueTable at = null;
IBlueRowCollection nt = null;
// BlueTable truly = new BlueTable(addedRows.schema);
// BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
foreach(DataPacket dp in packets)
{
ArrayList oldDeleted = deleted;
ArrayList oldAdded = added;
// CollectionHelpers.EqualDelegate ed =
// new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
added = new ArrayList();
deleted = new ArrayList();
if ( dt == null )
{
dt = new BlueTable(dp.schema);
at = new BlueTable(dp.schema);
}
deleted.AddRange(oldDeleted);
deleted.AddRange( CollectionHelpers.difference(
CollectionHelpers.difference(dp.deletedRows, oldAdded, ed),
oldDeleted, ed) );
// ICollection ta = CollectionHelpers.difference(addedRows, deletedRows, ed);
// ICollection tc = CollectionHelpers.difference(addedRows, ta, ed);
added.AddRange(dp.addedRows);
added.AddRange( CollectionHelpers.difference(
CollectionHelpers.difference(oldAdded, dp.deletedRows, ed),
added, ed) );
nt = dp.newRows;
}
foreach ( IBlueRow dr in added )
{
at.addRow(dr);
}
// foreach(IBlueRow r in tc)
// {
// truly.addRow(r);
// }
foreach ( IBlueRow dr in deleted )
{
dt.addRow(dr);
}
// return truly;
// }
return new DataPacket(nt,at,dt);
}
// public IBlueRowCollection getTrulyChangedOldRows(params string[] idColumns)
// {
// BlueTable truly = new BlueTable(deletedRows.schema);
// BlueRowIdComparator c = new BlueRowIdComparator(idColumns);
public DataPacket deepCopy ()
{
return new DataPacket (new OrderedBlueTable (newRows),
new OrderedBlueTable (newRows),
new BlueTable (deletedRows));
}
// CollectionHelpers.EqualDelegate ed =
// new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
public virtual DataPacket createImmutable ()
{
return
new DataPacket(
newRows is IImmutableRowCollection ? newRows : new ImmutableBlueTable(newRows),
addedRows,
deletedRows);
}
#region ICloneable Members
// ICollection td = CollectionHelpers.difference(deletedRows, addedRows, ed);
// ICollection tco = CollectionHelpers.difference(deletedRows, td, ed);
public object Clone()
{
return MemberwiseClone();
}
// foreach(IBlueRow r in tco)
// {
// truly.addRow(r);
// }
#endregion
// return truly;
// }
public string toIncrementalIDString()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder(schema.tableName);
sb.Append ("\ndeleted : ");
foreach (IBlueRow r in deletedRows)
{
sb.Append(r["id"]);
sb.Append(',');
}
sb.Append("\nadded : ");
foreach (IBlueRow r in addedRows)
{
sb.Append(r["id"]);
sb.Append(',');
}
sb.Append("\n");
return sb.ToString();
}
// public TablePacket toTablePacket ()
// {
// return new TablePacket (BlueDataUtility.toDataTable (newRows), BlueDataUtility.toDataTable (addedRows),
// BlueDataUtility.toDataTable (deletedRows));
public override string ToString()
{
return String.Format("DataPacket, schema {0} n {1} d {2} a {3}", schema.tableName, newRows.Count, deletedRows.Count, addedRows.Count);
}
}
}
// }
// public IBlueTableSchema schema
// {
// get
// {
// IBlueTableSchema retVal = newRows.schema != null ? newRows.schema :
// addedRows.schema != null ? addedRows.schema : deletedRows.schema;
// return retVal;
// }
// }
// /*
// status D total A total D this A This D' total A' Total
// x 0 0 0 0 0 0
// 0 0 0 1 1 this+
// 0 0 1 0 1this
// 0 0 1 1 1 this 1 this+
// x 0 1 0 0
// error 0 1 0 1
// 0 1 1 0 1 total-
// 0 1 1 1 1 total-, 1 this +
// x 1 0 0 0
// 1 0 0 1 1 this+
// error 1 0 1 0
// error 1 0 1 1
// x 1 1 0 0
// error 1 1 0 1
// 1 1 1 0 1 total -1 keep the old delete and remove the old add
// 1 1 1 1 1 total-, 1 this +
// d' = dthis - (dthis intersect a) + d // keep the old delete
// a' = a - (dthis intersect a) + athis // keep the new add
// * */
// public static DataPacket combineWithIds(ICollection packets, string[] idColumns)
// {
// if ( packets.Count == 0 )
// {
// return new DataPacket(
// new BlueTable(new DataTable()),
// new BlueTable(new DataTable()),
// new BlueTable(new DataTable()));
// }
// DataPacket.BlueRowIdComparator c = new DataPacket.BlueRowIdComparator(idColumns);
// CollectionHelpers.EqualDelegate ed =
// new CollectionHelpers.EqualDelegate(c.blueRowIdEqualEvaluator);
// ArrayList added = new ArrayList();
// ArrayList deleted = new ArrayList();
// BlueTable dt = null;
// BlueTable at = null;
// IBlueRowCollection nt = null;
// foreach(DataPacket dp in packets)
// {
// ArrayList oldDeleted = deleted;
// ArrayList oldAdded = added;
// added = new ArrayList();
// deleted = new ArrayList();
// if ( dt == null )
// {
// dt = new BlueTable(dp.schema);
// at = new BlueTable(dp.schema);
// }
// deleted.AddRange(oldDeleted);
// deleted.AddRange( CollectionHelpers.difference(
// CollectionHelpers.difference(dp.deletedRows, oldAdded, ed),
// oldDeleted, ed) );
// added.AddRange(dp.addedRows);
// added.AddRange( CollectionHelpers.difference(
// CollectionHelpers.difference(oldAdded, dp.deletedRows, ed),
// added, ed) );
// nt = dp.newRows;
// }
// foreach ( IBlueRow dr in added )
// {
// at.addRow(dr);
// }
// foreach ( IBlueRow dr in deleted )
// {
// dt.addRow(dr);
// }
// return new DataPacket(nt,at,dt);
// }
// public DataPacket deepCopy ()
// {
// return new DataPacket (new OrderedBlueTable (newRows),
// new OrderedBlueTable (newRows),
// new BlueTable (deletedRows));
// }
// public virtual DataPacket createImmutable ()
// {
// return
// new DataPacket(
// newRows is IImmutableRowCollection ? newRows : new ImmutableBlueTable(newRows),
// addedRows,
// deletedRows);
// }
// #region ICloneable Members
// public object Clone()
// {
// return MemberwiseClone();
// }
// #endregion
// public string toIncrementalIDString()
// {
// System.Text.StringBuilder sb = new System.Text.StringBuilder(schema.tableName);
// sb.Append ("\ndeleted : ");
// foreach (IBlueRow r in deletedRows)
// {
// sb.Append(r["id"]);
// sb.Append(',');
// }
// sb.Append("\nadded : ");
// foreach (IBlueRow r in addedRows)
// {
// sb.Append(r["id"]);
// sb.Append(',');
// }
// sb.Append("\n");
// return sb.ToString();
// }
// public override string ToString()
// {
// return String.Format("DataPacket, schema {0} n {1} d {2} a {3}", schema.tableName, newRows.Count, deletedRows.Count, addedRows.Count);
// }
// }
// }
@@ -2,171 +2,151 @@ using System;
using System.Collections;
using System.IO;
namespace BCG
{
/// <summary>
/// The only instance of IPubTableBroker. It handles the publishing of one tag, and holds a specialized serializer
/// that it initializes according to the table, to optimize serialiazation, hence bw and performance
/// This class is held (as an interface) by the PubTableBroker, which guarantees the sanity of calls,
/// ie the first call will always be create.
/// </summary>
public class PubTablePublisher : IPubTablePublisher
{
namespace BCG {
/// <summary>
/// The only instance of IPubTableBroker. It handles the publishing of one tag, and holds a specialized serializer
/// that it initializes according to the table, to optimize serialiazation, hence bw and performance
/// This class is held (as an interface) by the PubTableBroker, which guarantees the sanity of calls,
/// ie the first call will always be create.
/// </summary>
public class PubTablePublisher : IPubTablePublisher {
private readonly string _tag;
protected IBlueDataSerializer mySerializer;
protected PublisherCore myPubCore;
public PubTablePublisher (PublisherCore publisherCore)
{
public PubTablePublisher(string tag, PublisherCore publisherCore) {
_tag = tag;
bts.Log.Gen.info($"PubTablePublisher created for tag: {tag}");
myPubCore = publisherCore;
mySerializer = new BlueDataSerializationController ();
mySerializer = new BlueDataSerializationController();
}
#region IPubTablePublisher Members
public virtual void addRow (IBlueRow row)
{
public virtual void addRow(IBlueRow row) {
byte[] data;
mySerializer.serialize (StreamOpCode.add,
myGetRowCollectionArray (row),
mySerializer.serialize(StreamOpCode.add,
myGetRowCollectionArray(row),
out data);
myPublish (data, row.schema.tableName);
myPublish(data, row.schema.tableName);
}
public virtual void deleteRow (IBlueRow row)
{
public virtual void deleteRow(IBlueRow row) {
byte[] data;
mySerializer.serialize (StreamOpCode.remove,
myGetRowCollectionArray (row),
mySerializer.serialize(StreamOpCode.remove,
myGetRowCollectionArray(row),
out data);
myPublish (data, row.schema.tableName);
myPublish(data, row.schema.tableName);
}
public virtual void changeRow(IBlueRow row)
{
public virtual void changeRow(IBlueRow row) {
byte[] data;
mySerializer.serialize (StreamOpCode.change,
myGetRowCollectionArray (row),
mySerializer.serialize(StreamOpCode.change,
myGetRowCollectionArray(row),
out data);
myPublish (data, row.schema.tableName);
myPublish(data, row.schema.tableName);
}
public virtual void createTable (IBlueRowCollection rows)
{
public virtual void createTable(IBlueRowCollection rows) {
byte[] data;
mySerializer.serialize (StreamOpCode.create,
new IBlueRowCollection [] {rows},
mySerializer.serialize(StreamOpCode.create,
new IBlueRowCollection[] { rows },
out data);
myPublish (data, rows.schema.tableName);
bts.Log.Gen.info($"PubTablePublisher.createTable tag: {_tag} rows: {rows.Count} data: {data.Length}");
myPublish(data, rows.schema.tableName);
}
public virtual void batchRemoveAdd (IBlueRowCollection delRows, IBlueRowCollection addRows)
{
public virtual void batchRemoveAdd(IBlueRowCollection delRows, IBlueRowCollection addRows) {
byte[] data;
if (myIsRealChange (delRows, addRows))
batchChange (addRows);
else
{
mySerializer.serialize (StreamOpCode.multipleRemoveAdd,
new IBlueRowCollection []{delRows, addRows},
if (myIsRealChange(delRows, addRows))
batchChange(addRows);
else {
mySerializer.serialize(StreamOpCode.multipleRemoveAdd,
new IBlueRowCollection[] { delRows, addRows },
out data);
myPublish (data, delRows.schema.tableName);
myPublish(data, delRows.schema.tableName);
}
}
public virtual void batchChange (IBlueRowCollection rows)
{
public virtual void batchChange(IBlueRowCollection rows) {
byte[] data;
mySerializer.serialize (StreamOpCode.multipleChange,
new IBlueRowCollection [] {rows},
mySerializer.serialize(StreamOpCode.multipleChange,
new IBlueRowCollection[] { rows },
out data);
myPublish (data, rows.schema.tableName);
myPublish(data, rows.schema.tableName);
}
#endregion
#region private methods
private void myPublish (byte[] data, string tableName)
{
private void myPublish(byte[] data, string tableName) {
bts.Log.Gen.info($"PubTablePublisher.myPublish table: {tableName} data: {data.Length}");
if (data.Length > 0)
myPubCore.publish ("DataStreamTag",
PubStreamPrefixer.prefix (tableName),
new MemoryStream (data, 0, data.Length, false, true));
myPubCore.publish("DataStreamTag",
PubStreamPrefixer.prefix(tableName),
new MemoryStream(data, 0, data.Length, false, true));
}
private IBlueRowCollection[] myGetRowCollectionArray (IBlueRow r)
{
return new IBlueRowCollection []{
private IBlueRowCollection[] myGetRowCollectionArray(IBlueRow r) {
return new IBlueRowCollection[]{
BlueDataUtility.toBlueRowCollection (new IBlueRow[] {r})
};
}
private bool myIsRealChange (IBlueRowCollection delRows, IBlueRowCollection addRows)
{
if (delRows.Count == addRows.Count)
{
private bool myIsRealChange(IBlueRowCollection delRows, IBlueRowCollection addRows) {
if (delRows.Count == addRows.Count) {
foreach (IBlueRow dRow in delRows)
if (!addRows.containsID ((int)dRow["id"]))
if (!addRows.containsID((int)dRow["id"]))
return false;
return true;
}
else
} else
return false;
}
#endregion
}
public class IndependentTablePublisher : PubTablePublisher
{
public class IndependentTablePublisher : PubTablePublisher {
bool myIsCreated = false;
public IndependentTablePublisher (PublisherCore pubCore) : base (pubCore)
{}
public IndependentTablePublisher(string tag, PublisherCore pubCore) : base(tag, pubCore) { }
public override void addRow (IBlueRow row)
{
myCheckCreate (row.schema);
base.addRow (row);
public override void addRow(IBlueRow row) {
myCheckCreate(row.schema);
base.addRow(row);
}
public override void batchChange (IBlueRowCollection rows)
{
myCheckCreate (rows.schema);
base.batchChange (rows);
public override void batchChange(IBlueRowCollection rows) {
myCheckCreate(rows.schema);
base.batchChange(rows);
}
public override void batchRemoveAdd (IBlueRowCollection delRows, IBlueRowCollection addRows)
{
myCheckCreate (delRows.schema);
base.batchRemoveAdd (delRows, addRows);
public override void batchRemoveAdd(IBlueRowCollection delRows, IBlueRowCollection addRows) {
myCheckCreate(delRows.schema);
base.batchRemoveAdd(delRows, addRows);
}
public override void changeRow (IBlueRow row)
{
myCheckCreate (row.schema);
base.changeRow (row);
public override void changeRow(IBlueRow row) {
myCheckCreate(row.schema);
base.changeRow(row);
}
public override void deleteRow (IBlueRow row)
{
myCheckCreate (row.schema);
base.deleteRow (row);
public override void deleteRow(IBlueRow row) {
myCheckCreate(row.schema);
base.deleteRow(row);
}
public override void createTable(IBlueRowCollection rows)
{
public override void createTable(IBlueRowCollection rows) {
myIsCreated = true;
base.createTable (rows);
base.createTable(rows);
}
private void myCheckCreate (IBlueTableSchema schema)
{
if (!myIsCreated)
{
private void myCheckCreate(IBlueTableSchema schema) {
if (!myIsCreated) {
//so that the initiazliation work is done on the serializer
byte[] placeHolder;
mySerializer.serialize (StreamOpCode.create, new IBlueRowCollection [] {new BlueTable (schema)}, out placeHolder);
mySerializer.serialize(StreamOpCode.create, new IBlueRowCollection[] { new BlueTable(schema) }, out placeHolder);
myIsCreated = true;
}
}
@@ -1,18 +1,16 @@
using System;
namespace BCG
{
/// <summary>
/// Deals with the publication of one tag. Gets the specific implementaion of IBlueDataSerializer according to
/// the table name, from the config, and wraps around it. The external code that will deal with user calls for
/// row operations (PubTablePublisher) will only deal with this class, hence will be agnostic of the specalized
/// serialization.
/// </summary>
public class BlueDataSerializationController : IBlueDataSerializer
{
namespace BCG {
/// <summary>
/// Deals with the publication of one tag. Gets the specific implementaion of IBlueDataSerializer according to
/// the table name, from the config, and wraps around it. The external code that will deal with user calls for
/// row operations (PubTablePublisher) will only deal with this class, hence will be agnostic of the specalized
/// serialization.
/// </summary>
public class BlueDataSerializationController : IBlueDataSerializer {
private IBlueDataSerializer mySerializer;
public BlueDataSerializationController () {}
public BlueDataSerializationController() { }
#region IBlueDataSerializer Members
@@ -23,43 +21,37 @@ namespace BCG
/// <param name="op"></param>
/// <param name="rows"></param>
/// <param name="serializedData"></param>
public void serialize (byte op, IBlueRowCollection[] rows, out byte[] serializedData)
{
if (op == StreamOpCode.create)
{
public void serialize(byte op, IBlueRowCollection[] rows, out byte[] serializedData) {
if (op == StreamOpCode.create) {
if (mySerializer == null)
mySerializer = myGetSerializerForTable(rows[0].schema);
mySerializer.serialize (op, rows, out serializedData);
}
else
{
if (mySerializer != null)
{
mySerializer.serialize (op, rows, out serializedData);
}
else
{
serializedData = new byte[] {};
mySerializer.serialize(op, rows, out serializedData);
} else {
if (mySerializer != null) {
mySerializer.serialize(op, rows, out serializedData);
} else {
serializedData = new byte[] { };
}
}
}
#endregion
private IBlueDataSerializer myGetSerializerForTable(IBlueTableSchema theSchema)
{
private IBlueDataSerializer myGetSerializerForTable(IBlueTableSchema theSchema) {
// TODOds
return new UniversalSerializer(theSchema);
string serializerName = DataStreamGatewaySettings.instance.getSerializer(theSchema.tableName);
object[] serializerArgs = DataStreamGatewaySettings.instance.getSerializerArgs(theSchema.tableName);
if(serializerArgs != null)
if (serializerArgs != null)
return Activator.CreateInstance(Type.GetType(serializerName), theSchema, serializerArgs) as IBlueDataSerializer;
else
return Activator.CreateInstance(Type.GetType(serializerName), theSchema) as IBlueDataSerializer;
}
}
}
@@ -8,7 +8,7 @@ namespace BCG
public class UniversalSerializer : BlueDataSerializer
{
public UniversalSerializer (IBlueTableSchema schema)
: base ("BCG.PubsubUniversalDeserializer, DataStreamGateway", "BCG.ClientUniversalDeserializer")
: base ("BCG.PubsubUniversalDeserializer, DataStreamCore", "BCG.ClientUniversalDeserializer")
{
myRowSerializer = new UniversalRowSerializer (schema);
}
@@ -7,10 +7,11 @@ using System.Text;
namespace BCG
{
/// <summary>
/// Base class for all deserializers.
/// Base class for all pubsubs deserializers.
/// </summary>
public abstract class PubsubDeserializer : IPubsubDeserializer
{
// this is where the stream state is stored in pubsub?
protected IDictionary myState = new Hashtable ();
protected IBlueTableSchema mySchema;
protected string myClientDeserializerName; //for the getState method
@@ -35,6 +36,7 @@ namespace BCG
}
catch (EndOfStreamException)
{
// TODO, logically break loop
break;
}
if (op == StreamOpCode.create)
@@ -2,24 +2,22 @@ using System;
using System.Collections;
using System.IO;
namespace BCG
{
public class PubsubUniversalDeserializer : PubsubDeserializer
{
public PubsubUniversalDeserializer() {}
namespace BCG {
public class PubsubUniversalDeserializer : PubsubDeserializer {
public PubsubUniversalDeserializer() {
bts.Log.Gen.info("PubsubUniversalDeserializer.cons");
}
protected override IDictionary myGetRows (BinaryReader br, byte op, int noOfRows)
{
myDeserializer = myDeserializer == null ? new PubsubUniversalRowDeserializer (mySchema) : myDeserializer;
Hashtable retVal = new Hashtable ();
for (int i = 0; i < noOfRows; i++)
{
protected override IDictionary myGetRows(BinaryReader br, byte op, int noOfRows) {
myDeserializer = myDeserializer == null ? new PubsubUniversalRowDeserializer(mySchema) : myDeserializer;
Hashtable retVal = new Hashtable();
for (int i = 0; i < noOfRows; i++) {
int id; object row;
myDeserializer.deserializeRow (myState, br, op, out id, out row);
retVal.Add (id, row);
myDeserializer.deserializeRow(myState, br, op, out id, out row);
retVal.Add(id, row);
}
return retVal;
}
}
}
}
@@ -1,54 +1,46 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using BCG.Utilities;
namespace BCG
{
namespace BCG {
/// <summary>
/// Keeps a collection of TagStateBanks to hold the state of each tag
/// </summary>
public class PubsubServerTagHandler : IPubSubServerTagHandler
{
private IDictionary myTagStates = new Hashtable ();
public class PubsubServerTagHandler : IPubSubServerTagHandler {
private IDictionary<string, TagStateBank> _tag_state_map = new Dictionary<string, TagStateBank>();
private bool myPublishStatistics = //DataStreamGatewaySettings.instance.enablePubsubStats;
false;
public PubsubServerTagHandler() {}
#region IPubSubServerTagHandler Members
public byte[] getContent (string tag)
{
TagStateBank stateBank = myTagStates[tag] as TagStateBank;
if (stateBank != null)
{
return stateBank.getConent ();
}
else
{
// BlueEventLog.logEvent (String.Format ("Information requested for tag {0} which does not exist now", tag), BlueEventLevel.Warning);
return new byte[] {};
public byte[] getContent(string tag) {
TagStateBank tag_state_bank;
if (_tag_state_map.TryGetValue(tag, out tag_state_bank)) {
return tag_state_bank.getConent();
} else {
bts.Log.Gen.warn("Information requested for tag: {tag}, it does not exist now");
return new byte[] { };
}
}
public void update (string tag, Stream[] messageBodies)
{
if (myPublishStatistics)
{
public void update(string tag, Stream[] messageBodies) {
bts.Log.Gen.info($"PubsubServerTagHandler.update tag: {tag} streams: {messageBodies.Length}");
if (myPublishStatistics) {
StatisticsLogger.instance.log(tag, messageBodies);
}
if (!myTagStates.Contains (tag))
{
// BlueEventLog.logEvent (String.Format ("Tag {0} received for the first time and its state created", tag), BlueEventLevel.Information);
myTagStates.Add (tag, new TagStateBank ());
TagStateBank tag_state_bank;
if (!_tag_state_map.TryGetValue(tag, out tag_state_bank)) {
bts.Log.Gen.info("tag: {tag} received for the first time creating TagStateBank for it now");
tag_state_bank = new TagStateBank();
_tag_state_map.Add(tag, tag_state_bank);
}
(myTagStates[tag] as TagStateBank).update (messageBodies);
tag_state_bank.update(messageBodies);
}
public void doWork() {}
public void doWork() { }
public string[] supportedTagTypes {get {return new string [] {"DataStreamTag"};}}
public string[] supportedTagTypes { get { return new string[] { "DataStreamTag" }; } }
public void register(InternalPublishDelegate callback) { }
@@ -1,26 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace BCG
{
public class TagStateBank
{
//private IDictionary myState = new Hashtable ();
private PubsubDeserializationController myDeserializationController = new PubsubDeserializationController ();
public TagStateBank () {}
namespace BCG {
public class TagStateBank {
private PubsubDeserializationController myDeserializationController = new PubsubDeserializationController();
public byte[] getConent ()
{
return myDeserializationController.getState ();
public TagStateBank() { }
public TagStateBank(string tag) {
bts.Log.Gen.info("TagStateBank created for tag: {tag}");
}
public void update (Stream[] streams)
{
public byte[] getConent() {
return myDeserializationController.getState();
}
public void update(Stream[] streams) {
bts.Log.Gen.info($"TagStateBank.update streams: {streams.Length}");
byte[] ops;
Array rowCollection;
myDeserializationController.deserialize (streams, out ops, out rowCollection);
myDeserializationController.deserialize(streams, out ops, out rowCollection);
}
}
}
@@ -9,7 +9,7 @@ namespace BCG
public class CompressionSerializer : IBlueDataSerializer
{
private IBlueRowSerializer myRowSerializer;
private string myPubsubDeserializerName = "BCG.CompressionPubsubDeserializer, DataStreamGateway", myClientDeserializerName = "BCG.CompressionClientDeserializer";
private string myPubsubDeserializerName = "BCG.CompressionPubsubDeserializer, DataStreamCore", myClientDeserializerName = "BCG.CompressionClientDeserializer";
public CompressionSerializer (IBlueTableSchema schema)
{
@@ -0,0 +1,236 @@
// using System;
// using System.IO;
// using NUnit.Framework;
// namespace BCG
// {
// /// <summary>
// /// Tests the deserialization happening within the pubsub.
// /// </summary>
// [TestGroup]
// public class CompressionSerializationTest
// {
// protected IBlueTableSchema mySchema;
// protected BlueTable myTable;
// protected IBlueDataSerializer mySer;
// protected IPubsubDeserializer myPubsubDeser;
// protected IClientDeserializer myClientDeser;
// [Test]
// public static void test_compression()
// {
// int n_len = 10000000;
// for (int t = 0; t < 10; t++)
// {
// Random rnd = new Random(DateTime.Now.Millisecond);
// byte[] data = new byte[n_len];
// rnd.NextBytes(data);
// BCG.Utilities.General.HighPerformanceTimer timer = new Utilities.General.HighPerformanceTimer();
// timer.start();
// byte[] compr = UtilityMethods.compress(new MemoryStream(data));
// timer.stop();
// Console.WriteLine("Time to compress {0} bytes {1} msecs ratio {2}", n_len, timer.lastIntervalTime, (1.0 * data.Length)/(1.0 * compr.Length));
// timer.start();
// Stream decompr_str = UtilityMethods.decompress(compr);
// timer.stop();
// Console.WriteLine("Time to de-compress {0} bytes {1} msecs", n_len, timer.lastIntervalTime);
// decompr_str.Position = 0;
// Assert.AreEqual(data.Length, (int)decompr_str.Length);
// for (int i = 0; i < data.Length; i++)
// Assert.AreEqual(data[i], decompr_str.ReadByte());
// }
// }
// public CompressionSerializationTest()
// {
// mySchema = new BlueTableSchema(myGetTableName(),
// new ColumnInfo("id", 0, typeof(int)),
// new ColumnInfo("i1", 1, typeof(int)),
// new ColumnInfo("d1", 2, typeof(double)),
// new ColumnInfo("dt", 3, typeof(DateTime)),
// new ColumnInfo("x", 4, typeof(byte))
// );
// mySer = new CompressionSerializer(mySchema);
// myClientDeser = new ClientDeserializationController();
// myPubsubDeser = new PubsubDeserializationController();
// }
// protected virtual string myGetTableName()
// {
// return "testUniversal";
// }
// /// <summary>
// /// Tests the entire cycle. This is done by 'publishing' data to the serializationController (ie a series of
// /// adds, deletions, changes etc) and getting the bytes and feeding it into a pubsubDeseriazlier and a clientDeserializer.
// /// At every step the data is tested for consistency. At the end the getState is used to get all the data, and its passed
// /// through the clientDeserializer to get all the rows.
// /// </summary>
// [Test]
// public void testEntireProcess()
// {
// myTable = new BlueTable(mySchema);
// byte[] data;
// int id;
// //create
// for (id = 0; id < 100; id++)
// myTable.addRow(myGetRow(id));
// byte[] ops;
// Array rows;
// IBlueRowCollection del, add;
// IBlueRowCollection[] receivedData;
// IBlueRow r;
// //create
// mySer.serialize(StreamOpCode.create, new IBlueRowCollection[] { myTable }, out data);
// myWrite(StreamOpCode.create, data);
// myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// Assert.AreEqual(1, ops.Length);
// Assert.AreEqual(StreamOpCode.create, ops[0]);
// Assert.AreEqual(1, rows.Length);
// receivedData = rows.GetValue(0) as IBlueRowCollection[];
// Assert.AreEqual(1, receivedData.Length);
// BlueDataUtility.computeDifferences(receivedData[0], myTable, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// //single add
// r = myGetRow(id);
// BlueTable temp = new BlueTable(mySchema);
// myTable.addRow(r);
// temp.addRow(r);
// mySer.serialize(StreamOpCode.add, new IBlueRowCollection[] { temp }, out data);
// myWrite(StreamOpCode.add, data);
// myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// Assert.AreEqual(1, ops.Length);
// Assert.AreEqual(StreamOpCode.add, ops[0]);
// Assert.AreEqual(1, rows.Length);
// receivedData = rows.GetValue(0) as IBlueRowCollection[];
// Assert.AreEqual(1, receivedData.Length);
// BlueDataUtility.computeDifferences(receivedData[0], temp, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// //single delete
// r = myTable[0]; //delete row with id 0
// temp = new BlueTable(mySchema);
// myTable.deleteRow(0);
// temp.addRow(r);
// mySer.serialize(StreamOpCode.remove, new IBlueRowCollection[] { temp }, out data);
// myWrite(StreamOpCode.remove, data);
// myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// Assert.AreEqual(1, ops.Length);
// Assert.AreEqual(StreamOpCode.remove, ops[0]);
// Assert.AreEqual(1, rows.Length);
// receivedData = rows.GetValue(0) as IBlueRowCollection[];
// Assert.AreEqual(1, receivedData.Length);
// BlueDataUtility.computeDifferences(receivedData[0], temp, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// //batch deletes and adds
// //0 was removed earlier, so lets delete from 1 to 24 first, and then add 101 to 124
// BlueTable delRows = new BlueTable(mySchema), addRows = new BlueTable(mySchema);
// for (int i = 1; i < 25; i++)
// {
// delRows.addRow(myTable[i]);
// myTable.deleteRow(i);
// }
// for (id = 101; id < 125; id++)
// {
// r = myGetRow(id);
// addRows.addRow(r);
// myTable.addRow(r);
// }
// for (int i = 25; i < 125; i++)
// Assert.AreEqual(true, myTable.containsID(i));
// Assert.AreEqual(100, myTable.Count);
// mySer.serialize(StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] { delRows, addRows }, out data);
// myWrite(StreamOpCode.multipleRemoveAdd, data);
// myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// Assert.AreEqual(1, ops.Length);
// Assert.AreEqual(StreamOpCode.multipleRemoveAdd, ops[0]);
// Assert.AreEqual(1, rows.Length);
// receivedData = rows.GetValue(0) as IBlueRowCollection[];
// Assert.AreEqual(2, receivedData.Length);
// BlueDataUtility.computeDifferences(receivedData[0], delRows, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// BlueDataUtility.computeDifferences(receivedData[1], addRows, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// //pure changes only
// //change the first 25, 25-49
// BlueTable changedRows = new BlueTable(mySchema);
// for (int i = 25; i < 50; i++)
// {
// MutableBlueRow mr = new MutableBlueRow(myTable[i]);
// mr.setValue(4, Byte.MaxValue);
// myTable.changeRow(mr);
// changedRows.addRow(mr);
// }
// mySer.serialize(StreamOpCode.multipleChange, new IBlueRowCollection[] { changedRows }, out data);
// myWrite(StreamOpCode.multipleChange, data);
// myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// Assert.AreEqual(1, ops.Length);
// Assert.AreEqual(StreamOpCode.multipleChange, ops[0]);
// Assert.AreEqual(1, rows.Length);
// receivedData = rows.GetValue(0) as IBlueRowCollection[];
// Assert.AreEqual(1, receivedData.Length);
// BlueDataUtility.computeDifferences(receivedData[0], changedRows, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// //final test
// data = myPubsubDeser.getState();
// new ClientDeserializationController().deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
// Assert.AreEqual(1, ops.Length);
// Assert.AreEqual(StreamOpCode.create, ops[0]);
// Assert.AreEqual(1, rows.Length);
// receivedData = rows.GetValue(0) as IBlueRowCollection[];
// Assert.AreEqual(1, receivedData.Length);
// BlueDataUtility.computeDifferences(receivedData[0], myTable, out del, out add);
// Assert.AreEqual(0, del.Count);
// Assert.AreEqual(0, add.Count);
// }
// private IBlueRow myGetRow(int id)
// {
// return new BlueRow(mySchema, // the day pp fixed this test.
// id, id + 10, id * 3.0, new DateTime(2008, 6, 4, 0, 0, 0, DateTimeKind.Unspecified), Convert.ToByte(id));
// }
// private void myWrite(byte op, byte[] data)
// {
// string s = "";
// if (op == StreamOpCode.add)
// s = "add one row";
// else if (op == StreamOpCode.change)
// s = "change one row";
// else if (op == StreamOpCode.create)
// s = "create";
// else if (op == StreamOpCode.multipleChange)
// s = "multiple change";
// else if (op == StreamOpCode.multipleRemoveAdd)
// s = "multiple add remove";
// else if (op == StreamOpCode.remove)
// s = "remove one row";
// Console.WriteLine("op = {0}, size = {1}", s, data.Length);
// }
// }
// }
@@ -0,0 +1,100 @@
// using System;
// using System.IO;
// using System.Collections;
// using NUnit.Framework;
// namespace BCG
// {
// [TestGroup]
// public class FixedChangingRowSerializationTest
// {
// private IBlueTableSchema mySchema = new BlueTableSchema ("Test",
// new ColumnInfo ("i", 0, typeof(int)),
// new ColumnInfo ("b", 1, typeof(bool)),
// new ColumnInfo ("d", 2, typeof(double)),
// new ColumnInfo ("id", 3, typeof(int)),
// new ColumnInfo ("dt", 4, typeof(DateTime)),
// new ColumnInfo ("bt", 5, typeof(byte)));
// private BlueTable myState;
// private Random myRnd = new Random (DateTime.Now.Millisecond);
// private IBlueRowSerializer mySerializer;
// private IClientRowDeserializer myRowDeserializer;
// public FixedChangingRowSerializationTest ()
// {
// myState = new BlueTable (mySchema);
// mySerializer = new FixedChangingRowSerializer (mySchema, "bt");
// myRowDeserializer = new ClientFixedChangingRowDeserializer (mySchema, new string[] {"bt"});
// }
// [Test]
// public void addTest ()
// {
// for (int i = 0; i < 1000; i++)
// {
// BinaryWriter bw = new BinaryWriter (new MemoryStream ());
// IBlueRow r = myCreateRow (i);
// mySerializer.serializeRow (r, StreamOpCode.add, bw);
// BinaryReader br = new BinaryReader (new MemoryStream ((bw.BaseStream as MemoryStream).ToArray ()));
// Assert.AreEqual (r["i"], br.ReadInt32());
// Assert.AreEqual (r["b"], br.ReadBoolean ());
// Assert.AreEqual (r["d"], br.ReadDouble ());
// Assert.AreEqual (r["id"], br.ReadInt32 ());
// Assert.AreEqual (((DateTime)r["dt"]).Ticks, br.ReadInt64());
// Assert.AreEqual (r["bt"], br.ReadByte ());
// }
// }
// [Test]
// public void removeTest ()
// {
// for (int i = 0; i < 1000; i++)
// {
// BinaryWriter bw = new BinaryWriter (new MemoryStream ());
// IBlueRow r = myCreateRow (i);
// mySerializer.serializeRow (r, StreamOpCode.remove, bw);
// BinaryReader br = new BinaryReader (new MemoryStream ((bw.BaseStream as MemoryStream).ToArray ()));
// Assert.AreEqual (r["id"], br.ReadInt32());
// }
// }
// [Test]
// public void changeTest ()
// {
// for (int i = 0; i < 1000; i++)
// {
// BinaryWriter bw = new BinaryWriter (new MemoryStream ());
// IBlueRow r = myCreateRow (i);
// mySerializer.serializeRow (r, StreamOpCode.change, bw);
// BinaryReader br = new BinaryReader (new MemoryStream ((bw.BaseStream as MemoryStream).ToArray ()));
// Assert.AreEqual (r["id"], br.ReadInt32());
// Assert.AreEqual (r["bt"], br.ReadByte());
// bool isEnd = false;
// try
// {
// br.ReadByte ();
// }
// catch (EndOfStreamException)
// {
// isEnd = true;
// }
// Assert.That (isEnd);
// }
// }
// private IBlueRow myCreateRow (int id)
// {
// return new BlueRow (mySchema,
// myRnd.Next (1000),
// myRnd.Next (1000) % 2 == 0,
// myRnd.NextDouble (),
// id,
// DateTime.Now,
// Convert.ToByte (10));
// }
// }
// }
@@ -0,0 +1,40 @@
// using System;
// namespace BCG
// {
// public class TestFixedChangingSerializer : FixedChangingSerializer
// {
// public TestFixedChangingSerializer (IBlueTableSchema schema)
// : base (schema,
// new string[] {"x"},
// "BCG.PubsubTestFixedChangingDeserializer",
// "BCG.ClientTestFixedChangingDeserializer"
// )
// {}
// }
// public class PubsubTestFixedChangingDeserializer : PubsubFixedChangingDeserializer
// {
// public PubsubTestFixedChangingDeserializer () : base (new string[] {"x"})
// {}
// }
// public class ClientTestFixedChangingDeserializer : ClientFixedChangingDeserializer
// {
// public ClientTestFixedChangingDeserializer () : base (new string[] {"x"})
// {}
// }
// public class FixedChangingSerializationTest : UniversalSerializationTest
// {
// public FixedChangingSerializationTest () {}
// protected override string myGetTableName()
// {
// return "testFixedChanging";
// }
// }
// }
@@ -0,0 +1,73 @@
// using System;
// using System.Collections;
// using System.IO;
// using NUnit.Framework;
// using BCG.Utilities.General;
// namespace BCG
// {
// [TestFixture]
// public class MarketOptionTheoSerializationTest
// {
// private IBlueTableSchema mySchema = new BlueTableSchema ("marketOptionTheo",
// new ColumnInfo ("arrayIndex", 0, typeof(byte)),
// new ColumnInfo ("cell", 1, typeof(byte)),
// new ColumnInfo ("expiration", 2, typeof(DateTime)),
// new ColumnInfo ("id", 3, typeof(int)),
// new ColumnInfo ("value", 4, typeof(double))
// );
// public MarketOptionTheoSerializationTest () {}
// [Test]
// public void serializationPerformanceTest ()
// {
// MarketOptionTheoSerializer ser = new MarketOptionTheoSerializer (mySchema);
// IClientDeserializer deser = new MarketOptionTheoClientDeserializer ();
// BlueTable bt = new BlueTable (mySchema);
// int count = 3000;
// byte[] ops;
// Array rows;
// HighPerformanceTimer timer = new HighPerformanceTimer ();
// byte[] serData = null;
// for (int i = 0; i < count; i++)
// bt.addRow (myGetRow (i));
// ///serialization
// //create
// ser.serialize (StreamOpCode.create, new IBlueRowCollection[] {bt}, out serData);
// deser.deserialize (new Stream [] {new MemoryStream (serData)}, out ops, out rows);
// ArrayList times = new ArrayList ();
// for (int i = 0; i < 25; i++)
// {
// timer.start ();
// ser.serialize (StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] {bt, bt}, out serData);
// timer.stop ();
// times.Add (timer.lastIntervalTime);
// Console.WriteLine (String.Format ("serialization of {0} rows, time = {1}, size = {2}", count, timer.lastIntervalTime, serData.Length));
// }
// times.Sort ();
// Console.WriteLine ("Median time = {0}", times[times.Count/2]);
// //deserialization
// times.Clear ();
// for (int i = 0; i < 25; i++)
// {
// timer.start ();
// deser.deserialize (new Stream [] {new MemoryStream (serData)}, out ops, out rows);
// timer.stop();
// times.Add (timer.lastIntervalTime);
// Console.WriteLine (String.Format ("deserialization of {0} rows, time = {1}", count, timer.lastIntervalTime));
// }
// times.Sort ();
// Console.WriteLine ("Median time = {0}", times[times.Count/2]);
// }
// private IBlueRow myGetRow (int id)
// {
// return new BlueRow (mySchema,
// Convert.ToByte (2), Convert.ToByte (4), DateTime.Now, id, 10.324555);
// }
// }
// }
@@ -0,0 +1,46 @@
// using System;
// using NUnit.Framework;
// using BCG.Utilities.General;
// namespace BCG
// {
// [TestFixture]
// public class Performance
// {
// public Performance()
// {
// }
// [Test]
// public void testContructionTime ()
// {
// double totalTime;
// string deserName = "BCG.ClientUniversalDeserializer";
// HighPerformanceTimer timer = new HighPerformanceTimer ();
// IClientDeserializer cd;
// for (int i = 0; i < 100; i++)
// {
// timer.start ();
// cd = Activator.CreateInstance (Type.GetType (deserName)) as IClientDeserializer;
// timer.stop ();
// //Console.Write (timer.lastIntervalTime.ToString() + " ");
// }
// Console.WriteLine ("average time = " + timer.totalMilliseconds / 100);
// totalTime = timer.totalMilliseconds;
// timer = new HighPerformanceTimer ();
// for (int i = 0; i < 100; i++)
// {
// timer.start ();
// cd = new ClientUniversalDeserializer ();
// timer.stop ();
// //Console.Write (timer.lastIntervalTime.ToString () + " ");
// }
// Console.WriteLine ("average time = " + timer.totalMilliseconds / 100);
// Console.WriteLine ("Ratio = " + totalTime/timer.totalMilliseconds);
// }
// }
// }
@@ -0,0 +1,275 @@
// using System;
// using System.IO;
// using NUnit.Framework;
// namespace BCG
// {
// [TestFixture]
// public class TableAccumulatorTest
// {
// private IBlueTableSchema mySchema = new BlueTableSchema ("test",
// new ColumnInfo ("id", 0, typeof(int)),
// new ColumnInfo ("x", 1, typeof(int)));
// private SubscriberCore mySubCore = new SubscriberCore ();
// private IBlueRowCollection myNr, myAr, myDr;
// public TableAccumulatorTest() {}
// [SetUp]
// public void tearDown ()
// {
// myNr = myAr = myDr = null;
// }
// #region create
// [Test]
// public void testCreate ()
// {
// TableAccumulator ta = new TableAccumulator ("test", mySubCore);
// IBlueDataSerializer ser = new BlueDataSerializationController ();
// byte[] data;
// BlueTable bt = new BlueTable (mySchema);
// for (int i = 0; i < 100; i++)
// bt.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.create, new IBlueRowCollection[] {bt}, out data);
// ta.onUpdate += new TableUpdateDelegate (myHandleUpdate);
// ta.update (new Stream[] {new MemoryStream (data)});
// //testing the data
// IBlueRowCollection dr, ar;
// //new rows
// BlueDataUtility.computeDifferences (bt, myNr, out dr, out ar);
// Assert.AreEqual (0, dr.Count);
// Assert.AreEqual (0, ar.Count);
// //added rows
// BlueDataUtility.computeDifferences (bt, myAr, out dr, out ar);
// Assert.AreEqual (0, dr.Count);
// Assert.AreEqual (0, ar.Count);
// //deleted rows;
// Assert.AreEqual (0, myDr.Count);
// ta.onUpdate -= new TableUpdateDelegate (myHandleUpdate);
// }
// #endregion
// #region single add, delete and change
// [Test]
// public void testAddRemoveChange ()
// {
// TableAccumulator ta = new TableAccumulator ("test", mySubCore);
// IBlueDataSerializer ser = new BlueDataSerializationController ();
// byte[] data;
// BlueTable bt = new BlueTable (mySchema);
// for (int i = 0; i < 100; i++)
// bt.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.create, new IBlueRowCollection[] {bt}, out data);
// ta.onUpdate += new TableUpdateDelegate (myHandleUpdate);
// ta.update (new Stream[] {new MemoryStream (data)});
// //add
// //add a row with id 100
// bt.clear ();
// bt.addRow (new BlueRow (mySchema, 100, 200));
// ser.serialize (StreamOpCode.add, new IBlueRowCollection[] {bt}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //testing the add data
// Assert.AreEqual (101, myNr.Count);
// for (int i = 0; i < 101; i++)
// myNr.containsID (i);
// Assert.AreEqual (0, myDr.Count);
// Assert.AreEqual (1, myAr.Count);
// Assert.That (myAr.containsID (100));
// //remove
// //remove the row with id 0
// bt.clear ();
// bt.addRow (new BlueRow (mySchema, 0, 0));
// ser.serialize (StreamOpCode.remove, new IBlueRowCollection[] {bt}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //testing remove data
// Assert.AreEqual (100, myNr.Count);
// for (int i = 0; i < 101; i++)
// {
// Assert.That ((i == 0 && !myNr.containsID (i)) || (i != 0 && myNr.containsID (i)));
// }
// Assert.AreEqual (0, myAr.Count);
// Assert.AreEqual (1, myDr.Count);
// Assert.That (myDr.containsID (0));
// //change
// bt.clear ();
// bt.addRow (new BlueRow (mySchema, 100, -100));
// ser.serialize (StreamOpCode.change, new IBlueRowCollection[] {bt}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //testing changed data
// Assert.AreEqual (100, myNr.Count);
// Assert.AreEqual (1, myAr.Count);
// Assert.AreEqual (100, BlueDataUtility.extractRow (myAr, 0)["id"]);
// Assert.AreEqual (-100, BlueDataUtility.extractRow (myAr, 0)["x"]);
// Assert.AreEqual (1, myDr.Count);
// Assert.AreEqual (100, BlueDataUtility.extractRow (myDr, 0)["id"]);
// Assert.AreEqual (200, BlueDataUtility.extractRow (myDr, 0)["x"]);
// ta.onUpdate -= new TableUpdateDelegate (myHandleUpdate);
// }
// #endregion
// #region multiple change
// public void testMultipleChange ()
// {
// TableAccumulator ta = new TableAccumulator ("test", mySubCore);
// IBlueDataSerializer ser = new BlueDataSerializationController ();
// byte[] data;
// BlueTable bt = new BlueTable (mySchema);
// for (int i = 0; i < 100; i++)
// bt.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.create, new IBlueRowCollection[] {bt}, out data);
// ta.onUpdate += new TableUpdateDelegate (myHandleUpdate);
// ta.update (new Stream[] {new MemoryStream (data)});
// //partial rows changed
// bt.clear ();
// for (int i = 0; i < 50; i++)
// bt.addRow (new BlueRow (mySchema, i, -2*i));
// ser.serialize (StreamOpCode.multipleChange, new IBlueRowCollection[] {bt}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //checking received data
// Assert.AreEqual (100, myNr.Count);
// foreach (IBlueRow r in myNr)
// {
// if ((int)r["id"] < 50)
// Assert.AreEqual ((int)r["id"] * -2, r["x"]);
// else
// Assert.AreEqual ((int)r["id"] * 2, r["x"]);
// }
// Assert.AreEqual (50, myAr.Count);
// foreach (IBlueRow r in myAr)
// Assert.AreEqual ((int)r["id"] * -2, r["x"]);
// Assert.AreEqual (50, myDr.Count);
// foreach (IBlueRow r in myDr)
// Assert.AreEqual ((int)r["id"] * 2, r["x"]);
// //full rows changed
// bt.clear ();
// for (int i = 0; i < 100; i++)
// bt.addRow (new BlueRow (mySchema, i, -2*i));
// ser.serialize (StreamOpCode.multipleChange, new IBlueRowCollection[] {bt}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //checking received data
// Assert.AreEqual (100, myNr.Count);
// foreach (IBlueRow r in myNr)
// {
// Assert.AreEqual ((int)r["id"] * -2, r["x"]);
// }
// Assert.AreEqual (100, myAr.Count);
// foreach (IBlueRow r in myAr)
// Assert.AreEqual ((int)r["id"] * -2, r["x"]);
// Assert.AreEqual (100, myDr.Count);
// foreach (IBlueRow r in myDr)
// {
// if ((int)r["id"] < 50)
// Assert.AreEqual ((int)r["id"] * -2, r["x"]);
// else
// Assert.AreEqual ((int)r["id"] * 2, r["x"]);
// }
// ta.onUpdate -= new TableUpdateDelegate (myHandleUpdate);
// }
// #endregion
// #region multiple deletes/adds
// public void testMultipleDeletesAdds ()
// {
// TableAccumulator ta = new TableAccumulator ("test", mySubCore);
// IBlueDataSerializer ser = new BlueDataSerializationController ();
// byte[] data;
// BlueTable bt = new BlueTable (mySchema);
// for (int i = 0; i < 100; i++)
// bt.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.create, new IBlueRowCollection[] {bt}, out data);
// ta.onUpdate += new TableUpdateDelegate (myHandleUpdate);
// ta.update (new Stream[] {new MemoryStream (data)});
// BlueTable at = new BlueTable (mySchema),
// dt = new BlueTable (mySchema);
// for (int i = 0; i < 50; i++)
// dt.addRow (new BlueRow (mySchema, i, 2*i));
// for (int i = 100; i < 150; i++)
// at.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] {dt, at}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //checking state
// Assert.AreEqual (100, myNr.Count);
// for (int i = 50; i < 150; i++)
// Assert.That (myNr.containsID (i));
// Assert.AreEqual (50, myDr.Count);
// for (int i = 0; i < 50; i++)
// Assert.That (myDr.containsID (i));
// Assert.AreEqual (50, myAr.Count);
// for (int i = 100; i < 150; i++)
// Assert.That (myAr.containsID (i));
// ta.onUpdate -= new TableUpdateDelegate (myHandleUpdate);
// }
// #endregion
// #region multiple ops in one stream
// [Test]
// public void testMultipleOps ()
// {
// TableAccumulator ta = new TableAccumulator ("test", mySubCore);
// ta.onUpdate += new TableUpdateDelegate (myHandleUpdate);
// IBlueDataSerializer ser = new BlueDataSerializationController ();
// byte[] data;
// MemoryStream ms = new MemoryStream ();
// BlueTable bt = new BlueTable (mySchema);
// for (int i = 0; i < 100; i++)
// bt.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.create, new IBlueRowCollection[] {bt}, out data);
// ta.update (new Stream[] {new MemoryStream (data)});
// //ms.Write (data, 0, data.Length);
// //changing the first 5 rows
// bt.clear ();
// for (int i = 0; i < 5; i++)
// bt.addRow (new BlueRow (mySchema, i, 1000));
// ser.serialize (StreamOpCode.multipleChange, new IBlueRowCollection[] {bt}, out data);
// ms.Write (data, 0, data.Length);
// //delete id 5
// bt.clear ();
// bt.addRow (new BlueRow (mySchema, 5, 10));
// ser.serialize (StreamOpCode.remove, new IBlueRowCollection[] {bt}, out data);
// ms.Write (data, 0, data.Length);
// //add id 100
// bt.clear ();
// bt.addRow (new BlueRow (mySchema, 100, 200));
// ser.serialize (StreamOpCode.add, new IBlueRowCollection[] {bt}, out data);
// ms.Write (data, 0, data.Length);
// //delete 4 and add 5
// bt.clear ();
// BlueTable dels = new BlueTable (bt.schema);
// for (int i = 90; i < 94; i++)
// dels.addRow (new BlueRow (mySchema, i, i*2));
// for (int i = 101; i < 106; i++)
// bt.addRow (new BlueRow (mySchema, i, 2*i));
// ser.serialize (StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] {dels, bt}, out data);
// ms.Write (data, 0, data.Length);
// ms.Position = 0;
// ta.update (new Stream[] {ms});
// Assert.AreEqual (101, myNr.Count);
// Assert.AreEqual (10, myDr.Count);
// Assert.AreEqual (11, myAr.Count);
// ta.onUpdate -= new TableUpdateDelegate (myHandleUpdate);
// }
// #endregion
// private void myHandleUpdate (IBlueRowCollection nr, IBlueRowCollection ar, IBlueRowCollection dr)
// {
// myNr = nr;
// myAr = ar;
// myDr = dr;
// }
// }
// }
@@ -0,0 +1,58 @@
// using System;
// using System.IO;
// using NUnit.Framework;
// namespace BCG
// {
// [TestFixture]
// public class UniversalRowSerializerTest
// {
// private IBlueRowSerializer myRowSerializer;
// private IClientRowDeserializer myRowDeserializer;
// private Random myRnd = new Random (DateTime.Now.Millisecond);
// private IBlueTableSchema mySchema = new BlueTableSchema ("Test",
// new ColumnInfo ("id", 0, typeof(int)),
// new ColumnInfo ("int1", 1, typeof(int)),
// new ColumnInfo ("int2", 2, typeof(int)),
// new ColumnInfo ("double1", 3, typeof(double)),
// new ColumnInfo ("double2", 4, typeof(double)),
// new ColumnInfo ("byte1", 5, typeof(byte)),
// new ColumnInfo ("string1", 6, typeof(string)),
// new ColumnInfo ("string2", 7, typeof(string)));
// public UniversalRowSerializerTest () {}
// [Test]
// public void testSerialiazationCycle ()
// {
// myRowSerializer = new UniversalRowSerializer (mySchema);
// myRowDeserializer = new ClientUniversalRowDeserializer (mySchema);
// for (int i = 0; i < 10000; i++)
// {
// BinaryWriter bw = new BinaryWriter (new MemoryStream ());
// IBlueRow ir = myGetRandomRow ();
// myRowSerializer.serializeRow (ir, StreamOpCode.add, bw);
// IBlueRow or;
// (bw.BaseStream as MemoryStream).Position = 0;
// BinaryReader br = new BinaryReader (bw.BaseStream);
// myRowDeserializer.deserializeRow (null, br, StreamOpCode.add, out or);
// Assert.That (BlueDataUtility.computeRowEquality (ir, or));
// }
// }
// private IBlueRow myGetRandomRow ()
// {
// return new BlueRow (mySchema,
// myRnd.Next (1000),
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object : myRnd.Next (1000) as object,
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object: myRnd.Next (1000) as object,
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object : myRnd.NextDouble () as object,
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object : myRnd.NextDouble () as object,
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object : Convert.ToByte (76) as object,
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object : "abcdefgh" as object,
// myRnd.Next (5)% 3 == 0 ? DBNull.Value as object : "1234567890" as object
// );
// }
// }
// }
@@ -0,0 +1,13 @@
PubTableBroker allows publishing of streams through createTable, addRow, deleteRow, changeRow, makeBatchChanges ->
PubTablePublisher:IPubTablePublisher per tag (addRow, deleteRow, changeRow, createTable, batchRemoveAdd)
PubTablePublisher has BlueDataSerializationController:IBlueDataSerializer to serialize the rows to byte[]
BlueDataSerializationController uses a IBlueDataSerializer, which is specialized for the tag (using UniversalSerializer for now)
IBlueDataSerializer has just one function
void serialize (byte op, IBlueRowCollection[] rows, out byte[] serializedData);
the second arg is IBlueRowCollection[] because in case of op = StreamOpCode.multipleRemoveAdd, it has multiple IBlueRowCollection for rem and add
(BlueDataSerializer.serialize's comment has the serialization layout)
For each serializer we have 2 matching deserializers, IPubsubDeserializer (for PubSubservr) and IClientDeserializer (for clients subscribing to streams)
For UniversalSerializer, we have PubsubUniversalDeserializer and ClientUniversalDeserializer
@@ -3,6 +3,9 @@
<ItemGroup>
<ProjectReference Include="..\..\client\spark_api\spark_api.csproj" />
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
<ProjectReference Include="..\pubsub\pubsub.csproj" />
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
<ProjectReference Include="..\DataStream\DataStream.csproj" />
</ItemGroup>
<PropertyGroup>
@@ -1,16 +1,35 @@
using bts.utils;
using System;
using mbts.config;
using BCG;
using System;
using bts;
using mbts;
bts.utils.BTSNativeMethods.provide_command_line(new string[] { }, 0);
mbts.config.Configuration.initialize();
BTSNativeMethods.provide_command_line(args, args.Length);
// Must initialize config before using log system
Console.WriteLine("Initializing config...");
Configuration.initialize();
for (int i = 0; i < 10; i++)
{
bts.Log.Gen.info($"Starting DataStreamPublisher...log: {i}");
bts.Log.Gen.info($"Starting DSPublisher");
Console.WriteLine("Starting DSPublisher...");
// SimpleTCPClient.start("127.0.0.1", 12345);
// Task.Delay(1000000000).Wait();
//TestPubliser.publish();
//TestPubliser.subscribe();
// TestPublisher ts = new TestPublisher(false);
// ts.keep_publishing(TimeSpan.FromSeconds(10));
_subscribe_to_stream();
void _subscribe_to_stream() {
BCG.ViewStream vs = new TableStream("literal");
vs.onChange += on_change;
}
while (true) {
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
ViewStreamDatabase.instance.doWork();
}
void on_change(object obj) {
DataPacket dp = obj as DataPacket;
dp.newRows.print_table((col) => { return 10; });
}
@@ -1,5 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\client\spark_api\spark_api.csproj" />
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
<ProjectReference Include="..\pubsub\pubsub.csproj" />
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
<ProjectReference Include="..\DataStream\DataStream.csproj" />
<!-- <ProjectReference Include="..\..\client\spark_core\spark_core.csproj" /> -->
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
@@ -9,9 +9,11 @@ using mbts;
using mbts.config;
using bts.utils;
static class Program {
static class Program
{
[STAThread]
static void Main(string[] args) {
static void Main(string[] args)
{
BTSNativeMethods.provide_command_line(args, args.Length);
Configuration.initialize();
bts.Log.Gen.info($"Starting DSQA");
@@ -21,71 +23,10 @@ static class Program {
// TestPubliser.subscribe();
Console.WriteLine("Launching Main Window");
MainForm mainForm = new MainForm();
if (args.Length > 0) {
if (args.Length > 0)
{
mainForm.loadFile(args[0]);
}
Application.Run(mainForm);
}
}
class TestPubItem : IFormatter, IPubItem
{
public DateTime send_time = DateTime.Now;
public object Deserialize(Stream str)
{
BinaryReader br = new BinaryReader(str);
var d = br.ReadDouble();
TestPubItem rv = new TestPubItem();
rv.send_time = DateTime.FromOADate(d);
return rv;
}
public void Serialize(Stream str, Object obj)
{
TestPubItem tpi = obj as TestPubItem;
BinaryWriter bw = new BinaryWriter(str);
bw.Write(tpi.send_time.ToOADate());
}
public System.Runtime.Serialization.SerializationBinder? Binder { get; set; }
public System.Runtime.Serialization.StreamingContext Context { get; set; }
public System.Runtime.Serialization.ISurrogateSelector? SurrogateSelector { get; set; }
public string getTag()
{
return "Test_Tag";
}
}
class TestPubliser
{
public static void publish()
{
int n_pubs = 1000;
Publisher<TestPubItem> publisher = new Publisher<TestPubItem>();
for (int i = 0; i < n_pubs; i++)
{
TestPubItem pi = new TestPubItem();
pi.send_time = DateTime.Now;
bts.Log.Gen.info($"DSQA publishing tag: {pi.getTag()}");
publisher.publish(pi);
System.Threading.Thread.Sleep(100);
MasterWorker.getInstance(false).doWork();
}
}
public static void subscribe()
{
ManagedSubscriber ms = new ManagedSubscriber();
ms.subscribe("Test_Tag", new Handler(on_data));
while (true)
{
ms.doWork();
}
}
public static void on_data(IPubItem pi)
{
Console.WriteLine("Received data");
}
}
}
+5 -13
View File
@@ -21,19 +21,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spark_core", "..\client\spa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spark_api", "..\client\spark_api\spark_api.csproj", "{52DD33DB-00F5-44BF-AE0F-5FC58FB2277E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueRegistry", "BlueRegistry\BlueRegistry.csproj", "{0FD1BE7A-AEC8-4575-BA58-20E0F45E5214}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseUtilities", "BaseUtilities\BaseUtilities.csproj", "{A9EDEEBD-A03A-4281-8FAF-2419D3E7009C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GuiUtilities", "GuiUtilities\GuiUtilities.csproj", "{CADBA1B3-0837-44DD-85BB-70351AD3A028}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArithmeticExpressions", "ArithmeticExpressions\ArithmeticExpressions.csproj", "{EFE6AD17-2564-43A1-B0E5-A2A8DA173002}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamExpressions", "DataStreamExpressions\DataStreamExpressions.csproj", "{D46A152D-AD29-4BEF-980B-5896694E312F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColumnMapExpressions", "ColumnMapExpressions\ColumnMapExpressions.csproj", "{A844AB94-195B-4A7F-89CD-9A335985328E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExpressionCore", "ExpressionCore\ExpressionCore.csproj", "{B94AB04B-76D0-4D37-8F2E-7A57A70D289F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamTests", "DataStreamTests\DataStreamTests.csproj", "{66AB10D3-155F-4663-B1BC-D0818E17B87B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -80,6 +68,10 @@ Global
{52DD33DB-00F5-44BF-AE0F-5FC58FB2277E}.Debug|Any CPU.Build.0 = Debug|x64
{52DD33DB-00F5-44BF-AE0F-5FC58FB2277E}.Release|Any CPU.ActiveCfg = Release|x64
{52DD33DB-00F5-44BF-AE0F-5FC58FB2277E}.Release|Any CPU.Build.0 = Release|x64
{66AB10D3-155F-4663-B1BC-D0818E17B87B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66AB10D3-155F-4663-B1BC-D0818E17B87B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66AB10D3-155F-4663-B1BC-D0818E17B87B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66AB10D3-155F-4663-B1BC-D0818E17B87B}.Release|Any CPU.Build.0 = Release|Any CPU
{0FD1BE7A-AEC8-4575-BA58-20E0F45E5214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FD1BE7A-AEC8-4575-BA58-20E0F45E5214}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0FD1BE7A-AEC8-4575-BA58-20E0F45E5214}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.5.0" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\client\spark_api\spark_api.csproj" />
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
<ProjectReference Include="..\pubsub\pubsub.csproj" />
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
<ProjectReference Include="..\DataStream\DataStream.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,195 @@
using System;
using System.IO;
using NUnit.Framework;
namespace BCG {
/// <summary>
/// Tests the deserialization happening within the pubsub.
/// </summary>
public class UniversalSerializationTest {
protected IBlueTableSchema mySchema;
protected BlueTable myTable;
protected IBlueDataSerializer mySer = new BlueDataSerializationController();
protected IPubsubDeserializer myPubsubDeser = new PubsubDeserializationController();
protected IClientDeserializer myClientDeser = new ClientDeserializationController();
public UniversalSerializationTest() {
mySchema = new BlueTableSchema(myGetTableName(),
new ColumnInfo("id", 0, typeof(int)),
new ColumnInfo("i1", 1, typeof(int)),
new ColumnInfo("d1", 2, typeof(double)),
new ColumnInfo("dt", 3, typeof(DateTime)),
new ColumnInfo("x", 4, typeof(byte))
);
}
protected virtual string myGetTableName() {
return "testUniversal";
}
/// <summary>
/// Tests the entire cycle. This is done by 'publishing' data to the serializationController (ie a series of
/// adds, deletions, changes etc) and getting the bytes and feeding it into a pubsubDeseriazlier and a clientDeserializer.
/// At every step the data is tested for consistency. At the end the getState is used to get all the data, and its passed
/// through the clientDeserializer to get all the rows.
///
/// </summary>
[Test]
public void testEntireProcess() {
myTable = new BlueTable(mySchema);
byte[] data;
int id;
//create
for (id = 0; id < 100; id++)
myTable.addRow(myGetRow(id));
byte[] ops;
Array rows;
IBlueRowCollection del, add;
IBlueRowCollection[] receivedData;
IBlueRow r;
//create
mySer.serialize(StreamOpCode.create, new IBlueRowCollection[] { myTable }, out data);
myWrite(StreamOpCode.create, data);
myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
Assert.AreEqual(1, ops.Length);
Assert.AreEqual(StreamOpCode.create, ops[0]);
Assert.AreEqual(1, rows.Length);
receivedData = rows.GetValue(0) as IBlueRowCollection[];
Assert.AreEqual(1, receivedData.Length);
BlueDataUtility.computeDifferences(receivedData[0], myTable, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
//single add
r = myGetRow(id);
BlueTable temp = new BlueTable(mySchema);
myTable.addRow(r);
temp.addRow(r);
mySer.serialize(StreamOpCode.add, new IBlueRowCollection[] { temp }, out data);
myWrite(StreamOpCode.add, data);
myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
Assert.AreEqual(1, ops.Length);
Assert.AreEqual(StreamOpCode.add, ops[0]);
Assert.AreEqual(1, rows.Length);
receivedData = rows.GetValue(0) as IBlueRowCollection[];
Assert.AreEqual(1, receivedData.Length);
BlueDataUtility.computeDifferences(receivedData[0], temp, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
//single delete
r = myTable[0]; //delete row with id 0
temp = new BlueTable(mySchema);
myTable.deleteRow(0);
temp.addRow(r);
mySer.serialize(StreamOpCode.remove, new IBlueRowCollection[] { temp }, out data);
myWrite(StreamOpCode.remove, data);
myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
Assert.AreEqual(1, ops.Length);
Assert.AreEqual(StreamOpCode.remove, ops[0]);
Assert.AreEqual(1, rows.Length);
receivedData = rows.GetValue(0) as IBlueRowCollection[];
Assert.AreEqual(1, receivedData.Length);
BlueDataUtility.computeDifferences(receivedData[0], temp, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
//batch deletes and adds
//0 was removed earlier, so lets delete from 1 to 24 first, and then add 101 to 124
BlueTable delRows = new BlueTable(mySchema), addRows = new BlueTable(mySchema);
for (int i = 1; i < 25; i++) {
delRows.addRow(myTable[i]);
myTable.deleteRow(i);
}
for (id = 101; id < 125; id++) {
r = myGetRow(id);
addRows.addRow(r);
myTable.addRow(r);
}
for (int i = 25; i < 125; i++)
Assert.AreEqual(true, myTable.containsID(i));
Assert.AreEqual(100, myTable.Count);
mySer.serialize(StreamOpCode.multipleRemoveAdd, new IBlueRowCollection[] { delRows, addRows }, out data);
myWrite(StreamOpCode.multipleRemoveAdd, data);
myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
Assert.AreEqual(1, ops.Length);
Assert.AreEqual(StreamOpCode.multipleRemoveAdd, ops[0]);
Assert.AreEqual(1, rows.Length);
receivedData = rows.GetValue(0) as IBlueRowCollection[];
Assert.AreEqual(2, receivedData.Length);
BlueDataUtility.computeDifferences(receivedData[0], delRows, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
BlueDataUtility.computeDifferences(receivedData[1], addRows, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
//pure changes only
//change the first 25, 25-49
BlueTable changedRows = new BlueTable(mySchema);
for (int i = 25; i < 50; i++) {
MutableBlueRow mr = new MutableBlueRow(myTable[i]);
mr.setValue(4, Byte.MaxValue);
myTable.changeRow(mr);
changedRows.addRow(mr);
}
mySer.serialize(StreamOpCode.multipleChange, new IBlueRowCollection[] { changedRows }, out data);
myWrite(StreamOpCode.multipleChange, data);
myPubsubDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
myClientDeser.deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
Assert.AreEqual(1, ops.Length);
Assert.AreEqual(StreamOpCode.multipleChange, ops[0]);
Assert.AreEqual(1, rows.Length);
receivedData = rows.GetValue(0) as IBlueRowCollection[];
Assert.AreEqual(1, receivedData.Length);
BlueDataUtility.computeDifferences(receivedData[0], changedRows, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
//final test
data = myPubsubDeser.getState();
new ClientDeserializationController().deserialize(new Stream[] { new MemoryStream(data) }, out ops, out rows);
Assert.AreEqual(1, ops.Length);
Assert.AreEqual(StreamOpCode.create, ops[0]);
Assert.AreEqual(1, rows.Length);
receivedData = rows.GetValue(0) as IBlueRowCollection[];
Assert.AreEqual(1, receivedData.Length);
BlueDataUtility.computeDifferences(receivedData[0], myTable, out del, out add);
Assert.AreEqual(0, del.Count);
Assert.AreEqual(0, add.Count);
}
private IBlueRow myGetRow(int id) {
return new BlueRow(mySchema, // the day pp fixed this test.
id, id + 10, id * 3.0, new DateTime(2008, 6, 4, 0, 0, 0, DateTimeKind.Unspecified), Convert.ToByte(id));
}
private void myWrite(byte op, byte[] data) {
string s = "";
if (op == StreamOpCode.add)
s = "add one row";
else if (op == StreamOpCode.change)
s = "change one row";
else if (op == StreamOpCode.create)
s = "create";
else if (op == StreamOpCode.multipleChange)
s = "multiple change";
else if (op == StreamOpCode.multipleRemoveAdd)
s = "multiple add remove";
else if (op == StreamOpCode.remove)
s = "remove one row";
Console.WriteLine("yes, here , op = {0}, size = {1}", s, data.Length);
}
}
}
@@ -0,0 +1 @@
global using NUnit.Framework;
@@ -4,15 +4,13 @@ using System.Collections;
using System.Collections.Generic;
using BCG.Utilities;
namespace BCG
{
namespace BCG {
/// <summary>
/// Holds the state for a single tag. If the tagType has an
/// IPubSubServerTagHandler, it is updated and the state stored
/// there. Otherwise, this class saves the last published data.
/// </summary>
internal class SingleTagHandler
{
internal class SingleTagHandler {
private IPubSubServerTagHandler myHandler = null;
private string myTagType, myTag;
/// <summary>
@@ -20,9 +18,7 @@ namespace BCG
/// </summary>
private byte[] myData = null;
public SingleTagHandler(string tag, string tagType)
{
public SingleTagHandler(string tag, string tagType) {
myTagType = tagType;
myTag = tag;
myHandler = TagType2HandlerMap.getHandler(tagType, false);
@@ -30,23 +26,18 @@ namespace BCG
public string tagType { get { return myTagType; } }
public void publish(Stream data)
{
public void publish(Stream data) {
long pos = data.Position;
if (myHandler != null)
{
if (myHandler != null) {
myHandler.update(myTag, new Stream[] { data });
}
else
{
} else {
myData = new byte[data.Length];
data.Read(myData, 0, myData.Length);
}
data.Position = pos;
}
public byte[] getContent()
{
public byte[] getContent() {
return myHandler == null ? myData : myHandler.getContent(myTag);
}
}
@@ -54,46 +45,37 @@ namespace BCG
/// <summary>
/// Keeps the state of all the tags published.
/// </summary>
public class AllPublishedTagState
{
public class AllPublishedTagState {
private Dictionary<string, SingleTagHandler> myTagHandler = new Dictionary<string, SingleTagHandler>();
public AllPublishedTagState() { }
public void publish(string tag, string tagType, Stream data)
{
public void publish(string tag, string tagType, Stream data) {
if (!myTagHandler.ContainsKey(tag))
myTagHandler.Add(tag, new SingleTagHandler(tag, tagType));
myTagHandler[tag].publish(data);
}
public void publish(string tag, string tagType, byte[] data)
{
public void publish(string tag, string tagType, byte[] data) {
publish(tag, tagType, new MemoryStream(data));
}
public string[] publishedTags
{ get { return new ArrayList(myTagHandler.Keys).ToArray(typeof(string)) as string[]; } }
public string[] publishedTags { get { return new ArrayList(myTagHandler.Keys).ToArray(typeof(string)) as string[]; } }
public byte[] getContent(string tag, out string tagType)
{
public byte[] getContent(string tag, out string tagType) {
tagType = myTagHandler[tag].tagType;
return myTagHandler[tag].getContent();
}
public bool contains(string tag)
{
return myTagHandler.ContainsKey(tag);
public bool contains(string tag) {
return myTagHandler.ContainsKey(tag);
}
public void clear(string tag)
{
if (myTagHandler.ContainsKey(tag))
{
public void clear(string tag) {
if (myTagHandler.ContainsKey(tag)) {
myTagHandler.Remove(tag);
}
else{}
// BlueEventLog.logEvent("AllPublishTagState told to clear nonexisting tag " + tag, BlueEventLog2Level.Warning);
} else { }
// BlueEventLog.logEvent("AllPublishTagState told to clear nonexisting tag " + tag, BlueEventLog2Level.Warning);
}
}
@@ -1,117 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using mbts;
//using BCG.Utilities;
// using System;
// using System.Collections.Generic;
// using System.Text;
// using System.Runtime.InteropServices;
// using mbts;
// //using BCG.Utilities;
namespace BCG
{
public class PubSubServerUnmanagedTCPConnection : IPubSubServerConnection
{
private BlutoSubAddress myServerAddress;
private SmartConnectionManagedWrapper myWrapper;
private ConnectionStatusChange myConnCallback;
private SyncQueue<Pair<int, byte[]>> myAllMsgsQueue = new SyncQueue<Pair<int, byte[]>>();
// namespace BCG
// {
// public class PubSubServerUnmanagedTCPConnection : IPubSubServerConnection
// {
// private BlutoSubAddress myServerAddress;
// private SmartConnectionManagedWrapper myWrapper;
// private ConnectionStatusChange myConnCallback;
// private SyncQueue<Pair<int, byte[]>> myAllMsgsQueue = new SyncQueue<Pair<int, byte[]>>();
public PubSubServerUnmanagedTCPConnection(string serverURL, SmartConnectionManagedWrapper wrapper)
{
myServerAddress = new BlutoSubAddress(serverURL);
myWrapper = wrapper;
myWrapper.initConnection(new BlutoSubAddress(serverURL));
myWrapper.resgisterDataCallback(myServerAddress, new SmartConnectionManagedWrapper.MessageDelegate(myHandleServerMessages));
}
// public PubSubServerUnmanagedTCPConnection(string serverURL, SmartConnectionManagedWrapper wrapper)
// {
// myServerAddress = new BlutoSubAddress(serverURL);
// myWrapper = wrapper;
// myWrapper.initConnection(new BlutoSubAddress(serverURL));
// myWrapper.resgisterDataCallback(myServerAddress, new SmartConnectionManagedWrapper.MessageDelegate(myHandleServerMessages));
// }
#region IPubSubServerConnection Members
// #region IPubSubServerConnection Members
public void sendWithConfirmation(byte[] data, ref string confId)
{
//BlueEventLog.logAssert(false, "This function should not be used on this class");
}
// public void sendWithConfirmation(byte[] data, ref string confId)
// {
// //BlueEventLog.logAssert(false, "This function should not be used on this class");
// }
public void send(byte[] data)
{
myWrapper.send(myServerAddress, data);
}
// public void send(byte[] data)
// {
// myWrapper.send(myServerAddress, data);
// }
public void send(System.IO.Stream str)
{
send (StreamUtilityMethods.getBytesFromStream(str));
}
// public void send(System.IO.Stream str)
// {
// send (StreamUtilityMethods.getBytesFromStream(str));
// }
public IList<byte[]> getUpdates(TimeSpan timeout, int maxElements)
{
List<Pair<int, byte[]>> msgs = myAllMsgsQueue.dequeueMultipleElements(Convert.ToInt32 (timeout.TotalMilliseconds), maxElements);
List<byte[]> rv = new List<byte[]>();
bool connSet = false;
foreach (Pair<int, byte[]> p in msgs)
{
int msgType = p.first;
byte[] msg = p.second;
if (msgType == 1)
{
rv.Add(msg);
}
else
{
connSet = true;
string connMsg = "connection to " + myServerAddress.ToString() + (msgType == 2 ? " broken" : " established");
Console.WriteLine(connMsg);
myConnCallback(myServerAddress.ToString(), msgType == 3);
}
}
return connSet ? new List<byte[]>() : rv;
}
public string serverURL
{
get { return myServerAddress.ToString(); }
}
// public IList<byte[]> getUpdates(TimeSpan timeout, int maxElements)
// {
// List<Pair<int, byte[]>> msgs = myAllMsgsQueue.dequeueMultipleElements(Convert.ToInt32 (timeout.TotalMilliseconds), maxElements);
// List<byte[]> rv = new List<byte[]>();
// bool connSet = false;
// foreach (Pair<int, byte[]> p in msgs)
// {
// int msgType = p.first;
// byte[] msg = p.second;
// if (msgType == 1)
// {
// rv.Add(msg);
// }
// else
// {
// connSet = true;
// string connMsg = "connection to " + myServerAddress.ToString() + (msgType == 2 ? " broken" : " established");
// Console.WriteLine(connMsg);
// myConnCallback(myServerAddress.ToString(), msgType == 3);
// }
// }
// return connSet ? new List<byte[]>() : rv;
// }
public string clientURL
{
get { return myWrapper.getClientAsSeenByServer (serverURL); }
}
// public string serverURL
// {
// get { return myServerAddress.ToString(); }
// }
public void registerCallback(ConnectionStatusChange del)
{
myConnCallback = del;
}
// public string clientURL
// {
// get { return myWrapper.getClientAsSeenByServer (serverURL); }
// }
public void registerDataCallback(DataDelegate del)
{
}
// public void registerCallback(ConnectionStatusChange del)
// {
// myConnCallback = del;
// }
public void registerSendConfirmationCallback(SendConfirmationDelegate del)
{
}
// public void registerDataCallback(DataDelegate del)
// {
// }
#endregion
// public void registerSendConfirmationCallback(SendConfirmationDelegate del)
// {
// }
#region IDisposable Members
// #endregion
public void Dispose()
{
}
// #region IDisposable Members
#endregion
// public void Dispose()
// {
#region IWorker Members
public void doWork()
{
}
#endregion
// }
/// <summary>
/// this is the only method that it executed on
/// a different thread
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private void myHandleServerMessages(int msgType, byte[] msg)
{
myAllMsgsQueue.enqueue(new Pair<int, byte[]>(msgType, msg));
}
}
}
// #endregion
// #region IWorker Members
// public void doWork()
// {
// }
// #endregion
// /// <summary>
// /// this is the only method that it executed on
// /// a different thread
// /// </summary>
// /// <param name="data"></param>
// /// <returns></returns>
// private void myHandleServerMessages(int msgType, byte[] msg)
// {
// myAllMsgsQueue.enqueue(new Pair<int, byte[]>(msgType, msg));
// }
// }
// }
@@ -4,8 +4,7 @@ using System.Text;
using System.IO;
using BCG.Utilities.General;
namespace BCG
{
namespace BCG {
/// <summary>
/// This is the interface that both the PublisherCore and the
/// SubscriberCore use to communicate with the PubsubServer.
@@ -20,22 +19,23 @@ namespace BCG
/// multiple threads need to communicate to the PubSub, they
/// should create their own Subscribers.
/// </summary>
public interface IPubSubServerConnection : IDisposable, IWorker
{
public interface IPubSubServerConnection : IDisposable, IWorker {
/// <summary>
/// The delegate is fired signalling if the data send was
/// successful or not
/// </summary>
void sendWithConfirmation(byte[] data, ref string confId);
//void sendWithConfirmation(byte[] data, ref string confId);
/// <summary>
/// send is a non waiting call with no guarantee
/// of data being delivered
/// </summary>
void send (byte[] data);
/// <summary>
/// similiar to above
/// </summary>
// void send(byte[] data);
// /// <summary>
// /// similiar to above
// /// </summary>
void send(Stream str);
void send(PubSubMessage msg);
void send_with_confirmation(PubSubMessage msg, ref string confId);
/// <summary>
/// Returns with 0 or more elements, iff the timeout
/// expires or maxElements have been reached (selective polling),
@@ -51,13 +51,13 @@ namespace BCG
/// <summary>
/// server URL to which the connection is made
/// </summary>
string serverURL { get;}
string serverURL { get; }
/// <summary>
/// client URL as seen by the server. if a connection has not
/// been established (as can happen in TCP) an empty string
/// is returned
/// </summary>
string clientURL { get;}
string clientURL { get; }
/// <summary>
/// registers the callback to receive
@@ -25,48 +25,64 @@ namespace BCG
ITCPMessageHandler,
ITCPConnectionHandler
{
private ITCPConnection myConnection, myTempNewConnection;
private BlutoSubAddress myServerAddress;
private ThreadSafeQueue<Pair<string, bool>> myConfs = new ThreadSafeQueue<Pair<string, bool>>();
private SyncQueue<byte[]> myDataQueue = new SyncQueue<byte[]>();
private DateTime myLastHB = DateTime.Now;
private ConnectionStatusChange myConnCallback;
private DataDelegate myDataCallback;
private SendConfirmationDelegate myOnSendConfirmCallback;
private TimeSpan myConnectionDropThreshold =
private ITCPConnection _connection, _new_connection;
private readonly BlutoSubAddress _server_address;
// if a message(with confirm) can not be sent , its id is queued here,
// on reconnection, _on_send_onfirm_callback is fired with a negative on these ids, so the user
//can re-send it. The re-send mechanism is not in implemented in this class, but by the user of this class
private ThreadSafeQueue<string> _negative_unsent_confs = new ThreadSafeQueue<string>();
// in onData, data is queued here
private SyncQueue<byte[]> _in_data_queue = new SyncQueue<byte[]>();
private DateTime _last_hb = DateTime.Now;
private ConnectionStatusChange _conn_callback;
private DataDelegate _data_callback;
private SendConfirmationDelegate _on_send_onfirm_callback;
private readonly TimeSpan _connection_drop_threshold =
new TimeSpan(0, 0, 0, 0, PubSub3Config.instance.PS3_HeartBeatInterval * PubSub3Config.instance.PS3_MissingHeartBeatsForGC);
public PubSubServerManagedTCPConnection(string serverURL)
: this(new BlutoSubAddress(serverURL)) { }
public PubSubServerManagedTCPConnection(BlutoSubAddress serverAddress)
public PubSubServerManagedTCPConnection(BlutoSubAddress server_address)
{
myServerAddress = serverAddress;
ClientToServerManagedTCPConnector.connectTo(serverAddress, this);
_server_address = server_address;
_connect_to_ps_server();
}
private void _connect_to_ps_server()
{
bts.Log.Gen.info($"PubSubServerManagedTCPConnection._connect_to_ps_server server: {_server_address}");
ClientToServerManagedTCPConnector.connect_to(_server_address, this, TimeSpan.FromSeconds(1));
}
#region IPubSubServerConnection Members
public void sendWithConfirmation(byte[] data, ref string confId)
public void sendWithConfirmation(byte[] data, ref string conf_id)
{
if (myConnection != null)
bts.Log.Gen.info($"PubSubServerManagedTCPConnection.sendWithConfirmation server: {_server_address} data: {data.Length} myConnection : {_connection != null}");
if (_connection != null)
{
myConnection.sendWithConfirmation(data, ref confId, new SendConfirmationDelegate(myOnSendConfirm));
_connection.sendWithConfirmation(data, ref conf_id, (msg_id, confirmed) =>
{
if (_on_send_onfirm_callback != null)
_on_send_onfirm_callback(msg_id, confirmed);
});
}
else
{
confId = Guid.NewGuid().ToString();
myConfs.enqueue(new Pair<string, bool>(confId, false));
bts.Log.Gen.warn($"PubSubServerManagedTCPConnection.sendWithConfirmation server: {_server_address} no connection, buffering send");
conf_id = Guid.NewGuid().ToString();
_negative_unsent_confs.enqueue(conf_id);
}
}
public void send(byte[] data)
{
Console.WriteLine($"PubSubServerManagedTCPConnection.send server: {myServerAddress} data: {data.Length} myConnection : {myConnection != null}");
if (myConnection != null)
bts.Log.Gen.info($"PubSubServerManagedTCPConnection.send server: {_server_address} data: {data.Length} myConnection : {_connection != null}");
if (_connection != null)
{
Console.WriteLine("PubSubServerManagedTCPConnection.send server: " + myServerAddress + "data: " + data.Length);
myConnection.send(data);
bts.Log.Gen.info("PubSubServerManagedTCPConnection.send server: " + _server_address + "data: " + data.Length);
_connection.send(data);
}
}
@@ -76,14 +92,25 @@ namespace BCG
send(br.ReadBytes(Convert.ToInt32(str.Length - str.Position)));
}
public void send(PubSubMessage msg)
{
send(msg.to_stream());
}
public void send_with_confirmation(PubSubMessage msg, ref string conf_id)
{
var bytes = msg.to_bytes();
sendWithConfirmation(bytes, ref conf_id);
}
public IList<byte[]> getUpdates(TimeSpan timeout, int maxElements)
{
return myDataQueue.dequeueMultipleElements(Convert.ToInt32(timeout.TotalMilliseconds), maxElements);
return _in_data_queue.dequeueMultipleElements(Convert.ToInt32(timeout.TotalMilliseconds), maxElements);
}
public string serverURL
{
get { return myServerAddress.ToString(); }
get { return _server_address.ToString(); }
}
public string clientURL
@@ -93,7 +120,7 @@ namespace BCG
string rv = "";
lock (this)
{
if (myConnection == null)
if (_connection == null)
{
rv = "";
}
@@ -103,7 +130,7 @@ namespace BCG
{
string ip;
int port;
myConnection.getSelfAddress(out ip, out port);
_connection.getSelfAddress(out ip, out port);
rv = new BlutoSubAddress(ip, port).ToString();
}
else
@@ -118,40 +145,40 @@ namespace BCG
public void registerCallback(ConnectionStatusChange del)
{
myConnCallback = del;
_conn_callback = del;
}
public void registerDataCallback(DataDelegate del)
{
myDataCallback = del;
_data_callback = del;
}
public void registerSendConfirmationCallback(SendConfirmationDelegate del)
{
myOnSendConfirmCallback = del;
_on_send_onfirm_callback = del;
}
#endregion
#region IDisposable Members
private bool myIsDisposed = false;
private bool _is_disposed = false;
public void Dispose()
{
Console.WriteLine("PubSubServerManagedTCPConnection.Dispose");
bts.Log.Gen.info("PubSubServerManagedTCPConnection.Dispose");
//throw new Exception("The method or operation is not implemented.");
if (myConnection != null)
if (_connection != null)
{
(myConnection as AsyncTCPConnection).Dispose();
_connection.Dispose();
}
myIsDisposed = true;
_is_disposed = true;
}
public bool isDisposed
{
get
{
return myIsDisposed;
return _is_disposed;
}
}
@@ -168,17 +195,40 @@ namespace BCG
/// <param name="message"></param>
public void onData(RemoteMessage message)
{
Console.WriteLine($"PubSubServerManagedTCPConnection.onData msg:type: {message.messageType}");
if (message.messageType == RemoteMessageType.data)
bts.Log.Gen.info($"PubSubServerManagedTCPConnection.onData message: {message}");
// TODO check for disconenction
switch (message.messageType)
{
if (myDataCallback != null)
myDataCallback(message.remoteConnectionInfo.ToString(), message.message);
case RemoteMessageType.Data:
if (_data_callback != null)
_data_callback(message.remoteConnectionInfo.ToString(), message.message);
else
_in_data_queue.enqueue(message.message);
break;
case RemoteMessageType.Heartbeat:
_last_hb = DateTime.Now;
break;
case RemoteMessageType.Connection:
_conn_callback(_server_address.ToString(), true);
break;
case RemoteMessageType.Disconnection:
if (_conn_callback != null)
_conn_callback(_server_address.ToString(), false);
_connection.Dispose();
_connect_to_ps_server();
break;
}
if (message.messageType == RemoteMessageType.Data)
{
if (_data_callback != null)
_data_callback(message.remoteConnectionInfo.ToString(), message.message);
else
myDataQueue.enqueue(message.message);
_in_data_queue.enqueue(message.message);
}
else
{
myLastHB = DateTime.Now;
_last_hb = DateTime.Now;
}
}
@@ -197,16 +247,56 @@ namespace BCG
int port;
connection.getPeerAddress(out ip, out port);
BlutoSubAddress add = new BlutoSubAddress(ip, port);
Console.WriteLine($"PubSubServerManagedTCPConnection.onConnection add: {add.ToString()}");
if (add.ToString() == myServerAddress.ToString())
bts.Log.Gen.info($"PubSubServerManagedTCPConnection.onConnection add: {add.ToString()} connection type: {connection.GetType()}");
if (add.ToString() == _server_address.ToString())
{
myLastHB = DateTime.Now;
myTempNewConnection = connection;
_last_hb = DateTime.Now;
_new_connection = connection;
}
}
#endregion
void _dispose_and_reconnect_if_missing_hb()
{
if (!_connection.isDisposed)
{
TimeSpan hb_interval = DateTime.Now - _last_hb;
bool hb_missed = hb_interval > _connection_drop_threshold;
if (hb_missed)
{
if (_conn_callback != null)
_conn_callback(_server_address.ToString(), false);
bts.Log.Gen.info("PubSubServerManagedTCPConnection._dispose_and_reconnect_if_missing_hb disposing connecion: {myServerAddress}");
_connection.Dispose();
_connect_to_ps_server();
}
}
else
{
// already disposed, nothing to do
}
}
void _check_for_new_connection()
{
if (_new_connection != null)
{
_connection = _new_connection;
_new_connection = null; // since we are using its presence as a marker of nw connections
bts.Log.Gen.info("PubSubServerManagedTCPConnection._check_for_new_connection assigning new connection");
_connection.register(this);
if (_conn_callback != null)
_conn_callback(_server_address.ToString(), true);
if (_on_send_onfirm_callback != null)
{
var msg_ids = _negative_unsent_confs.dequeueAll();
foreach (var id in msg_ids)
_on_send_onfirm_callback(id, false);
}
}
}
#region IWorker Members
/// <summary>
@@ -216,55 +306,56 @@ namespace BCG
/// </summary>
public void doWork()
{
//_dispose_and_reconnect_if_missing_hb();
_check_for_new_connection();
///check for heartbeats and let clients know in
///case of missing hb (connection breaking)
TimeSpan curr_hb_interval = DateTime.Now - myLastHB;
bool hb_missed = curr_hb_interval > myConnectionDropThreshold;
bool conn_disposed = myConnection != null && myConnection.isDisposed;
if (conn_disposed || hb_missed)
{
if (hb_missed)
{
// since conn breakage was diagnosed logically, lets physically close the connection
myConnection.Dispose();
string dispose_msg = $"PubSubServerManagedTCPConnection.doWork server: {myServerAddress} Disposing connection conn_disposed: {conn_disposed} hb_missed: {hb_missed}";
Console.WriteLine(dispose_msg);
}
myConnection = null; // this is used as a marker for a dead connection
if (myConnCallback != null)
myConnCallback(myServerAddress.ToString(), false);
string reconn_msg = $"PubSubServerManagedTCPConnection.doWork disconnecting client from server: {myServerAddress} conn_disposed: {conn_disposed} hb_missed: {hb_missed} " +
$"because of missing hbs last_hb: {myLastHB}, now: {DateTime.Now} curr_hb_interval: {curr_hb_interval.TotalSeconds} threshold: {myConnectionDropThreshold.TotalSeconds} conn_disposed: {conn_disposed}";
Console.WriteLine(reconn_msg);
ClientToServerManagedTCPConnector.connectTo(myServerAddress, this);
}
if (myTempNewConnection != null)
{
if (myConnection != null)
{
// TODOds
// log error and close it
// BlueEventLog.logAssert(myConnection == null, "Connection has to be nulled out and disposed "
// + " before a new connection is established");
}
Console.WriteLine("PubSubServerManagedTCPConnection hooking new connection");
myConnection = myTempNewConnection;
myTempNewConnection = null;
myConnection.register(this);
myConfs.dequeueAll();
if (myConnCallback != null)
myConnCallback(myServerAddress.ToString(), true);
}
foreach (Pair<string, bool> p in myConfs.dequeueAll())
if (myOnSendConfirmCallback != null)
myOnSendConfirmCallback(p.first, p.second);
// TimeSpan hb_interval = DateTime.Now - myLastHB;
// bool hb_missed = hb_interval > myConnectionDropThreshold;
// bool conn_disposed = myConnection != null || myConnection.isDisposed;
// if (conn_disposed || hb_missed)
// {
// if (hb_missed)
// {
// // since conn breakage was diagnosed logically, lets physically close the connection
// myConnection.Dispose();
// string dispose_msg = $"PubSubServerManagedTCPConnection.doWork server: {myServerAddress} Disposing connection conn_disposed: {conn_disposed} hb_missed: {hb_missed}";
// Console.WriteLine(dispose_msg);
// }
// myConnection = null; // this is used as a marker for a dead connection
// if (myConnCallback != null)
// myConnCallback(myServerAddress.ToString(), false);
// string reconn_msg = $"PubSubServerManagedTCPConnection.doWork disconnecting client from server: {myServerAddress} conn_disposed: {conn_disposed} hb_missed: {hb_missed} " +
// $"because of missing hbs last_hb: {myLastHB}, now: {DateTime.Now} curr_hb_interval: {hb_interval.TotalSeconds} threshold: {myConnectionDropThreshold.TotalSeconds} conn_disposed: {conn_disposed}";
// ClientToServerManagedTCPConnector.connectTo(myServerAddress, this);
// }
// if (myTempNewConnection != null)
// {
// if (myConnection != null)
// {
// // TODOds
// // log error and close it
// // BlueEventLog.logAssert(myConnection == null, "Connection has to be nulled out and disposed "
// // + " before a new connection is established");
// }
// Console.WriteLine("PubSubServerManagedTCPConnection hooking new connection");
// myConnection = myTempNewConnection;
// myTempNewConnection = null;
// myConnection.register(this);
// myConfs.dequeueAll();
// if (myConnCallback != null)
// myConnCallback(myServerAddress.ToString(), true);
// }
// foreach (Pair<string, bool> p in myConfs.dequeueAll())
// if (myOnSendConfirmCallback != null)
// myOnSendConfirmCallback(p.first, p.second);
}
#endregion
private void myOnSendConfirm(string messageId, bool confirmed)
{
myConfs.enqueue(new Pair<string, bool>(messageId, confirmed));
}
// private void myOnSendConfirm(string messageId, bool confirmed) {
// _negative_confs.enqueue(new Pair<string, bool>(messageId, confirmed));
// }
}
}
@@ -7,144 +7,116 @@ using System.Text;
using BCG;
//using BCG.Utilities;
using System.Collections.Generic;
namespace BCG
{
public class MetaData : ICloneable
{
private Hashtable myHash = new Hashtable();
namespace BCG {
// Thhis "wraps" around the following 4 PubSub meta objects, serializes it on the client and
// deserialize it on the pubsub
// PubMetaData
// SubMetaData
// TransactionMetaData
// UnSubMetaData
public class MetaData : ICloneable {
private IDictionary _name_value_map = new Dictionary<string, string>();
int mySize = -1;
public MetaData()
{}
public MetaData() { }
public MetaData(object o)
{copyFrom(o);}
public MetaData(object o) { copyFrom(o); }
public MetaData(Stream s)
{
public MetaData(Stream s) {
long initPos = s.Position;
load(s);
mySize = Convert.ToInt32(s.Position - initPos);
}
public string this[string name]
{
get
{return (string) myHash[name];}
set
{
public string this[string name] {
get { return (string)_name_value_map[name]; }
set {
if (value != null)
myHash[name] = value;
_name_value_map[name] = value;
}
}
public void add(string name, string [] values)
{
private void _add_string_array(string name, string[] values) {
StringBuilder sb = new StringBuilder();
foreach (string s in values)
{
foreach (string s in values) {
if (sb.Length != 0)
sb.Append(" ");
sb.Append(s);
}
myHash[name] = sb.ToString();
_name_value_map[name] = sb.ToString();
}
public int getAsInt(string name)
{return Int32.Parse(this[name]);}
private int getAsInt(string name) { return Int32.Parse(this[name]); }
public string[] getAsStringArray (string name)
{
private string[] _get_as_string_array(string name) {
if (this[name] != "" && this[name] != null)
return this[name].Split(' ');
else
return new string[0];
}
public int size()
{
if (mySize < 0)
{
public int size() {
if (mySize < 0) {
MemoryStream ms = new MemoryStream();
this.save(ms);
return mySize = (int)ms.Position;
}
else
} else
return mySize;
}
public bool isEqual (MetaData md)
{
if (md.myHash.Keys.Count != myHash.Keys.Count)
private bool isEqual(MetaData md) {
if (md._name_value_map.Keys.Count != _name_value_map.Keys.Count)
return false;
foreach (string k in myHash.Keys)
if (!myHash[k].Equals(md.myHash[k]))
foreach (string k in _name_value_map.Keys)
if (!_name_value_map[k].Equals(md._name_value_map[k]))
return false;
return true;
}
public void load(Stream s)
{
myHash = new Hashtable();
string [] state =
// loads the content of the stream into this instance's map
private void load(Stream s) {
_name_value_map = new Hashtable();
string[] state =
new BinaryReader(s).ReadString().Split('\n');
for (int i = 0; i < state.Length-1; i+= 2)
myHash[state[i]] = state[i+1];
for (int i = 0; i < state.Length - 1; i += 2)
_name_value_map[state[i]] = state[i + 1];
}
public void save(Stream s)
{
// writes the content of this instance to stream s
public void save(Stream s) {
new BinaryWriter(s).Write(this.ToString());
}
public override string ToString()
{
public override string ToString() {
StringBuilder sb = new StringBuilder();
foreach (string key in myHash.Keys)
sb.AppendFormat("{0}\n{1}\n",key,myHash[key]);
foreach (string key in _name_value_map.Keys)
sb.AppendFormat("{0}\n{1}\n", key, _name_value_map[key]);
return sb.ToString();
}
public void copyFrom(object o)
{
// iterates through the fields and enters the name, values into _hash
public void copyFrom(object o) {
this["op-code"] = o.GetType().Name;
foreach (FieldInfo fi in o.GetType().GetFields())
{
foreach (FieldInfo fi in o.GetType().GetFields()) {
if (fi.GetValue(o) == null)
continue;
else if (fi.GetValue(o) is String[])
add(fi.Name, (string[])fi.GetValue(o));
_add_string_array(fi.Name, (string[])fi.GetValue(o));
else
myHash[fi.Name] = fi.GetValue(o).ToString();
_name_value_map[fi.Name] = fi.GetValue(o).ToString();
}
}
public void copyTo(object o)
{
foreach (FieldInfo fi in o.GetType().GetFields())
{
// copies the name value map into object o
public void copyTo(object o) {
foreach (FieldInfo fi in o.GetType().GetFields()) {
string value = this[fi.Name];
//this should only be here temporarily, while the new decompression changes are waiting to go into prod.
if (value == null)
{
//BlueEventLog.logEvent("Error: Metadata missing field " + fi.Name, BlueEventLog2Level.MissingMetadata);
}
else
{
if (value == null) {
} else {
if (fi.FieldType.Equals(typeof(string)))
fi.SetValue(o, value);
else if (fi.FieldType.Equals(typeof(int)))
@@ -167,11 +139,10 @@ namespace BCG
}
}
public object Clone()
{
public object Clone() {
MemoryStream ms = new MemoryStream();
this.save(ms);
ms.Seek(0,SeekOrigin.Begin);
ms.Seek(0, SeekOrigin.Begin);
return new MetaData(ms);
}
}
@@ -1,25 +1,25 @@
using System;
// using System;
namespace BCG
{
[Serializable]
public class RenewMetaData
{
public string subscriber;
public int lease;
public bool c;
public SubAddress getSubAddress()
{return SubAddress.decode(subscriber);}
// namespace BCG
// {
// [Serializable]
// public class RenewMetaData
// {
// public string subscriber;
// public int lease;
// public bool c;
public RenewMetaData()
{}
// public SubAddress getSubAddress()
// {return SubAddress.decode(subscriber);}
public RenewMetaData(string s,
int lease)
{
this.subscriber = s;
this.lease = lease;
}
}
}
// public RenewMetaData()
// {}
// public RenewMetaData(string s,
// int lease)
// {
// this.subscriber = s;
// this.lease = lease;
// }
// }
// }
@@ -3,37 +3,33 @@ using System.Collections;
using System.Reflection;
using BCG.Utilities;
using System.Collections.Generic;
using System.Reactive.Subjects;
namespace BCG
{
public class TagType2HandlerMap
{
namespace BCG {
public class TagType2HandlerMap {
private static TagType2HandlerMap myServerHandlerMap = null,
myPublisherStateMap = null;
private Dictionary<string, IPubSubServerTagHandler> myTagTypeToPubHandlerMap = new Dictionary<string, IPubSubServerTagHandler>();
private Dictionary<string, IPubSubServerTagHandler> myTagTypeToPubHandlerMap =
new Dictionary<string, IPubSubServerTagHandler>();
public TagType2HandlerMap()
{
if (PubSub3Config.instance.PS3_TagTypeToAssemblyMap != null)
{
foreach (TagTypeToAssembly.Entry entry in PubSub3Config.instance.PS3_TagTypeToAssemblyMap.entries)
{
try
{
public TagType2HandlerMap() {
if (PubSub3Config.instance.PS3_TagTypeToAssemblyMap != null) {
foreach (TagTypeToAssembly.Entry entry in PubSub3Config.instance.PS3_TagTypeToAssemblyMap.entries) {
try {
var ass_loc = assembly_location;
bts.Log.Gen.info($"TagType2HandlerMap entry: {entry} assembly_location: {ass_loc}");
Assembly assem = Assembly.LoadFrom(entry.assembly);
Type t = assem.GetType(entry.handlerClass, true, false);
Type t = assem.GetType(entry.handlerClass, true, true);
object obj = Activator.CreateInstance(t);
IPubSubServerTagHandler tagHandler = obj as IPubSubServerTagHandler;
bts.Log.Gen.info($"TagType2HandlerMap successfully created obj: {obj} of type: {t} from assem: {assem}");
string[] tagTypes = tagHandler.supportedTagTypes;
foreach (string tagType in tagTypes)
{
foreach (string tagType in tagTypes) {
bts.Log.Gen.info($"TagType2HandlerMap adding tagType: {tagType} tagHandler: {tagHandler}");
myTagTypeToPubHandlerMap[tagType] = tagHandler;
}
}
catch (Exception ex)
{
// BlueEventLog.logEvent(string.Format("error happened while loading type from the assembly ", entry.handlerClass, entry.assembly), BlueEventLevel.Warning);
// BlueEventLog.logEvent(ex);
} catch (Exception ex) {
bts.Log.Gen.error($"TagType2HandlerMap threw exception ex: {ex}");
if (ex is OutOfMemoryException)
throw ex;
}
@@ -41,30 +37,41 @@ namespace BCG
}
}
private IPubSubServerTagHandler myGetHandlerFromTagType(string tagType)
{
public static string assembly_location {
get {
// string codeBase = Assembly.GetExecutingAssembly().CodeBase;
// UriBuilder uri = new UriBuilder(codeBase);
// string path = Uri.UnescapeDataString(uri.Path);
// return Path.GetDirectoryName(path);
// Get the executing assembly
Assembly executingAssembly = Assembly.GetExecutingAssembly();
// Get the location (path) of the executing assembly
string assembly_location = executingAssembly.Location;
return assembly_location;
}
}
private IPubSubServerTagHandler myGetHandlerFromTagType(string tagType) {
IPubSubServerTagHandler rv;
myTagTypeToPubHandlerMap.TryGetValue(tagType, out rv);
bts.Log.Gen.info($"TagType2HandlerMap.myGetHandlerFromTagType tag_type: {tagType} rv: {rv}");
return rv;
}
public static IPubSubServerTagHandler getHandler(string type, bool isServer)
{
lock (typeof(IPubSubServerTagHandler))
{
if (isServer)
{
public static IPubSubServerTagHandler getHandler(string type, bool isServer) {
lock (typeof(IPubSubServerTagHandler)) {
if (isServer) {
if (myServerHandlerMap == null)
myServerHandlerMap = new TagType2HandlerMap();
return myServerHandlerMap.myGetHandlerFromTagType(type);
}
else
{
} else {
if (myPublisherStateMap == null)
myPublisherStateMap = new TagType2HandlerMap();
return myPublisherStateMap.myGetHandlerFromTagType(type);
}
}
}
}
}
}
@@ -1,17 +1,18 @@
using System;
namespace BCG
{
namespace BCG {
[Serializable]
public class TagTypeToAssembly
{
public class TagTypeToAssembly {
//[Serializable]
public class Entry
{
public string handlerClass;
public string assembly;
public class Entry {
public string handlerClass = "BCG.PubSubServerTagHandler";
// TODOds
public string assembly = "C:\\Users\\m_tah\\spark\\build\\Debug\\bin\\net7.0\\DataStreamCore.dll";
public override string ToString() {
return $"handlerClass: {handlerClass} assembly: {assembly}";
}
}
public Entry[] entries;
public Entry[] entries = new Entry[] { new Entry() };
}
}
@@ -5,17 +5,13 @@ using System.Text.RegularExpressions;
//using BCG.Utilities.BlueConfiguration;
//using BCG.Utilities;
namespace BCG
{
namespace BCG {
public class PubSub3Config //: ConfigurationRequest
{
private static PubSub3Config myInstance;
public static PubSub3Config instance
{
get
{
if (myInstance == null)
{
public static PubSub3Config instance {
get {
if (myInstance == null) {
myInstance = new PubSub3Config();
//myInstance = (PubSub3Config) ConfigurationRequester.request(typeof(PubSub3Config));
}
@@ -43,7 +39,7 @@ namespace BCG
private string[] myPS3_CrushableTags = new string[] { };
//moved from PS2
private TagTypeToAssembly myTagTypeToAssemblyMap;
private TagTypeToAssembly myTagTypeToAssemblyMap = new TagTypeToAssembly();
private string myPS3_ServerQueue;
//substation stuff
@@ -83,122 +79,101 @@ namespace BCG
// bluecomm transition
//public ConfigKeys.BlueComm_PSTransition BlueComm_PSTransition { get; set; }
public PubSub3Config()
{
public PubSub3Config() {
//BlueComm_PSTransition = new BCG.ConfigKeys.BlueComm_PSTransition(true);
}
public bool isValid()
{
public bool isValid() {
return true;
}
public int PS3_retriesOnNoBufferSpace
{
public int PS3_retriesOnNoBufferSpace {
get { return myPS3_retriesOnNoBufferSpace; }
set { myPS3_retriesOnNoBufferSpace = value; }
}
public int PS3_millisecondsBetweenNoBufferSpaceRetries
{
public int PS3_millisecondsBetweenNoBufferSpaceRetries {
get { return myPS3_millisecondsBetweenNoBufferSpaceRetries; }
set { myPS3_millisecondsBetweenNoBufferSpaceRetries = value; }
}
public int PS3_millisecondsBetweenTimeSliceUpdates
{
public int PS3_millisecondsBetweenTimeSliceUpdates {
get { return myPS3_millisecondsBetweenTimeSliceUpdates; }
set { myPS3_millisecondsBetweenTimeSliceUpdates = value; }
}
public bool BlueComm_mustDie
{
public bool BlueComm_mustDie {
get { return myBlueComm_mustDie; }
set { myBlueComm_mustDie = value; }
}
public int PS3_HeartBeatInterval
{
public int PS3_HeartBeatInterval {
get { return myPS3_HeartBeatInterval; }
set { myPS3_HeartBeatInterval = value; }
}
public int PS3_DoItAllSecondsBetweenLogs
{
public int PS3_DoItAllSecondsBetweenLogs {
get { return myPS3_DoItAllSecondsBetweenLogs; }
set { myPS3_DoItAllSecondsBetweenLogs = value; }
}
public int PS3_MissingHeartBeatsForGC
{
public int PS3_MissingHeartBeatsForGC {
get { return myPS3_MissingHeartBeatsBeforeGC; }
set { myPS3_MissingHeartBeatsBeforeGC = value; }
}
public bool PS3_UseManagedSockets
{
public bool PS3_UseManagedSockets {
get { return myPS3_UseManagedSockets; }
set { myPS3_UseManagedSockets = value; }
}
public int PS3_StateUpdatePeriod
{
public int PS3_StateUpdatePeriod {
get { return myPS3_StateUpdatePeriod; }
set { myPS3_StateUpdatePeriod = value; }
}
public int PS3_StatisticsUpdatePeriod
{
public int PS3_StatisticsUpdatePeriod {
get { return myPS3_StatisticsUpdatePeriod; }
set { myPS3_StatisticsUpdatePeriod = value; }
}
public int PS3_DisposedConnectionCheckPeriod
{
public int PS3_DisposedConnectionCheckPeriod {
get { return myPS3_DisposedConnectionCheckPeriod; }
set { myPS3_DisposedConnectionCheckPeriod = value; }
}
public int PS3_MessageProcessingWarningThreshold
{
public int PS3_MessageProcessingWarningThreshold {
get { return myPS3_MessageProcessingWarningThreshold; }
set { myPS3_MessageProcessingWarningThreshold = value; }
}
public int PS3_millisecondsBetweenSubInfoUpdates
{
public int PS3_millisecondsBetweenSubInfoUpdates {
get { return myPS3_millisecondsBetweenSubInfoUpdates; }
set { myPS3_millisecondsBetweenSubInfoUpdates = value; }
}
public double PS3_LatencyReportThresholdMS
{
public double PS3_LatencyReportThresholdMS {
get { return myPS3_LatencyReportThresholdMS; }
set { myPS3_LatencyReportThresholdMS = value; }
}
public int PS3_ServerPort
{
public int PS3_ServerPort {
get { return myPS3_ServerPort; }
set { myPS3_ServerPort = value; }
}
public PubSubRoute[] getSubRouting()
{ return getRouting(); }
public PubSubRoute[] getSubRouting() { return getRouting(); }
public PubSubRoute[] getPubRouting()
{ return getRouting(); }
public PubSubRoute[] getPubRouting() { return getRouting(); }
public PubSubRoute[] getRouting()
{
public PubSubRoute[] getRouting() {
// TODO
return new PubSubRoute[] { };
// return getRouting(SitesCore.getMySiteName());
}
public PubSubRoute[] getRouting(string forSite)
{
public PubSubRoute[] getRouting(string forSite) {
// TODO
return new PubSubRoute[] { };
// if (sites_layout != null) {
@@ -214,14 +189,12 @@ namespace BCG
return null;
}
public List<string> getAllPubSubs()
{
public List<string> getAllPubSubs() {
return new List<string>();
//return getAllPubSubs(SitesCore.getMySiteName());
}
public List<string> getAllPubSubs(string forSite)
{
public List<string> getAllPubSubs(string forSite) {
List<string> result = new List<string>();
foreach (PubSubRoute r in getRouting(forSite))
result.AddRange(r.getAllPubSubs());
@@ -233,17 +206,14 @@ namespace BCG
// public ConfigKeys.sites_siteName sites_siteName { get; set; }
public TagTypeToAssembly PS3_TagTypeToAssemblyMap
{
public TagTypeToAssembly PS3_TagTypeToAssemblyMap {
get { return myTagTypeToAssemblyMap; }
set { myTagTypeToAssemblyMap = value; }
}
//[Description("PUBSUB: The Message queue to look for pub sub messages")]
public string PS3_ServerQueue
{
get
{
public string PS3_ServerQueue {
get {
if (myPS3_ServerQueue == null || myPS3_ServerQueue == "")
return "PubSubQueue";
else
@@ -252,14 +222,12 @@ namespace BCG
set { myPS3_ServerQueue = value; }
}
public bool PS3_InternallyPublishSubInfo
{
public bool PS3_InternallyPublishSubInfo {
get { return myPS3_InternallyPublishSubInfo; }
set { myPS3_InternallyPublishSubInfo = value; }
}
public string[] PS3_CrushableTags
{
public string[] PS3_CrushableTags {
get { return myPS3_CrushableTags; }
set { myPS3_CrushableTags = value; }
}
@@ -299,95 +267,80 @@ namespace BCG
// }
public bool PS3_UseSubstations
{
public bool PS3_UseSubstations {
get { return myPS3_UseSubstations; }
set { myPS3_UseSubstations = value; }
}
public PubSubPortRange PS3_PortRange
{
public PubSubPortRange PS3_PortRange {
get { return myPS3_PortRange; }
set { myPS3_PortRange = value; }
}
public bool PS3_BindToRandomPort
{
public bool PS3_BindToRandomPort {
get { return myPS3_BindToRandomPort; }
set { myPS3_BindToRandomPort = value; }
}
public bool PS3_IsSubstation
{
public bool PS3_IsSubstation {
get { return myPS3_IsSubstation; }
set { myPS3_IsSubstation = value; }
}
public bool PS3_UseDynamicClients
{
public bool PS3_UseDynamicClients {
get { return myPS3_UseDynamicClients; }
set { myPS3_UseDynamicClients = value; }
}
public bool PS3_UseManagedClientsInNativeCode
{
public bool PS3_UseManagedClientsInNativeCode {
get { return myPS3_UseManagedClientsInNativeCode; }
set { myPS3_UseManagedClientsInNativeCode = value; }
}
public string PS3_CompressedTagsRegex
{
public string PS3_CompressedTagsRegex {
get { return myPS3_CompressedTagsRegex; }
set { myPS3_CompressedTagsRegex = value; }
}
public string PS3_DebugTags
{
public string PS3_DebugTags {
get { return myPS3_DebugTags; }
set { myPS3_DebugTags = value; }
}
public string PS3_TagsToReportCompressionRatio
{
public string PS3_TagsToReportCompressionRatio {
get { return myPS3_TagsToReportCompressionRatio; }
set { myPS3_TagsToReportCompressionRatio = value; }
}
public bool PS3_DisableMSMQ
{
public bool PS3_DisableMSMQ {
get { return myPS3_DisableMSMQ; }
set { myPS3_DisableMSMQ = true; }
}
public string PS3_IPTranslation
{
public string PS3_IPTranslation {
get { return myPS3_IPTranslation; }
set { myPS3_IPTranslation = value; }
}
public long PS3_GCActivationThreshold
{
public long PS3_GCActivationThreshold {
get { return myGCActivationThreshold; }
set { myGCActivationThreshold = value; }
}
public int PS3_WaitPeriodAfterGC
{
public int PS3_WaitPeriodAfterGC {
get { return myWaitPeriodAfterGC; }
set { myWaitPeriodAfterGC = value; }
}
public bool PS3_UsePrepublishedServerState
{
public bool PS3_UsePrepublishedServerState {
get { return myPS3_UsePrepublishedServerState; }
set { myPS3_UsePrepublishedServerState = value; }
}
public int PS3_MaxPacketSize
{
public int PS3_MaxPacketSize {
get { return myPS3_MaxPacketSize; }
set { myPS3_MaxPacketSize = value; }
}
@@ -404,21 +357,17 @@ namespace BCG
// set { myRecovery_PubSubCopies = value; }
// }
public bool isTagDebugTag(string tag)
{
if (myDebugTagsRegex == null)
{
public bool isTagDebugTag(string tag) {
if (myDebugTagsRegex == null) {
myDebugTagsRegex = new Regex(myPS3_DebugTags, RegexOptions.IgnoreCase);
}
return myDebugTagsRegex.IsMatch(tag);
}
public bool isTagCompressed(string tag)
{
public bool isTagCompressed(string tag) {
if (myCompressedTagsRegex == null)
{
if (myCompressedTagsRegex == null) {
myCompressedTagsRegex = new Regex(myPS3_CompressedTagsRegex, RegexOptions.IgnoreCase);
}
@@ -426,10 +375,8 @@ namespace BCG
return (myCompressedTagsRegex.IsMatch(tag));
}
public bool shouldReportTagsCompressionRatio(string tag)
{
if (myTagsToReportCompressionRatioRegex == null)
{
public bool shouldReportTagsCompressionRatio(string tag) {
if (myTagsToReportCompressionRatioRegex == null) {
myTagsToReportCompressionRatioRegex = new Regex(myPS3_TagsToReportCompressionRatio, RegexOptions.IgnoreCase);
}
return (myTagsToReportCompressionRatioRegex.IsMatch(tag));
@@ -45,8 +45,7 @@ namespace BCG
public SendConfirmationDelegate onSendDel;
public AsyncMessage(byte[] theBuffer, int theOffset)
: this(theBuffer, theOffset, String.Empty, null)
{ }
: this(theBuffer, theOffset, String.Empty, null) { }
public AsyncMessage(byte[] theBuffer, int theOffset, string theMessageId, SendConfirmationDelegate theOnSendDel)
{
@@ -445,7 +444,7 @@ namespace BCG
myDataReceived = true;
Console.WriteLine($"AsyncTCPConnection Data received for the first time from peer {myPeer.ToString()}");
}
myMessageHandler.onData(new RemoteMessage(data, RemoteMessageType.data, myPeer));
myMessageHandler.onData(new RemoteMessage(data, RemoteMessageType.Data, myPeer));
}
else if (msgType == 1)
@@ -456,7 +455,7 @@ namespace BCG
Console.WriteLine($"AsyncTCPConnection HB received for the first time from peer {myPeer.ToString()}");
}
myLastHBReceivedTime = DateTime.Now;
myMessageHandler.onData(new RemoteMessage(null, RemoteMessageType.heartbeat, myPeer));
myMessageHandler.onData(new RemoteMessage(null, RemoteMessageType.Heartbeat, myPeer));
}
myReadSize();
}
@@ -0,0 +1,296 @@
using BCG;
using Google.Protobuf;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using BCG;
using System.Xml.Serialization;
using System.Reflection;
using BCG.Utilities.General;
using System.Net.WebSockets;
namespace BCG
{
public class AsyncTCPConnection2 : ITCPConnection, IWorker, IDisposable
{
//private Socket _socket;
// tied to the socket above
private NetworkStream _nw_stream;
private readonly ConnectionSide _side;
ITCPMessageHandler _message_handler;
private int _msg_id = 0;
RemoteConnectionInfo _peer_address;
RemoteConnectionInfo _self_address;
private TimeSpan _hb_period = TimeSpan.FromSeconds(1);
private DateTime _last_hb_sent = DateTime.MinValue;
private DateTime _last_hb_received = DateTime.MaxValue;
private static byte _msg_type_data = 1;
private static byte _msg_type_hb = 0;
private bool _is_disposed = false;
SyncQueue<QueuedMessage> _data_send_queue = new SyncQueue<QueuedMessage>();
public class QueuedMessage
{
public string id;
public SendConfirmationDelegate del;
public byte[] data;
public QueuedMessage(string id, SendConfirmationDelegate del, byte[] data)
{
id = id;
del = del;
data = data;
}
public QueuedMessage(byte[] data)
: this(String.Empty, null, data) { }
}
public enum ConnectionSide
{
Client,
Server
}
public AsyncTCPConnection2(Socket socket, ConnectionSide side)
{
//_socket = socket;
_nw_stream = new NetworkStream(socket);
_side = side;
IPEndPoint r_ep = socket.RemoteEndPoint as IPEndPoint;
_peer_address = new RemoteConnectionInfo(r_ep.Address.ToString(), r_ep.Port);
var loc_ep = socket.LocalEndPoint as IPEndPoint;
_self_address = new RemoteConnectionInfo(loc_ep.Address.ToString(), loc_ep.Port);
}
public void register(ITCPMessageHandler message_handler)
{
_message_handler = message_handler;
Task.Run(async () => _keep_reading());
Task.Run(async () => await _keep_sending());
//_keep_reading();
// if add a _keep_sending threadis added then we can maek send a non async
// methid making it much easier to integrate with the rest
}
// this thread pulls
private async Task _keep_sending()
{
bts.Log.Gen.info($"TCPConnection._keep_sending starting");
while (!_is_disposed)
{
try
{
QueuedMessage m = _data_send_queue.dequeue(100);
if (m == null)
{
continue;
}
await send_async(m.data);
if (String.IsNullOrEmpty(m.id))
{
m.del(m.id, true);
}
}
catch (Exception ex)
{
bts.Log.Gen.error($"TCPConnection._keep_sending ex: {ex.Message}");
await Task.Delay(100);
_handle_error(ex);
}
}
}
private async Task _keep_reading()
{
bts.Log.Gen.info($"TCPConnection._keep_reading starting");
while (!_is_disposed)
{
try
{
byte[] msg = await TCPSocketUtils.read_bytes_async(_nw_stream);
bts.Log.Gen.info($"AsyncTCPConnection2._keep_reading side: {_side} self: {get_self_address()} peer: {get_peer_address()} msg len: {msg.Length}");
await _handle_msg(msg);
}
catch (Exception ex)
{
bts.Log.Gen.error($"TCPConnection._keep_reading ex: {ex.Message}");
await Task.Delay(100);
_handle_error(ex);
}
}
}
private async Task _handle_msg(byte[] msg)
{
// read the first byte to read the msg type and deal with it accordingly
BinaryReader br = new BinaryReader(new MemoryStream(msg));
byte msg_type = br.ReadByte();
if (msg_type == _msg_type_data)
{
byte[] data = br.ReadBytes(msg.Length - 1);
RemoteMessage m = new RemoteMessage(data, RemoteMessageType.Data, _peer_address);
_message_handler.onData(m);
}
else
{
RemoteMessage m = new RemoteMessage(null, RemoteMessageType.Heartbeat, _peer_address);
_message_handler.onData(m);
}
}
// not very efficient
private static byte[] _prefix_msg_type(byte[] data)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(_msg_type_data);
bw.Write(data);
ms.Position = 0;
return ms.ToArray();
}
private async void _handle_error(Exception ex)
{
bts.Log.Gen.error($"TCPConnection._handle_error ex: {ex}");
try
{
var socket = _nw_stream.Socket;
socket.Close();
socket.Dispose();
}
catch (Exception ex2)
{
bts.Log.Gen.error($"TCPConnection._handle_error got exception when closing Socket ex: {ex}");
}
_is_disposed = true;
RemoteMessage rm = new RemoteMessage(new byte[] { }, RemoteMessageType.Disconnection, _peer_address);
_message_handler.onData(rm);
}
public void send_with_confirmation(byte[] data, string confId, SendConfirmationDelegate del) { }
public async Task send_with_confirmation_async(byte[] data, string conf_id, SendConfirmationDelegate del)
{
try
{
conf_id = (++_msg_id).ToString();
await TCPSocketUtils.send_bytes_async(_nw_stream, data);
del(conf_id, true);
}
catch (Exception ex)
{
_handle_error(ex);
}
}
public void sendWithConfirmation(byte[] data, ref string conf_id, SendConfirmationDelegate del)
{
conf_id = (++_msg_id).ToString();
send(data);
del(conf_id, true);
}
public void send(byte[] data)
{
Task.Run(async () => await send_async(data));
bts.Log.Gen.info($"AsyncTCPConnection2.send self: {get_self_address()} peer: {get_peer_address()} msg len: {data.Length} sent successfully");
//_data_send_queue.enqueue(new QueuedMessage(data));
}
public async Task send_async(byte[] data)
{
// prefix 4 bytes for type (data vs hb)
MemoryStream str = new MemoryStream();
BinaryWriter bw = new BinaryWriter(str);
bw.Write(_msg_type_data);
bw.Write(data);
try
{
await TCPSocketUtils.send_bytes_async(_nw_stream, str.ToArray());
}
catch (Exception ex)
{
bts.Log.Gen.error($"AsyncTCPConnection2.send_async ex: {ex}");
_handle_error(ex);
}
}
public void getPeerAddress(out string ip, out int port)
{
ip = _peer_address.ip;
port = _peer_address.port;
///.Net has some problems getting the port, so using
///native code for that
//sockaddr addr = new sockaddr();
//int namelen = 16;
//getsockname(mySock.Handle, ref addr, ref namelen);
//port = addr.sin_port;
}
public RemoteConnectionInfo get_peer_address()
{
string ip; int port;
getPeerAddress(out ip, out port);
return new RemoteConnectionInfo(ip, port);
}
public RemoteConnectionInfo get_self_address()
{
string ip; int port;
getSelfAddress(out ip, out port);
return new RemoteConnectionInfo(ip, port);
}
public void getSelfAddress(out string ip, out int port)
{
ip = _self_address.ip;
port = _self_address.port;
}
private async void _send_hb()
{
if (_last_hb_sent - DateTime.Now > _hb_period)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(_msg_type_hb);
ms.Position = 0;
byte[] hb_msg = ms.ToArray();
await TCPSocketUtils.send_bytes_async(_nw_stream, hb_msg);
}
}
public void doWork()
{
_send_hb();
}
public void Dispose()
{
_nw_stream.Close();
_nw_stream.Dispose();
_is_disposed = true;
}
public bool isDisposed
{
get
{
return _is_disposed;
}
}
}
}
@@ -4,21 +4,19 @@ using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
//using BCG.Utilities;
//using BCG.Utilities.General;
namespace BCG
{
internal class SocketConnectionArgs
{
namespace BCG {
internal class SocketConnectionArgs {
public EndPoint ep;
public Socket sock;
public ITCPConnectionHandler handler;
public string serverURL;
internal SocketConnectionArgs(EndPoint theEp, Socket theSock, ITCPConnectionHandler theHandler,
string theServerURL)
{
string theServerURL) {
ep = theEp;
sock = theSock;
handler = theHandler;
@@ -26,46 +24,46 @@ namespace BCG
}
}
public class ClientToServerManagedTCPConnector
{
public class ClientToServerManagedTCPConnector {
private static Random myRnd = new Random(DateTime.Now.Millisecond);
private static TimeSpan myHBTimeSpan = new TimeSpan(0, 0, 0, 0, PubSub3Config.instance.PS3_HeartBeatInterval);
private static int myWaitTimeBeforeRetryingUpperLimit = 5000,
myWaitTimeBeforeRetryingLowerLimit = 1000;
public static void connectTo(BlutoSubAddress serverAddress, ITCPConnectionHandler handler)
{
// TODOds
// BlueEventLog.logEvent(String.Format("Connection being attempted to server {0}", serverAddress.ToString()),
// PS3LogLevels.connection);
public static void connectTo(BlutoSubAddress serverAddress, ITCPConnectionHandler handler) {
Console.WriteLine($"ClientToServerManagedTCPConnector.connectTo server: {serverAddress}");
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
EndPoint ep = new IPEndPoint(IPAddress.Parse(serverAddress.ip), serverAddress.port);
sock.BeginConnect(ep, new AsyncCallback(myOnConnect), new SocketConnectionArgs(ep, sock, handler, serverAddress.ToString()));
}
private static void myOnConnect(IAsyncResult res)
{
public static async Task connect_to_async(BlutoSubAddress serverAddress, ITCPConnectionHandler handler, TimeSpan wait_before_retrying, int max_n_attempts = 1024) {
bts.Log.Gen.info($"ClientToServerManagedTCPConnector.connectTo server: {serverAddress}");
await TCPSocketUtils.connect_to_server_async(serverAddress.ip, serverAddress.port, handler, wait_before_retrying, max_n_attempts);
}
public static void connect_to(BlutoSubAddress serverAddress, ITCPConnectionHandler handler, TimeSpan wait_before_retrying, int max_n_attempts = 1024) {
bts.Log.Gen.info($"ClientToServerManagedTCPConnector.connectTo server: {serverAddress}");
Task.Run(async () => {
await TCPSocketUtils.connect_to_server_async(serverAddress.ip, serverAddress.port, handler, wait_before_retrying, max_n_attempts);
});
}
private static void myOnConnect(IAsyncResult res) {
Console.WriteLine("ClientToServerManagedTCPConnector.myOnConnect " + res.ToString() + " " + res.AsyncState.ToString());
SocketConnectionArgs args = res.AsyncState as SocketConnectionArgs;
try
{
try {
args.sock.EndConnect(res);
}
catch (SocketException sex)
{
} catch (SocketException sex) {
string errMsg = String.Format("{0}: Connection to {1} failed.", DateTime.Now.ToString(), args.serverURL.ToString());
//BlueEventLog.logEvent(sex.Message + ";" + errMsg, PS3LogLevels.disconnection);
//Console.WriteLine(errMsg);
if (args.handler.isDisposed)
{
if (args.handler.isDisposed) {
string doneMsg = String.Format("{0}: Connection to {1} was disposed. Not Retrying.", DateTime.Now.ToString(), args.serverURL.ToString());
//Console.WriteLine(doneMsg);
// BlueEventLog.logEvent(doneMsg, PS3LogLevels.disconnection);
return;
}
else
{
} else {
string retryMsg = String.Format("{0}: Retrying Connection to {1}.", DateTime.Now.ToString(), args.serverURL.ToString());
//Console.WriteLine(retryMsg);
//BlueEventLog.logEvent(retryMsg, PS3LogLevels.disconnection);
@@ -2,15 +2,13 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace BCG
{
namespace BCG {
public delegate void SendConfirmationDelegate(string messageId, bool confirmed);
/// <summary>
/// This is the very basic connection that sits right
/// on top of the sockets (unmanaged, managed whatever).
/// on top of the sockets (used on both server and client)
/// </summary>
public interface ITCPConnection : IDisposable
{
public interface ITCPConnection : IDisposable {
/// <summary>
/// The delegate is fired signalling if the data send was
/// successful or not
@@ -18,7 +16,7 @@ namespace BCG
/// <param name="data"></param>
/// <param name="confId"></param>
/// <param name="del"></param>
void sendWithConfirmation (byte[] data, ref string confId, SendConfirmationDelegate del);
void sendWithConfirmation(byte[] data, ref string confId, SendConfirmationDelegate del);
/// <summary>
/// sends data to the other side. theres no guaranatee that
/// data is delievered.
@@ -54,6 +52,6 @@ namespace BCG
/// hence this is an indicator of whether the connection is
/// alive or dead
/// </summary>
bool isDisposed { get;}
bool isDisposed { get; }
}
}
@@ -2,46 +2,51 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using bts.utils;
namespace BCG
{
public class RemoteConnectionInfo
{
namespace BCG {
public class RemoteConnectionInfo {
private string myIp;
private int myPort;
private IPEndPoint myEndPoint;
public RemoteConnectionInfo(string ip, int port)
{
public RemoteConnectionInfo(string ip, int port) {
myIp = ip;
myPort = port;
}
public RemoteConnectionInfo(string ip, short port, IPEndPoint endPoint)
: this (ip, port)
{
: this(ip, port) {
myEndPoint = endPoint;
}
public string ip
{
public string ip {
get { return myIp; }
}
public int port
{
public int port {
get { return myPort; }
}
public IPEndPoint endPoint
{
public IPEndPoint endPoint {
get { return myEndPoint; }
}
public override string ToString()
{
public override string ToString() {
return ip + ":" + port;
}
public override int GetHashCode() {
return ip.GetHashCode() ^ port.GetHashCode();
}
public override bool Equals(object? obj) {
if (obj == null) {
return false;
}
RemoteConnectionInfo other = obj as RemoteConnectionInfo;
return other != null && other.ip == ip && other.port == port;
}
}
}
@@ -9,7 +9,7 @@ namespace BCG
/// </summary>
public enum RemoteMessageType
{
heartbeat, data, connection, disconnection
Heartbeat, Data, Connection, Disconnection
}
/// <summary>
@@ -45,5 +45,11 @@ namespace BCG
get { return myConnInfo; }
}
override public string ToString()
{
Func<byte[], int> len = (byte[] m) => { return m == null ? 0 : m.Length; };
return $"type: {myMsgType} conn: {myConnInfo} msg: {len(myMsg)}";
}
}
}
@@ -5,39 +5,30 @@ using System.Text;
//using BCG.Utilities.General;
//using BCG.Utilities;
namespace BCG
{
public class ServerToClientManagedTCPConnectionAcceptor
{
namespace BCG {
public class ServerToClientManagedTCPConnectionAcceptor {
private static Dictionary<int, SingleServerToClientManagedTCPConnectionAcceptor> myPortToSingleServerAcceptorMap = new Dictionary<int, SingleServerToClientManagedTCPConnectionAcceptor>();
private static object mySyncObject = new object();
public static int activateWithRandomPort(ITCPConnectionHandler handler, TimeSpan clientHBTimeSpan)
{
public static int activateWithRandomPort(ITCPConnectionHandler handler, TimeSpan clientHBTimeSpan) {
SingleServerToClientManagedTCPConnectionAcceptor theAcceptor = new SingleServerToClientManagedTCPConnectionAcceptor();
int portNo = theAcceptor.activateWithRandomPort(handler, clientHBTimeSpan);
lock (mySyncObject)
{
lock (mySyncObject) {
myPortToSingleServerAcceptorMap[portNo] = theAcceptor;
}
return portNo;
return portNo;
}
public static int activate(ITCPConnectionHandler handler, int port, TimeSpan clientHBTimeSpan)
{
lock (mySyncObject)
{
if (myPortToSingleServerAcceptorMap.ContainsKey(port))
{
public static int activate(ITCPConnectionHandler handler, int port, TimeSpan clientHBTimeSpan) {
lock (mySyncObject) {
if (myPortToSingleServerAcceptorMap.ContainsKey(port)) {
string msg = string.Format("Error: Application is already accepting clients on port {0}", port);
// BlueEventLog.logEvent(msg, BlueEventLog2Level.Error);
return port;
}
else
{
} else {
SingleServerToClientManagedTCPConnectionAcceptor theAcceptor = new SingleServerToClientManagedTCPConnectionAcceptor();
int assignedport = theAcceptor.activate(handler, port, clientHBTimeSpan);
myPortToSingleServerAcceptorMap[assignedport] = theAcceptor;
@@ -46,6 +37,23 @@ namespace BCG
} //end lock
} //end activate code
public static int accept_connections(ITCPConnectionHandler handler, int port, TimeSpan clientHBTimeSpan) {
lock (mySyncObject) {
if (myPortToSingleServerAcceptorMap.ContainsKey(port)) {
string msg = string.Format("Error: Application is already accepting clients on port {0}", port);
// BlueEventLog.logEvent(msg, BlueEventLog2Level.Error);
return port;
} else {
SingleServerToClientManagedTCPConnectionAcceptor ps_acceptor = new SingleServerToClientManagedTCPConnectionAcceptor();
int assignedport = ps_acceptor.accept_on_port(handler, "127.0.0.1", port, clientHBTimeSpan);
myPortToSingleServerAcceptorMap[assignedport] = ps_acceptor;
return assignedport;
}
} //end lock
} //end activate code
}
}
@@ -4,13 +4,12 @@ using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
//using BCG.Utilities;
namespace BCG
{
public class SingleServerToClientManagedTCPConnectionAcceptor
{
namespace BCG {
public class SingleServerToClientManagedTCPConnectionAcceptor {
private TimeSpan myHBTimeSpan,
myWaitTimeBeforeRetrying = new TimeSpan(0, 0, 0, 0, 250);
private ITCPConnectionHandler myHandler;
@@ -18,58 +17,50 @@ namespace BCG
private int myPort;
public int activateWithRandomPort(ITCPConnectionHandler handler, TimeSpan clientHBTimeSpan)
{
public int activateWithRandomPort(ITCPConnectionHandler handler, TimeSpan clientHBTimeSpan) {
myHBTimeSpan = clientHBTimeSpan;
myHandler = handler;
myAcceptSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int port = 0;
bool madeItThrough = false;
// BlueEventLog.logEvent("Looking for open port to run the server on.", PS3LogLevels.connection);
// BlueEventLog.logEvent("Looking for open port to run the server on.", PS3LogLevels.connection);
Random randomizer = new Random();
PubSubPortRange theRange = PubSub3Config.instance.PS3_PortRange;
//if the range of ports is 1000, then trying 5,000 times means
//your odds of missing an open port are less than 1%
int maxAttempts = (theRange.maxPort - theRange.minPort) * 5;
int maxAttempts = (theRange.maxPort - theRange.minPort) * 5;
int totalAttempts = 0;
while (!madeItThrough)
{
port = randomizer.Next();
while (!madeItThrough) {
port = randomizer.Next();
port = theRange.minPort + (port % (theRange.maxPort - theRange.minPort));
try
{
try {
myAcceptSock.Bind(new IPEndPoint(IPAddress.Any, port));
madeItThrough = true;
}
catch (Exception)
{
} catch (Exception) {
totalAttempts++;
if (totalAttempts < maxAttempts){
if (totalAttempts < maxAttempts) {
//BlueEventLog.logEvent("Couldn't bind to port " + port.ToString() + "; retrying...", PS3LogLevels.connection);
}
else
{
} else {
// BlueEventLog2.instance().abort("Couldn't find an open port to advertise the server on. Consider modifying PS3_PortRange. Talk to Mark for details.");
}
}
}
myPort = port;
myAcceptSock.Listen(250);
myAcceptSock.BeginAccept(new AsyncCallback(myOnAccept), new object[] { });
myAcceptSock.BeginAccept(new AsyncCallback(myOnAccept), new object[] { });
return myPort;
}
public int activate (ITCPConnectionHandler handler, int port, TimeSpan clientHBTimeSpan)
{
public int activate(ITCPConnectionHandler handler, int port, TimeSpan clientHBTimeSpan) {
myHBTimeSpan = clientHBTimeSpan;
myHandler = handler;
myAcceptSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endpoint = new IPEndPoint (IPAddress.Any, port);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, port);
myAcceptSock.Bind(endpoint);
myAcceptSock.Listen(250);
myAcceptSock.BeginAccept(new AsyncCallback(myOnAccept), new object[] { });
@@ -77,15 +68,18 @@ namespace BCG
return myPort; // not sure why we need this class variable myPort, but I am just keeping it up with the existing code
}
private void myOnAccept(IAsyncResult res)
{
public int accept_on_port(ITCPConnectionHandler handler, string ip, int port, TimeSpan client_HB_timespan) {
Task.Run(async () => {
await TCPSocketUtils.accept_connections_async(ip, port, handler, TimeSpan.FromSeconds(1));
});
return port;
}
private void myOnAccept(IAsyncResult res) {
Socket newSock;
try
{
try {
newSock = myAcceptSock.EndAccept(res);
}
catch (Exception ex)
{
} catch (Exception ex) {
// BlueEventLog.logEvent(ex);
Thread.Sleep(myWaitTimeBeforeRetrying);
myAcceptSock.BeginAccept(new AsyncCallback(myOnAccept), new object[] { });
@@ -98,10 +92,10 @@ namespace BCG
ITCPConnection newConn = new AsyncTCPConnection(newSock, myHBTimeSpan);
myHandler.onConnection(newConn);
myAcceptSock.BeginAccept(new AsyncCallback(myOnAccept), new object[] { });
string ip;int port;
newConn.getPeerAddress (out ip, out port);
string ip; int port;
newConn.getPeerAddress(out ip, out port);
string connMsg = String.Format("Connection to port {2} made from {0}:{1}", ip, port, myPort);
// BlueEventLog.logEvent(connMsg, PS3LogLevels.connection);
// BlueEventLog.logEvent(connMsg, PS3LogLevels.connection);
//Console.WriteLine(connMsg);
}
}
@@ -0,0 +1,113 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using BCG;
using System.Xml.Serialization;
using System.Reflection;
using BCG.Utilities.General;
using System.Net.WebSockets;
namespace BCG
{
// utility functions for TCP socket async communications. Does the following
// client to server connect
// server to client connect accepting
// send data
// receive data
public static class TCPSocketUtils
{
#region socket opening and connecting
// keeps accepting connections forever
public static async Task accept_connections_async(string ip, int port, ITCPConnectionHandler handler,
TimeSpan wait_after_error)
{
IPAddress ipAddress = String.IsNullOrEmpty(ip) ? IPAddress.Parse(ip) : IPAddress.Any;
var ip_end_point = new IPEndPoint(ipAddress, port);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ip_end_point);
listener.Listen(10);
Socket client_socket = null;
while (true)
{
try
{
// keeps on accepting connections
client_socket = await listener.AcceptAsync();
AsyncTCPConnection2 new_conn = new(client_socket, AsyncTCPConnection2.ConnectionSide.Server);
handler.onConnection(new_conn);
}
catch (Exception ex)
{
bts.Log.Gen.error($"TCPConnection.accept ex: {ex} trying again");
Task.Delay(wait_after_error);
}
}
}
// connects to the server and ona successful connection, calls con__handler.on_connection_async with an ITCPConnection.
// In case of failures to connect it waits for a given amount of time before retrying
public static async Task<Socket> connect_to_server_async(string ip, int server_port, ITCPConnectionHandler conn_handler,
TimeSpan wait_after_failed_attempt, int n_max_attempts = 1024)
{
Socket client_socket = null;
for (int i = 0; i < n_max_attempts; i++)
{
try
{
string log_conn = $"{ip}:{server_port}";
bts.Log.Gen.info($"AsyncTCPConnection2.connect_to_server conn: {log_conn} attempt no: {i}");
IPAddress server_ip_address = IPAddress.Parse(ip);
client_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await client_socket.ConnectAsync(server_ip_address, server_port);
bts.Log.Gen.info($"AsyncTCPConnection2.connect_to_server conn: {log_conn} successfully connected after {i} attempts");
ITCPConnection new_conn = new AsyncTCPConnection2(client_socket, AsyncTCPConnection2.ConnectionSide.Client);
conn_handler.onConnection(new_conn);
break;
}
catch (Exception ex)
{
bts.Log.Gen.error($"AsyncTCPConnection2.connect_to_server threw ex: {ex}, will reattempt now");
Task.Delay(wait_after_failed_attempt);
}
}
return client_socket;
}
#endregion
#region data sending/receiving
// prefixes the size of the data and sends it as 2 sends, for size and data
// (can be done as one send perhaps)
public static async Task send_bytes_async(NetworkStream nw_stream, byte[] data_buff)
{
var data_sz = data_buff.Length;
byte[] sz_buff = new byte[4];
// aend the size first
BinaryWriter bw = new BinaryWriter(new MemoryStream(sz_buff));
bw.Write(data_sz);
await nw_stream.WriteAsync(sz_buff, 0, 4);
await nw_stream.WriteAsync(data_buff, 0, data_buff.Length);
}
// reads the bytes on a connected socket, by doing the opposite of the above,
// reads the size first and then the data
public static async Task<byte[]> read_bytes_async(NetworkStream nw_stream)
{
byte[] sz_buffer = new byte[4];
//Asynchronously reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
int bytesRead = await nw_stream.ReadAsync(sz_buffer, 0, sz_buffer.Length);
BinaryReader br = new BinaryReader(new MemoryStream(sz_buffer));
int msg_sz = br.ReadInt32();
byte[] data_buffer = new byte[msg_sz];
bytesRead = await nw_stream.ReadAsync(data_buffer, 0, data_buffer.Length);
//Console.WriteLine($"read_bytes sz: {data_buffer.Length}");
return data_buffer;
}
#endregion
}
}
+23 -15
View File
@@ -4,31 +4,39 @@ using System.IO;
using BCG;
using BCG.Utilities;
namespace BCG
{
// Tuple of
public class PubSubMessage
{
public PubSubMessage (MetaData metaData, Stream body)
{this.metaData = metaData; this.body = body;}
namespace BCG {
// PubItems are published to the pubsub wrapped in this class. It contains PubMetaData, wrapped in the MetaData
// object and the actualy published payload in the body stream
public class PubSubMessage {
public PubSubMessage(MetaData metaData, Stream body) { this.meta_data = metaData; this.body = body; }
public PubSubMessage (MetaData metaData)
{this.metaData = metaData;}
public PubSubMessage(PubMetaData pub_meta_data, Stream body)
: this(new MetaData(pub_meta_data), body) { }
public MetaData metaData;
public PubSubMessage(MetaData metaData) { this.meta_data = metaData; }
public MetaData meta_data;
public Stream body = new MemoryStream(0);
public Stream toStream()
{
public Stream to_stream() {
MemoryStream ms = new MemoryStream();
metaData.save(ms);
if (body.Length == 0 || body.Length == body.Position)
meta_data.save(ms);
if (body.Length == 0 || body.Length == body.Position) {
bts.Log.Gen.error("Error: Trying to publishing message with no content.");
Console.WriteLine("Error: Trying to publishing message with no content.");
}
StreamUtilityMethods.copyTo(new Stream[] { body }, ms);
ms.Position = 0;
return ms;
}
public byte[] to_bytes() {
return StreamUtilityMethods.getBytesFromStream(to_stream());
}
public override string ToString() {
return $"PubSubMessage meta:data: {meta_data.ToString()} body.Posiiton: {body.Position} body.Length: {body.Length}";
}
}
}
+7 -8
View File
@@ -2,22 +2,21 @@ using System;
using System.Collections;
using System.IO;
namespace BCG
{
namespace BCG {
/// <summary>
/// this is the data returned from the
/// pubsub server
/// </summary>
public class PubSubUpdate
{
public PubSubUpdate(string tag, string tagType, Stream body)
{ this.tag = tag; this.body = body; this.tagType = tagType; }
public class PubSubUpdate {
public PubSubUpdate(string tag, string tagType, Stream body) { this.tag = tag; this.body = body; this.tagType = tagType; }
public string tag;
public Stream body;
public string tagType;
public override string ToString() {
return $"PubSubUpdate tag: {tag} tag_type: {tagType} len: {body.Position}";
}
};
}
+26 -130
View File
@@ -7,171 +7,67 @@ using System.Text.RegularExpressions;
using BCG.Utilities;
namespace BCG
{
public class PublisherCore : IPublisherCore
{
//private static BlueCommManaged.IPubSub myBCPS;
// TODO: what is this?
// public static void setPubSub(BlueCommManaged.IPubSub ps)
// {
// lock(typeof(PublisherCore))
// {
// BlueEventLog2.instance().assert(myBCPS == null,
// "PublisherCore.setPubSub() should be called only once and before any use of PublisherCore");
// myBCPS = ps;
// }
// }
namespace BCG {
public class PublisherCore : IPublisherCore {
public static string pubSubBlueCommPrefix = "ps/";
public static string pubSubBlueCommTransactionPrefix = "tgps/";
public static string pubSubBlueCommTransactionComponentPrefix = "tcps/";
// public static BlueCommManaged.IPubSub getPubSub()
// {
// lock (typeof(PublisherCore)) {
// return myBCPS;
// }
// }
enum Destination
{
enum Destination {
None,
BlueComm,
PubSub,
Both
}
//private IPublisherCore myBlueCommPublisher = null;
private IPublisherCore myPubSubPublisher = null;
private Dictionary<string, Destination> myPubDestinations =
new Dictionary<string, Destination>();
private IPublisherCore _publisher_core = null;
public PublisherCore()
{
myPubSubPublisher = new StaticPublisherCore();
//myBlueCommPublisher = new BlueCommPublisherCore(getPubSub());
public PublisherCore() {
_publisher_core = new StaticPublisherCore();
}
public PublisherCore(IPubSubRouter theRouter)
{
myPubSubPublisher = new StaticPublisherCore(theRouter);
//myBlueCommPublisher = new BlueCommPublisherCore(getPubSub());
public PublisherCore(IPubSubRouter theRouter) {
_publisher_core = new StaticPublisherCore(theRouter);
}
public PublisherCore(string URL)
{
myPubSubPublisher = new StaticPublisherCore(URL);
//myBlueCommPublisher = new BlueCommPublisherCore(getPubSub());
public PublisherCore(string URL) {
_publisher_core = new StaticPublisherCore(URL);
}
#region IPublisherCore Methods
public void Dispose()
{
myPubSubPublisher.Dispose();
//myBlueCommPublisher.Dispose();
public void Dispose() {
_publisher_core.Dispose();
}
public int getNumberOfWaitingMessages() { return myPubSubPublisher.getNumberOfWaitingMessages(); }
public int getNumberOfWaitingMessages() { return _publisher_core.getNumberOfWaitingMessages(); }
private Destination myGetPublishDestionation (string tag)
{
return Destination.PubSub;
// lock (this)
// {
// if (PubSub3Config.instance.BlueComm_mustDie)
// return Destination.PubSub;
// else
// {
// Destination d;
// return Destination.PubSub;
// if (myPubDestinations.TryGetValue(tag, out d))
// return d;
// else
// {
// foreach (string regexp in PubSub3Config.instance.BlueComm_PSTransition.tagsToPublishInPubSub)
// if (Regex.IsMatch(tag, regexp))
// {
// d = Destination.PubSub;
// foreach (string regexp2 in PubSub3Config.instance.BlueComm_PSTransition.exceptionsToTagsToPublishInPubSub)
// if (Regex.IsMatch(tag, regexp2))
// {
// d = Destination.None;
// break;
// }
// break;
// }
// if (!tag.StartsWith("mon"))
// foreach (string regexp in PubSub3Config.instance.BlueComm_PSTransition.tagsToPublishInBlueComm)
// if (Regex.IsMatch(tag, regexp))
// {
// if (d == Destination.PubSub)
// d = Destination.Both;
// else
// d = Destination.BlueComm;
// foreach (string regexp2 in PubSub3Config.instance.BlueComm_PSTransition.exceptionsToTagsToPublishInBlueComm)
// if (Regex.IsMatch(tag, regexp2))
// {
// if (d == Destination.Both)
// d = Destination.PubSub;
// else if (d == Destination.BlueComm)
// d = Destination.None;
// break;
// }
// break;
// }
// myPubDestinations[tag] = d;
// return d;
// }
// }
// }
}
public void publish(string tag, Stream content)
{
public void publish(string tag, Stream content) {
publish(tag, "", content);
}
public void publish(string tagType, string tag, Stream content)
{
Destination d = myGetPublishDestionation(tag);
if (d == Destination.PubSub || d == Destination.Both)
myPubSubPublisher.publish(tagType, tag, content);
if (d == Destination.BlueComm || d == Destination.Both){}
//myBlueCommPublisher.publish(tagType, tag, content);
public void publish(string tagType, string tag, Stream content) {
bts.Log.Gen.info($"PublisherCore.publish tag: {tag} stream.Length: {content.Length} stream.Position: {content.Position}");
_publisher_core.publish(tagType, tag, content);
}
public void beginTransaction()
{
myPubSubPublisher.beginTransaction();
//myBlueCommPublisher.beginTransaction();
public void beginTransaction() {
_publisher_core.beginTransaction();
}
public void commitTransaction()
{
myPubSubPublisher.commitTransaction();
//myBlueCommPublisher.commitTransaction();
public void commitTransaction() {
_publisher_core.commitTransaction();
}
public void abortTransaction()
{
myPubSubPublisher.abortTransaction();
//myBlueCommPublisher.abortTransaction();
public void abortTransaction() {
_publisher_core.abortTransaction();
}
public void clearState(string tagToClear)
{
Destination d = myGetPublishDestionation(tagToClear);
if (d == Destination.PubSub || d == Destination.Both)
myPubSubPublisher.clearState(tagToClear);
if (d == Destination.BlueComm || d == Destination.Both){}
//myBlueCommPublisher.clearState(tagToClear);
public void clearState(string tagToClear) {
_publisher_core.clearState(tagToClear);
}
public bool inTransaction
{ get { return myPubSubPublisher.inTransaction; } }
public bool inTransaction { get { return _publisher_core.inTransaction; } }
#endregion
@@ -3,27 +3,25 @@ using System.IO;
using System.Collections;
using BCG.Utilities;
namespace BCG
{
namespace BCG {
/// <summary>
/// Controls (ie creates dynamically) an IPubsubDeserializer based on the type name which is
/// part of the published data. Since its also a IPubsubDeserializer, all subsequent calls
/// are passed though to the interface
/// </summary>
public class PubsubDeserializationController : IPubsubDeserializer
{
public class PubsubDeserializationController : IPubsubDeserializer {
private IPubsubDeserializer myDeserializer;
public PubsubDeserializationController() { }
public void update(Stream stream)
{
public void update(Stream stream) {
bts.Log.Gen.info("PubsubDeserializationController.update stream: {stream.Position} / {stream.Length}");
byte[] ops;
Array rows;
deserialize(new Stream[] { stream }, out ops, out rows);
}
public void update(byte[] bytes)
{
public void update(byte[] bytes) {
bts.Log.Gen.info("PubsubDeserializationController.update bytes: {bytes.Length}");
byte[] ops;
Array rows;
deserialize(new Stream[] { new MemoryStream(bytes, 0, bytes.Length, false, true) }, out ops, out rows);
@@ -31,39 +29,36 @@ namespace BCG
#region IPubsubDeserializer Members
public void deserialize(Stream[] streams, out byte[] theOps, out Array theRows)
{
if (myDeserializer != null)
{
public void deserialize(Stream[] streams, out byte[] theOps, out Array theRows) {
if (myDeserializer != null) {
myDeserializer.deserialize(streams, out theOps, out theRows);
}
else
{
bts.Log.Gen.info($"PubsubDeserializationController.deserialize myDeserializer: {myDeserializer} ops: {theOps.Length} theRows: {theRows.Length}");
} else {
Stream totalStream = UtilityMethods.getAggregatedStream(streams);
long initialPos = totalStream.Position;
BinaryReader br = new BinaryReader(totalStream);
byte opCode = br.ReadByte();
if (opCode == StreamOpCode.create)
{
bts.Log.Gen.info($"PubsubDeserializationController.deserialize opCode: {opCode}");
if (opCode == StreamOpCode.create) {
string deserName = br.ReadString();
if (deserName == "BCG.PubsubUniversalDeserializer") // so we can play old replay files which would not include the assembly name
deserName = "BCG.PubsubUniversalDeserializer, DataStreamGateway";
myDeserializer = Activator.CreateInstance(Type.GetType(deserName))
as IPubsubDeserializer;
// TODOds
if (deserName == "BCG.PubsubUniversalDeserializer, DataStreamGateway") // so we can play old replay files which would not include the assembly name
deserName = "BCG.PubsubUniversalDeserializer, DataStreamCore";
myDeserializer = Activator.CreateInstance(Type.GetType(deserName)) as IPubsubDeserializer;
totalStream.Position = initialPos;
myDeserializer.deserialize(new Stream[] { totalStream }, out theOps, out theRows);
}
else
{
// BlueEventLog.logEvent("Received a non create before a create. Bad op code was " + opCode.ToString(), BlueEventLevel.Warning);
bts.Log.Gen.info($"PubsubDeserializationController.deserialize myDeserializer: {myDeserializer} ops: {theOps.Length} theRows: {theRows.Length}");
} else {
bts.Log.Gen.error($"Received a non create before a create. Bad op code was : {opCode} ");
theOps = new byte[] { };
theRows = new object[] { };
}
}
}
public byte[] getState()
{
public byte[] getState() {
return myDeserializer == null ? new byte[] { } : myDeserializer.getState();
}
@@ -9,17 +9,14 @@ using System.IO;
using System.Diagnostics;
using mbts;
namespace BCG
{
namespace BCG {
public class ManagedTCPMessageHub : IPubsubMessageHub,
ITCPConnectionHandler,
ITCPMessageHandler
{
ITCPMessageHandler {
private int myPort;
private bool myIsDisposed = false;
public int port
{
public int port {
get { return myPort; }
//property is read only
@@ -66,8 +63,7 @@ namespace BCG
private DateTime myLastHeartbeatDeadCollectionTime = DateTime.Now;
private DateTime myLastDisposedDeadCollectionTime = DateTime.Now;
public ManagedTCPMessageHub(int port, TimeSpan hbSendInterval, int missingHBsForGC, TimeSpan collectDisposedConnectionsPeriod)
{
public ManagedTCPMessageHub(int port, TimeSpan hbSendInterval, int missingHBsForGC, TimeSpan collectDisposedConnectionsPeriod) {
myPort = port;
myHeartbeatSendInterval = hbSendInterval;
mySubscriberDropThreshold = new TimeSpan(0, 0, 0, 0, Convert.ToInt32(hbSendInterval.TotalMilliseconds * missingHBsForGC));
@@ -81,24 +77,21 @@ namespace BCG
#region IPubsubMessageHub Members
public void registerDataCallback(DataDelegate del)
{
public void registerDataCallback(DataDelegate del) {
// BlueEventLog.logAssert(!myActivated, "connection callbacks should be registered before the call to activate");
myDataCb = del;
}
public void registerConnectionCallback(ConnectionStatusChange del)
{
public void registerConnectionCallback(ConnectionStatusChange del) {
//BlueEventLog.logAssert(!myActivated, "data callbacks should be registered before the call to activate");
myConnCb = del;
}
public void activate()
{
public void activate() {
if (PubSub3Config.instance.PS3_BindToRandomPort || myPort == 0)
myPort = ServerToClientManagedTCPConnectionAcceptor.activateWithRandomPort(this, myHeartbeatSendInterval);
else
myPort = ServerToClientManagedTCPConnectionAcceptor.activate(this, myPort, myHeartbeatSendInterval);
myPort = ServerToClientManagedTCPConnectionAcceptor.accept_connections(this, myPort, myHeartbeatSendInterval);
string msg = String.Format("TCP Component is ready, listening on port {0} for incoming connections", myPort);
Console.WriteLine(msg);
@@ -108,19 +101,16 @@ namespace BCG
doItAllThread.Start();
}
public List<Pair<string, byte[]>> getUpdates(TimeSpan timeout, int maxElements)
{
public List<Pair<string, byte[]>> getUpdates(TimeSpan timeout, int maxElements) {
return myReceivedData.dequeueMultipleElements(timeout, maxElements);
}
public bool send(string receiver, byte[] data)
{
public bool send(string receiver, byte[] data) {
mySendData.enqueue(new Pair<string, byte[]>(receiver, data));
return true;
}
public bool send(string receiver, System.IO.Stream str)
{
public bool send(string receiver, System.IO.Stream str) {
BinaryReader br = new BinaryReader(str);
return send(receiver, br.ReadBytes(Convert.ToInt32(str.Length - str.Position)));
}
@@ -133,17 +123,13 @@ namespace BCG
/// Reports back connected and disconnected connections
/// via the ConnectionStatucChange callback
/// </summary>
public void doWork()
{
if (myConnCb != null)
{
foreach (string nc in myNewConnectionURLs.dequeueAll())
{
public void doWork() {
if (myConnCb != null) {
foreach (string nc in myNewConnectionURLs.dequeueAll()) {
//BlueEventLog.logEvent(String.Format("doWork : New client {0} connected, making connection callback", nc), PS3LogLevels.connection);
myConnCb(nc, true);
}
foreach (string dc in myDeadConnectionURLs.dequeueAll())
{
foreach (string dc in myDeadConnectionURLs.dequeueAll()) {
//BlueEventLog.logEvent(String.Format("doWork : Client {0} disconnected, making disconnection callback", dc), PS3LogLevels.disconnection);
myConnCb(dc, false);
}
@@ -160,8 +146,7 @@ namespace BCG
/// stored in the hashtable and used for later communication)
/// </summary>
/// <param name="connection"></param>
public void onConnection(ITCPConnection connection)
{
public void onConnection(ITCPConnection connection) {
myNewConnections.enqueue(connection);
}
@@ -169,48 +154,38 @@ namespace BCG
#region ITCPMessageHandler Members
public void onData(RemoteMessage message)
{
public void onData(RemoteMessage message) {
Console.WriteLine("ManagedTCPMessgageHub.onData recv msg :" + message.remoteConnectionInfo.ToString());
string sender = new BlutoSubAddress(message.remoteConnectionInfo.ip, message.remoteConnectionInfo.port).ToString();
if (message.messageType == RemoteMessageType.data)
{
if (message.messageType == RemoteMessageType.Data) {
if (myDataCb != null)
myDataCb(sender, message.message);
else
myReceivedData.enqueue(new Pair<string, byte[]>(sender, message.message));
}
else if (message.messageType == RemoteMessageType.heartbeat)
} else if (message.messageType == RemoteMessageType.Heartbeat)
myReceivedHeartbeats.enqueue(sender);
else
{
else {
//BlueEventLog.logEvent("Unknown message type from the client", BlueEventLevel.Error);
}
}
#endregion
class TimmingInfo
{
public TimmingInfo()
{
class TimmingInfo {
public TimmingInfo() {
myTimer = new Stopwatch();
reset();
}
public void start()
{
if (PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs > 0)
{
public void start() {
if (PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs > 0) {
myTimer.Reset();
myTimer.Start();
}
}
public void stop()
{
if (PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs > 0)
{
public void stop() {
if (PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs > 0) {
myTimer.Stop();
myMin = Math.Min(myMin, myTimer.ElapsedMilliseconds);
myMax = Math.Max(myMax, myTimer.ElapsedMilliseconds);
@@ -219,16 +194,14 @@ namespace BCG
}
}
public void reset()
{
public void reset() {
myMin = Double.MaxValue;
myMax = Double.MinValue;
myTotal = 0;
myNMeasurements = 0;
}
public override string ToString()
{
public override string ToString() {
if (myNMeasurements > 0)
return String.Format("min={0} max={1} avg={2} nMeasurements={3}", myMin, myMax, myTotal / myNMeasurements, myNMeasurements);
else
@@ -242,8 +215,7 @@ namespace BCG
private double myTotal;
}
private void myDoItAll()
{
private void myDoItAll() {
Dictionary<string, TimmingInfo> times = new Dictionary<string, TimmingInfo>();
times.Add("myHandleNewConnections", new TimmingInfo());
times.Add("myCollectDisposedConnections", new TimmingInfo());
@@ -252,12 +224,9 @@ namespace BCG
DateTime lastTimmingLog = DateTime.Now;
while (true)
{
try
{
while (true)
{
while (true) {
try {
while (true) {
///new connections
times["myHandleNewConnections"].start();
myHandleNewConnections();
@@ -279,16 +248,12 @@ namespace BCG
Pair<string, byte[]> p = mySendData.dequeue(myReadSendQueueTimeout);
times["send"].start();
if (p != null)
{
if (p != null) {
ITCPConnection conn;
myConnections.TryGetValue(p.first, out conn);
if (conn != null)
{
if (conn != null) {
conn.send(p.second);
}
else
{
} else {
string warningMsg = String.Format("sending data to {0} failed, this client might have " +
"disconnected, in which case it will be garbage collected within 60 secs", p.first);
//BlueEventLog.logEvent(warningMsg, PS3LogLevels.disconnection);
@@ -297,25 +262,21 @@ namespace BCG
times["send"].stop();
if (PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs > 0 &&
(DateTime.Now - lastTimmingLog).TotalSeconds > PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs)
{
(DateTime.Now - lastTimmingLog).TotalSeconds > PubSub3Config.instance.PS3_DoItAllSecondsBetweenLogs) {
lastTimmingLog = DateTime.Now;
StringBuilder b = new StringBuilder();
b.AppendFormat("myDoItAll stats:\n");
b.AppendFormat("queue size: {0}\n", mySendData.getCount());
foreach (string timerName in times.Keys)
{
foreach (string timerName in times.Keys) {
b.AppendFormat("{0}: {1}\n", timerName, times[timerName]);
times[timerName].reset();
}
//BlueEventLog.logEvent(b.ToString(), PS3LogLevels.performance);
}
}
}
catch (Exception ex)
{
} catch (Exception ex) {
//BlueEventLog.logEvent(ex);
if (ex is OutOfMemoryException)
throw ex;
@@ -323,19 +284,15 @@ namespace BCG
}
}
private void myCollectDisposedConnections()
{
if (DateTime.Now - myLastDisposedDeadCollectionTime > myCollectDisposedConnectionsPeriod)
{
private void myCollectDisposedConnections() {
if (DateTime.Now - myLastDisposedDeadCollectionTime > myCollectDisposedConnectionsPeriod) {
myLastDisposedDeadCollectionTime = DateTime.Now;
List<string> disposedURLs = new List<string>();
foreach (KeyValuePair<string, ITCPConnection> p in myConnections)
{
foreach (KeyValuePair<string, ITCPConnection> p in myConnections) {
if (p.Value.isDisposed)
disposedURLs.Add(p.Key);
}
foreach (string url in disposedURLs)
{
foreach (string url in disposedURLs) {
string disposeMsg = String.Format("Collecting disposed connections : {0} is disposed by the connection itself, " +
"connection count before deleting this = {1}", url, myConnections.Count);
Console.WriteLine(disposeMsg);
@@ -346,10 +303,8 @@ namespace BCG
}
}
private void myCollectMissingHeartbeatConnections()
{
if (DateTime.Now - myLastHeartbeatDeadCollectionTime > mySubscriberDropThreshold)
{
private void myCollectMissingHeartbeatConnections() {
if (DateTime.Now - myLastHeartbeatDeadCollectionTime > mySubscriberDropThreshold) {
myLastHeartbeatDeadCollectionTime = DateTime.Now;
///these are all the hbs received bw the last
///and current collectDeadConnection calls
@@ -365,10 +320,9 @@ namespace BCG
foreach (string clientURL in myConnections.Keys)
if (!indexedHbs.ContainsKey(clientURL))
deadClients.Add(clientURL);
foreach (string deadClient in deadClients)
{
foreach (string deadClient in deadClients) {
string disposeMsg = String.Format("Collecting missing HB connections : {0} is dead due to missing hbs, Disposing it now, " +
"connection count before deleting this = {1}", deadClient, myConnections.Count);
"connection count before deleting this = {1}", deadClient, myConnections.Count);
//BlueEventLog.logEvent(disposeMsg, PS3LogLevels.disconnection);
Console.WriteLine(disposeMsg);
myConnections[deadClient].Dispose();
@@ -378,11 +332,9 @@ namespace BCG
}
}
private void myHandleNewConnections()
{
private void myHandleNewConnections() {
IList<ITCPConnection> newConns = myNewConnections.dequeueAll();
foreach (ITCPConnection conn in newConns)
{
foreach (ITCPConnection conn in newConns) {
string ip;
int port;
conn.getPeerAddress(out ip, out port);
@@ -399,13 +351,11 @@ namespace BCG
}
#region IDisposable Memebers
public void Dispose()
{
public void Dispose() {
myIsDisposed = true;
}
public bool isDisposed
{
public bool isDisposed {
get { return myIsDisposed; }
}
#endregion
@@ -4,23 +4,20 @@ using System.Text;
using BCG.Utilities.General;
using System.IO;
namespace BCG
{
namespace BCG {
/// <summary>
/// Periodicaly publishes a heartbeat, under the tag name System_Heartbeat.
/// A subscriber can subscribe to it, and find out of a PubSub is alive or
/// not. Infact more so, if the subsriptions are working or not.
/// </summary>
internal class SystemHeartbeatPublisher : IWorker
{
internal class SystemHeartbeatPublisher : IWorker {
public static string tagType = "System_Heartbeat";
public static string tagName = "System_Heartbeat";
private static SystemHeartbeatPublisher mySelf;
private SystemHeartbeatPublisher ()
{
private SystemHeartbeatPublisher() {
///this is using a multithreaded MasterWorker since the
///regular one is called within the MessageReactor, which
///waits 2500 msecs before calling doWork. This 2500 msecs
@@ -29,16 +26,14 @@ namespace BCG
MasterWorker.getInstance(true).addWorker(this, new TimeSpan(0, 0, 0, 0, 500));
}
public static void init()
{
public static void init() {
if (mySelf == null)
mySelf = new SystemHeartbeatPublisher();
}
#region IWorker Members
public void doWork()
{
public void doWork() {
PubMetaData pub = new PubMetaData(tagType, tagName, 1, "local", ClientInfo.thisClient.processString);
MetaData md = new MetaData(pub);
MemoryStream ms = new MemoryStream();
@@ -16,10 +16,8 @@ using System.Collections.Generic;
using mbts;
using mbts.spark;
namespace BCG
{
public class PubSubMessageReactor
{
namespace BCG {
public class PubSubMessageReactor {
private ServerMessageHub myMessageHub;
private delegate void MyMsgHandler(string sender, Stream msg, MetaData m);
private Dictionary<string, MyMsgHandler> myOperationToHandler = new Dictionary<string, MyMsgHandler>();
@@ -39,32 +37,24 @@ namespace BCG
/* This delegate allows pubsub components to be notified when the identity of the pubsub is known*/
public delegate void IdentityFoundDelegate(string identity, bool isRoot);
public event IdentityFoundDelegate onIdentityFound;
public void fireIdentityFound(string identity, bool isRoot)
{
public void fireIdentityFound(string identity, bool isRoot) {
if (onIdentityFound != null)
onIdentityFound(identity, isRoot);
}
private IPubSubGovernor myGovernor;
public Dictionary<string, bool> myTagCompressionState = new Dictionary<string, bool>();
public PubSubMessageReactor() : this(false, false, string.Empty, string.Empty) { }
public PubSubMessageReactor(string q) : this(false, false, string.Empty, q) { }
public PubSubMessageReactor(bool clearQueue, bool bootEvent, string oldIP, string psq)
{
public PubSubMessageReactor(bool clearQueue, bool bootEvent, string oldIP, string psq) {
myOperationToHandler.Add(typeof(PubMetaData).Name, new MyMsgHandler(myHandlePub));
myOperationToHandler.Add(typeof(SubMetaData).Name, new MyMsgHandler(myHandleSub));
myOperationToHandler.Add(typeof(UnSubMetaData).Name, new MyMsgHandler(myHandleUnsub));
myOperationToHandler.Add(typeof(TransactionMetaData).Name, new MyMsgHandler(myHandleTransaction));
// TODO, governor needs to be removed since its subststaion retired code
// if (PubSub3Config.instance.PS3_Components.governor != null)
// myGovernor = PubSubComponentFactory.buildGovernor(this);
//BlueEventLog.logEvent("System Initialized", PS3LogLevels.info);
bts.Log.Gen.info("PubSubMessageReactor.cons System Initialized");
myReceivingProcThread = new Thread(new ThreadStart(myReceivingThreadProc));
myMessageHub = ServerMessageHub.instance;
@@ -75,93 +65,49 @@ namespace BCG
#region message handlers
public PubSubState state
{
public PubSubState state {
get { return myState; }
//this variable is read only
}
private void myHandlePub(string sender, Stream msg, MetaData m)
{
// all publishes to the pubsub end here
private void myHandlePub(string sender, Stream msg_str, MetaData meta_data) {
bts.Log.Gen.info($"PubSubMessageReactor.myHandlePub sender: {sender} metadata: {meta_data} str.pos: {msg_str.Position} str.len: {msg_str.Length}");
mySingleTagTimeSliceTimer.start();
///the position in the stream is set to where the data starts with,
///since the meta data was already read in the myProcessMsg
PubMetaData pub = new PubMetaData();
m.copyTo(pub);
meta_data.copyTo(pub);
pub.connection = sender;
Console.WriteLine("PubSubMessageReactor.myHandlePub sender: " + sender + " tag: " + pub.tag);
//check to see if this publish took a while to get here
pub.warnIfLatencyExceedsThreshold();
//check the governor to see if this publish is allowed, if we have a governor
PubSubGovernorResponse response = PubSubGovernorResponse.Accepted;
if (myGovernor != null)
response = myGovernor.requestToPublish(pub, msg);
if (response != PubSubGovernorResponse.Accepted)
{
// BlueEventLog2.instance().logEvent(string.Concat("PubSub Governor ",
// myGovernor.GetType().Name,
// " returned response ",
// response.ToString(),
// " publish on tag",
// pub.tag,
// "was ignored."), BlueEventLog2Level.Warning);
return;
}
//report the fact that we have a publish on this tag, if it's a debug tag
if (PubSub3Config.instance.isTagDebugTag(pub.tag))
{
// BlueEventLog.logEvent(string.Concat(GetType().Name,
// " got publish on tag ",
// pub.tag,
// " from app ", pub.publishingApp,
// " over connection ",
// pub.connection, ".\n",
// pub.isCompressed ? "Data was compressed.\n" : "Data was not compresed.\n",
// "total size: ",
// pub.size),
// PS3LogLevels.debug);
}
var subs_for_tag = myState.getSubscriberConnectionsForTag(pub.tag);
bts.Log.Gen.info($"PubSubMessageReactor.myHandlePub {subs_for_tag.Count} subs for tag: {pub.tag}");
///for all the subscribers, sends the messages over straightaway
foreach (string address in myState.getSubscriberConnectionsForTag(pub.tag))
{
foreach (string address in myState.getSubscriberConnectionsForTag(pub.tag)) {
///the position is adjusted to zero, so as to include
///the meta data as part of the message
msg.Position = 0;
myMessageHub.send(address, msg);
msg_str.Position = 0;
bts.Log.Gen.info($"PubSubMessageReactor.myHandlePub sending tag: {pub.tag} to {address} len: {msg_str.Length - msg_str.Position}");
myMessageHub.send(address, msg_str);
}
//reset the position of the message so we can decompress it appropriately
msg.Position = 0;
msg.Position = m.size();
msg_str.Position = 0;
msg_str.Position = meta_data.size();
if (pub.isCompressed)
{
long mdLength = msg.Position;
long compressedSize = msg.Length - mdLength;
if (compressedSize == 0)
{
if (pub.isCompressed) {
long mdLength = msg_str.Position;
long compressedSize = msg_str.Length - mdLength;
if (compressedSize == 0) {
string errorMsg = "Error: tag " + pub.tag + " had compressed size of 0 bytes. This shouldnt' happen. Not decompressing tag or sending out update.";
//BlueEventLog.logEvent(errorMsg, BlueEventLevel.Error);
bts.Log.Gen.error(errorMsg);
return;
}
msg = StreamDecompressor.decompressStream(msg);
long decompressedSize = msg.Length - mdLength;
if (decompressedSize != pub.decompressedSize || compressedSize != pub.size)
{
msg_str = StreamDecompressor.decompressStream(msg_str);
long decompressedSize = msg_str.Length - mdLength;
if (decompressedSize != pub.decompressedSize || compressedSize != pub.size) {
string compressionWarning = string.Format("Warning: Stream for tag {0} decompressed from {1} to {2} bytes, with {3} byes of metadata. Metadata expected {4} to {5}. Tag state not updated.",
pub.tag,
compressedSize,
@@ -169,43 +115,30 @@ namespace BCG
mdLength,
pub.size,
pub.decompressedSize);
//BlueEventLog.logEvent(compressionWarning, BlueEventLevel.Error);
bts.Log.Gen.warn(compressionWarning);
return;
}
}
//give the user a notification of the compression status of the tag has changed.
if ((!(myTagCompressionState.ContainsKey(pub.tag)) ||
myTagCompressionState[pub.tag] != pub.isCompressed))
{
myTagCompressionState[pub.tag] != pub.isCompressed)) {
string compressionMessage;
myTagCompressionState[pub.tag] = pub.isCompressed;
if (pub.isCompressed)
{
if (pub.isCompressed) {
compressionMessage = "Tag " + pub.tag + " is compressed.";
//BlueEventLog.logEvent(compressionMessage, PS3LogLevels.compressionRatio);
}
else
{
} else {
compressionMessage = "Tag " + pub.tag + " is not compressed.";
//BlueEventLog.logEvent(compressionMessage, PS3LogLevels.compressionRatio);
}
}
///updating state
msg.Position = 0;
msg.Position += m.size();
myState.updatePubData(pub, msg);
msg_str.Position = 0;
msg_str.Position += meta_data.size();
myState.updatePubData(pub, msg_str);
mySingleTagTimeSliceTimer.stop();
double thisTagProcessingTime = mySingleTagTimeSliceTimer.lastIntervalTime;
if (onSingleTagPub != null)
onSingleTagPub(pub.tag, thisTagProcessingTime);
@@ -213,8 +146,8 @@ namespace BCG
}
private void myHandleSub(string sender, Stream msg, MetaData m)
{
private void myHandleSub(string sender, Stream msg, MetaData m) {
bts.Log.Gen.info($"PubSubMessageReactor.myHandleSub sender: {sender} metadata: {m} str.pos: {msg.Position} str.len: {msg.Length}");
SubMetaData sub = new SubMetaData();
m.copyTo(sub);
sub.connection = sender;
@@ -222,12 +155,10 @@ namespace BCG
///update the state
myState.sub(sub);
///to all these new subscriber s, send the existing data
foreach (string tag in sub.tags)
{
foreach (string tag in sub.tags) {
byte[] data = myState.getContent(tag);
//ie data has been published once
if (data != null)
{
if (data != null) {
string tagType = myState.getTagType(tag);
///passing "" as the 4th arg, as PubMeta is used both by the
///publisher to publish data to the server (where the publisher
@@ -237,17 +168,14 @@ namespace BCG
///needed as of now, so its left black to save a few bytes
PubMetaData pub;
MemoryStream realContent;
if (PubSub3Config.instance.isTagCompressed(tag))
{
if (PubSub3Config.instance.isTagCompressed(tag)) {
SharpZipCompressor Kompessor = new SharpZipCompressor();
realContent = new MemoryStream();
Kompessor.compress(new MemoryStream(data), realContent);
pub = new PubMetaData(tagType, tag, (int)realContent.Length, (int)data.Length, "", "");
}
else
{
} else {
realContent = new MemoryStream(data);
pub = new PubMetaData(tagType, tag, data.Length, "", "");
}
@@ -262,8 +190,7 @@ namespace BCG
}
}
private void myHandleUnsub(string sender, Stream msg, MetaData m)
{
private void myHandleUnsub(string sender, Stream msg, MetaData m) {
UnSubMetaData unsub = new UnSubMetaData();
m.copyTo(unsub);
if (unsub.connection.Trim().Length == 0)
@@ -271,8 +198,7 @@ namespace BCG
myState.unsub(unsub);
}
private void myHandleTransaction(string sender, Stream msg, MetaData md)
{
private void myHandleTransaction(string sender, Stream msg, MetaData md) {
mySingleTagTimeSliceTimer.start();
TransactionMetaData t = new TransactionMetaData();
md.copyTo(t);
@@ -280,8 +206,7 @@ namespace BCG
///form the structure tag->byte[]*
Dictionary<string, byte[]> tagToMessages = new Dictionary<string, byte[]>();
BinaryReader br = new BinaryReader(msg);
for (int i = 0; i < nMessages; i++)
{
for (int i = 0; i < nMessages; i++) {
MetaData pubMd = new MetaData(msg);
PubMetaData pub = new PubMetaData();
pubMd.copyTo(pub);
@@ -289,8 +214,7 @@ namespace BCG
byte[] tagData = new byte[pub.size];
msg.Read(tagData, 0, tagData.Length);
//report the fact that we have a publish on this tag, if it's a debug tag
if (PubSub3Config.instance.isTagDebugTag(pub.tag))
{
if (PubSub3Config.instance.isTagDebugTag(pub.tag)) {
// BlueEventLog.logEvent(string.Concat(GetType().Name,
// " got publish on tag ",
// pub.tag,
@@ -315,13 +239,11 @@ namespace BCG
}
///this gives subscriber->tag*
Dictionary<string, List<string>> subscriberToTags = myState.getSubscriberConnectionsForTags(tagToMessages.Keys);
foreach (KeyValuePair<string, List<string>> kvp in subscriberToTags)
{
foreach (KeyValuePair<string, List<string>> kvp in subscriberToTags) {
MemoryStream subStream = new MemoryStream();
TransactionMetaData subTransaction = new TransactionMetaData(kvp.Value.Count);
new MetaData(subTransaction).save(subStream);
foreach (string tag in kvp.Value)
{
foreach (string tag in kvp.Value) {
byte[] tagData = tagToMessages[tag];
PubMetaData pub = new PubMetaData(myState.getTagType(tag), tag, tagData.Length, "", "");
new MetaData(pub).save(subStream);
@@ -336,8 +258,7 @@ namespace BCG
double timeExpended = mySingleTagTimeSliceTimer.lastIntervalTime;
//Don't try to divide by zero
int numTags = tagToMessages.Keys.Count;
if (numTags != 0)
{
if (numTags != 0) {
double timeExpendedPerTag = timeExpended / tagToMessages.Keys.Count;
if (onSingleTagPub != null)
foreach (string tag in tagToMessages.Keys)
@@ -351,18 +272,16 @@ namespace BCG
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
private void myProcessMsg(string sender, Stream msg, out MetaData md)
{
md = new MetaData(msg);
private void myProcessMsg(string sender, Stream msg, out MetaData md) {
md = new MetaData(msg); // msg's Posiiton moved to end of meta data
MyMsgHandler op = myOperationToHandler[md["op-code"]];
//BlueEventLog.logEvent(string.Format("process message {0}", m));
bts.Log.Gen.info($"PubSubMessageReactor.myProcessMsg sender: {sender} metadata: {md}");
op(sender, msg, md);
}
#endregion
private void myHandleConnections(string client, bool connected)
{
private void myHandleConnections(string client, bool connected) {
Console.WriteLine("PubSubMessageReactor.myHandleConnections client: " + client + " connected: " + connected);
///interested in disconnections only, as connections of no
///significance until they subscribe, in which case an entry
@@ -371,13 +290,11 @@ namespace BCG
myState.removeConnection(client);
}
public void stop()
{
public void stop() {
myStop = true;
}
public void start()
{
public void start() {
myReceivingProcThread.Start();
}
@@ -385,8 +302,7 @@ namespace BCG
/// loops around and reads messages from the messageReceiver. calls processMsg
/// passing in the IClientMessage. also logs stuff about the message.
/// </summary>
private void myReceivingThreadProc()
{
private void myReceivingThreadProc() {
TimeSpan receiveTimeout = new TimeSpan(0, 0, 0, 0, 2500);
myMessageHub.activate();
@@ -398,31 +314,25 @@ namespace BCG
string sender;
Stream msg;
MetaData meta;
while (!myStop)
{
while (!myStop) {
sender = null;
msg = null;
meta = null;
try
{
try {
List<Pair<string, byte[]>> receivedData = myMessageHub.getUpdates(receiveTimeout, 1);
if (receivedData.Count > 0)
{
if (receivedData.Count > 0) {
sender = receivedData[0].first;
msg = new MemoryStream(receivedData[0].second);
myTimer.start();
myProcessMsg(sender, msg, out meta);
myTimer.stop();
if (myTimer.lastIntervalTime > myProcessingWarningThreshold)
{
if (myTimer.lastIntervalTime > myProcessingWarningThreshold) {
string warningMsg = String.Format("processing metadata {0} took {1} msecs", meta, myTimer.lastIntervalTime);
//BlueEventLog.logEvent(warningMsg, PS3LogLevels.performance);
}
}
myMasterWorker.doWork();
}
catch (Exception e)
{
} catch (Exception e) {
//BlueEventLog.logEvent(e, BlueEventLevel.Error);
Console.WriteLine("{0} : exception handling message: {1}\n", DateTime.Now, e.Message);
string errMsg = String.Format("Following information about the meta data and sender is available : " +
@@ -7,21 +7,19 @@ using System.IO;
using mbts;
namespace BCG
{
namespace BCG {
/// <summary>
/// Mantains all the state that there is in the server.
/// This information is keyed off the tags (rather than
/// keyed off subscribers or publishers)
/// State information consists of 2 distints sets :
/// State information consists of 2 distinct sets :
/// myTagToData consists of all the data published to
/// this pubsub.
/// myTagToTagInfo consists of all the subscription and
/// publishing information
/// </summary>
///
public class PubSubState
{
public class PubSubState {
public delegate void PubSubStateSingleTagChangeDelegate(PubSubSingleTagStateEvent theEvent);
public event PubSubStateSingleTagChangeDelegate onSingleTagChange;
@@ -33,8 +31,7 @@ namespace BCG
private Dictionary<string, SingleTagData> myTagToData = new Dictionary<string, SingleTagData>();
private Dictionary<string, SingleTagPubSubMap> myTagToPubsubMap = new Dictionary<string, SingleTagPubSubMap>();
public PubSubState()
{
public PubSubState() {
SystemSubscriptionMapPublisher.init(this);
SystemStatsPublisher.init(this);
SystemHeartbeatPublisher.init();
@@ -49,13 +46,10 @@ namespace BCG
/// </summary>
/// <param name="sub"></param>
/// <param name="md"></param>
public void sub(SubMetaData sub)
{
public void sub(SubMetaData sub) {
///tag based key ds update
foreach (string tag in sub.tags)
{
if (!myTagToPubsubMap.ContainsKey(tag))
{
foreach (string tag in sub.tags) {
if (!myTagToPubsubMap.ContainsKey(tag)) {
myTagToPubsubMap.Add(tag, new SingleTagPubSubMap(tag));
}
myTagToPubsubMap[tag].onSub(sub);
@@ -67,20 +61,15 @@ namespace BCG
onTagMapChanged(sub.tags);
}
public void unsub(UnSubMetaData unsub)
{
foreach (string tag in unsub.tags)
{
if (myTagToPubsubMap.ContainsKey(tag))
{
public void unsub(UnSubMetaData unsub) {
foreach (string tag in unsub.tags) {
if (myTagToPubsubMap.ContainsKey(tag)) {
///maybe check here, that if there are no subscribers
///and publishers for the tag then remove it.
myTagToPubsubMap[tag].onUnsub(unsub);
if (onSingleTagChange != null)
onSingleTagChange(new PubSubSingleTagStateEvent(tag, PubSubSingleTagStateEvent.EventType.unsubscription, unsub.connection, unsub.unsubscribingApp));
}
else
{
} else {
string warningMsg = String.Format("{0} was never published or subscribed on this pubsub, hence" +
" the unsub call by app {1} is voided", tag, unsub.unsubscribingApp);
//BlueEventLog.logEvent(warningMsg, BlueEventLevel.Warning);
@@ -90,11 +79,9 @@ namespace BCG
onTagMapChanged(unsub.tags);
}
public void removeConnection(string connection)
{
public void removeConnection(string connection) {
List<string> tagsEffected = new List<string>();
foreach (KeyValuePair<string, SingleTagPubSubMap> p in myTagToPubsubMap)
{
foreach (KeyValuePair<string, SingleTagPubSubMap> p in myTagToPubsubMap) {
///maybe check here, that if there are no subscribers
///and publishers for the tag then remove it.
bool wasPublisher = false;
@@ -103,8 +90,7 @@ namespace BCG
if (p.Value.onConnectionRemoveIfExists(connection, out wasPublisher, out wasSubscriber))
tagsEffected.Add(tag);
if (onSingleTagChange != null)
{
if (onSingleTagChange != null) {
//we don't know the app or key qualifier or anything for these connection. that is unfortunate.
if (wasPublisher)
onSingleTagChange(new PubSubSingleTagStateEvent(tag, PubSubSingleTagStateEvent.EventType.publisherDie, connection, ""));
@@ -128,67 +114,60 @@ namespace BCG
/// </summary>
/// <param name="tag"></param>
/// <param name="msg"></param>
public void updatePubData(PubMetaData pub, Stream msg)
{
public void updatePubData(PubMetaData pub, Stream msg) {
int sz = (int)(msg.Length - msg.Position);
bts.Log.Gen.info($"PubSubData.updatePubData pub: msg : {msg.Position} / {msg.Length} sz: {sz}");
///this is the only place where SingleTagData should be created
if (!myTagToData.ContainsKey(pub.tag))
{
if (!myTagToData.ContainsKey(pub.tag)) {
///first time data is published for this tag
myTagToData.Add(pub.tag, new SingleTagData(pub.tag, pub.type));
}
myTagToData[pub.tag].pubUpdate(msg);
if (!myTagToPubsubMap.ContainsKey(pub.tag))
{
if (!myTagToPubsubMap.ContainsKey(pub.tag)) {
myTagToPubsubMap.Add(pub.tag, new SingleTagPubSubMap(pub.tag));
}
bool pubChanged = false;
myTagToPubsubMap[pub.tag].onPub(pub, out pubChanged);
if (pubChanged)
{
if (pubChanged) {
if (onTagMapChanged != null)
onTagMapChanged(new string[] { pub.tag });
if (onSingleTagChange != null)
onSingleTagChange(
new PubSubSingleTagStateEvent(pub.tag,
PubSubSingleTagStateEvent.EventType.publish,
new PubSubSingleTagStateEvent(pub.tag,
PubSubSingleTagStateEvent.EventType.publish,
pub.connection, pub.publishingApp));
}
if (onPublishStats != null)
onPublishStats(pub.tag, sz);
}
#endregion
public ICollection<string> getSubscriberConnectionsForTag(string tag)
{
public ICollection<string> getSubscriberConnectionsForTag(string tag) {
if (myTagToPubsubMap.ContainsKey(tag))
return myTagToPubsubMap[tag].subscriberConnections;
else
return new string[] { };
}
public ICollection<string> getSubscribingAppsForTag(string tag)
{
public ICollection<string> getSubscribingAppsForTag(string tag) {
if (myTagToPubsubMap.ContainsKey(tag))
return myTagToPubsubMap[tag].subscripingApps;
else
return new string[] { };
}
public byte[] getContent(string tag)
{
public byte[] getContent(string tag) {
if (!myTagToData.ContainsKey(tag))
return null;
else
return myTagToData[tag].getCurrentContent();
}
public string getTagType(string tag)
{
public string getTagType(string tag) {
if (!myTagToData.ContainsKey(tag))
return null;
else
@@ -207,29 +186,23 @@ namespace BCG
/// <param name="deadPublishers"></param>
public void getAllConnections(string tag, out Dictionary<string, string> subscribers,
out Dictionary<string, string> activePublishers,
out ICollection<Pair<string, string>> deadPublishers)
{
if (myTagToPubsubMap.ContainsKey(tag))
{
out ICollection<Pair<string, string>> deadPublishers) {
if (myTagToPubsubMap.ContainsKey(tag)) {
SingleTagPubSubMap map = myTagToPubsubMap[tag];
subscribers = map.subscribers;
activePublishers = map.activePublishers;
deadPublishers = map.deadPublishers;
}
else
{
} else {
subscribers = activePublishers = new Dictionary<string, string>();
deadPublishers = new List<Pair<string, string>>();
}
}
public ICollection<string> allTags
{
public ICollection<string> allTags {
get { return myTagToPubsubMap.Keys; }
}
public ICollection<string> tagsWithData
{
public ICollection<string> tagsWithData {
get { return myTagToData.Keys; }
}
@@ -239,15 +212,11 @@ namespace BCG
/// </summary>
/// <param name="tags"></param>
/// <returns></returns>
public Dictionary<string, List<string>> getSubscriberConnectionsForTags(IEnumerable<string> tags)
{
public Dictionary<string, List<string>> getSubscriberConnectionsForTags(IEnumerable<string> tags) {
Dictionary<string, List<string>> retVal = new Dictionary<string, List<string>>();
foreach (string tag in tags)
{
if (myTagToPubsubMap.ContainsKey(tag))
{
foreach (string sub in myTagToPubsubMap[tag].subscriberConnections)
{
foreach (string tag in tags) {
if (myTagToPubsubMap.ContainsKey(tag)) {
foreach (string sub in myTagToPubsubMap[tag].subscriberConnections) {
if (!retVal.ContainsKey(sub))
retVal.Add(sub, new List<string>());
retVal[sub].Add(tag);
@@ -7,21 +7,18 @@ using System.Collections.Generic;
using BCG.Utilities;
using mbts;
namespace BCG
{
namespace BCG {
/// <summary>
/// SingleTagData consists of (as the name implies)
/// the data published for a tag
/// </summary>
internal class SingleTagData
{
internal class SingleTagData {
private string myTagType = null;
private string myTag;
private byte[] myLastPublishedMsg;
private IPubSubServerTagHandler myHandler;
public SingleTagData(string tag, string tagType)
{
public SingleTagData(string tag, string tagType) {
myTag = tag;
myTagType = tagType;
if (myTagType == SystemSubscriptionMapPublisher.tagType)
@@ -29,6 +26,7 @@ namespace BCG
else if (myTagType == SystemStatsPublisher.tagType)
myHandler = SystemStatsPublisher.getInstance();
else
// this is where it gets the stream handler
myHandler = TagType2HandlerMap.getHandler(myTagType, true);
if (myHandler != null)
myHandler.register(new InternalPublishDelegate(myHandleHandlerCallbacks));
@@ -38,16 +36,13 @@ namespace BCG
public string tagType { get { return myTagType; } }
internal void pubUpdate(Stream stream)
{
if (myHandler != null)
{
try
{
internal void pubUpdate(Stream stream) {
string handler_str = myHandler != null ? myHandler.GetType().ToString() : "NULL";
bts.Log.Gen.info($"SingleTagData.pubUpdate tag: {myTag} handler: {handler_str} stream: {stream.Position} / {stream.Length}");
if (myHandler != null) {
try {
myHandler.update(myTag, new Stream[] { stream });
}
catch (Exception e)
{
} catch (Exception e) {
// BlueEventLog.logEvent(e);
string errMsg = "tag handler threw an exception " + e.Message + " for tag type = " + myTagType +
" tag = " + myTag + " length = " + stream.Length + "\n" +
@@ -58,30 +53,22 @@ namespace BCG
else
throw new ApplicationException(errMsg, e);
}
}
else
{
} else {
myLastPublishedMsg = new byte[stream.Length - stream.Position];
stream.Read(myLastPublishedMsg, 0, myLastPublishedMsg.Length);
}
}
public byte[] getCurrentContent()
{
if (myHandler != null)
{
public byte[] getCurrentContent() {
if (myHandler != null) {
return myHandler.getContent(myTag);
}
else
{
} else {
return myLastPublishedMsg;
}
}
private void myHandleHandlerCallbacks(ICollection<Triplet<string, string, byte[]>> cbItems)
{
foreach (Triplet<string, string, byte[]> p in cbItems)
{
private void myHandleHandlerCallbacks(ICollection<Triplet<string, string, byte[]>> cbItems) {
foreach (Triplet<string, string, byte[]> p in cbItems) {
string tagName = p.first, tagType = p.second;
byte[] data = p.third;
PubMetaData pub = new PubMetaData(tagType, tagName, data.Length, "local", ClientInfo.thisClient.processString);
@@ -7,8 +7,7 @@ using BCG.Utilities.General;
using mbts;
using mbts.spark;
namespace BCG
{
namespace BCG {
/// <summary>
/// Deals with the subscriptions (and getting data) from one
/// pubsub server. Once again, theres no sharing of conenctions
@@ -17,15 +16,13 @@ namespace BCG
/// its concerned with (passed as a conctructor arg).
/// </summary>
internal interface ISingleServerSubscriberCore : IDisposable
{
internal interface ISingleServerSubscriberCore : IDisposable {
IList<PubSubUpdate> getUpdates(int timeout);
event PubSubConnectionChange onPubSubConnectionChange;
void subscribe(params string[] tags);
void unsubscribe(params string[] tags);
}
internal class SingleServerSubscriberCore : IDisposable, ISingleServerSubscriberCore
{
internal class SingleServerSubscriberCore : IDisposable, ISingleServerSubscriberCore {
private HighPerformanceTimer myTimer = new HighPerformanceTimer();
private PubSubServerConnectionFactory myConnectionFactory;
private IPubSubServerConnection myConnection;
@@ -33,15 +30,13 @@ namespace BCG
public event PubSubConnectionChange onPubSubConnectionChange;
public SingleServerSubscriberCore(string serverURL, PubSubServerConnectionFactory connectionFactory)
{
public SingleServerSubscriberCore(string serverURL, PubSubServerConnectionFactory connectionFactory) {
myConnectionFactory = connectionFactory;
myConnection = myConnectionFactory.getConnection(serverURL);
myConnection.registerCallback(new ConnectionStatusChange(myHandleServerReboot));
}
public IList<PubSubUpdate> getUpdates()
{
public IList<PubSubUpdate> getUpdates() {
return getUpdates(1);
}
@@ -51,54 +46,41 @@ namespace BCG
/// </summary>
/// <param name="timeout"></param>
/// <returns></returns>
public IList<PubSubUpdate> getUpdates(int timeout)
{
public IList<PubSubUpdate> getUpdates(int timeout) {
myConnection.doWork();
List<PubSubUpdate> retVal = new List<PubSubUpdate>();
IList<byte[]> dataItems = myConnection.getUpdates(new TimeSpan(0, 0, 0, 0, timeout), Int32.MaxValue);
foreach (byte[] data in dataItems)
{
foreach (byte[] data in dataItems) {
processMessage(data, retVal);
}
return retVal;
}
public List<string> getSubscribedTags()
{
public List<string> getSubscribedTags() {
return myTags;
}
public void subscribe(params string[] tags)
{
foreach (string tag in tags)
{
if (myTags.Contains(tag))
{
public void subscribe(params string[] tags) {
foreach (string tag in tags) {
if (myTags.Contains(tag)) {
string errMsg = String.Format("tag {0} was already subscribed from server {1}",
tag, myConnection.serverURL);
// BlueEventLog.logEvent(errMsg, BlueEventLevel.Warning);
}
else
{
} else {
myTags.Add(tag);
}
}
mySubscribe(tags);
}
public void unsubscribe(params string[] tags)
{
public void unsubscribe(params string[] tags) {
List<string> unsubTags = new List<string>();
foreach (string tag in tags)
{
if (myTags.Contains(tag))
{
foreach (string tag in tags) {
if (myTags.Contains(tag)) {
myTags.Remove(tag);
unsubTags.Add(tag);
}
else
{
} else {
string errMsg = String.Format("tag {0} is being unsubscribed from server {1}, eventhough " +
"it was never subscribed", tag, myConnection.serverURL);
// BlueEventLog.logEvent(errMsg, BlueEventLevel.Warning);
@@ -108,13 +90,13 @@ namespace BCG
Stream str = new MemoryStream();
new MetaData(unsub).save(str);
str.Position = 0;
// this is where data is actually sent out
myConnection.send(str);
}
#region IDisposable Members
public void Dispose()
{
public void Dispose() {
///remove the subscriber
//myConnection.send(new PubSubMessage(new MetaData(new RemoveSubscriberMetaData(myConnection.clientURL))).toStream());
myConnection.Dispose();
@@ -126,8 +108,7 @@ namespace BCG
#endregion
private void mySubscribe(params string[] tags)
{
private void mySubscribe(params string[] tags) {
SubMetaData sub = new SubMetaData(myConnection.clientURL, tags);
Stream str = new MemoryStream();
new MetaData(sub).save(str);
@@ -135,20 +116,16 @@ namespace BCG
myConnection.send(str);
}
private void myHandleServerReboot(string serverURL, bool connection)
{
if (connection)
{
private void myHandleServerReboot(string serverURL, bool connection) {
if (connection) {
//ie connection established again, so has to
//resubscribe to all the tags
// BlueEventLog.logEvent("Connection to " + serverURL + " established....resubscribing to all the tags",
// PS3LogLevels.disconnection);
mySubscribe(myTags.ToArray());
}
else
{
} else {
// BlueEventLog.logEvent("Connection to " + serverURL + " broke....attempting to reconnect...",
// PS3LogLevels.disconnection);
}
@@ -158,18 +135,17 @@ namespace BCG
onPubSubConnectionChange(connection, serverURL);
}
internal static void processMessage(byte[] data, List<PubSubUpdate> updates)
{
if (data != null && data.Length > 0)
{
internal static void processMessage(byte[] data, List<PubSubUpdate> updates) {
bts.Log.Gen.info($"SingleServerSubscriberCore.processMessage data_len: {data.Length}");
if (data != null && data.Length > 0) {
MemoryStream str = new MemoryStream(data);
MetaData md = new MetaData(str);
bts.Log.Gen.info($"SingleServerSubscriberCore.processMessage meta_data: {md}");
MemoryStream bodyStream = str;
long bodyPosition = str.Position;
object op = Activator.CreateInstance (Type.GetType("BCG." + md["op-code"]));
object op = Activator.CreateInstance(Type.GetType("BCG." + md["op-code"]));
md.copyTo(op);
if (op is PubMetaData)
{
if (op is PubMetaData) {
PubMetaData p = op as PubMetaData;
//BCG.BlueTrace.WriteBlueCommReceiveW(p.tag, p.publishTimeTicks);
@@ -177,41 +153,29 @@ namespace BCG
p.warnIfLatencyExceedsThreshold();
//find out if we need to decompress this data
Stream realBody = bodyStream;
if (p.isCompressed)
{
if (p.isCompressed) {
long compressedSize = bodyStream.Length - bodyStream.Position;
if (compressedSize == 0)
{
if (compressedSize == 0) {
string errorMsg = "Error: tag " + p.tag + " had compressed size of 0 bytes. This shouldnt' happen. Not decompressing tag or sending out update.";
Console.WriteLine(errorMsg);
//BlueEventLog.logEvent(errorMsg, BlueEventLevel.Error);
return;
}
realBody = StreamDecompressor.decompressStream(bodyStream);
realBody.Position = bodyPosition;
}
updates.Add(new PubSubUpdate(p.tag, p.type, realBody));
}
else if (op is TransactionMetaData)
{
} else if (op is TransactionMetaData) {
TransactionMetaData tr = op as TransactionMetaData;
for (int i = 0; i < tr.nMessages; i++)
{
for (int i = 0; i < tr.nMessages; i++) {
PubMetaData pub = new PubMetaData();
new MetaData(bodyStream).copyTo(pub);
byte[] trConstituent = new byte[pub.size];
bodyStream.Read(trConstituent, 0, trConstituent.Length);
updates.Add(new PubSubUpdate(pub.tag, pub.type, new MemoryStream(trConstituent)));
}
}
else{}
//BlueEventLog.logAssert(false, "Unknown message received: " + md.ToString() + " , only Pub and TransactionMetaData are legal");
} else { }
//BlueEventLog.logAssert(false, "Unknown message received: " + md.ToString() + " , only Pub and TransactionMetaData are legal");
}
}
}
+146 -212
View File
@@ -15,91 +15,79 @@ using mbts;
* This file was originally called 'PublisherCore.cs'. It was renamed so that the publisher core could be replaced.
*
* */
namespace BCG
{
public class CrushedTagManager
{
private static CrushedTagManager mySelf;
private Dictionary<string, bool> myTags = new Dictionary<string, bool>();
public static CrushedTagManager instance
{
get
{
if (mySelf == null)
mySelf = new CrushedTagManager();
return mySelf;
namespace BCG {
// Provides a function to check if a tag is crushabel or not
public class CrushedTagManager {
private static CrushedTagManager _self;
private Dictionary<string, bool> _tag_map = new Dictionary<string, bool>();
public static CrushedTagManager instance {
get {
if (_self == null)
_self = new CrushedTagManager();
return _self;
}
}
public bool isTagCrushable(string tag)
{
public bool is_tag_crushable(string tag) {
tag = tag.ToLower();
lock (typeof(CrushedTagManager))
{
if (!myTags.ContainsKey(tag))
{
bool rv = false;
lock (typeof(CrushedTagManager)) {
if (!_tag_map.TryGetValue(tag, out rv)) {
foreach (string r in PubSub3Config.instance.PS3_CrushableTags)
if (new System.Text.RegularExpressions.Regex(r).IsMatch(tag))
{
myTags.Add(tag, true);
if (new System.Text.RegularExpressions.Regex(r).IsMatch(tag)) {
_tag_map.Add(tag, true);
break;
}
if (!myTags.ContainsKey(tag))
myTags.Add(tag, false);
_tag_map.Add(tag, false);
}
}
return myTags[tag];
return rv;
}
}
/// <summary>
/// All the data for a single tag, thats published within
/// a transaction
/// </summary>
public class TagWaitingInTransaction
{
private bool myIsCrushable;
private List<byte[]> myData = new List<byte[]>();
private int myTotalSize = 0;
private string myTag, myTagType;
public TagWaitingInTransaction(string theTagType, string theTag)
{
myTag = theTag;
myTagType = theTagType;
myIsCrushable = CrushedTagManager.instance.isTagCrushable(myTag);
public class TagWaitingInTransaction {
private bool _is_crushable;
private List<byte[]> _buffered_data = new List<byte[]>();
// this is the size of all the buffered data
private int _total_size = 0;
private string _tag, _tag_type;
public TagWaitingInTransaction(string theTagType, string theTag) {
_tag = theTag;
_tag_type = theTagType;
_is_crushable = CrushedTagManager.instance.is_tag_crushable(_tag);
}
public void addPub(Stream pubStream)
{
if (myIsCrushable)
{
byte[] newData = new byte[(int)(pubStream.Length - pubStream.Position)];
pubStream.Read(newData, 0, newData.Length);
myData.Clear();
myData.Add(newData);
myTotalSize = newData.Length;
}
else
{
byte[] newData = new byte[(int)(pubStream.Length - pubStream.Position)];
pubStream.Read(newData, 0, newData.Length);
myData.Add(newData);
myTotalSize += newData.Length;
public void add_pub(Stream pub_stream) {
if (_is_crushable) {
// extract bytes, clear _buffered_data and queue to _buffered_data
byte[] new_data = new byte[(int)(pub_stream.Length - pub_stream.Position)];
pub_stream.Read(new_data, 0, new_data.Length);
_buffered_data.Clear();
_buffered_data.Add(new_data);
_total_size = new_data.Length;
} else {
// extract btes and queue to _buffered_data
byte[] new_data = new byte[(int)(pub_stream.Length - pub_stream.Position)];
pub_stream.Read(new_data, 0, new_data.Length);
_buffered_data.Add(new_data);
_total_size += new_data.Length;
}
}
public void writeTo(Stream s, string connection, string publishingApp)
{
new MetaData(new PubMetaData(myTagType, myTag, myTotalSize, connection, publishingApp)).save(s);
foreach (byte[] data in myData)
public void write_to(Stream s, string connection, string publishing_app) {
new MetaData(new PubMetaData(_tag_type, _tag, _total_size, connection, publishing_app)).save(s);
foreach (byte[] data in _buffered_data)
s.Write(data, 0, data.Length);
}
public string tag { get { return myTag; } }
public string tagType { get { return myTagType; } }
public List<byte[]> data { get { return myData; } }
public string tag { get { return _tag; } }
public string tagType { get { return _tag_type; } }
public List<byte[]> data { get { return _buffered_data; } }
}
public enum PublisherCoreMessageType
{
public enum PublisherCoreMessageType {
transactionBegin,
transactionCommit,
transactionAbort,
@@ -107,37 +95,35 @@ namespace BCG
clear
}
public class PublisherCoreMessage
{
public class PublisherCoreMessage {
public PublisherCoreMessageType msgType;
public string tagType, tag;
public Stream data;
public PublisherCoreMessage(string tagToClear)
{
public PublisherCoreMessage(string tagToClear) {
tag = tagToClear;
msgType = PublisherCoreMessageType.clear;
}
public PublisherCoreMessage(PublisherCoreMessageType theMsgType)
{
public PublisherCoreMessage(PublisherCoreMessageType theMsgType) {
msgType = theMsgType;
}
public PublisherCoreMessage(string theTagType, string theTag, Stream theData)
{
public PublisherCoreMessage(string theTagType, string theTag, Stream theData) {
msgType = PublisherCoreMessageType.publish;
tagType = theTagType;
tag = theTag;
data = theData;
}
public override string ToString() {
return $"PublisherCoreMessage tag: {tag} data.Position: {data.Position} data.Length: {data.Length}";
}
}
// this class uses an internal queue + thread to serialize and process calls
// made through its public interface (IPublisherCore)
public class StaticPublisherCore : IPublisherCore
{
public class StaticPublisherCore : IPublisherCore {
// used to allow for different transports
// to be used when communicating to a pubsubserver
protected PubSubServerConnectionFactory myConnectionFactory = new PubSubServerConnectionFactory(false);
@@ -172,57 +158,48 @@ namespace BCG
public StaticPublisherCore()
// TODOds
: this(new PubSubRouter())
{ }
: this(new PubSubRouter()) { }
public StaticPublisherCore(string serverURL)
: this(new PubSubRouter(new PubSubRoute(serverURL, ".*")))
{ }
: this(new PubSubRouter(new PubSubRoute(serverURL, ".*"))) { }
public StaticPublisherCore(IPubSubRouter r)
{
public StaticPublisherCore(IPubSubRouter r) {
myRouter = r;
Thread pumpThread = new Thread(new ThreadStart(myMessagePump));
pumpThread.IsBackground = true;
pumpThread.Start();
}
public void Dispose()
{ }
public void Dispose() { }
#endregion
public int getNumberOfWaitingMessages() { return myMainQueue.getCount(); }
#region Main Thread - all library functions are called on the main thread and queued to be picked by the pump
public void publish(string tag, Stream content)
{ publish("", tag, content); }
public void publish(string tag, Stream content) { publish("", tag, content); }
public void publish(string tagType, string tag, Stream content)
{
myMainQueue.enqueue(new PublisherCoreMessage(tagType, tag, content));
public void publish(string tagType, string tag, Stream content) {
PublisherCoreMessage msg = new PublisherCoreMessage(tagType, tag, content);
bts.Log.Gen.info($"StaticPublisherCore.publish msg: {msg}");
myMainQueue.enqueue(msg);
}
public void beginTransaction()
{
public void beginTransaction() {
myMainQueue.enqueue(new PublisherCoreMessage(PublisherCoreMessageType.transactionBegin));
}
public void commitTransaction()
{
public void commitTransaction() {
myMainQueue.enqueue(new PublisherCoreMessage(PublisherCoreMessageType.transactionCommit));
}
public void abortTransaction()
{
public void abortTransaction() {
myMainQueue.enqueue(new PublisherCoreMessage(PublisherCoreMessageType.transactionAbort));
}
public bool inTransaction
{ get { return myInTransaction; } }
public bool inTransaction { get { return myInTransaction; } }
public void clearState(string tag)
{
public void clearState(string tag) {
myMainQueue.enqueue(new PublisherCoreMessage(tag));
}
@@ -230,70 +207,51 @@ namespace BCG
#region Message Pump Thread - this is where messages are dequeued and the action performed
private void myMessagePump()
{
while (true)
{
try
{
while (true)
{
private void myMessagePump() {
while (true) {
try {
while (true) {
object data = myMainQueue.dequeue(1000);
if (data != null)
{
if (data != null) {
int qc = myMainQueue.getCount();
PublisherCoreMessage msg = data as PublisherCoreMessage;
if (msg.msgType == PublisherCoreMessageType.transactionBegin)
{
bts.Log.Gen.info($"StaticPublisherCore.myMessagePump msg: {msg}");
if (msg.msgType == PublisherCoreMessageType.transactionBegin) {
myBeginTransaction();
}
else if (msg.msgType == PublisherCoreMessageType.transactionCommit)
{
} else if (msg.msgType == PublisherCoreMessageType.transactionCommit) {
myCommitTransaction();
}
else if (msg.msgType == PublisherCoreMessageType.transactionAbort)
{
} else if (msg.msgType == PublisherCoreMessageType.transactionAbort) {
myAbortTransaction();
}
else if (msg.msgType == PublisherCoreMessageType.publish)
{
} else if (msg.msgType == PublisherCoreMessageType.publish) {
myPublish(msg.tagType, msg.tag, msg.data);
}
else if (msg.msgType == PublisherCoreMessageType.clear)
{
} else if (msg.msgType == PublisherCoreMessageType.clear) {
myClearState(msg.tag);
}
}
foreach (IPubSubServerConnection conn in mySenders)
{
foreach (IPubSubServerConnection conn in mySenders) {
conn.doWork();
}
}
}
catch (Exception ex)
{
// BlueEventLog.logEvent(ex);
} catch (Exception ex) {
bts.Log.Gen.error($"StaticPublisherCore.myMessagePump exception ex: {ex}");
if (ex is OutOfMemoryException)
throw ex;
}
}
}
private void myBeginTransaction()
{
private void myBeginTransaction() {
// BlueEventLog.logAssert(!inTransaction);
//BlueEventLog.logEvent("StaticPublisherCore Starting Transaction.", BlueEventLevel.Information);
myInTransaction = true;
}
private void myCommitTransaction()
{
private void myCommitTransaction() {
myEndTransaction(true);
}
private void myAbortTransaction()
{
private void myAbortTransaction() {
myEndTransaction(false);
}
@@ -304,21 +262,17 @@ namespace BCG
//keep it consistent with the way it was done earlier), this should
//simply publish it non transactionally (easy way out), or
//transactionally with respect to each pubsub
protected virtual void myEndTransaction(bool success)
{
lock (this)
{
protected virtual void myEndTransaction(bool success) {
lock (this) {
// BlueEventLog.logAssert(inTransaction);
//BlueEventLog.logEvent("StaticPublisherCore Finishing Transaction.", BlueEventLevel.Information);
myInTransaction = false;
if (success)
{
if (success) {
// pubsub server -> tags with updates
Dictionary<string, List<string>> routesToTags = new Dictionary<string, List<string>>();
// group updates per pubsub server
foreach (string tag in myWaitingInTransactionMessages.Keys)
{
foreach (string tag in myWaitingInTransactionMessages.Keys) {
string thisURL = myRouter.getPubURLForTag(tag);
if (!routesToTags.ContainsKey(thisURL))
routesToTags[thisURL] = new List<string>();
@@ -327,17 +281,14 @@ namespace BCG
// more than one server means we won't be able to honor the transactionality request
// log a warning if that is the case.
if (routesToTags.Keys.Count > 1)
{
if (routesToTags.Keys.Count > 1) {
//this is going to be a long error message, but it's an importat one to be able to debug.
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.Append("Tags within this transaction are routed to different pubSub servers.\n");
errorMessageBuilder.Append("This will break the transactionality of clients receiving the data. Details:\n");
foreach (string route in routesToTags.Keys)
{
foreach (string tag in routesToTags[route])
{
foreach (string route in routesToTags.Keys) {
foreach (string tag in routesToTags[route]) {
errorMessageBuilder.Append("\tTag ");
errorMessageBuilder.Append(tag);
errorMessageBuilder.Append(" is routed to ");
@@ -351,16 +302,14 @@ namespace BCG
}
// iterate through each server with pending messages
foreach (KeyValuePair<string, List<string>> kvp in routesToTags)
{
foreach (KeyValuePair<string, List<string>> kvp in routesToTags) {
IPubSubServerConnection transactionSender = null;
string publishingApp = ClientInfo.thisClient.processString;
string connection = kvp.Key;
Stream transactionData = new MemoryStream();
// iterate through each of the pending tag updates for one server
foreach (string tag in kvp.Value)
{
foreach (string tag in kvp.Value) {
///it would be the same transaction sender that would
///return each time
transactionSender = myGetOrBuildSender(tag);
@@ -372,7 +321,7 @@ namespace BCG
// update internal state
myState.publish(waiting.tag, waiting.tagType, data);
// add a pubsub header and copy each message to the transactionData stream
waiting.writeTo(transactionData, connection, publishingApp);
waiting.write_to(transactionData, connection, publishingApp);
}
// now transactionData holds all the updates for all the tags
// that are to be sent to the PubSub represented by transactionSender
@@ -384,36 +333,33 @@ namespace BCG
transactionData.Position = 0;
// send the entire thing to the specific pubsub server.
transactionSender.send(new PubSubMessage(new MetaData(tMd), transactionData).toStream());
// this is where the data is actually sent out !
var ps_msg = new PubSubMessage(new MetaData(tMd), transactionData);
Console.WriteLine($"serverConn.send metadata: {ps_msg.meta_data}");
bts.Log.Gen.info($"StaticPublisherCore.send ps_msg: {ps_msg}");
transactionSender.send(ps_msg);
}
}
myWaitingInTransactionMessages.Clear();
}
}
protected virtual void myPublish(string tagType, string tag, Stream content)
{
if (myInTransaction)
{
protected virtual void myPublish(string tagType, string tag, Stream content) {
bts.Log.Gen.info($"StaticPublisherCore.myPublish tag: {tag} content: {content.Position} / {content.Length} myInTransaction: {myInTransaction}");
if (myInTransaction) {
///if its in transaction message is cached, and is sent
///only when theres a commit or abort
if (!myWaitingInTransactionMessages.ContainsKey(tag))
myWaitingInTransactionMessages.Add(tag, new TagWaitingInTransaction(tagType, tag));
myWaitingInTransactionMessages[tag].addPub(content);
}
else
{
//if (CrushedTagManager.instance.isTagCrushable(tag))
myWaitingInTransactionMessages[tag].add_pub(content);
} else {
{
myState.publish(tag, tagType, content);
if (!myCrushableTagsWaitingOnAck.ContainsKey(tag))
{
// BlueEventLog.logEvent("Sending crushable tag " + tag, BlueEventLevel.Diagnosis);
if (!myCrushableTagsWaitingOnAck.ContainsKey(tag)) {
bts.Log.Gen.info("Sending crushable tag: {tag}");
mySendData(tag, tagType, content);
}
else
{
// BlueEventLog.logEvent("Could not send tag " + tag + " since its waiting on an ack", BlueEventLevel.Diagnosis);
} else {
bts.Log.Gen.info("Could not send tag: {tag} since its waiting on an ack");
myCrushableTagsWaitingOnAck[tag].second++;
}
}
@@ -428,64 +374,60 @@ namespace BCG
}
// add header, possibly compress the data, and sendto appropriate pubsub
private void mySendData(string tag, string tagType, Stream content)
{
private void mySendData(string tag, string tagType, Stream content) {
bts.Log.Gen.info($"StaticPublisherCore.mySendData tag: {tag} tagType: {tagType}");
long initPos = content.Position;
// locate right pubsub for this tag
IPubSubServerConnection serverConn = myGetOrBuildSender(tag);
Stream contentToPublish = content;
PubMetaData pubMd;
PubMetaData pub_md;
if (PubSub3Config.instance.isTagCompressed(tag))
{
if (PubSub3Config.instance.isTagCompressed(tag)) {
contentToPublish = new MemoryStream();
SharpZipCompressor Kompressor = new SharpZipCompressor();
Kompressor.compress(content, contentToPublish);
contentToPublish.Position = 0;
pubMd = new PubMetaData(tagType, tag, (int)contentToPublish.Length, (int)content.Length, serverConn.serverURL, ClientInfo.thisClient.processString);
if (PubSub3Config.instance.shouldReportTagsCompressionRatio(tag))
{
pub_md = new PubMetaData(tagType, tag, (int)contentToPublish.Length, (int)content.Length, serverConn.serverURL, ClientInfo.thisClient.processString);
if (PubSub3Config.instance.shouldReportTagsCompressionRatio(tag)) {
string msg = String.Format("Compressed tag {0} from {1} to {2} bytes, for a ratio of {3}.", tag, content.Length, contentToPublish.Length, (float)content.Length / (float)contentToPublish.Length);
// BlueEventLog.logEvent(msg, PS3LogLevels.compressionRatio);
}
}
else
pubMd = new PubMetaData(tagType, tag, (int)content.Length, serverConn.serverURL, ClientInfo.thisClient.processString);
} else
pub_md = new PubMetaData(tagType, tag, (int)content.Length, serverConn.serverURL, ClientInfo.thisClient.processString);
content.Position = initPos;
if (CrushedTagManager.instance.isTagCrushable(tag))
{
if (CrushedTagManager.instance.is_tag_crushable(tag)) {
string refId = String.Empty;
Console.WriteLine("StaticPublisherCore.mySend serverConn.sendWithConfirmation tag: " + tag + " server: " + serverConn.serverURL);
serverConn.sendWithConfirmation((new PubSubMessage(new MetaData(pubMd), contentToPublish).toStream() as MemoryStream).ToArray(), ref refId);
// this is where the data is actually sent out (there are multiple sends)
PubSubMessage ps_msg = new PubSubMessage(new MetaData(pub_md), contentToPublish);
//Console.WriteLine($"serverConn.send_with_confirmation metadata: {ps_msg.meta_data}");
bts.Log.Gen.info($"serverConn.send_with_confirmation metadata: {ps_msg.meta_data}");
bts.Log.Gen.info($"StaticPublisherCore.send ps_msg: {ps_msg}");
serverConn.send_with_confirmation(ps_msg, ref refId);
myCrushableTagsWaitingOnAck.Add(tag, new Pair<string, int>(refId, 0));
}
else
{
Console.WriteLine("StaticPublisherCore.mySend serverConn.send tag: " + tag + " server: " + serverConn.serverURL);
serverConn.send(new PubSubMessage(new MetaData(pubMd), contentToPublish).toStream());
} else {
//Console.WriteLine("StaticPublisherCore.mySend serverConn.send tag: " + tag + " server: " + serverConn.serverURL);
// this is where the data is actually sent out
var ps_msg = new PubSubMessage(pub_md, contentToPublish);
bts.Log.Gen.info($"StaticPublisherCore.send ps_msg: {ps_msg}");
serverConn.send(ps_msg);
}
}
private void myClearState(string tag)
{
if (myTagToSender.ContainsKey(tag))
{
private void myClearState(string tag) {
if (myTagToSender.ContainsKey(tag)) {
myTagToSender.Remove(tag);
}
myState.clear(tag);
}
protected virtual IPubSubServerConnection myGetOrBuildSender(string tag)
{
if (!myTagToSender.ContainsKey(tag))
{
protected virtual IPubSubServerConnection myGetOrBuildSender(string tag) {
if (!myTagToSender.ContainsKey(tag)) {
string route = myRouter.getPubURLForTag(tag);
IPubSubServerConnection sender = myConnectionFactory.getConnection(route);
myTagToSender.Add(tag, sender);
if (!mySenders.Contains(sender))
{
if (!mySenders.Contains(sender)) {
mySenders.Add(sender);
sender.registerCallback(new ConnectionStatusChange(myHandleServerReboot));
sender.registerSendConfirmationCallback(new SendConfirmationDelegate(myOnSendConfirm));
@@ -497,15 +439,11 @@ namespace BCG
///in case of the server coming up, it publishes all the stored state
///for that server, back to it
protected void myHandleServerReboot(string serverURL, bool connection)
{
if (connection)
{
protected void myHandleServerReboot(string serverURL, bool connection) {
if (connection) {
string thisPublisherInfo = ClientInfo.thisClient.processString;
foreach (KeyValuePair<string, IPubSubServerConnection> p in myTagToSender)
{
if (p.Value.serverURL == serverURL)
{
foreach (KeyValuePair<string, IPubSubServerConnection> p in myTagToSender) {
if (p.Value.serverURL == serverURL) {
string tagType;
string tag = p.Key;
myCrushableTagsWaitingOnAck.Clear();
@@ -547,16 +485,12 @@ namespace BCG
/// of waiting for ack
/// </summary>
private Dictionary<string, Pair<string, int>> myCrushableTagsWaitingOnAck = new Dictionary<string, Pair<string, int>>();
private void myOnSendConfirm(string messageId, bool confirmed)
{
foreach (string tag in new List<string>(myCrushableTagsWaitingOnAck.Keys))
{
private void myOnSendConfirm(string messageId, bool confirmed) {
foreach (string tag in new List<string>(myCrushableTagsWaitingOnAck.Keys)) {
Pair<string, int> tagData = myCrushableTagsWaitingOnAck[tag];
if (messageId == tagData.first)
{
if (messageId == tagData.first) {
myCrushableTagsWaitingOnAck.Remove(tag);
if (tagData.second > 0)
{
if (tagData.second > 0) {
// BlueEventLog.logEvent("Missed sending " + tagData.second + " messages, sending latest message now", BlueEventLevel.Diagnosis);
/// this data was waiting on an
/// ack, need to resend it
@@ -0,0 +1,132 @@
using System;
using System.Linq.Expressions;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Spark.Core.Reactive;
using System.Security.Cryptography.X509Certificates;
using BCG;
namespace BCG
{
// This uses AsyncTCPConnection2's stateful async functions
public class SimpleTCPClientAsync : ITCPConnectionHandler, ITCPMessageHandler
{
AsyncTCPConnection2 _conn = null;
int _m_msgs_received = 0;
public static async Task start(string ip, int port)
{
SimpleTCPClientAsync c = new SimpleTCPClientAsync(ip, port);
c.connect();
}
public void connect()
{
Task.Run(async () => await TCPSocketUtils.connect_to_server_async("127.0.0.1", 12345, this, TimeSpan.FromSeconds(2)));
}
public void onConnection(ITCPConnection connection)
{
Console.WriteLine("SimpleTCPClientAsync.onConnection connected to server, starting task to send data in a loop");
connection.register(this);
// start sending data
Task.Run(async () =>
{
byte[] buff = new byte[1024];
for (int i = 0; i < buff.Length; i++)
{
buff[i] = (byte)i;
}
_conn = connection as AsyncTCPConnection2;
while (!_conn.isDisposed)
{
await _conn.send_async(buff);
await Task.Delay(100);
}
});
}
public void onData(RemoteMessage msg)
{
_m_msgs_received++;
Console.WriteLine($"SimpleTCPClientAsync.onData n_msgs: {_m_msgs_received} msg: {msg}");
if (msg.messageType == RemoteMessageType.Disconnection)
{
connect();
}
}
public bool isDisposed { get { return false; } }
public void Dispose() { }
public SimpleTCPClientAsync(string ip, int port) { }
}
public class SimpleTCPClient : ITCPConnectionHandler, ITCPMessageHandler
{
private int _n_msgs_received = 0;
AsyncTCPConnection2 _conn = null;
public static void start(string ip, int port)
{
SimpleTCPClient c = new SimpleTCPClient(ip, port);
c.connect();
}
public void connect()
{
Console.WriteLine("SimpleTCPClient.onConnection connect() called");
ClientToServerManagedTCPConnector.connect_to(new BlutoSubAddress("bluto://127.0.0.1:12345"), this, TimeSpan.FromSeconds(1));
}
public void onConnection(ITCPConnection connection)
{
_conn = connection as AsyncTCPConnection2;
Console.WriteLine("SimpleTCPClient.onConnection connected to server, starting task to send data in a loop");
_conn.register(this);
byte[] buff = new byte[1024];
for (int i = 0; i < buff.Length; i++)
{
buff[i] = (byte)i;
}
while (!_conn.isDisposed)
{
_conn.send(buff);
System.Threading.Thread.Sleep(1000);
}
// Task.Run(async () =>
// {
// while (!_conn.isDisposed)
// {
// await _conn.send_async(buff);
// await Task.Delay(100);
// }
// });
}
public void onData(RemoteMessage msg)
{
_n_msgs_received++;
Console.WriteLine($"SimpleTCPClient.onData messages received: {_n_msgs_received} msg: {msg} messages received: {_n_msgs_received}");
if (msg.messageType == RemoteMessageType.Disconnection)
{
connect();
}
}
public bool isDisposed { get { return false; } }
public void Dispose() { }
public SimpleTCPClient(string ip, int port) { }
}
}
@@ -0,0 +1,123 @@
using BCG;
using Google.Protobuf;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using BCG;
using System.Xml.Serialization;
using System.Reflection;
using System.Data;
using System.Collections.Generic;
namespace BCG
{
public class SimpleTCPServerAsync : ITCPConnectionHandler, ITCPMessageHandler
{
int _n_msgs_received = 0;
SingleServerToClientManagedTCPConnectionAcceptor _acceptor = new SingleServerToClientManagedTCPConnectionAcceptor();
IDictionary<RemoteConnectionInfo, ITCPConnection> _conn_map = new Dictionary<RemoteConnectionInfo, ITCPConnection>();
public static async Task start()
{
Console.WriteLine("SimpleTCPServer.start accepting socket connections");
SimpleTCPServerAsync s = new SimpleTCPServerAsync();
//await AsyncTCPConnection2.accept_connections("127.0.0.1", 12345, s, TimeSpan.FromMilliseconds(100));
s.accept();
}
// public static async Task init()
// {
// }
public void accept()
{
_acceptor.accept_on_port(this, "127.0.0.1", 12345, TimeSpan.Zero);
}
public void onConnection(ITCPConnection connection)
{
AsyncTCPConnection2 new_conn = connection as AsyncTCPConnection2;
RemoteConnectionInfo rci = new_conn.get_peer_address();
_conn_map.Add(rci, new_conn);
Console.WriteLine($"SimpleTCPServerAsync.onConnection new client connected conn: {rci}");
new_conn.register(this);
}
public void onData(RemoteMessage msg)
{
Console.WriteLine($"SimpleTCPServerAsync.onData msg: {msg}");
RemoteConnectionInfo rci = msg.remoteConnectionInfo;
ITCPConnection this_conn;
bool found = _conn_map.TryGetValue(rci, out this_conn);
if (!found)
{
Console.WriteLine("Could not find connection !!!!!!");
return;
}
_n_msgs_received++;
Console.WriteLine($"SimpleTCPServerAsync.onData msgs_received: {_n_msgs_received} msg: {msg} ci: {rci} echoing it back");
if (msg.messageType == RemoteMessageType.Data)
{
this_conn.send(msg.message);
// Task.Run(async () => {
// Console.WriteLine($"SimpleTCPServerAsync.onData sending msg: {msg} to client");
// await _conn.send_async(msg.message);
// });
}
}
public bool isDisposed { get { return false; } }
public void Dispose() { }
}
// public class SimpleTCPServer : ITCPConnectionHandler, ITCPMessageHandler {
// private AsyncTCPConnection2 _conn = null;
// private int _n_msgs_received = 0;
// SingleServerToClientManagedTCPConnectionAcceptor _acceptor = new SingleServerToClientManagedTCPConnectionAcceptor();
// public static async Task start() {
// Console.WriteLine("SimpleTCPServer.start accepting socket connections");
// SimpleTCPServer s = new SimpleTCPServer();
// s.accept();
// //await AsyncTCPConnection2.accept_connections("127.0.0.1", 12345, s, TimeSpan.FromMilliseconds(100));
// }
// public void accept() {
// _acceptor.accept_on_port(this, "127.0.0.1", 12345, TimeSpan.Zero);
// }
// public void onConnection(ITCPConnection connection) {
// Console.WriteLine("SimpleTCPServerAsync.onConnection new client connected");
// _conn = connection as AsyncTCPConnection2;
// connection.register(this);
// }
// public async void onData(RemoteMessage msg) {
// _n_msgs_received++;
// Console.WriteLine($"SimpleTCPServerAsync.onData msg: {msg} , msgs received: {_n_msgs_received} echoing it back");
// if (msg.messageType == RemoteMessageType.data && _conn != null) {
// Task.Run(async () => {
// //Console.WriteLine($"SimpleTCPServerAsync.onData sending msg: {msg} to client");
// //await _conn.send_async(msg.message);
// _conn.send(msg.message);
// });
// }
// }
// public bool isDisposed { get { return false; } }
// public void Dispose() { }
// }
}
@@ -0,0 +1,52 @@
using BCG;
using bts;
using System;
using System.IO;
using System.Runtime.Serialization;
namespace BCG {
public class TestPubItem : IPubItem {
int i = 100;
public static string test_tag = "TestTag";
public string getTag() {
return test_tag;
}
public void to_stream(Stream str) {
BinaryWriter bw = new BinaryWriter(str);
//bw.Write(d);
bw.Write(i);
}
}
public class TestPublisher {
TestPubItem _tbi = new TestPubItem();
IPublisherCore pcore = new StaticPublisherCore();
bool _hit_key_to_send = false;
public TestPublisher(bool hit_key_to_send) {
_hit_key_to_send = hit_key_to_send;
bts.Log.Gen.info($"Started TestPubliser _hit_key_to_send: {_hit_key_to_send}");
}
public void keep_publishing(TimeSpan wait_per, int n_pubs = System.Int32.MaxValue) {
TestPubItem pi = new TestPubItem();
for (int i = 0; i < n_pubs; i++) {
if (_hit_key_to_send) {
Console.WriteLine("Hit key to send data");
Console.ReadLine();
}
MemoryStream ms = new MemoryStream();
pi.to_stream(ms);
ms.Position = 0;
pcore.beginTransaction();
pcore.publish(TestPubItem.test_tag, ms);
pcore.commitTransaction();
if (!_hit_key_to_send)
System.Threading.Thread.Sleep(wait_per);
}
}
}
}
@@ -0,0 +1,31 @@
using BCG;
using bts;
using System;
using System.IO;
using System.Runtime.Serialization;
namespace BCG {
public class TestSubscriber {
SubscriberCore _sub_core = new SubscriberCore();
public TestSubscriber() {
bts.Log.Gen.info("Started TestSubscriber");
}
public void keep_polling(TimeSpan wait_per, int n_polls = System.Int32.MaxValue) {
_sub_core.subscribe(TestPubItem.test_tag);
for (int i = 0; i < n_polls; i++) {
var list = _sub_core.getUpdates();
if (list.Count > 0) {
Console.WriteLine($"Received {list.Count} items");
}
foreach (var p in list) {
Console.WriteLine($"Received item: {p} iter: {i}");
}
System.Threading.Thread.Sleep(wait_per);
}
}
}
}
+11 -12
View File
@@ -1,22 +1,24 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
//using BCG.Utilities;
//using BCG.Utilities.General;
namespace BCG
{
class PubSub2Main
{
namespace BCG {
class PubSub2Main {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main(string[] args)
{
public static async Task Main(string[] args) {
bts.utils.BTSNativeMethods.provide_command_line(new string[] { }, 0);
mbts.config.Configuration.initialize();
// SimpleTCPServerAsync.start();
// Task.Delay(1000000000).Wait();
if (args.Length > 0 && args[0] == "daemon")
args = args.Skip(1).ToArray();
@@ -26,14 +28,11 @@ namespace BCG
long currentMemory = 0;
int defaultWaitTime = 100;
bool gced = false;
new Thread(() =>
{
while (true)
{
new Thread(() => {
while (true) {
gced = false;
currentMemory = GC.GetTotalMemory(false);
if (config.PS3_GCActivationThreshold > 0 && currentMemory > config.PS3_GCActivationThreshold)
{
if (config.PS3_GCActivationThreshold > 0 && currentMemory > config.PS3_GCActivationThreshold) {
string gcMsg = String.Format("GCing memory, mem before GC = {0}", currentMemory);
// BlueEventLog.logEvent(gcMsg, PS3LogLevels.info);
Console.WriteLine(gcMsg);
@@ -1,19 +0,0 @@
syntax = "proto3";
package Bts.DataStream;
option csharp_namespace = "Bts.DataStream";
message DataStreamConfig {
repeated string assemblies = 1;
bool use_static_parser = 2;
bool log_blob_packets = 3;
bool is_test_mode = 4;
bool profile_streams = 5;
double profile_threshold = 6;
bool use_new_filter = 7;
bool use_new_map = 8;
bool use_increments_for_multiple_ops = 9;
bool use_uncopied_new_rows_in_fire = 10;
bool use_modularized_data_stream_bridge = 11;
}