/// <summary> /// disconnect removes a connection to the database, a connection /// which was previously established via Raft consensus. /// </summary> /// <param name="c"></param> internal async Task disconnect(StoreConnection c) { var cmd = new Command { Typ = CommandType.disconnect, Sub = new connectionSub { ConnID = c.ID } }; await raft.Accept(cmd).ThrowOnError(); stats.NumDisconnects.WriteMetric(1); }
/// <summary> /// Connection returns the connection for the given ID. /// </summary> /// <param name="id"></param> /// <param name="conn"></param> /// <returns></returns> public bool Connection(ulong id, out StoreConnection conn) { connsMu.EnterReadLock(); try { return(conns.TryGetValue(id, out conn)); } finally { connsMu.ExitReadLock(); } }
/// <summary> /// Execute executes queries that return no rows, but do modify the database. If connection /// is nil then the utility connection is used. /// </summary> /// <param name="c"></param> /// <param name="ex"></param> /// <returns></returns> internal async Task <ExecuteResponse> execute(StoreConnection c, ExecuteRequest ex) { if (c == null) { connsMu.EnterReadLock(); try { c = conns[defaultConnID]; } finally { connsMu.ExitReadLock(); } } c.SetLastUsedNow(); var start = DateTime.Now; var cmd = new Command { Typ = CommandType.execute, Sub = new databaseSub { ConnID = c.ID, Atomic = ex.Atomic, Queries = ex.Queries, Timings = ex.Timings } }; var f = await raft.Accept(cmd).ThrowOnError(); if (f is FsmExecuteResponse <Command> ) { return(new ExecuteResponse { Results = (f as FsmExecuteResponse <Command>).Results, Time = (DateTime.Now - start).TotalSeconds, Raft = new RaftResponse { NodeID = ID } }); } else if (f is ErrorResponse <Command> ) { throw new Exception((f as ErrorResponse <Command>).Error); } else { throw new Exception("unsupported type"); } }
internal async Task <ExecuteResponse> executeOrAbort(StoreConnection c, ExecuteRequest ex) { if (c == null) { connsMu.EnterReadLock(); try { c = conns[defaultConnID]; } finally { connsMu.ExitReadLock(); } } bool errored = false; try { var f = await c.Store.execute(c, ex); errored = f.Results.Any(r => !string.IsNullOrEmpty(r.Error)); return(f); } catch (Exception e) { errored = true; c.Logger.LogError(e.ToString()); throw; } finally { if (errored) { try { await c.AbortTransaction(); } catch (Exception e) { c.Logger.LogWarning($"WARNING: failed to abort transaction on {c}: {e.Message}"); } } } }
/// <summary> /// Query executes queries that return rows, and do not modify the database. If /// connection is nil, then the utility connection is used. /// </summary> /// <param name="c"></param> /// <param name="qr"></param> /// <returns></returns> internal async Task <QueryResponse> query(StoreConnection c, QueryRequest qr) { if (c == null) { connsMu.EnterReadLock(); try { c = conns[defaultConnID]; } finally { connsMu.ExitReadLock(); } } c.SetLastUsedNow(); restoreMu.EnterReadLock(); try { var start = DateTime.Now; if (qr.Lvl == ConsistencyLevel.Strong) { var d = new databaseSub { ConnID = c.ID, Atomic = qr.Atomic, Queries = qr.Queries, Timings = qr.Timings }; var cmd = new Command { Typ = CommandType.query, Sub = d }; var f = await raft.Accept(cmd).ThrowOnError(); if (f is FsmQueryResponse <Command> ) { return(new QueryResponse { Rows = (f as FsmQueryResponse <Command>).Rows, Time = (DateTime.Now - start).TotalSeconds, Raft = new RaftResponse { NodeID = ID } }); } else if (f is ErrorResponse <Command> ) { throw new Exception((f as ErrorResponse <Command>).Error); } else { throw new Exception("unsupported type"); } } if (qr.Lvl == ConsistencyLevel.Weak && !(raft.State is Leader)) { throw new NotLeaderException(); } var r = c.db.Query(qr.Queries.ToArray(), qr.Atomic, qr.Timings); return(new QueryResponse { Rows = r, Time = (DateTime.Now - start).TotalSeconds }); } finally { restoreMu.ExitReadLock(); } }