bingo/sqlserver/Source/MangoIndexData.cs (244 lines of code) (raw):

using System; using System.Collections.Generic; using System.Text; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using System.Globalization; namespace indigo { public class MangoIndexData : BingoIndexData { object _sync_object = new Object(); public MangoIndexData (BingoIndexID id, string id_column, string data_column, string bingo_schema) : base(id, id_column, data_column, bingo_schema) { } public override IndexType getIndexType () { return IndexType.Molecule; } public override void CreateTables (SqlConnection conn) { base.CreateTables(conn); StringBuilder cmd = new StringBuilder(); // Create shadow table cmd.AppendFormat(@"CREATE TABLE {0} (id int not null, storage_id int not null, gross VARCHAR(500), cmf varbinary(max), xyz varbinary(max), mass real not null, fragments int not null", shadowTable); for (int i = 0; i < MangoIndex.COUNTED_ELEMENTS_COUNT; i++) cmd.AppendFormat(", {0} int not null", BingoCore.mangoGetCountedElementName(i)); cmd.Append(")"); BingoSqlUtils.ExecNonQuery(conn, cmd.ToString()); // Create shadow table for molecule components BingoSqlUtils.ExecNonQuery(conn, "CREATE TABLE {0} (id int not null, hash int not null, count int not null, primary key(id, hash))", componentsTable); } public override void createIndices (SqlConnection conn) { BingoSqlUtils.ExecNonQuery(conn, "ALTER TABLE {0} ADD PRIMARY KEY (storage_id)", shadowTable); BingoSqlUtils.ExecNonQuery(conn, "CREATE UNIQUE INDEX id ON {0}(id)", shadowTable); BingoSqlUtils.ExecNonQuery(conn, "CREATE INDEX gross ON {0}(gross)", shadowTable); BingoSqlUtils.ExecNonQuery(conn, "CREATE INDEX mass ON {0}(mass)", shadowTable); for (int i = 0; i < MangoIndex.COUNTED_ELEMENTS_COUNT; i++) { BingoSqlUtils.ExecNonQuery(conn, "CREATE INDEX {1} ON {0}({1})", shadowTable, BingoCore.mangoGetCountedElementName(i)); } // Create indices for components shadow table BingoSqlUtils.ExecNonQuery(conn, "CREATE INDEX id ON {0}(id)", componentsTable); BingoSqlUtils.ExecNonQuery(conn, "CREATE INDEX hash ON {0}(hash)", componentsTable); BingoSqlUtils.ExecNonQuery(conn, "CREATE INDEX count ON {0}(hash, count)", componentsTable); } public override void DropTables (SqlConnection conn) { base.DropTables(conn); BingoSqlUtils.ExecNonQueryNoThrow(conn, "DROP TABLE " + shadowTable); BingoSqlUtils.ExecNonQueryNoThrow(conn, "DROP TABLE " + componentsTable); } DataTable shadow_datatable = null; DataTable components_datatable = null; public void addToShadowTable (SqlConnection conn, MangoIndex index, int id, int storage_id) { lock (_sync_object) { if (shadow_datatable == null) _createDataTables(); if (shadow_datatable.Rows.Count >= 10000) _flushShadowTable(conn); DataRow shadow_row = shadow_datatable.NewRow(); shadow_row["id"] = id; shadow_row["storage_id"] = storage_id; shadow_row["gross"] = index.gross; shadow_row["cmf"] = index.cmf; shadow_row["xyz"] = index.xyz; shadow_row["mass"] = index.mass; int fragments_count = 0; for (int i = 0; i < index.hash.elements.Count; i++) fragments_count += index.hash.elements[i].count; shadow_row["fragments"] = fragments_count; string[] counted = index.counted_elements_str.Split(','); for (int i = 0; i < MangoIndex.COUNTED_ELEMENTS_COUNT; i++) shadow_row[BingoCore.mangoGetCountedElementName(i)] = Convert.ToInt32(counted[i + 1]); shadow_datatable.Rows.Add(shadow_row); foreach (MoleculeHashElement elem in index.hash.elements) { DataRow comp_row = components_datatable.NewRow(); comp_row["id"] = id; comp_row["hash"] = elem.hash; comp_row["count"] = elem.count; components_datatable.Rows.Add(comp_row); } } } private void _createDataTables () { shadow_datatable = new DataTable(); DataColumnCollection sc = shadow_datatable.Columns; sc.Add(new DataColumn("id", Type.GetType("System.Int32"))); sc.Add(new DataColumn("storage_id", Type.GetType("System.Int32"))); sc.Add(new DataColumn("gross", Type.GetType("System.String"))); sc.Add(new DataColumn("cmf", Type.GetType("System.Array"))); sc.Add(new DataColumn("xyz", Type.GetType("System.Array"))); sc.Add(new DataColumn("mass", Type.GetType("System.Single"))); sc.Add(new DataColumn("fragments", Type.GetType("System.Int32"))); for (int i = 0; i < MangoIndex.COUNTED_ELEMENTS_COUNT; i++) sc.Add(new DataColumn(BingoCore.mangoGetCountedElementName(i), Type.GetType("System.Int32"))); components_datatable = new DataTable(); DataColumnCollection cc = components_datatable.Columns; cc.Add(new DataColumn("id", Type.GetType("System.Int32"))); cc.Add(new DataColumn("hash", Type.GetType("System.Int32"))); cc.Add(new DataColumn("count", Type.GetType("System.Int32"))); } public override bool needFlush() { lock (_sync_object) { if (base.needFlush()) return true; return shadow_datatable != null && (shadow_datatable.Rows.Count > 0 || components_datatable.Rows.Count > 0); } } public override void flush(SqlConnection conn) { lock (_sync_object) { base.flush(conn); _flushShadowTable(conn); } } private void _flushShadowTable (SqlConnection conn) { if (shadow_datatable == null || (shadow_datatable.Rows.Count == 0 && components_datatable.Rows.Count == 0)) return; if (conn.ConnectionString == "context connection=true") { // SqlBulkInsert cannot be used in the context connection _flushShadowTableInContext(conn); return; } BingoTimer timer = new BingoTimer("shadow_table.flush"); using (SqlTransaction transaction = conn.BeginTransaction()) { // Copy shadow table using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.TableLock, transaction)) { bulkCopy.DestinationTableName = shadowTable; foreach (DataColumn dc in shadow_datatable.Columns) bulkCopy.ColumnMappings.Add(dc.ColumnName, dc.ColumnName); bulkCopy.BatchSize = shadow_datatable.Rows.Count; bulkCopy.BulkCopyTimeout = 3600; bulkCopy.WriteToServer(shadow_datatable); } shadow_datatable.Rows.Clear(); // Copy components table using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.TableLock, transaction)) { bulkCopy.DestinationTableName = componentsTable; foreach (DataColumn dc in components_datatable.Columns) bulkCopy.ColumnMappings.Add(dc.ColumnName, dc.ColumnName); bulkCopy.BatchSize = components_datatable.Rows.Count; bulkCopy.BulkCopyTimeout = 3600; bulkCopy.WriteToServer(components_datatable); } components_datatable.Rows.Clear(); transaction.Commit(); } timer.end(); } private void _flushShadowTableInContext (SqlConnection conn) { foreach (DataRow row in shadow_datatable.Rows) { using (SqlCommand cmd = new SqlCommand()) { cmd.CommandTimeout = 3600; StringBuilder cmd_text = new StringBuilder(); cmd_text.AppendFormat("INSERT INTO {0} VALUES ", shadowTable); cmd_text.AppendFormat(CultureInfo.InvariantCulture, "({0}, {1}, '{2}', @cmf, @xyz, {3}, {4} ", row["id"], row["storage_id"], row["gross"], row["mass"], row["fragments"]); for (int i = 0; i < MangoIndex.COUNTED_ELEMENTS_COUNT; i++) cmd_text.AppendFormat(", {0}", row[BingoCore.mangoGetCountedElementName(i)]); cmd_text.Append(")"); cmd.Parameters.AddWithValue("@cmf", new SqlBinary((byte[])row["cmf"])); cmd.Parameters.AddWithValue("@xyz", new SqlBinary((byte[])row["xyz"])); cmd.Connection = conn; cmd.CommandText = cmd_text.ToString(); cmd.ExecuteNonQuery(); } } shadow_datatable.Rows.Clear(); foreach (DataRow row in components_datatable.Rows) { using (SqlCommand cmd = new SqlCommand()) { cmd.CommandTimeout = 3600; StringBuilder cmd_text = new StringBuilder(); cmd_text.AppendFormat("INSERT INTO {0} VALUES ", componentsTable); cmd_text.AppendFormat("({0}, {1}, {2}) ", row["id"], row["hash"], row["count"]); cmd.Connection = conn; cmd.CommandText = cmd_text.ToString(); cmd.ExecuteNonQuery(); } } components_datatable.Rows.Clear(); } public byte[] getXyz (int storage_id, SqlConnection conn) { object ret = BingoSqlUtils.ExecObjQuery(conn, "SELECT xyz from {0} where storage_id={1}", shadowTable, storage_id); return (byte[])ret; } public override void prepareForDeleteRecord (SqlConnection conn) { lock (_sync_object) { _flushShadowTable(conn); } } public override void deleteRecordById (int id, SqlConnection conn) { lock (_sync_object) { base.deleteRecordById(id, conn); BingoSqlUtils.ExecNonQuery(conn, "DELETE from {0} where id={1}", componentsTable, id); } } public string componentsTable { get { return "[" + bingo_schema + "].components_" + id.table_id; } } } }