DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
Session.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 
21 using Deveel.Data.Diagnostics;
22 using Deveel.Data.Security;
23 using Deveel.Data.Services;
24 using Deveel.Data.Sql;
26 
27 namespace Deveel.Data {
32  public sealed class Session : ISession {
33  private List<LockHandle> lockHandles;
34  private bool disposed;
35 
44  public Session(ITransaction transaction, User user) {
45  if (transaction == null)
46  throw new ArgumentNullException("transaction");
47 
48  if (user == null)
49  throw new ArgumentNullException("user");
50 
51  if (user.IsSystem || user.IsPublic)
52  throw new ArgumentException(String.Format("Cannot open a session for user '{0}'.", user.Name));
53 
54  Transaction = transaction;
55  Context = transaction.Context.CreateSessionContext();
56 
57  transaction.Database.Sessions.Add(this);
58 
59  User = user;
60  StartedOn = DateTimeOffset.UtcNow;
61  }
62 
64  Dispose(false);
65  }
66 
67  public void Dispose() {
68  Dispose(true);
69  GC.SuppressFinalize(this);
70  }
71 
72  public string CurrentSchema {
73  get { return Transaction.CurrentSchema(); }
74  }
75 
76  public DateTimeOffset? LastCommandTime { get; private set; }
77 
78  public DateTimeOffset StartedOn { get; private set; }
79 
80  public ISessionContext Context { get; private set; }
81 
82  public User User { get; private set; }
83 
85  get { return Transaction; }
86  }
87 
89  get { return Context; }
90  }
91 
92  IEnumerable<KeyValuePair<string, object>> IEventSource.Metadata {
93  get { return GetMetadata(); }
94  }
95 
96  private IEnumerable<KeyValuePair<string, object>> GetMetadata() {
97  return new Dictionary<string, object> {
99  { KnownEventMetadata.LastCommandTime, LastCommandTime },
100  { KnownEventMetadata.SessionStartTime, StartedOn },
101  };
102  }
103 
104  public ITransaction Transaction { get; private set; }
105 
106  private void AssertNotDisposed() {
107  if (disposed)
108  throw new ObjectDisposedException("Session");
109  }
110 
111  public void Access(IEnumerable<IDbObject> objects, AccessType accessType) {
112  if (Database == null)
113  return;
114 
115  lock (Database) {
116  var lockables = objects.OfType<ILockable>().ToArray();
117  if (lockables.Length == 0)
118  return;
119 
120  CheckAccess(lockables, accessType);
121 
122  var isolation = Transaction.Isolation;
123 
124  LockHandle handle;
125 
126  if (isolation == IsolationLevel.Serializable) {
127  handle = Database.Locker.Lock(lockables, AccessType.ReadWrite, LockingMode.Exclusive);
128  } else {
129  throw new NotImplementedException(string.Format("The locking for isolation '{0}' is not implemented yet.", isolation));
130  }
131 
132  if (handle != null) {
133  if (lockHandles == null)
134  lockHandles = new List<LockHandle>();
135 
136  lockHandles.Add(handle);
137  }
138  }
139  }
140 
141  public void Exit(IEnumerable<IDbObject> objects, AccessType accessType) {
142  // Only SERIALIZABLE isolation is supported, that means locks for read and write
143  // are acquired on access and released only at the end of the session/transaction
144  throw new NotImplementedException("The Exit mechanism is not implemented");
145  }
146 
147  public void Lock(IEnumerable<IDbObject> objects, AccessType accessType, LockingMode mode) {
148  lock (Database) {
149  var lockables = objects.OfType<ILockable>().ToArray();
150  if (lockables.Length == 0)
151  return;
152 
153  // Before we can lock the objects, we must wait for them
154  // to be available...
155  CheckAccess(lockables, accessType);
156 
157  var handle = Database.Locker.Lock(lockables, accessType, mode);
158 
159  if (lockHandles == null)
160  lockHandles = new List<LockHandle>();
161 
162  lockHandles.Add(handle);
163  }
164  }
165 
166  private void CheckAccess(ILockable[] lockables, AccessType accessType) {
167  if (lockHandles == null || lockables == null)
168  return;
169 
170  foreach (var handle in lockHandles) {
171  foreach (var lockable in lockables) {
172  if (handle.IsHandled(lockable))
173  handle.CheckAccess(lockable, accessType);
174  }
175  }
176  }
177 
178  private void ReleaseLocks() {
179  if (Database == null)
180  return;
181 
182  lock (Database) {
183  if (lockHandles != null) {
184  foreach (var handle in lockHandles) {
185  if (handle != null)
186  handle.Release();
187  }
188  }
189  }
190  }
191 
193  get { return Transaction.Database; }
194  }
195 
196  private void OnCommand() {
197  LastCommandTime = DateTimeOffset.UtcNow;
198  }
199 
200  public void Commit() {
201  AssertNotDisposed();
202 
203  if (Transaction != null) {
204  try {
206  } finally {
207  OnCommand();
208  DisposeTransaction();
209  }
210  }
211  }
212 
213  public void Rollback() {
214  AssertNotDisposed();
215 
216  if (Transaction != null) {
217  try {
219  } finally {
220  OnCommand();
221  DisposeTransaction();
222  }
223  }
224  }
225 
226  private void DisposeTransaction() {
227  ReleaseLocks();
228 
229  if (Database != null)
230  Database.Sessions.Remove(this);
231 
232  Transaction = null;
233  }
234 
235  public IQuery CreateQuery() {
236  return new Query(this);
237  }
238 
239  private void Dispose(bool disposing) {
240  if (!disposed) {
241  if (disposing) {
242  try {
243  Rollback();
244  } catch (Exception) {
245  // TODO: Notify the underlying system
246  }
247  }
248 
249  lockHandles = null;
250  disposed = true;
251  }
252  }
253  }
254 }
IQuery CreateQuery()
Definition: Session.cs:235
The system implementation of a transaction model that handles isolated operations within a database c...
Definition: Transaction.cs:35
IDatabase ITransaction. Database
Definition: Transaction.cs:105
LockingMode
The mode applied to a lock over a resource during a transaction.
Definition: LockingMode.cs:24
void Commit()
Commits all write operation done during the lifetime of this transaction and invalidates it...
Definition: Transaction.cs:179
void Rollback()
Rolls-back all the modifications made by the user in this session
Definition: Session.cs:213
bool IsSystem
Gets a boolean value indicating if this user represents the SYSTEM special user.
Definition: User.cs:64
void ReleaseLocks()
Definition: Session.cs:178
void Exit(IEnumerable< IDbObject > objects, AccessType accessType)
Definition: Session.cs:141
The default implementation of a database in a system.
Definition: Database.cs:38
IDatabase Database
Gets the database this transaction belongs to.
Definition: ITransaction.cs:48
List< LockHandle > lockHandles
Definition: Session.cs:33
The representation of a single database in the system.
Definition: IDatabase.cs:40
bool IsPublic
Gets a boolean value indicating if this user represents the PUBLIC special user.
Definition: User.cs:72
LockHandle Lock(ILockable[] lockables, AccessType accessType, LockingMode mode)
Definition: Locker.cs:45
This is a session that is constructed around a given user and a transaction, to the given database...
Definition: Session.cs:32
IEventSource ParentSource
Gets an optional parent source.
Definition: IEventSource.cs:49
void Rollback()
Rollback any write operations done during the lifetime of this transaction and invalidates it...
Definition: Transaction.cs:239
IEnumerable< KeyValuePair< string, object > > Metadata
Gets the list of metadata associated to the source.
Definition: IEventSource.cs:57
An isolated session to a given database for a given user, encapsulating the transaction for operation...
Definition: ISession.cs:30
void Lock(IEnumerable< IDbObject > objects, AccessType accessType, LockingMode mode)
Definition: Session.cs:147
bool Add(ISession session)
void Dispose(bool disposing)
Definition: Session.cs:239
Session(ITransaction transaction, User user)
Constructs the session for the given user and transaction to the given database.
Definition: Session.cs:44
new ITransactionContext Context
Definition: ITransaction.cs:31
IEnumerable< KeyValuePair< string, object > > GetMetadata()
Definition: Session.cs:96
ActiveSessionList Sessions
Gets a list of all the open sessions to the database.
Definition: IDatabase.cs:65
void CheckAccess(ILockable[] lockables, AccessType accessType)
Definition: Session.cs:166
void Remove(ISession session)
void DisposeTransaction()
Definition: Session.cs:226
void Commit()
Commits the latest changes made by the user in the session.
Definition: Session.cs:200
void AssertNotDisposed()
Definition: Session.cs:106
ActiveSessionList Sessions
Definition: Database.cs:81
The simplest implementation of a transaction.
Definition: ITransaction.cs:30
Provides the information for a user in a database system
Definition: User.cs:27
void Access(IEnumerable< IDbObject > objects, AccessType accessType)
Definition: Session.cs:111
Represents the origin of system events, providing a mechanism to fill the metadata before dispatching...
Definition: IEventSource.cs:40
string Name
Gets the name that uniquely identify a user within a database system.
Definition: User.cs:57