DatabaseEngine.h
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25  */
26 
32 #ifndef __DATABASE_ENGINE_H__
33 #define __DATABASE_ENGINE_H__
34 
35 // INCLUDES ===================================================================
36 #include <nscore.h>
37 #include "sqlite3.h"
38 
39 #include <deque>
40 #include <list>
41 #include <map>
42 
43 #include "DatabaseQuery.h"
44 #include "sbIDatabaseEngine.h"
45 
46 #include <prmon.h>
47 #include <prlog.h>
48 
49 #include <nsAutoLock.h>
50 #include <nsAutoPtr.h>
51 #include <nsCOMArray.h>
52 #include <nsRefPtrHashtable.h>
53 #include <nsServiceManagerUtils.h>
54 #include <nsIIdleService.h>
55 #include <nsIThread.h>
56 #include <nsIThreadPool.h>
57 #include <nsThreadUtils.h>
58 #include <nsIRunnable.h>
59 #include <nsIObserver.h>
60 #include <nsStringGlue.h>
61 #include <nsTArray.h>
62 #include <nsITimer.h>
63 
64 #include "sbLeadingNumbers.h"
65 
66 // DEFINES ====================================================================
67 #define SONGBIRD_DATABASEENGINE_CONTRACTID \
68  "@songbirdnest.com/Songbird/DatabaseEngine;1"
69 #define SONGBIRD_DATABASEENGINE_CLASSNAME \
70  "Songbird Database Engine Interface"
71 #define SONGBIRD_DATABASEENGINE_CID \
72 { /* 67d9edfd-9a76-4d60-9d76-59181801e193 */ \
73  0x67d9edfd, \
74  0x9a76, \
75  0x4d60, \
76  {0x9d, 0x76, 0x59, 0x18, 0x18, 0x1, 0xe1, 0x93} \
77 }
78 // EXTERNS ====================================================================
79 extern CDatabaseEngine *gEngine;
80 
81 // FUNCTIONS ==================================================================
82 void SQLiteUpdateHook(void *pData, int nOp, const char *pArgA, const char *pArgB, sqlite_int64 nRowID);
83 
84 // CLASSES ====================================================================
87 
88 class collationBuffers;
89 
91  public nsIObserver
92 {
93 public:
94  friend class QueryProcessorQueue;
95 
97  NS_DECL_NSIOBSERVER
98  NS_DECL_SBIDATABASEENGINE
99 
100  CDatabaseEngine();
101  virtual ~CDatabaseEngine();
102 
103  static CDatabaseEngine* GetSingleton();
104 
105  PRInt32 Collate(collationBuffers *aCollationBuffers,
106  const NATIVE_CHAR_TYPE *aStr1,
107  const NATIVE_CHAR_TYPE *aStr2);
108 
109  typedef enum {
112  } threadpoolmsg_t;
113 
114 protected:
115  NS_IMETHOD Init();
116  NS_IMETHOD Shutdown();
117 
118  nsresult OpenDB(const nsAString &dbGUID,
119  CDatabaseQuery *pQuery,
120  sqlite3 ** ppHandle);
121 
122  nsresult CloseDB(sqlite3 *pHandle);
123 
124  already_AddRefed<QueryProcessorQueue> GetQueueByQuery(CDatabaseQuery *pQuery, PRBool bCreate = PR_FALSE);
125  already_AddRefed<QueryProcessorQueue> CreateQueueFromQuery(CDatabaseQuery *pQuery);
126 
127  PRInt32 SubmitQueryPrivate(CDatabaseQuery *pQuery);
128 
129  static void PR_CALLBACK QueryProcessor(CDatabaseEngine* pEngine,
130  QueryProcessorQueue * pQueue);
131 
132  already_AddRefed<nsIEventTarget> GetEventTarget();
133 
134 private:
135  //[query list]
136  typedef std::list<CDatabaseQuery *> querylist_t;
137 
138  void DoSimpleCallback(CDatabaseQuery *pQuery);
139  void ReportError(sqlite3*, sqlite3_stmt*);
140 
141  nsresult InitMemoryConstraints();
142 
143  nsresult GetDBPrefs(const nsAString &dbGUID,
144  PRInt32 *cacheSize,
145  PRInt32 *pageSize);
146 
147  nsresult CreateDBStorePath();
148  nsresult GetDBStorePath(const nsAString &dbGUID, CDatabaseQuery *pQuery, nsAString &strPath);
149 
150  nsresult GetCurrentCollationLocale(nsCString &aCollationLocale);
151  PRInt32 CollateWithLeadingNumbers(collationBuffers *aCollationBuffers,
152  const NATIVE_CHAR_TYPE *aStr1,
153  PRInt32 *number1Length,
154  const NATIVE_CHAR_TYPE *aStr2,
155  PRInt32 *number2Length);
156  PRInt32 CollateForCurrentLocale(collationBuffers *aCollationBuffers,
157  const NATIVE_CHAR_TYPE *aStr1,
158  const NATIVE_CHAR_TYPE *aStr2);
159 
160  nsresult MarkDatabaseForPotentialDeletion(const nsAString &aDatabaseGUID,
161  CDatabaseQuery *pQuery);
162  nsresult PromptToDeleteDatabases();
163  nsresult DeleteMarkedDatabases();
164 
165  nsresult RunAnalyze();
166 
167 private:
168  typedef std::map<sqlite3 *, collationBuffers *> collationMap_t;
169  collationMap_t m_CollationBuffersMap;
170 
171  PRLock * m_pDBStorePathLock;
172  nsString m_DBStorePath;
173 
174  //[database guid / thread]
175  nsRefPtrHashtableMT<nsStringHashKey, QueryProcessorQueue> m_QueuePool;
176  // enum function for queue processor hashtable.
177  template<class T>
178  static NS_HIDDEN_(PLDHashOperator)
179  EnumerateIntoArrayStringKey(const nsAString& aKey,
180  T* aData,
181  void* aArray);
182 
183  PRMonitor* m_pThreadMonitor;
184  PRMonitor* m_CollationBuffersMapMonitor;
185 
186  PRBool m_AttemptShutdownOnDestruction;
187  PRBool m_IsShutDown;
188 
189  PRBool m_MemoryConstraintsSet;
190 
191  PRBool m_PromptForDelete;
192  PRBool m_DeleteDatabases;
193 
194  typedef std::map<nsString, nsRefPtr<CDatabaseQuery> > deleteDatabaseMap_t;
195  deleteDatabaseMap_t m_DatabasesToDelete;
196 
197  nsCOMPtr<nsITimer> m_PromptForDeleteTimer;
198 
199  nsCOMPtr<nsIThreadPool> m_pThreadPool;
200 
201  // Tracks if we've successfully added an idle observer.
202  PRPackedBool m_AddedIdleObserver;
203 
204  // Pre-allocated memory for sqlite page cache and scratch.
205  // Created in InitMemoryConstraints and destroyed in Shutdown.
206  // Used to avoid fragmentation.
207  void* m_pPageSpace;
208  void* m_pScratchSpace;
209 
210  nsCString mCollationLocale;
211 #ifdef XP_MACOSX
212  CollatorRef m_Collator;
213 #endif
214 };
215 
216 class QueryProcessorQueue : public nsIRunnable
217 {
218  friend class CDatabaseEngine;
220 
221 public:
222  //[thread queue]
223  typedef nsTArray<CDatabaseQuery *> queryqueue_t;
224 
225 public:
227 
229  : m_pEngine(nsnull)
230  , m_Shutdown(PR_FALSE)
231  , m_Running(PR_FALSE)
232  , m_pHandleLock(nsnull)
233  , m_pHandle(nsnull)
234  , m_pQueueMonitor(nsnull)
235  , m_AnalyzeCount(0) {
236  MOZ_COUNT_CTOR(QueryProcessorQueue);
237  }
238 
240  if(m_pHandleLock) {
241  PR_DestroyLock(m_pHandleLock);
242  }
243 
244  if(m_pQueueMonitor) {
245  nsAutoMonitor::DestroyMonitor(m_pQueueMonitor);
246  }
247 
248  MOZ_COUNT_DTOR(QueryProcessorQueue);
249  }
250 
251  nsresult Init(CDatabaseEngine *pEngine,
252  const nsAString &aGUID,
253  sqlite3 *pHandle) {
254  NS_ENSURE_ARG_POINTER(pEngine);
255  NS_ENSURE_ARG_POINTER(pHandle);
256 
257  m_pHandleLock = PR_NewLock();
258  NS_ENSURE_TRUE(m_pHandleLock, NS_ERROR_OUT_OF_MEMORY);
259 
260  m_pQueueMonitor = nsAutoMonitor::NewMonitor("QueryProcessorQueue.m_pQueueMonitor");
261  NS_ENSURE_TRUE(m_pQueueMonitor, NS_ERROR_OUT_OF_MEMORY);
262 
263  m_pEngine = pEngine;
264  m_pHandle = pHandle;
265 
266  m_GUID = aGUID;
267 
269  NS_ENSURE_TRUE(m_pEventTarget, NS_ERROR_UNEXPECTED);
270 
271  return NS_OK;
272  }
273 
274  NS_IMETHOD Run()
275  {
276  NS_ENSURE_TRUE(m_pEngine, NS_ERROR_NOT_INITIALIZED);
277 
279  this);
280 
281  return NS_OK;
282  }
283 
284  nsresult PushQueryToQueue(CDatabaseQuery *pQuery,
285  PRBool bPushToFront = PR_FALSE) {
286  NS_ENSURE_ARG_POINTER(pQuery);
287 
288  nsAutoMonitor mon(m_pQueueMonitor);
289 
290  CDatabaseQuery **p = nsnull;
291 
292  if(bPushToFront) {
293  p = m_Queue.InsertElementAt(0, pQuery);
294  } else {
295  p = m_Queue.AppendElement(pQuery);
296  }
297 
298  NS_ENSURE_TRUE(p, NS_ERROR_OUT_OF_MEMORY);
299 
300  return NS_OK;
301  }
302 
303  nsresult PopQueryFromQueue(CDatabaseQuery ** ppQuery) {
304  NS_ENSURE_ARG_POINTER(ppQuery);
305 
306  nsAutoMonitor mon(m_pQueueMonitor);
307 
308  if(m_Queue.Length()) {
309  *ppQuery = m_Queue[0];
310  m_Queue.RemoveElementAt(0);
311 
312  return NS_OK;
313  }
314 
315  return NS_ERROR_NOT_AVAILABLE;
316  }
317 
318  nsresult GetQueueSize(PRUint32 &aSize) {
319  aSize = 0;
320 
321  nsAutoMonitor mon(m_pQueueMonitor);
322  aSize = m_Queue.Length();
323 
324  return NS_OK;
325  }
326 
327  nsresult ClearQueue() {
328  nsAutoMonitor mon(m_pQueueMonitor);
329 
330  queryqueue_t::size_type current = 0;
331  queryqueue_t::size_type length = m_Queue.Length();
332 
333  for(; current < length; current++) {
334 
335  CDatabaseQuery *pQuery = m_Queue[current];
336  NS_RELEASE(pQuery);
337  }
338 
339  m_Queue.Clear();
340 
341  return NS_OK;
342  }
343 
344  nsresult RunQueue() {
345  nsAutoMonitor mon(m_pQueueMonitor);
346 
347  // If the query processor for this queue isn't running right now
348  // start running it on the threadpool.
349  if(!m_Running) {
350  m_Running = PR_TRUE;
351 
352  nsresult rv =
353  m_pEventTarget->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
354  NS_ENSURE_SUCCESS(rv, rv);
355  }
356 
357  return NS_OK;
358  }
359 
360  nsresult PrepareForShutdown() {
361  NS_ENSURE_TRUE(m_pEngine, NS_ERROR_NOT_INITIALIZED);
362  m_Shutdown = PR_TRUE;
363 
364  nsAutoMonitor mon(m_pQueueMonitor);
365  return mon.NotifyAll();
366  }
367 
368  nsresult Shutdown() {
369  nsresult rv = ClearQueue();
370  NS_ENSURE_SUCCESS(rv, rv);
371 
372  rv = m_pEngine->CloseDB(m_pHandle);
373  NS_ENSURE_SUCCESS(rv, rv);
374 
375  m_pHandle = nsnull;
376  return NS_OK;
377  }
378 
379 protected:
381  nsCOMPtr<nsIEventTarget> m_pEventTarget;
382 
383  nsString m_GUID;
384 
385  PRPackedBool m_Shutdown;
386  PRPackedBool m_Running;
387 
388  PRLock * m_pHandleLock;
389  sqlite3* m_pHandle;
390 
391  PRMonitor * m_pQueueMonitor;
393 
394  PRUint32 m_AnalyzeCount;
395 };
396 
397 // These classes are used for time-critical string copy during the collation
398 // algorithm and replace usage of nsString/nsCString in order to eliminate
399 // repeated allocations. The idea is just to hold on to a buffer which
400 // can grow in size but never reduce: as more strings get collated, the buffers
401 // quickly reach the maximum size needed and the only subsequent operations
402 // are memcopys. This is fine because the strings that are collated are never
403 // megabytes or even kilobytes of data, the largest ones will rarely exceed
404 // a few hundreds of bytes.
405 class fastString {
406 public:
408  mBuffer(nsnull),
409  mBufferLen(0) {}
410  virtual ~fastString() {
411  if (mBuffer)
412  free(mBuffer);
413  }
414  inline void grow_native(PRInt32 aLength) {
415  grow(aLength, sizeof(NATIVE_CHAR_TYPE));
416  }
417  inline void grow_utf16(PRInt32 aLength) {
418  grow(aLength, sizeof(UTF16_CHARTYPE));
419  }
420  inline void copy_native(const NATIVE_CHAR_TYPE *aFrom, PRInt32 aSize) {
421  grow_native(aSize);
422  copy(aFrom, aSize, sizeof(NATIVE_CHAR_TYPE));
423  mBuffer[aSize] = 0;
424  }
425  inline void copy_utf16(const UTF16_CHARTYPE *aFrom, PRInt32 aSize) {
426  grow_utf16(aSize);
427  copy(aFrom, aSize, sizeof(UTF16_CHARTYPE));
428  ((UTF16_CHARTYPE*)mBuffer)[aSize] = 0;
429  }
430  inline NATIVE_CHAR_TYPE *buffer(){
431  return mBuffer;
432  }
433  inline PRInt32 bufferLength() {
434  return mBufferLen;
435  }
436 private:
437  inline void grow(PRInt32 aLength, PRInt32 aCharSize) {
438  int s = ((aLength)+1)*aCharSize;
439  if (mBufferLen < s) {
440  if (mBuffer)
441  free(mBuffer);
442  mBuffer = (NATIVE_CHAR_TYPE *)malloc(s);
443  mBufferLen = s;
444  }
445  }
446  inline void copy(const void *aFrom, PRInt32 aSize, PRInt32 aCharSize) {
447  memcpy(mBuffer, aFrom, aSize * aCharSize);
448  }
449  NATIVE_CHAR_TYPE *mBuffer;
450  PRInt32 mBufferLen;
451 };
452 
454 public:
459 };
460 
461 #endif // __DATABASE_ENGINE_H__
nsresult PushQueryToQueue(CDatabaseQuery *pQuery, PRBool bPushToFront=PR_FALSE)
NATIVE_CHAR_TYPE * buffer()
return NS_OK
nsresult Init(CDatabaseEngine *pEngine, const nsAString &aGUID, sqlite3 *pHandle)
Leading Numbers Parsing.
already_AddRefed< QueryProcessorQueue > GetQueueByQuery(CDatabaseQuery *pQuery, PRBool bCreate=PR_FALSE)
CDatabaseEngine * gEngine
fastString encodingConversionBuffer2
fastString substringExtractionBuffer1
queryqueue_t m_Queue
NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER NS_DECL_SBIDATABASEENGINE CDatabaseEngine()
PRInt32 SubmitQueryPrivate(CDatabaseQuery *pQuery)
[USER CODE SHOULD NOT REFERENCE THIS CLASS]
static CDatabaseEngine * GetSingleton()
fastString substringExtractionBuffer2
PRMonitor * m_pQueueMonitor
virtual ~CDatabaseEngine()
NS_DECL_ISUPPORTS QueryProcessorQueue()
already_AddRefed< nsIEventTarget > GetEventTarget()
virtual ~fastString()
void grow_utf16(PRInt32 aLength)
already_AddRefed< QueryProcessorQueue > CreateQueueFromQuery(CDatabaseQuery *pQuery)
void grow_native(PRInt32 aLength)
void copy_native(const NATIVE_CHAR_TYPE *aFrom, PRInt32 aSize)
NS_IMETHOD Shutdown()
void SQLiteUpdateHook(void *pData, int nOp, const char *pArgA, const char *pArgB, sqlite_int64 nRowID)
nsresult OpenDB(const nsAString &dbGUID, CDatabaseQuery *pQuery, sqlite3 **ppHandle)
void copy_utf16(const UTF16_CHARTYPE *aFrom, PRInt32 aSize)
PRPackedBool m_Shutdown
PRInt32 bufferLength()
static void PR_CALLBACK QueryProcessor(CDatabaseEngine *pEngine, QueryProcessorQueue *pQueue)
fastString encodingConversionBuffer1
PRPackedBool m_Running
nsresult PopQueryFromQueue(CDatabaseQuery **ppQuery)
nsresult PrepareForShutdown()
nsCOMPtr< nsIEventTarget > m_pEventTarget
nsresult GetQueueSize(PRUint32 &aSize)
PRInt32 Collate(collationBuffers *aCollationBuffers, const NATIVE_CHAR_TYPE *aStr1, const NATIVE_CHAR_TYPE *aStr2)
nsTArray< CDatabaseQuery * > queryqueue_t
_updateTextAndScrollDataForFrame aData
nsresult CloseDB(sqlite3 *pHandle)
CDatabaseEngine * m_pEngine
Songbird Database Object Definition.