bingo/sqlserver/Source/BingoIndexData.cs (382 lines of code) (raw):

using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.Data.SqlClient; using System.Resources; using System.Reflection; namespace indigo { public abstract class BingoIndexData { public BingoIndexID id; public string id_column; public string data_column; public string bingo_schema; public BingoFingerprints fingerprints; public BingoStorage storage; public enum IndexType { Molecule, Reaction } public bool keep_cache; public bool locked = false; public BingoIndexData (BingoIndexID id, string id_column, string data_column, string bingo_schema) { this.id = id; this.id_column = id_column; this.data_column = data_column; this.bingo_schema = bingo_schema; keep_cache = false; fingerprints = new BingoFingerprints(this); storage = new BingoStorage(this); } private static BingoIndexData _extractIndexData (SqlConnection conn, string bingo_schema, BingoIndexID id, bool throw_if_not_exists) { BingoIndexData data = null; using (SqlCommand cmd = new SqlCommand(String.Format( "SELECT id_column, data_column, type FROM {0} WHERE obj_id = '{1}'", _contextTable(bingo_schema), id.table_id), conn)) { using (SqlDataReader reader = cmd.ExecuteReader()) { if (!reader.Read()) { if (throw_if_not_exists) throw new Exception("Cannot find Bingo index for table with id=" + id.table_id); else return null; } string id_column = Convert.ToString(reader[0]); string data_column = Convert.ToString(reader[1]); string type = Convert.ToString(reader[2]); if (type.ToLower().Equals("molecule")) data = new MangoIndexData(id, id_column, data_column, bingo_schema); if (type.ToLower().Equals("reaction")) data = new RingoIndexData(id, id_column, data_column, bingo_schema); if (data == null) throw new Exception("unknown type: " + type); } } data.keep_cache = (BingoConfig.getInt(conn, bingo_schema, "KEEP_CACHE", id.table_id) != 0); return data; } public abstract IndexType getIndexType (); private static string _contextTable (string bingo_schema) { return "[" + bingo_schema + "].CONTEXT"; } public class BingoIndexDataRefs { public BingoIndexData index_data; public List<int> session_ids; } private static object index_data_list_lock = new Object(); private static ArrayList index_data_list = new ArrayList(); public static BingoIndexData CreateIndexData (int spid, SqlConnection conn, string bingo_schema, string table, string id_column, string data_column, bool reaction) { lock (index_data_list_lock) { BingoIndexID id = new BingoIndexID(conn, table); _DropIndexData(conn, bingo_schema, id, false); BingoIndexData data; if (reaction) data = new RingoIndexData(id, id_column, data_column, bingo_schema); else data = new MangoIndexData(id, id_column, data_column, bingo_schema); BingoSqlUtils.ExecNonQuery(conn, "INSERT INTO {0} VALUES({1}, {2}, '{3}', '{4}', '{5}', '{6}')", _contextTable(bingo_schema), id.table_id, id.database_id, id.FullTableName(conn), id_column, data_column, reaction ? "reaction" : "molecule"); data.CreateTables(conn); _AddIndexDataToList(spid, data); BingoLog.logMessage("Bingo index for table {0} has been initialized", id.FullTableName(conn)); return data; } } public static void DropIndexData (SqlConnection conn, string bingo_schema, string table, bool throw_if_not_exists) { BingoIndexID id = new BingoIndexID(conn, table); DropIndexData(conn, bingo_schema, id, throw_if_not_exists); } public static void DropIndexData (SqlConnection conn, string bingo_schema, BingoIndexID id, bool throw_if_not_exists) { lock (index_data_list_lock) { _DropIndexData(conn, bingo_schema, id, throw_if_not_exists); } } private static void _DropIndexData (SqlConnection conn, string bingo_schema, BingoIndexID id, bool throw_if_not_exists) { BingoIndexData data = _extractIndexData(conn, bingo_schema, id, throw_if_not_exists); if (data != null) { data.DropTables(conn); data.DropTriggers(conn); } BingoSqlUtils.ExecNonQueryNoThrow(conn, "DELETE FROM {0} WHERE obj_id = '{1}'", _contextTable(bingo_schema), id.table_id); for (int i = index_data_list.Count - 1; i >= 0; i--) { BingoIndexDataRefs refs = (BingoIndexDataRefs)index_data_list[i]; if (refs.index_data.id.Equals(id)) { index_data_list.RemoveAt(i); BingoLog.logMessage("Sessions for table {0} have been released", id.InformationName(conn)); } } if (data != null) BingoLog.logMessage("Bingo index for table {0} has been dropped", id.InformationName(conn)); } public static BingoIndexData GetIndexData (SqlConnection conn, string bingo_schema, int table_id, int database_id, int spid) { BingoIndexID id = new BingoIndexID(table_id, database_id); return GetIndexDataById(conn, bingo_schema, id, spid); } public static BingoIndexData GetIndexData (SqlConnection conn, string bingo_schema, string table, int spid) { BingoIndexID id = new BingoIndexID(conn, table); return GetIndexDataById(conn, bingo_schema, id, spid); } private static BingoIndexData GetIndexDataById (SqlConnection conn, string bingo_schema, BingoIndexID id, int spid) { lock (index_data_list_lock) { foreach (BingoIndexDataRefs index_data_refs in index_data_list) { if (index_data_refs.index_data.id.Equals(id)) { if (!index_data_refs.session_ids.Contains(spid)) { BingoLog.logMessage("Existing BingoIndexData added for spid={0} table={1}", spid, id.FullTableName(conn)); index_data_refs.session_ids.Add(spid); } return index_data_refs.index_data; } } BingoLog.logMessage("Extracting new BingoIndexData for spid={0} table={1}", spid, id.FullTableName(conn)); BingoIndexData data = _extractIndexData(conn, bingo_schema, id, true); _AddIndexDataToList(spid, data); return data; } } private static void _AddIndexDataToList (int spid, BingoIndexData data) { BingoIndexDataRefs new_refs = new BingoIndexDataRefs(); new_refs.index_data = data; new_refs.session_ids = new List<int>(); new_refs.session_ids.Add(spid); index_data_list.Add(new_refs); } class TableWithId { public string table_name { get; set; } public int id { get; set; } }; public static void DropAllIndices (SqlConnection conn, string bingo_schema, bool only_invalid) { List<TableWithId> tables = new List<TableWithId>(); using (SqlCommand cmd = new SqlCommand(String.Format( "SELECT full_table_name, obj_id FROM {0}", _contextTable(bingo_schema)), conn)) { cmd.CommandTimeout = 3600; using (SqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { string full_table_name = Convert.ToString(reader[0]); int table_id = Convert.ToInt32(reader[1]); tables.Add(new TableWithId() { table_name = full_table_name, id = table_id } ); } } } foreach (TableWithId table in tables) { if (only_invalid) { object ret = BingoSqlUtils.ExecObjQuery(conn, "SELECT OBJECT_NAME({0})", table.id); if (ret != null) continue; } DropIndexData(conn, bingo_schema, table.table_name, false); } } public static void FlushInAllSessions (int spid, bool check_spid) { lock (index_data_list_lock) { SqlConnection ctx_conn = null; try { for (int i = index_data_list.Count - 1; i >= 0; i--) { BingoIndexDataRefs refs = (BingoIndexDataRefs)index_data_list[i]; if (check_spid && !refs.session_ids.Contains(spid)) continue; if (!refs.index_data.needFlush()) continue; if (ctx_conn == null) { ctx_conn = new SqlConnection("context connection=true"); ctx_conn.Open(); } refs.index_data.flush(ctx_conn); } } finally { if (ctx_conn != null) ctx_conn.Close(); } } } public static void OnSessionClose (int spid) { FlushInAllSessions(spid, true); lock (index_data_list_lock) { for (int i = index_data_list.Count - 1; i >= 0; i--) { BingoIndexDataRefs refs = (BingoIndexDataRefs)index_data_list[i]; refs.session_ids.Remove(spid); if (refs.session_ids.Count < 1 && !refs.index_data.keep_cache) { index_data_list.RemoveAt(i); BingoLog.logMessage("Session for table {0} has been released", refs.index_data.id.InformationName()); } } } } public virtual void CreateTables (SqlConnection conn) { storage.createTables(conn); fingerprints.createTables(conn); } public virtual void DropTables (SqlConnection conn) { storage.dropTables(conn); fingerprints.dropTables(conn); } public virtual bool needFlush() { if (storage.needFlush() || fingerprints.needFlush()) return true; return false; } public virtual void flush (SqlConnection conn) { storage.flush(conn); fingerprints.flush(conn); } public virtual void prepareForDeleteRecord (SqlConnection conn) { } public void CreateTriggers (SqlConnection conn) { string cur_db_name = null; try { cur_db_name = BingoSqlUtils.ExecStringQuery(conn, "SELECT DB_NAME()"); BingoSqlUtils.ExecNonQueryNoThrow(conn, "USE {0}", id.DatabaseName(conn)); string bingo_db_schema = cur_db_name + "." + bingo_schema; string full_name = id.FullTableName(conn); object[] trigger_params = new object[] { null, full_name, id_column, data_column, bingo_db_schema, id.table_id, id.database_id }; trigger_params[0] = GetTriggerName("Insert", conn, cur_db_name); string insert_trigger = String.Format(resource.OnInsertTrigger, trigger_params); BingoSqlUtils.ExecNonQuery(conn, "{0}", insert_trigger); trigger_params[0] = GetTriggerName("Delete", conn, cur_db_name); string delete_trigger = String.Format(resource.OnDeleteTrigger, trigger_params); BingoSqlUtils.ExecNonQuery(conn, "{0}", delete_trigger); trigger_params[0] = GetTriggerName("Update", conn, cur_db_name); string update_trigger = String.Format(resource.OnUpdateTrigger, trigger_params); BingoSqlUtils.ExecNonQuery(conn, "{0}", update_trigger); } finally { if (cur_db_name != null) BingoSqlUtils.ExecNonQueryNoThrow(conn, "USE {0}", cur_db_name); } } public void DropTriggers (SqlConnection conn) { string cur_db_name = null; try { cur_db_name = BingoSqlUtils.ExecStringQuery(conn, "SELECT DB_NAME()"); BingoSqlUtils.ExecNonQueryNoThrow(conn, "USE {0}", id.DatabaseName(conn)); BingoSqlUtils.ExecNonQueryNoThrow(conn, "DROP TRIGGER {0}", GetTriggerName("Insert", conn, cur_db_name)); BingoSqlUtils.ExecNonQueryNoThrow(conn, "DROP TRIGGER {0}", GetTriggerName("Delete", conn, cur_db_name)); BingoSqlUtils.ExecNonQueryNoThrow(conn, "DROP TRIGGER {0}", GetTriggerName("Update", conn, cur_db_name)); } finally { if (cur_db_name != null) BingoSqlUtils.ExecNonQueryNoThrow(conn, "USE {0}", cur_db_name); } } public virtual void deleteRecordById (int id, SqlConnection conn) { int? storage_id = getStorageIdById(conn, id); if (!storage_id.HasValue) // Such molecule wasn't added to the molecule // index because it might be invalid return; storage.deleteRecord(storage_id.Value, conn); BingoSqlUtils.ExecNonQuery(conn, "DELETE from {0} where id={1}", shadowTable, id); } public virtual void createIndices (SqlConnection conn) { } private string GetTriggerName (string operation, SqlConnection conn, string bingo_db) { return String.Format("{0}.[bingo_{1}_{2}_{3}]", id.SchemaName(conn), bingo_db, id.table_id, operation); } public string fingerprintsTable { get { return "[" + bingo_schema + "].fingerprints_" + id.table_id; } } public string fingerprintBitsTable { get { return "[" + bingo_schema + "].fingerprint_bits_" + id.table_id; } } public string storageTable { get { return "[" + bingo_schema + "].storage_" + id.table_id; } } public string shadowTable { get { return "[" + bingo_schema + "].shadow_" + id.table_id; } } public void syncContextParameters (SqlConnection conn, string bingo_schema) { fingerprints.syncContextParameters(getIndexType() == IndexType.Reaction); keep_cache = (BingoConfig.getInt(conn, bingo_schema, "KEEP_CACHE", id.table_id) != 0); } public void setKeepCache (SqlConnection conn, string bingo_schema, bool keep) { if (keep_cache != keep) { keep_cache = keep; BingoConfig.setInt(conn, bingo_schema, "KEEP_CACHE", id.table_id, keep ? 1 : 0); BingoLog.logMessage("SetKeepCache has changed for {0} table. New value is {1}", id.FullTableName(conn), keep); } } public int? getStorageIdById (SqlConnection conn, int id) { return BingoSqlUtils.ExecIntQuery(conn, "SELECT storage_id from {0} where id={1}", shadowTable, id); } } }