source: trunk/sources/HeuristicLab.Hive.Server.ADODataAccess/DataAdapterBase.cs @ 1134

Last change on this file since 1134 was 1134, checked in by svonolfe, 12 years ago

Further improved locking mechanism (avoid race conditions, performance) (#372)

File size: 5.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Data;
24using System.Collections.Generic;
25using System.Linq;
26using System.Text;
27using HeuristicLab.Hive.Contracts.BusinessObjects;
28using System.Threading;
29
30namespace HeuristicLab.Hive.Server.ADODataAccess {
31  abstract class DataAdapterBase<AdapterT, ObjT, RowT>
32    where AdapterT : new()
33    where RowT : System.Data.DataRow
34    where ObjT : IHiveObject, new() {
35
36    private static Mutex lockersMutex =
37      new Mutex();
38
39    private static IDictionary<long, Mutex> lockers =
40      new Dictionary<long, Mutex>();
41
42    private static IDictionary<long, int> lockCount =
43      new Dictionary<long, int>();
44
45    protected void LockRow(long id) {
46      Mutex rowLock = null;
47
48      /////begin critical section////
49      lockersMutex.WaitOne();
50
51      if (!lockers.ContainsKey(id)) {
52        lockers[id] = new Mutex();
53        lockCount[id] = 0;
54      }
55      rowLock = lockers[id];
56      lockCount[id]++;
57     
58      lockersMutex.ReleaseMutex();
59      /////end critical section////
60
61      rowLock.WaitOne();
62    }
63
64    protected void UnlockRow(long id) {
65      Mutex rowLock = lockers[id];
66      rowLock.ReleaseMutex();
67
68      /////begin critical section////
69      lockersMutex.WaitOne();
70
71      lockCount[id]--;
72      if (lockCount[id] == 0)
73        lockers.Remove(id);
74
75      lockersMutex.ReleaseMutex();
76      /////end critical section////
77    }
78   
79    protected AdapterT Adapter {
80      get {
81        return new AdapterT();
82      }
83    }
84
85    #region Abstract methods
86    protected abstract RowT ConvertObj(ObjT obj, RowT row);
87
88    protected abstract ObjT ConvertRow(RowT row, ObjT obj);
89
90    protected abstract RowT InsertNewRow(ObjT obj);
91
92    protected abstract void UpdateRow(RowT row);
93
94    protected abstract IEnumerable<RowT> FindById(long id);
95
96    protected abstract IEnumerable<RowT> FindAll();
97    #endregion
98
99    protected delegate IEnumerable<RowT> Selector();
100
101    protected ObjT Convert(RowT row, ObjT obj) {
102      try {
103        obj = ConvertRow(row, obj);
104        return obj;
105      }
106      catch (DeletedRowInaccessibleException) {
107        return default(ObjT);
108      }
109      catch (RowNotInTableException) {
110        return default(ObjT);
111      }
112    }
113
114    protected virtual RowT FindSingleRow(Selector selector) {
115      RowT row = default(RowT);
116
117      IEnumerable<RowT> found =
118        selector();
119
120      if (found.Count<RowT>() == 1)
121        row = found.First<RowT>();
122
123      return row;
124    }
125
126    protected virtual ObjT FindSingle(Selector selector) {
127      RowT row = FindSingleRow(selector);
128
129      if (row != null) {
130        ObjT obj = new ObjT();
131        obj = Convert(row, obj);
132
133        return obj;
134      } else {
135        return default(ObjT);
136      }
137    }
138
139    protected virtual ICollection<ObjT> FindMultiple(Selector selector) {
140      IEnumerable<RowT> found =
141        selector();
142
143      IList<ObjT> result =
144        new List<ObjT>();
145
146      foreach (RowT row in found) {
147        ObjT obj = new ObjT();
148        obj = Convert(row, obj);
149        if(obj != null)
150          result.Add(obj);
151      }
152
153      return result;
154    }
155
156    protected virtual RowT GetRowById(long id) {
157      return FindSingleRow(
158        delegate() {
159          return FindById(id);
160        });
161    }
162
163    public virtual void Update(ObjT obj) {
164      if (obj != null) {
165        RowT row =
166          GetRowById(obj.Id);
167
168        if (row == null) {
169          row = InsertNewRow(obj);
170          UpdateRow(row);
171        }
172
173        obj.Id = (long)row[row.Table.PrimaryKey[0]];
174        LockRow(obj.Id);
175
176        ConvertObj(obj, row);
177        UpdateRow(row);
178
179        UnlockRow(obj.Id);
180      }
181    }
182
183    public virtual ObjT GetById(long id) {
184      return FindSingle(delegate() {
185        return FindById(id);
186      });
187    }
188
189    public virtual ICollection<ObjT> GetAll() {
190      return new List<ObjT>(
191        FindMultiple(
192          new Selector(FindAll)));
193    }
194
195    public virtual bool Delete(ObjT obj) {
196      bool success = false;
197     
198      if (obj != null) {
199        LockRow(obj.Id);
200
201        RowT row =
202          GetRowById(obj.Id);
203
204        if (row != null) {
205          row.Delete();
206          UpdateRow(row);
207
208          success = true;
209        }
210
211        UnlockRow(obj.Id);
212      }
213
214      return success;
215    }
216  }
217}
218
Note: See TracBrowser for help on using the repository browser.