2f45f0fb4536404e497c1390aee2eaae71292b2c
[framework/web/wrt-commons.git] / modules / db / include / dpl / db / thread_database_support.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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  * @file    thread_database_support.h
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk)
19  * @version 1.0
20  * @brief   This file contains the declaration of thread database support
21  */
22
23 #ifndef DPL_THREAD_DATABASE_SUPPORT_H
24 #define DPL_THREAD_DATABASE_SUPPORT_H
25
26 #include <string>
27 #include <dpl/db/sql_connection.h>
28 #include <dpl/db/orm_interface.h>
29 #include <dpl/thread.h>
30 #include <dpl/assert.h>
31 #include <stdint.h>
32
33 namespace DPL
34 {
35 namespace DB
36 {
37
38 /**
39  * Thread database support
40  *
41  * Associate database connection with thread lifecycle
42  *
43  */
44
45 class ThreadDatabaseSupport :
46     public DPL::DB::ORM::IOrmInterface
47 {
48   private:
49     typedef DPL::DB::SqlConnection *SqlConnectionPtr;
50     typedef DPL::ThreadLocalVariable<SqlConnectionPtr> TLVSqlConnectionPtr;
51     typedef DPL::ThreadLocalVariable<size_t> TLVSizeT;
52     typedef DPL::ThreadLocalVariable<bool> TLVBool;
53
54     TLVSqlConnectionPtr m_connection;
55     TLVBool m_linger;
56     TLVSizeT m_refCounter;
57     TLVSizeT m_transactionDepth;
58     TLVSizeT m_attachCount;
59     TLVBool m_transactionCancel;
60     std::string m_address;
61     DPL::DB::SqlConnection::Flag::Type m_flags;
62
63     TLVSqlConnectionPtr &Connection()
64     {
65         return m_connection;
66     }
67
68     TLVBool &Linger()
69     {
70         return m_linger;
71     }
72
73     TLVSizeT &RefCounter()
74     {
75         return m_refCounter;
76     }
77
78     TLVSizeT &TransactionDepth()
79     {
80         return m_transactionDepth;
81     }
82
83     TLVSizeT &AttachCount()
84     {
85         return m_attachCount;
86     }
87
88     TLVBool &TransactionCancel()
89     {
90         return m_transactionCancel;
91     }
92
93     void CheckedConnectionDelete()
94     {
95         Assert(!Connection().IsNull());
96         Assert(*Linger() == true);
97
98         if (*RefCounter() > 0 || *AttachCount() > 0) {
99             return;
100         }
101
102         // Destroy connection
103         LogInfo("Destroying thread database connection: " << m_address);
104
105         delete *Connection();
106
107         // Blocking destroy
108         Connection().GuardValue(false);
109         Linger().GuardValue(false);
110         RefCounter().GuardValue(false);
111         TransactionCancel().GuardValue(false);
112         TransactionDepth().GuardValue(false);
113         AttachCount().GuardValue(false);
114
115         Connection().Reset();
116         Linger().Reset();
117         RefCounter().Reset();
118         TransactionCancel().Reset();
119         TransactionDepth().Reset();
120         AttachCount().Reset();
121     }
122
123     void TransactionUnref()
124     {
125         LogPedantic("Unref transaction");
126
127         if (--(*TransactionDepth()) == 0) {
128             LogPedantic("Transaction is finalized");
129
130             if (*TransactionCancel()) {
131                 LogPedantic("Transaction will be rolled back");
132                 (*Connection())->ExecCommand("ROLLBACK;");
133             } else {
134                 LogPedantic("Transaction will be commited");
135                 (*Connection())->ExecCommand("COMMIT;");
136             }
137         }
138     }
139
140   public:
141     ThreadDatabaseSupport(const std::string &address,
142                           DPL::DB::SqlConnection::Flag::Type flags) :
143         m_address(address),
144         m_flags(flags)
145     {
146     }
147
148     virtual ~ThreadDatabaseSupport()
149     {
150     }
151
152     void AttachToThread()
153     {
154         Linger() = false;
155
156         if (!Connection().IsNull()) {
157             // Add reference
158             ++*AttachCount();
159             return;
160         }
161
162         // Initialize SQL connection described in traits
163         LogInfo("Attaching thread database connection: " << m_address);
164
165         Connection() = new DPL::DB::SqlConnection(m_address.c_str(), m_flags);
166
167         RefCounter() = 0;
168
169         AttachCount() = 1;
170
171         //Init Transaction related variables
172         TransactionDepth() = 0;
173         TransactionCancel() = false;
174
175         // Blocking destroy
176         Connection().GuardValue(true);
177         Linger().GuardValue(true);
178         RefCounter().GuardValue(true);
179         TransactionDepth().GuardValue(true);
180         AttachCount().GuardValue(true);
181         TransactionCancel().GuardValue(true);
182     }
183
184     void DetachFromThread()
185     {
186         // Calling thread must support thread database connections
187         Assert(!Connection().IsNull());
188
189         // Remove reference
190         --*AttachCount();
191
192         if (*AttachCount() > 0) {
193             return;
194         }
195
196         // It must not be in linger state yet
197         Assert(*Linger() == false);
198
199         LogInfo("Detaching thread database connection: " << m_address);
200
201         // Enter linger state
202         *Linger() = true;
203
204         // Checked delete
205         CheckedConnectionDelete();
206     }
207
208     bool IsAttached()
209     {
210         return !AttachCount().IsNull() && *AttachCount() > 0;
211     }
212
213     DPL::DB::SqlConnection::DataCommand *AllocDataCommand(
214             const std::string &statement)
215     {
216         // Calling thread must support thread database connections
217         Assert(!Connection().IsNull());
218
219         // Calling thread must not be in linger state
220         Assert(*Linger() == false);
221
222         // Add reference
223         ++*RefCounter();
224
225         // Create new unmanaged data command
226         return (*Connection())->PrepareDataCommand(statement.c_str()).release();
227     }
228
229     void FreeDataCommand(DPL::DB::SqlConnection::DataCommand *command)
230     {
231         // Calling thread must support thread database connections
232         Assert(!Connection().IsNull());
233
234         // Delete data command
235         delete command;
236
237         // Unreference SQL connection
238         --*RefCounter();
239
240         // If it is linger state, connection may be destroyed
241         if (*Linger() == true) {
242             CheckedConnectionDelete();
243         }
244     }
245
246     void TransactionBegin()
247     {
248         // Calling thread must support thread database connections
249         Assert(!Connection().IsNull());
250
251         LogPedantic("Begin transaction");
252
253         // Addref transaction
254         if (++(*TransactionDepth()) == 1) {
255             LogPedantic("Transaction is initialized");
256
257             TransactionCancel() = false;
258             (*Connection())->ExecCommand("BEGIN;");
259         }
260     }
261
262     void TransactionCommit()
263     {
264         // Calling thread must support thread database connections
265         Assert(!Connection().IsNull());
266
267         LogPedantic("Commit transaction");
268
269         // Unref transation
270         TransactionUnref();
271     }
272
273     void TransactionRollback()
274     {
275         // Calling thread must support thread database connections
276         Assert(!Connection().IsNull());
277
278         // Cancel and unref transaction
279         TransactionCancel() = true;
280         TransactionUnref();
281     }
282
283     DPL::DB::SqlConnection::RowID GetLastInsertRowID()
284     {
285         // Calling thread must support thread database connections
286         Assert(!Connection().IsNull());
287
288         return (*Connection())->GetLastInsertRowID();
289     }
290
291     bool CheckTableExist(const char *name)
292     {
293         // Calling thread must support thread database connections
294         Assert(!Connection().IsNull());
295
296         return (*Connection())->CheckTableExist(name);
297     }
298 };
299
300 }
301 }
302
303 #endif // DPL_THREAD_DATABASE_SUPPORT_H