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