27 #include <sbIDatabaseQuery.h>
28 #include <sbILibraryManager.h>
29 #include <sbIPropertyManager.h>
33 #include <nsAutoLock.h>
34 #include <nsCOMArray.h>
35 #include <nsComponentManagerUtils.h>
36 #include <nsIObserverService.h>
37 #include <nsIProxyObjectManager.h>
38 #include <nsServiceManagerUtils.h>
39 #include <nsIThreadManager.h>
40 #include <nsThreadUtils.h>
41 #include <nsUnicharUtils.h>
43 #include <nsXPCOMCIDInternal.h>
45 #include <nsThreadUtils.h>
46 #include <nsIClassInfoImpl.h>
47 #include <nsIProgrammingLanguage.h>
49 #include <nsIStringBundle.h>
50 #include <nsIPrefBranch.h>
51 #include <nsIPrefService.h>
58 #include <sbIJobProgressService.h>
63 #include <sbIPropertyArray.h>
64 #include <sbIPropertyInfo.h>
66 #include <sbIDatabaseQuery.h>
78 #define SB_LOCALDATABASE_CACHE_FLUSH_DELAY (1000)
80 #define CACHE_HASHTABLE_SIZE 500
87 #define SORTINVALIDATE_TIMER_PERIOD 50
89 #define NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID "xpcom-shutdown-threads"
90 #define NS_FINAL_UI_STARTUP_OBSERVER_ID "final-ui-startup"
98 : mWritePendingCount(0),
99 mDependentGUIDArrayMonitor(nsnull),
103 mSortInvalidateJob(nsnull)
112 if (mDependentGUIDArrayMonitor) {
113 nsAutoMonitor::DestroyMonitor(mDependentGUIDArrayMonitor);
117 nsAutoMonitor::DestroyMonitor(mMonitor);
124 sbLocalDatabasePropertyCache::GetWritePending(PRBool *aWritePending)
126 NS_ASSERTION(mLibrary,
"You didn't initialize!");
127 NS_ENSURE_ARG_POINTER(aWritePending);
128 *aWritePending = (mWritePendingCount > 0);
135 const nsAString& aLibraryResourceGUID)
137 NS_ASSERTION(!mLibrary,
"Already initialized!");
138 NS_ENSURE_ARG_POINTER(aLibrary);
140 mLibraryResourceGUID = aLibraryResourceGUID;
142 nsresult rv = aLibrary->GetDatabaseGuid(mDatabaseGUID);
143 NS_ENSURE_SUCCESS(rv, rv);
145 rv = aLibrary->GetDatabaseLocation(getter_AddRefs(mDatabaseLocation));
146 NS_ENSURE_SUCCESS(rv, rv);
149 NS_ENSURE_SUCCESS(rv, rv);
151 mDependentGUIDArrayMonitor =
152 nsAutoMonitor::NewMonitor(
"sbLocalDatabasePropertyCache::mDependentGUIDArrayMonitor");
153 NS_ENSURE_TRUE(mDependentGUIDArrayMonitor, NS_ERROR_OUT_OF_MEMORY);
155 mMonitor = nsAutoMonitor::NewMonitor(
"sbLocalDatabasePropertyCache::mMonitor");
156 NS_ENSURE_TRUE(mMonitor, NS_ERROR_OUT_OF_MEMORY);
158 rv = LoadProperties();
159 NS_ENSURE_SUCCESS(rv, rv);
162 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
165 NS_ENSURE_SUCCESS(rv, rv);
167 rv = mThreadPoolService->SetIdleThreadTimeout(15000);
168 NS_ENSURE_SUCCESS(rv, rv);
170 mFlushTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
171 NS_ENSURE_SUCCESS(rv, rv);
173 rv = mFlushTimer->Init(
this,
175 nsITimer::TYPE_REPEATING_SLACK);
176 NS_ENSURE_SUCCESS(rv, rv);
178 mInvalidateTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
179 NS_ENSURE_SUCCESS(rv, rv);
184 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
185 NS_ENSURE_SUCCESS(rv, rv);
188 rv = observerService->AddObserver(
this,
191 NS_ENSURE_SUCCESS(rv, rv);
193 rv = observerService->AddObserver(
this,
196 NS_ENSURE_SUCCESS(rv, rv);
199 rv = observerService->AddObserver(
this,
202 NS_ENSURE_SUCCESS(rv, rv);
205 rv = observerService->AddObserver(
this,
208 NS_ENSURE_SUCCESS(rv, rv);
211 nsCOMPtr<sbIDatabaseQuery> query;
212 rv = MakeQuery(getter_AddRefs(query));
213 NS_ENSURE_SUCCESS(rv, rv);
216 getter_AddRefs(mItemSelectPreparedStatement));
217 NS_ENSURE_SUCCESS(rv, rv);
220 getter_AddRefs(mSecondaryPropertySelectPreparedStatement));
221 NS_ENSURE_SUCCESS(rv, rv);
224 getter_AddRefs(mMediaItemsFtsAllDeletePreparedStatement));
225 NS_ENSURE_SUCCESS(rv, rv);
228 getter_AddRefs(mMediaItemsFtsAllInsertPreparedStatement));
229 NS_ENSURE_SUCCESS(rv, rv);
232 getter_AddRefs(mPropertiesDeletePreparedStatement));
233 NS_ENSURE_SUCCESS(rv, rv);
236 getter_AddRefs(mPropertiesInsertPreparedStatement));
237 NS_ENSURE_SUCCESS(rv, rv);
242 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
244 nsString updateSQL = NS_LITERAL_STRING(
"UPDATE media_items SET ");
246 updateSQL.Append(NS_LITERAL_STRING(
" = ? WHERE media_item_id = ?"));
248 nsCOMPtr<sbIDatabasePreparedStatement> updateMediaItemPreparedStatement;
249 rv = query->PrepareQuery(updateSQL, getter_AddRefs(updateMediaItemPreparedStatement));
250 NS_ENSURE_SUCCESS(rv,rv);
253 updateMediaItemPreparedStatement);
254 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
259 success = mLibraryMediaItemUpdatePreparedStatements.Init(sStaticPropertyCount);
260 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
262 nsString updateSQL = NS_LITERAL_STRING(
"UPDATE library_media_item SET ");
264 updateSQL.Append(NS_LITERAL_STRING(
" = ?"));
266 nsCOMPtr<sbIDatabasePreparedStatement> updateMediaItemPreparedStatement;
267 rv = query->PrepareQuery(updateSQL, getter_AddRefs(updateMediaItemPreparedStatement));
268 NS_ENSURE_SUCCESS(rv,rv);
271 updateMediaItemPreparedStatement);
272 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
279 sbLocalDatabasePropertyCache::Shutdown()
281 TRACE(
"sbLocalDatabasePropertyCache[0x%.8x] - Shutdown()",
this);
286 rv = mFlushTimer->Cancel();
287 NS_ENSURE_SUCCESS(rv, rv);
292 if (mSortInvalidateJob) {
293 mSortInvalidateJob->Shutdown();
294 mSortInvalidateJob = nsnull;
297 if(mWritePendingCount) {
301 mItemSelectPreparedStatement = nsnull;
302 mSecondaryPropertySelectPreparedStatement = nsnull;
303 mMediaItemsFtsAllDeletePreparedStatement = nsnull;
304 mMediaItemsFtsAllInsertPreparedStatement = nsnull;
305 mPropertiesDeletePreparedStatement = nsnull;
306 mPropertiesInsertPreparedStatement = nsnull;
308 mMediaItemsUpdatePreparedStatements.Clear();
309 mLibraryMediaItemUpdatePreparedStatements.Clear();
316 sbLocalDatabasePropertyCache::RetrievePrimaryProperties(
sbIDatabaseQuery* query,
318 IDToBagMap & aIDToBagMap,
319 nsCOMArray<sbLocalDatabaseResourcePropertyBag> & aBags,
320 nsTArray<PRUint32> & aMissesIDs)
324 PRUint32
const length = aGuids.Length();
325 PRUint32 itemsRequested = length;
326 for (PRUint32
i = 0;
i < length; ++
i) {
328 nsString
const & aGuid = aGuids[
i];
329 if (aGuid.IsEmpty()) {
334 rv = query->AddPreparedStatement(mItemSelectPreparedStatement);
335 NS_ENSURE_SUCCESS(rv, rv);
338 NS_ENSURE_SUCCESS(rv, rv);
342 if (itemsRequested == 0)
345 rv = query->Execute(&dbOk);
346 NS_ENSURE_SUCCESS(rv, rv);
347 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
349 nsCOMPtr<sbIDatabaseResult> result;
350 rv = query->GetResultObject(getter_AddRefs(result));
351 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
354 rv = result->GetRowCount(&rowCount);
355 NS_ENSURE_SUCCESS(rv, rv);
358 NS_ENSURE_TRUE(rowCount == itemsRequested, NS_ERROR_UNEXPECTED);
362 aMissesIDs.SetLength(rowCount);
365 nsString mediaItemIdStr;
368 for (PRUint32 row = 0; row < rowCount; row++) {
370 rv = result->GetRowCell(row, 0, mediaItemIdStr);
371 NS_ENSURE_SUCCESS(rv, rv);
373 PRUint32 mediaItemId = mediaItemIdStr.ToInteger(&rv);
374 NS_ENSURE_SUCCESS(rv, rv);
376 rv = result->GetRowCell(row, 1, guid);
377 NS_ENSURE_SUCCESS(rv, rv);
379 nsRefPtr<sbLocalDatabaseResourcePropertyBag> bag =
381 NS_ENSURE_TRUE(bag, NS_ERROR_OUT_OF_MEMORY);
383 nsresult rv = bag->Init();
384 NS_ENSURE_SUCCESS(rv, rv);
387 rv = result->GetRowCell(row,
i + 1, value);
388 NS_ENSURE_SUCCESS(rv, rv);
390 if (!value.IsVoid()) {
393 NS_ENSURE_SUCCESS(rv, rv);
398 PRInt32
const index = aGuids.IndexOf(guid);
399 NS_ENSURE_TRUE(index >= 0, NS_ERROR_UNEXPECTED);
401 aMissesIDs[index] = mediaItemId;
403 PRBool
const success = aIDToBagMap.Put(mediaItemId, bag);
404 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
406 aBags.ReplaceObjectAt(bag, index);
414 sbLocalDatabasePropertyCache::RetrieveSecondaryProperties(
sbIDatabaseQuery* query,
415 nsTArray<PRUint32> itemIDs,
416 IDToBagMap
const & bags)
420 PRUint32
const length = itemIDs.Length();
424 for (PRUint32
i = 0;
i < length; ++
i) {
426 rv = query->AddPreparedStatement(mSecondaryPropertySelectPreparedStatement);
427 NS_ENSURE_SUCCESS(rv, rv);
430 NS_ENSURE_SUCCESS(rv, rv);
434 rv = query->Execute(&dbOk);
435 NS_ENSURE_SUCCESS(rv, rv);
436 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
438 nsCOMPtr<sbIDatabaseResult> result;
439 rv = query->GetResultObject(getter_AddRefs(result));
440 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
443 rv = result->GetRowCount(&rowCount);
444 NS_ENSURE_SUCCESS(rv, rv);
446 nsString objSearchable;
447 nsString objSortable;
449 nsString propertyIDStr;
450 nsRefPtr<sbLocalDatabaseResourcePropertyBag> bag;
451 for (PRUint32 row = 0; row < rowCount; row++) {
453 nsString mediaItemIdStr;
454 rv = result->GetRowCell(row, 0, mediaItemIdStr);
455 NS_ENSURE_SUCCESS(rv, rv);
457 PRUint32 mediaItemId = mediaItemIdStr.ToInteger(&rv);
458 NS_ENSURE_SUCCESS(rv, rv);
460 bags.Get(mediaItemId, getter_AddRefs(bag));
461 NS_ENSURE_TRUE(bag, NS_ERROR_FAILURE);
464 rv = result->GetRowCell(row, 1, propertyIDStr);
465 NS_ENSURE_SUCCESS(rv, rv);
467 PRUint32 propertyID = propertyIDStr.ToInteger(&rv);
468 NS_ENSURE_SUCCESS(rv, rv);
470 rv = result->GetRowCell(row, 2, obj);
471 NS_ENSURE_SUCCESS(rv, rv);
473 rv = bag->PutValue(propertyID, obj);
475 NS_ENSURE_SUCCESS(rv, rv);
485 nsCOMPtr<sbIDatabaseQuery> query;
486 nsresult rv = MakeQuery(getter_AddRefs(query));
487 NS_ENSURE_SUCCESS(rv, rv);
491 NS_ENSURE_SUCCESS(rv, rv);
494 rv = query->Execute(&dbOk);
495 NS_ENSURE_SUCCESS(rv, rv);
496 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
498 nsCOMPtr<sbIDatabaseResult> result;
499 rv = query->GetResultObject(getter_AddRefs(result));
500 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
503 rv = result->GetRowCount(&rowCount);
504 NS_ENSURE_SUCCESS(rv, rv);
506 for (PRUint32 row = 0; row < rowCount; row++) {
508 nsString propertyIDStr;
509 rv = result->GetRowCell(row, 0, propertyIDStr);
510 NS_ENSURE_SUCCESS(rv, rv);
512 PRUint32 propertyID = propertyIDStr.ToInteger(&rv);
513 NS_ENSURE_SUCCESS(rv, rv);
516 rv = result->GetRowCell(row, 1, obj);
517 NS_ENSURE_SUCCESS(rv, rv);
519 rv = aBag->
PutValue(propertyID, obj);
520 NS_ENSURE_SUCCESS(rv, rv);
523 rv = MakeQuery(getter_AddRefs(query));
524 NS_ENSURE_SUCCESS(rv, rv);
528 NS_ENSURE_SUCCESS(rv, rv);
530 rv = query->Execute(&dbOk);
531 NS_ENSURE_SUCCESS(rv, rv);
532 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
534 rv = query->GetResultObject(getter_AddRefs(result));
535 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
537 rv = result->GetRowCount(&rowCount);
538 NS_ENSURE_SUCCESS(rv, rv);
540 NS_ASSERTION(rowCount == 1,
"Failed to get data from library_media_item");
544 rv = result->GetRowCell(0,
i, value);
545 NS_ENSURE_SUCCESS(rv, rv);
547 if (!value.IsVoid()) {
551 NS_ENSURE_SUCCESS(rv, rv);
565 PRInt32 aLibraryItemPosition)
567 return aLibraryItemPosition == -1 ? aGUIDs.Length() : (aGUIDs.Length() - 1);
571 nsresult sbLocalDatabasePropertyCache::RetrieveProperties(
573 nsCOMArray<sbLocalDatabaseResourcePropertyBag> & aBags)
576 PRInt32
const libraryItemPosition = aGUIDs.IndexOf(mLibraryResourceGUID);
578 if (libraryItemPosition != -1) {
579 aGUIDs[libraryItemPosition].Truncate();
586 if (aGUIDs.Length() > 0) {
587 nsCOMPtr<sbIDatabaseQuery> query;
588 nsresult rv = MakeQuery(getter_AddRefs(query));
589 NS_ENSURE_SUCCESS(rv, rv);
594 nsTArray<PRUint32> itemIDs(aGUIDs.Length());
595 IDToBagMap idToBagMap;
596 PRBool
const success = idToBagMap.Init(aGUIDs.Length());
597 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
599 rv = RetrievePrimaryProperties(query, aGUIDs, idToBagMap, aBags, itemIDs);
600 NS_ENSURE_SUCCESS(rv, rv);
602 NS_ASSERTION(idToBagMap.Count() ==
GetGUIDCount(aGUIDs, libraryItemPosition) &&
603 GetGUIDCount(aGUIDs, libraryItemPosition) == itemIDs.Length() &&
604 GetGUIDCount(aGUIDs, libraryItemPosition) == PRUint32(aBags.Count()),
605 "RetrieveProperties returned an inconsistent result set");
608 rv = RetrieveSecondaryProperties(query, itemIDs, idToBagMap);
612 if (libraryItemPosition != -1) {
613 nsRefPtr<sbLocalDatabaseResourcePropertyBag> bag =
615 NS_ENSURE_TRUE(bag, NS_ERROR_OUT_OF_MEMORY);
618 NS_ENSURE_SUCCESS(rv, rv);
620 rv = RetrieveLibraryProperties(bag);
621 NS_ENSURE_SUCCESS(rv, rv);
624 aGUIDs[libraryItemPosition] = mLibraryResourceGUID;
625 aBags.ReplaceObjectAt(bag, libraryItemPosition);
635 PRUint32 aLength) : mCharArray(aCharArray), mLength(aLength)
637 NS_ASSERTION(aCharArray,
"PRUnicharAdaptor must be not passed a null pointer");
640 NS_ASSERTION(aIndex < mLength,
641 "PRunicharAdaptor::operator [] index exceeds array length");
642 return nsDependentString(mCharArray[aIndex]);
649 for (PRUint32 index = 0; index < mLength; ++index) {
650 if (aItemToRemove.Equals(mCharArray[index])) {
653 memcpy(mCharArray + index,
654 mCharArray + index + 1,
655 (mLength - index - 1) *
sizeof(PRUnichar *));
662 PRInt32
IndexOf(nsAString
const & aItemToFind)
const
664 for (PRUint32 index = 0; index < mLength; ++index) {
665 if (aItemToFind.Equals(mCharArray[index])) {
672 PRUnichar
const * * mCharArray;
677 sbLocalDatabasePropertyCache::CacheProperties(
const PRUnichar **aGUIDArray,
678 PRUint32 aGUIDArrayCount)
680 TRACE(
"sbLocalDatabasePropertyCache[0x%.8x] - CacheProperties(%d)",
this,
683 NS_ASSERTION(mLibrary,
"You didn't initialize!");
689 NS_WARNING(
"Requested to cache more items than the cache can hold, ignoring request");
693 nsTArray<nsString> misses;
694 PRBool cacheLibraryMediaItem = PR_FALSE;
701 nsAutoMonitor mon(mMonitor);
703 for (PRUint32
i = 0;
i < aGUIDArrayCount;
i++) {
705 nsDependentString guid(aGUIDArray[
i]);
707 if (mCache.Get(guid) == nsnull) {
709 if (guid.Equals(mLibraryResourceGUID)) {
710 cacheLibraryMediaItem = PR_TRUE;
713 nsString* newElement = misses.AppendElement(guid);
714 NS_ENSURE_TRUE(newElement, NS_ERROR_OUT_OF_MEMORY);
719 PRUint32
const numMisses = misses.Length();
724 nsCOMArray<sbLocalDatabaseResourcePropertyBag> bags(numMisses);
725 rv = RetrieveProperties(misses, bags);
726 NS_ENSURE_SUCCESS(rv, rv);
727 NS_ENSURE_TRUE(bags.Count() == PRInt32(numMisses), NS_ERROR_UNEXPECTED);
728 for (PRUint32 index = 0; index < numMisses; ++index) {
732 TRACE(
"sbLocalDatabasePropertyCache[0x%.8x] - CacheProperties() - "
733 "media item with id %s not found in database",
734 this, NS_ConvertUTF16toUTF8(misses[index]).
get());
740 NS_ASSERTION(misses[index].Equals(temp),
"inserting an bag that doesn't match the guid");
742 mCache.Put(misses[index], bag);
746 TRACE(
"sbLocalDatabasePropertyCache[0x%.8x] - CacheProperties() - Misses %d",
this,
754 sbLocalDatabasePropertyCache::GetProperties(
const PRUnichar **aGUIDArray,
755 PRUint32 aGUIDArrayCount,
756 PRUint32 *aPropertyArrayCount,
759 NS_ASSERTION(mLibrary,
"You didn't initialize!");
761 NS_ENSURE_ARG_POINTER(aPropertyArrayCount);
762 NS_ENSURE_ARG_POINTER(aPropertyArray);
764 if (!aGUIDArrayCount) {
765 NS_WARNING(
"Asked for 0 properties in call to GetProperties!");
766 *aPropertyArrayCount = 0;
767 *aPropertyArray = nsnull;
772 nsAutoArrayPtr<sbILocalDatabaseResourcePropertyBag*> propertyBagArray(
773 static_cast<sbILocalDatabaseResourcePropertyBag**> (
775 NS_ENSURE_TRUE(propertyBagArray, NS_ERROR_OUT_OF_MEMORY);
783 PRBool cacheUpdated = PR_FALSE;
785 nsAutoMonitor mon(mMonitor);
787 for (i = 0; i < aGUIDArrayCount; i++) {
789 nsDependentString
const guid(aGUIDArray[i]);
794 if (mDirty.Get(guid, nsnull)) {
801 NS_ENSURE_SUCCESS(rv, rv);
807 bag = mCache.Get(guid);
811 NS_ADDREF(propertyBagArray[i] = bag);
815 PRUint32 *
const newIndex = missesIndex.AppendElement(i);
816 NS_ENSURE_TRUE(newIndex, NS_ERROR_OUT_OF_MEMORY);
818 nsString *
const newGuid =
819 misses.AppendElement(guid);
820 NS_ENSURE_TRUE(newGuid, NS_ERROR_OUT_OF_MEMORY);
827 i == aGUIDArrayCount - 1;
828 if (timeToRead && misses.Length() > 0) {
830 nsCOMArray<sbLocalDatabaseResourcePropertyBag> bags(
CACHE_SIZE);
831 rv = RetrieveProperties(misses, bags);
834 if (bags.Count() > 0) {
835 PRUint32
const missesLength = missesIndex.Length();
836 NS_ENSURE_TRUE(PRInt32(missesLength) == bags.Count(),
837 NS_ERROR_UNEXPECTED);
839 for (PRUint32 index = 0; index < missesLength; ++index) {
840 PRUint32
const missIndex = missesIndex[index];
844 rv = NS_ERROR_NOT_AVAILABLE;
849 if (!cacheUpdated && missIndex <
CACHE_SIZE) {
853 NS_ASSERTION(temp.Equals(aGUIDArray[missIndex]),
"inserting an bag that doesn't match the guid");
855 mCache.Put(nsDependentString(aGUIDArray[missIndex]), bag);
857 NS_ADDREF(propertyBagArray[missIndex] = bag);
859 cacheUpdated = PR_TRUE;
862 NS_WARNING(
"RetrieveProperties didn't retrieve anything");
871 for (PRUint32 index = 0; index <
i; ++index) {
872 NS_IF_RELEASE(propertyBagArray[index]);
877 *aPropertyArrayCount = aGUIDArrayCount;
878 *aPropertyArray = propertyBagArray.forget();
884 PRUint32 aGUIDArrayCount,
886 PRUint32 aPropertyArrayCount,
887 PRBool aWriteThroughNow)
889 NS_ASSERTION(mLibrary,
"You didn't initialize!");
890 NS_ENSURE_ARG_POINTER(aGUIDArray);
891 NS_ENSURE_ARG_POINTER(aPropertyArray);
892 NS_ENSURE_TRUE(aGUIDArrayCount == aPropertyArrayCount, NS_ERROR_INVALID_ARG);
900 nsAutoMonitor mon(mMonitor);
901 for(PRUint32 i = 0; i < aGUIDArrayCount; i++) {
902 nsDependentString
const guid(aGUIDArray[i]);
903 nsRefPtr<sbLocalDatabaseResourcePropertyBag> bag;
905 bag = mCache.Get(guid);
908 PRUint32 mediaItemId;
909 rv = aPropertyArray[
i]->GetMediaItemId(&mediaItemId);
910 NS_ENSURE_SUCCESS(rv, rv);
914 nsCOMPtr<nsIStringEnumerator> ids;
915 rv = aPropertyArray[
i]->GetIds(getter_AddRefs(ids));
916 NS_ENSURE_SUCCESS(rv, rv);
921 while(NS_SUCCEEDED(ids->HasMore(&hasMore)) && hasMore) {
922 rv = ids->GetNext(
id);
923 NS_ENSURE_SUCCESS(rv, rv);
925 rv = aPropertyArray[
i]->GetProperty(
id, value);
926 NS_ENSURE_SUCCESS(rv, rv);
928 bag->SetProperty(
id, value);
930 NS_ENSURE_TRUE(bag, NS_ERROR_UNEXPECTED);
931 mDirty.Put(guid, bag);
935 if(aWriteThroughNow) {
937 NS_ENSURE_SUCCESS(rv, rv);
952 PRUint32 aMediaItemID,
957 mMediaItemID(aMediaItemID),
958 mIsLibrary(aIsLibrary) {}
959 nsresult
Process(PRUint32 aDirtyPropertyKey);
967 PRUint32 mMediaItemID;
969 nsTArray<nsString> mTopLevelSets;
977 PRBool success = mCache->
GetPropertyID(aDirtyPropertyKey, propertyID);
978 NS_ENSURE_TRUE(success, NS_ERROR_UNEXPECTED);
982 NS_WARNING(
"Attempt to change the SB_PROPERTY_GUID property");
987 nsresult rv = mBag->GetPropertyByID(aDirtyPropertyKey, value);
988 NS_ENSURE_SUCCESS(rv, rv);
993 nsCOMPtr<sbIDatabasePreparedStatement> topLevelPropertyUpdate;
995 success = mCache->mMediaItemsUpdatePreparedStatements.Get(aDirtyPropertyKey,
996 getter_AddRefs(topLevelPropertyUpdate));
999 success = mCache->mLibraryMediaItemUpdatePreparedStatements.Get(aDirtyPropertyKey,
1000 getter_AddRefs(topLevelPropertyUpdate));
1002 NS_ENSURE_TRUE(success, NS_ERROR_UNEXPECTED);
1004 rv = mQuery->AddPreparedStatement(topLevelPropertyUpdate);
1005 NS_ENSURE_SUCCESS(rv,rv);
1007 nsString columnName;
1009 NS_ENSURE_SUCCESS(rv,rv);
1011 PRUint32 columnType = (PRUint32)-1;
1013 NS_ENSURE_SUCCESS(rv, rv);
1016 rv = mQuery->BindStringParameter(0, value);
1017 NS_ENSURE_SUCCESS(rv,rv);
1021 NS_ENSURE_SUCCESS(rv,rv);
1022 rv = mQuery->BindInt64Parameter(0, intVal);
1023 NS_ENSURE_SUCCESS(rv,rv);
1026 NS_WARNING(
"Failed to determine the column type of a top level property.");
1027 return NS_ERROR_CANNOT_CONVERT_DATA;
1030 rv = mQuery->BindInt32Parameter(1, mMediaItemID);
1031 NS_ENSURE_SUCCESS(rv,rv);
1035 if (value.IsVoid()) {
1036 rv = mQuery->AddPreparedStatement(mCache->mPropertiesDeletePreparedStatement);
1037 NS_ENSURE_SUCCESS(rv, rv);
1039 rv = mQuery->BindInt32Parameter(0, mMediaItemID);
1040 NS_ENSURE_SUCCESS(rv, rv);
1042 rv = mQuery->BindInt32Parameter(1, aDirtyPropertyKey);
1043 NS_ENSURE_SUCCESS(rv, rv);
1046 nsString searchable;
1047 rv = mBag->GetSearchablePropertyByID(aDirtyPropertyKey, searchable);
1048 NS_ENSURE_SUCCESS(rv, rv);
1051 rv = mBag->GetSortablePropertyByID(aDirtyPropertyKey, sortable);
1052 NS_ENSURE_SUCCESS(rv, rv);
1054 nsString secondarySortable;
1056 aDirtyPropertyKey, secondarySortable);
1057 NS_ENSURE_SUCCESS(rv, rv);
1059 rv = mQuery->AddPreparedStatement(mCache->mPropertiesInsertPreparedStatement);
1060 NS_ENSURE_SUCCESS(rv, rv);
1062 rv = mQuery->BindInt32Parameter(0, mMediaItemID);
1063 NS_ENSURE_SUCCESS(rv, rv);
1065 rv = mQuery->BindInt32Parameter(1, aDirtyPropertyKey);
1066 NS_ENSURE_SUCCESS(rv, rv);
1068 rv = mQuery->BindStringParameter(2, value);
1069 NS_ENSURE_SUCCESS(rv, rv);
1071 rv = mQuery->BindStringParameter(3, searchable);
1072 NS_ENSURE_SUCCESS(rv, rv);
1074 rv = mQuery->BindStringParameter(4, sortable);
1075 NS_ENSURE_SUCCESS(rv, rv);
1077 rv = mQuery->BindStringParameter(5, secondarySortable);
1078 NS_ENSURE_SUCCESS(rv, rv);
1088 dirtyPropsEnum->
Process(aKey->GetKey());
1089 return PL_DHASH_NEXT;
1106 NS_ENSURE_TRUE(dirtyItem->
mGUIDs.AppendElement(aKey),
1108 nsresult rv = aBag->GetMediaItemId(dirtyItem->
mIDs.AppendElement());
1109 NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
1111 return PL_DHASH_NEXT;
1118 return PL_DHASH_NEXT;
1124 sbLocalDatabasePropertyCache::Write()
1126 NS_ASSERTION(mLibrary,
"You didn't initialize!");
1127 nsresult rv =
NS_OK;
1129 nsCOMPtr<sbIDatabaseQuery> query;
1130 PRUint32 dirtyItemCount;
1135 nsAutoMonitor mon(mMonitor);
1137 if (!mDirty.Count()) {
1142 dirtyItemCount = mDirty.EnumerateRead(
EnumDirtyItems, (
void *) &dirtyItems);
1143 mWritePendingCount = 0;
1145 if (!dirtyItemCount)
1148 rv = MakeQuery(getter_AddRefs(query));
1149 NS_ENSURE_SUCCESS(rv, rv);
1151 rv = query->AddQuery(NS_LITERAL_STRING(
"begin"));
1152 NS_ENSURE_SUCCESS(rv, rv);
1156 for (PRUint32 i = 0; i < dirtyItemCount; ++
i) {
1157 rv = query->AddPreparedStatement(mMediaItemsFtsAllDeletePreparedStatement);
1158 NS_ENSURE_SUCCESS(rv, rv);
1159 rv = query->BindInt32Parameter(0, dirtyItems.
mIDs[i]);
1160 NS_ENSURE_SUCCESS(rv, rv);
1164 for(PRUint32 i = 0; i < dirtyItemCount; ++
i) {
1165 nsRefPtr<sbLocalDatabaseResourcePropertyBag> bag;
1166 nsString
const guid(dirtyItems.
mGUIDs[i]);
1167 if (mDirty.Get(guid, getter_AddRefs(bag))) {
1169 PRUint32
const mediaItemId = dirtyItems.
mIDs[
i];
1171 PRBool
const isLibrary = guid.Equals(mLibraryResourceGUID);
1178 PRUint32 dirtyPropsCount;
1179 rv = bag->EnumerateDirty(
EnumDirtyProps, (
void *) &dirtyPropertyEnumerator, &dirtyPropsCount);
1180 NS_ENSURE_SUCCESS(rv, rv);
1185 nsString newFTSData;
1186 nsCOMPtr<nsIStringEnumerator> bagProperties;
1187 rv = bag->GetIds(getter_AddRefs(bagProperties));
1188 NS_ENSURE_SUCCESS(rv, rv);
1190 while (NS_SUCCEEDED(bagProperties->HasMore(&hasMore)) && hasMore) {
1191 nsAutoString propertyId;
1192 rv = bagProperties->GetNext(propertyId);
1193 NS_ENSURE_SUCCESS(rv, rv);
1195 PRBool hasProperty, isUserViewable;
1196 rv = mPropertyManager->HasProperty(propertyId, &hasProperty);
1197 NS_ENSURE_SUCCESS(rv, rv);
1202 nsCOMPtr<sbIPropertyInfo> propertyInfo;
1203 rv = mPropertyManager->GetPropertyInfo(propertyId,
1204 getter_AddRefs(propertyInfo));
1205 NS_ENSURE_SUCCESS(rv,rv);
1206 rv = propertyInfo->GetUserViewable(&isUserViewable);
1207 NS_ENSURE_SUCCESS(rv,rv);
1209 if (isUserViewable) {
1210 PRUint32 propertyDBID;
1211 rv = GetPropertyDBID(propertyId, &propertyDBID);
1212 NS_ENSURE_SUCCESS(rv, rv);
1213 nsString propertySearchable;
1214 rv = bag->GetSearchablePropertyByID(propertyDBID, propertySearchable);
1215 NS_ENSURE_SUCCESS(rv, rv);
1216 newFTSData.Append(propertySearchable);
1217 newFTSData.AppendLiteral(
" ");
1221 if (!newFTSData.IsEmpty()) {
1222 rv = query->AddPreparedStatement(mMediaItemsFtsAllInsertPreparedStatement);
1223 NS_ENSURE_SUCCESS(rv, rv);
1224 rv = query->BindInt32Parameter(0, dirtyItems.
mIDs[i]);
1225 NS_ENSURE_SUCCESS(rv, rv);
1226 rv = query->BindStringParameter(1, newFTSData);
1227 NS_ENSURE_SUCCESS(rv, rv);
1232 rv = query->AddQuery(NS_LITERAL_STRING(
"commit"));
1233 NS_ENSURE_SUCCESS(rv, rv);
1242 rv = query->Execute(&dbOk);
1243 NS_ENSURE_SUCCESS(rv, rv);
1244 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
1246 if(!NS_IsMainThread()) {
1247 nsCOMPtr<nsIThread> mainThread;
1248 rv = NS_GetMainThread(getter_AddRefs(mainThread));
1249 NS_ENSURE_SUCCESS(rv, rv);
1251 nsCOMPtr<nsIRunnable> runnable =
1254 InvalidateGUIDArrays);
1255 NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
1262 rv = mainThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
1263 NS_ENSURE_SUCCESS(rv, rv);
1266 rv = InvalidateGUIDArrays();
1267 NS_ENSURE_SUCCESS(rv, rv);
1271 mInvalidateTimer->Cancel();
1277 sbLocalDatabasePropertyCache::GetPropertyDBID(
const nsAString& aPropertyID,
1280 NS_ENSURE_ARG_POINTER(_retval);
1282 *_retval = GetPropertyDBIDInternal(aPropertyID);
1287 sbLocalDatabasePropertyCache::Observe(
nsISupports* aSubject,
1289 const PRUnichar*
aData)
1291 nsresult rv =
NS_OK;
1294 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
1295 NS_ASSERTION(NS_SUCCEEDED(rv),
"Prop cache failed to get observer service");
1296 if (NS_SUCCEEDED(rv)) {
1297 observerService->RemoveObserver(
this, aTopic);
1309 PRBool hasInvalidData = PR_FALSE;
1310 GetSetInvalidSortDataPref(PR_FALSE, hasInvalidData);
1311 if (NS_SUCCEEDED(rv) && hasInvalidData) {
1312 nsCOMPtr<sbIJobProgress> job;
1313 InvalidateSortData(getter_AddRefs(job));
1318 nsCOMPtr<sbIJobProgressService> progressService =
1319 do_GetService(
"@songbirdnest.com/Songbird/JobProgressService;1", &rv);
1320 NS_ENSURE_SUCCESS(rv, rv);
1321 rv = progressService->ShowProgressDialog(job, nsnull, 0);
1322 NS_ENSURE_SUCCESS(rv, rv);
1330 if (mSortInvalidateJob) {
1331 mSortInvalidateJob->Shutdown();
1332 mSortInvalidateJob = nsnull;
1335 if(SameCOMIdentity(aSubject, mFlushTimer)) {
1336 rv = DispatchFlush();
1337 NS_ENSURE_SUCCESS(rv, rv);
1339 else if(SameCOMIdentity(aSubject, mInvalidateTimer)) {
1340 rv = InvalidateGUIDArrays();
1341 NS_ENSURE_SUCCESS(rv, rv);
1349 sbLocalDatabasePropertyCache::InvalidateSortData(
sbIJobProgress** _retval)
1351 NS_ENSURE_ARG_POINTER(_retval);
1352 NS_ENSURE_TRUE(!mSortInvalidateJob, NS_ERROR_ALREADY_INITIALIZED);
1353 nsresult rv =
NS_OK;
1358 PRBool hasInvalidData = PR_TRUE;
1359 GetSetInvalidSortDataPref(PR_TRUE, hasInvalidData);
1363 NS_ENSURE_TRUE(mSortInvalidateJob, NS_ERROR_OUT_OF_MEMORY);
1366 mSortInvalidateJob->Init(
this, mLibrary);
1367 NS_ENSURE_SUCCESS(rv, rv);
1369 NS_ADDREF(*_retval = mSortInvalidateJob);
1377 PRBool hasInvalidData = PR_FALSE;
1378 GetSetInvalidSortDataPref(PR_TRUE, hasInvalidData);
1380 mSortInvalidateJob = nsnull;
1385 sbLocalDatabasePropertyCache::GetSetInvalidSortDataPref(
1386 PRBool aWrite, PRBool&
aValue)
1390 nsresult rv = mLibrary->GetDatabaseGuid(guid);
1391 NS_ENSURE_SUCCESS(rv, rv);
1392 nsCString
pref = NS_LITERAL_CSTRING(
"songbird.propertycache.");
1393 pref.Append(NS_LossyConvertUTF16toASCII(guid));
1394 pref.AppendLiteral(
".invalidSortData");
1396 nsCOMPtr<nsIPrefBranch> prefBranch =
1397 do_GetService(
"@mozilla.org/preferences-service;1", &rv);
1398 NS_ENSURE_SUCCESS(rv, rv);
1399 nsCOMPtr<nsIPrefService> prefRoot = do_QueryInterface(prefBranch, &rv);
1400 NS_ENSURE_SUCCESS(rv, rv);
1404 rv = prefBranch->SetBoolPref(pref.get(),
aValue);
1405 NS_ENSURE_SUCCESS(rv, rv);
1406 rv = prefRoot->SavePrefFile(nsnull);
1407 NS_ASSERTION(NS_SUCCEEDED(rv),
"Failed to save prefs.");
1410 rv = prefBranch->GetBoolPref(
1412 if (NS_FAILED(rv)) {
1420 sbLocalDatabasePropertyCache::AddDependentGUIDArray(
1423 NS_ENSURE_TRUE(aGUIDArray, );
1425 nsAutoMonitor mon(mDependentGUIDArrayMonitor);
1426 nsCOMPtr<nsISupports> supports =
1427 do_QueryInterface(static_cast<sbILocalDatabaseGUIDArray*>(aGUIDArray));
1428 nsCOMPtr<nsIWeakReference> weakRef =
1429 do_QueryInterface(static_cast<sbSupportsWeakReference*>(aGUIDArray));
1430 mDependentGUIDArrays[supports.get()] = weakRef;
1436 sbLocalDatabasePropertyCache::RemoveDependentGUIDArray(
1439 NS_ENSURE_TRUE(aGUIDArray, );
1440 nsAutoMonitor mon(mDependentGUIDArrayMonitor);
1442 nsCOMPtr<nsISupports> supports =
1443 do_QueryInterface(static_cast<sbILocalDatabaseGUIDArray*>(aGUIDArray));
1444 DependentGUIDArrays_t::iterator it = mDependentGUIDArrays.find(supports);
1445 if(it != mDependentGUIDArrays.end()) {
1446 mDependentGUIDArrays.erase(it);
1453 sbLocalDatabasePropertyCache::DispatchFlush()
1455 nsCOMPtr<nsIRunnable> runnable =
1457 NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
1459 nsresult rv = mThreadPoolService->Dispatch(runnable, NS_DISPATCH_NORMAL);
1460 NS_ENSURE_SUCCESS(rv, rv);
1462 LOG(
"property cache flush operation dispatched");
1468 sbLocalDatabasePropertyCache::RunFlushThread()
1471 NS_ASSERTION(NS_SUCCEEDED(rv),
"Failed to flush property cache; will retry");
1477 NS_ENSURE_ARG_POINTER(_retval);
1481 nsCOMPtr<sbIDatabaseQuery> query =
1483 NS_ENSURE_SUCCESS(rv, rv);
1485 rv = query->SetDatabaseGUID(mDatabaseGUID);
1486 NS_ENSURE_SUCCESS(rv, rv);
1488 if (mDatabaseLocation) {
1489 rv = query->SetDatabaseLocation(mDatabaseLocation);
1490 NS_ENSURE_SUCCESS(rv, rv);
1493 rv = query->SetAsyncQuery(PR_FALSE);
1494 NS_ENSURE_SUCCESS(rv, rv);
1496 NS_ADDREF(*_retval = query);
1501 sbLocalDatabasePropertyCache::LoadProperties()
1506 if (!mPropertyIDToDBID.IsInitialized()) {
1507 PRBool success = mPropertyIDToDBID.Init(100);
1508 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1511 mPropertyIDToDBID.Clear();
1514 if (!mPropertyDBIDToID.IsInitialized()) {
1515 PRBool success = mPropertyDBIDToID.Init(100);
1516 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1519 mPropertyDBIDToID.Clear();
1522 nsCOMPtr<sbIDatabaseQuery> query;
1523 rv = MakeQuery(getter_AddRefs(query));
1524 NS_ENSURE_SUCCESS(rv, rv);
1527 NS_ENSURE_SUCCESS(rv, rv);
1529 rv = query->Execute(&dbOk);
1530 NS_ENSURE_SUCCESS(rv, rv);
1531 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
1533 nsCOMPtr<sbIDatabaseResult> result;
1534 rv = query->GetResultObject(getter_AddRefs(result));
1535 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
1538 rv = result->GetRowCount(&rowCount);
1539 NS_ENSURE_SUCCESS(rv, rv);
1541 for (PRUint32 i = 0; i < rowCount; i++) {
1542 nsAutoString propertyDBIDStr;
1543 rv = result->GetRowCell(i, 0, propertyDBIDStr);
1544 NS_ENSURE_SUCCESS(rv, rv);
1546 PRUint32 propertyDBID = propertyDBIDStr.ToInteger(&rv);
1547 NS_ENSURE_SUCCESS(rv, rv);
1549 nsString propertyID;
1550 rv = result->GetRowCell(i, 1, propertyID);
1551 NS_ENSURE_SUCCESS(rv, rv);
1553 PRBool success = mPropertyDBIDToID.Put(propertyDBID, propertyID);
1554 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1556 TRACE(
"Added %d => %s to property name cache", propertyDBID,
1557 NS_ConvertUTF16toUTF8(propertyID).
get());
1559 success = mPropertyIDToDBID.Put(propertyID, propertyDBID);
1560 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1572 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1575 NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
1583 sbLocalDatabasePropertyCache::AddDirty(
const nsAString &aGuid,
1587 NS_ENSURE_ARG_POINTER(aBag);
1588 nsAutoString guid(aGuid);
1590 nsAutoMonitor mon(mMonitor);
1594 if (mDirty.Get(guid, nsnull)) {
1595 NS_WARNING(
"Property cache forcing Write() due to duplicate "
1596 "guids in the dirty bag list. This should be a rare event.");
1604 NS_ENSURE_SUCCESS(rv, rv);
1610 mDirty.Put(guid, aBag);
1611 ++mWritePendingCount;
1614 std::set<PRUint32> dirtyPropIds;
1616 NS_ENSURE_SUCCESS(rv, rv);
1618 mDirtyForInvalidation.insert(dirtyPropIds.begin(), dirtyPropIds.end());
1623 rv = mInvalidateTimer->Cancel();
1624 NS_ENSURE_SUCCESS(rv, rv);
1626 rv = mInvalidateTimer->Init(
this, 1000, nsITimer::TYPE_ONE_SHOT);
1627 NS_ENSURE_SUCCESS(rv, rv);
1633 sbLocalDatabasePropertyCache::InvalidateGUIDArrays()
1636 nsCOMArray<sbILocalDatabaseGUIDArray> arrays;
1639 nsAutoMonitor mon(mDependentGUIDArrayMonitor);
1640 DependentGUIDArrays_t::iterator cit = mDependentGUIDArrays.begin();
1641 DependentGUIDArrays_t::iterator end = mDependentGUIDArrays.end();
1642 while (cit != end) {
1643 nsCOMPtr<sbILocalDatabaseGUIDArray> guidArray =
1644 do_QueryReferent(cit->second);
1648 NS_ENSURE_TRUE(arrays.AppendObject(guidArray.get()), NS_ERROR_OUT_OF_MEMORY);
1652 DependentGUIDArrays_t::iterator deleteIter = cit;
1654 mDependentGUIDArrays.erase(deleteIter);
1659 std::vector<PRUint32> dirtyPropIDs;
1664 nsAutoMonitor mon(mMonitor);
1665 std::insert_iterator<std::vector<PRUint32> > insertIter(dirtyPropIDs,
1666 dirtyPropIDs.end());
1667 std::copy(mDirtyForInvalidation.begin(),
1668 mDirtyForInvalidation.end(),
1670 mDirtyForInvalidation.clear();
1673 PRInt32
const count = arrays.Count();
1674 for (PRInt32 index = 0; index <
count; ++index) {
1676 arrays[index]->MayInvalidate(&dirtyPropIDs[0],
1677 dirtyPropIDs.size());
1678 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
1679 "Failed to invalidate GUID array, GUIDs may be stale.");
1685 sbLocalDatabasePropertyCache::GetPropertyDBIDInternal(
const nsAString& aPropertyID)
1688 if (!mPropertyIDToDBID.Get(aPropertyID, &retval)) {
1689 nsresult rv = InsertPropertyIDInLibrary(aPropertyID, &retval);
1701 nsAString& aPropertyID)
1703 nsString propertyID;
1704 if (mPropertyDBIDToID.Get(aPropertyDBID, &propertyID)) {
1705 aPropertyID = propertyID;
1712 sbLocalDatabasePropertyCache::InsertPropertyIDInLibrary(
const nsAString& aPropertyID,
1713 PRUint32 *aPropertyDBID)
1715 NS_ENSURE_ARG_POINTER(aPropertyDBID);
1718 nsCOMPtr<sbIDatabaseQuery> query;
1719 nsresult rv = MakeQuery(getter_AddRefs(query));
1720 NS_ENSURE_SUCCESS(rv, rv);
1723 NS_ENSURE_SUCCESS(rv, rv);
1725 rv = query->BindStringParameter(0, aPropertyID);
1726 NS_ENSURE_SUCCESS(rv, rv);
1728 sql.AssignLiteral(
"select last_insert_rowid()");
1729 rv = query->AddQuery(sql);
1730 NS_ENSURE_SUCCESS(rv, rv);
1733 rv = query->Execute(&dbOk);
1734 NS_ENSURE_SUCCESS(rv, rv);
1735 NS_ENSURE_TRUE(dbOk == 0, NS_ERROR_FAILURE);
1737 nsCOMPtr<sbIDatabaseResult> result;
1738 rv = query->GetResultObject(getter_AddRefs(result));
1739 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
1741 nsAutoString propertyDBIDStr;
1742 rv = result->GetRowCell(0, 0, propertyDBIDStr);
1743 NS_ENSURE_SUCCESS(rv, rv);
1745 PRUint32 propertyDBID = propertyDBIDStr.ToInteger(&rv);
1746 NS_ENSURE_SUCCESS(rv, rv);
1748 *aPropertyDBID = propertyDBID;
1750 mPropertyDBIDToID.Put(propertyDBID, nsAutoString(aPropertyID));
1751 mPropertyIDToDBID.Put(nsAutoString(aPropertyID), propertyDBID);
1759 PRUint32 aPropertyDBID,
1762 NS_ENSURE_ARG_POINTER(aBag);
1763 nsresult rv =
NS_OK;
1769 NS_ENSURE_SUCCESS(rv, rv);
1771 nsCOMPtr<sbIPropertyInfo> propertyInfo;
1772 rv = mPropertyManager->GetPropertyInfo(
id,
1773 getter_AddRefs(propertyInfo));
1774 NS_ENSURE_SUCCESS(rv, rv);
1776 nsCOMPtr<sbIPropertyArray> secondaryProps;
1777 rv = propertyInfo->GetSecondarySort(getter_AddRefs(secondaryProps));
1778 NS_ENSURE_SUCCESS(rv, rv);
1782 if (secondaryProps) {
1783 PRUint32 secondaryPropCount;
1784 rv = secondaryProps->GetLength(&secondaryPropCount);
1785 NS_ENSURE_SUCCESS(rv, rv);
1787 nsTArray<nsString>
strings(secondaryPropCount);
1789 for (PRUint32 i = 0; i < secondaryPropCount; i++) {
1790 nsCOMPtr<sbIProperty> property;
1791 rv = secondaryProps->GetPropertyAt(i, getter_AddRefs(property));
1792 NS_ENSURE_SUCCESS(rv, rv);
1794 nsString propertyID;
1795 rv =
property->GetId(propertyID);
1796 NS_ENSURE_SUCCESS(rv, rv);
1799 rv = aBag->GetSortablePropertyByID(GetPropertyDBIDInternal(propertyID),
1801 NS_ENSURE_SUCCESS(rv, rv);
1803 nsString* appended = strings.AppendElement(sortable);
1804 NS_ENSURE_TRUE(appended, NS_ERROR_OUT_OF_MEMORY);
1837 mShouldShutdown(PR_FALSE),
1841 mNotificationTimer(nsnull),
1843 mCompletedItemCount(0),
1852 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Destroyed",
1861 NS_ENSURE_ARG_POINTER(aPropCache);
1862 NS_ENSURE_ARG_POINTER(aLibrary);
1863 NS_ENSURE_TRUE(!mThread, NS_ERROR_ALREADY_INITIALIZED);
1864 NS_ASSERTION(NS_IsMainThread(),
1865 "sbLocalDatabaseSortInvalidateJob::Init called off the main thread!");
1866 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Initialized",
1870 mPropCache = aPropCache;
1871 mLibrary = aLibrary;
1875 mCompletedItemCount = 0;
1879 mTitleText = strings.
Get(
"propertycache.invalidatesortjob.title",
1880 "Updating Library");
1881 mStatusText = strings.
Get(
"propertycache.invalidatesortjob.status",
1882 "Rebuilding library sorting data");
1883 mFailedText = strings.
Get(
"propertycache.invalidatesortjob.failed",
1887 if (!mNotificationTimer) {
1888 mNotificationTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
1889 NS_ENSURE_SUCCESS(rv, rv);
1891 rv = mNotificationTimer->Init(
this,
1893 nsITimer::TYPE_REPEATING_SLACK);
1894 NS_ENSURE_SUCCESS(rv, rv);
1897 rv = NS_NewThread(getter_AddRefs(mThread),
this);
1898 NS_ENSURE_SUCCESS(rv, rv);
1905 NS_ASSERTION(NS_IsMainThread(),
1906 "sbLocalDatabaseSortInvalidateJob::Shutdown called off the main thread!");
1907 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Shutdown requested",
1911 mShouldShutdown = PR_TRUE;
1916 if (mNotificationTimer) {
1917 rv = mNotificationTimer->Cancel();
1918 NS_ASSERTION(NS_SUCCEEDED(rv),
"Failed to cancel a notification timer");
1919 mNotificationTimer = nsnull;
1924 mThread->Shutdown();
1934 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::Run()
1936 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Thread Starting",
1940 nsCOMPtr<sbIMediaListBatchCallback> batchCallback =
1942 NS_ENSURE_TRUE(batchCallback, NS_ERROR_OUT_OF_MEMORY);
1945 batchCallback, static_cast<sbIJobProgress*>(
this));
1946 if (NS_FAILED(rv)) {
1950 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Thread Finished",
this);
1956 sbLocalDatabaseSortInvalidateJob::RunLibraryBatch(
nsISupports* aUserData)
1958 TRACE(
"sbLocalDatabaseSortInvalidateJob::RunLibraryBatch[0x%.8x]");
1959 NS_ENSURE_ARG_POINTER(aUserData);
1963 NS_ENSURE_TRUE(thisJob->mPropCache, NS_ERROR_UNEXPECTED);
1968 if (NS_FAILED(rv)) {
1981 sbLocalDatabaseSortInvalidateJob::OnEnumerationBegin(
sbIMediaList *aMediaList,
1984 NS_ENSURE_ARG_POINTER(aMediaList);
1985 NS_ENSURE_ARG_POINTER(_retval);
1992 sbLocalDatabaseSortInvalidateJob::OnEnumeratedItem(
sbIMediaList *aMediaList,
1996 NS_ENSURE_ARG_POINTER(aMediaList);
1997 NS_ENSURE_ARG_POINTER(aMediaItem);
1998 NS_ENSURE_ARG_POINTER(_retval);
1999 nsresult rv =
NS_OK;
2010 nsCOMPtr<sbIPropertyArray> properties;
2011 rv = aMediaItem->GetProperties(nsnull, getter_AddRefs(properties));
2012 NS_ENSURE_SUCCESS(rv,
NS_OK);
2014 nsCOMPtr<sbIMutablePropertyArray> newPropertyArray =
2016 NS_ENSURE_SUCCESS(rv, rv);
2017 rv = newPropertyArray->SetStrict(PR_FALSE);
2018 NS_ENSURE_SUCCESS(rv,
NS_OK);
2021 rv = properties->GetLength(&propCount);
2022 NS_ENSURE_SUCCESS(rv,
NS_OK);
2024 for (PRUint32 i = 0; i < propCount; i++) {
2025 nsCOMPtr<sbIProperty> property;
2026 rv = properties->GetPropertyAt(i, getter_AddRefs(property));
2027 NS_ENSURE_SUCCESS(rv,
NS_OK);
2029 nsString propertyID;
2030 rv =
property->GetId(propertyID);
2031 NS_ENSURE_SUCCESS(rv,
NS_OK);
2034 nsString propertyValue;
2035 rv =
property->GetValue(propertyValue);
2036 NS_ENSURE_SUCCESS(rv,
NS_OK);
2038 rv = newPropertyArray->AppendProperty(propertyID, propertyValue);
2039 NS_ENSURE_SUCCESS(rv,
NS_OK);
2043 rv = aMediaItem->SetProperties(newPropertyArray);
2044 NS_ENSURE_SUCCESS(rv,
NS_OK);
2046 mCompletedItemCount++;
2048 if (mShouldShutdown) {
2051 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Thread saw shutdown request",
2060 sbLocalDatabaseSortInvalidateJob::OnEnumerationEnd(
sbIMediaList *aMediaList,
2061 nsresult aStatusCode)
2063 NS_ENSURE_ARG_POINTER(aMediaList);
2064 if (mCompletedItemCount == mTotalItemCount) {
2070 mShouldShutdown = PR_TRUE;
2072 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Finished enumerating",
2083 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetStatus(PRUint16* aStatus)
2085 NS_ENSURE_ARG_POINTER( aStatus );
2091 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetBlocked(PRBool* aBlocked)
2093 NS_ENSURE_ARG_POINTER( aBlocked );
2094 *aBlocked = PR_FALSE;
2099 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetStatusText(nsAString& aText)
2101 NS_ASSERTION(NS_IsMainThread(), \
2102 "sbLocalDatabaseSortInvalidateJob::GetStatusText is main thread only!");
2103 nsresult rv =
NS_OK;
2106 aText = mFailedText;
2108 aText = mStatusText;
2115 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetTitleText(nsAString& aText)
2122 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetProgress(PRUint32* aProgress)
2124 NS_ENSURE_ARG_POINTER( aProgress );
2125 NS_ASSERTION(NS_IsMainThread(), \
2126 "sbLocalDatabaseSortInvalidateJob::GetProgress is main thread only!");
2128 *aProgress = mCompletedItemCount;
2133 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetTotal(PRUint32* aTotal)
2135 NS_ENSURE_ARG_POINTER( aTotal );
2136 NS_ASSERTION(NS_IsMainThread(), \
2137 "sbLocalDatabaseSortInvalidateJob::GetTotal is main thread only!");
2139 *aTotal = mTotalItemCount;
2144 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetErrorCount(PRUint32*
aCount)
2146 NS_ENSURE_ARG_POINTER( aCount );
2147 NS_ASSERTION(NS_IsMainThread(), \
2148 "sbLocalDatabaseSortInvalidateJob::GetErrorCount is main thread only!");
2155 NS_IMETHODIMP sbLocalDatabaseSortInvalidateJob::GetErrorMessages(
nsIStringEnumerator** aMessages)
2157 NS_ENSURE_ARG_POINTER(aMessages);
2158 NS_ASSERTION(NS_IsMainThread(), \
2159 "sbLocalDatabaseSortInvalidateJob::GetErrorMessages is main thread only!");
2162 *aMessages = nsnull;
2163 nsTArray<nsString>
empty;
2164 nsCOMPtr<nsIStringEnumerator> enumerator =
2166 NS_ENSURE_TRUE(enumerator, NS_ERROR_OUT_OF_MEMORY);
2168 enumerator.forget(aMessages);
2177 NS_ENSURE_ARG_POINTER(aListener);
2178 NS_ASSERTION(NS_IsMainThread(), \
2179 "sbLocalDatabaseSortInvalidateJob::AddJobProgressListener is main thread only!");
2180 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Listener added",
2183 PRInt32 index = mListeners.IndexOf(aListener);
2186 return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
2188 PRBool
succeeded = mListeners.AppendObject(aListener);
2189 return succeeded ?
NS_OK : NS_ERROR_OUT_OF_MEMORY;
2196 NS_ENSURE_ARG_POINTER(aListener);
2197 NS_ASSERTION(NS_IsMainThread(), \
2198 "sbLocalDatabaseSortInvalidateJob::RemoveJobProgressListener is main thread only!");
2199 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Listener removed",
2202 PRInt32 indexToRemove = mListeners.IndexOf(aListener);
2203 if (indexToRemove < 0) {
2205 return NS_ERROR_UNEXPECTED;
2209 PRBool succeeded = mListeners.RemoveObjectAt(indexToRemove);
2210 NS_ENSURE_TRUE(succeeded, NS_ERROR_FAILURE);
2221 sbLocalDatabaseSortInvalidateJob::Observe(
nsISupports *aSubject,
2223 const PRUnichar *aData)
2225 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Notification Timer Callback",
this);
2229 for (PRInt32 i = mListeners.Count() - 1; i >= 0; --
i) {
2230 mListeners[
i]->OnJobProgress(
this);
2234 TRACE(
"sbLocalDatabaseSortInvalidateJob[0x%.8x] - Finishing job...",
this);
2238 rv = mLibrary->Flush();
2239 NS_ASSERTION(NS_SUCCEEDED(rv),
2240 "sbLocalDatabaseSortInvalidateJob failed to flush library!");
2243 rv = mLibrary->Optimize(PR_FALSE);
2244 NS_ASSERTION(NS_SUCCEEDED(rv),
2245 "sbLocalDatabaseSortInvalidateJob failed to optimize library!");
static const int MediaItemBindCount
NS_IMPL_CI_INTERFACE_GETTER5(sbLocalDatabaseSortInvalidateJob, nsIClassInfo, sbIJobProgress, nsIRunnable, sbIMediaListEnumerationListener, nsIObserver) sbLocalDatabaseSortInvalidateJob
#define SB_PRLOG_SETUP(x)
EnumDirtyItemsSetDirty(nsAString const &aKey, sbLocalDatabaseResourcePropertyBag *aBag, void *aClosure)
EnumDirtyItems(nsAString const &aKey, sbLocalDatabaseResourcePropertyBag *aBag, void *aClosure)
static nsString PropertiesDelete()
#define SONGBIRD_DATABASEQUERY_CONTRACTID
PRUint32 GetGUIDCount(T const &aGUIDs, PRInt32 aLibraryItemPosition)
static nsCOMPtr< nsIObserverService > observerService
S sbAppendStringArray(S &aTarget, Sep const &aSeparator, T const &aStringArray, E aExtractor)
static nsString MediaItemsFtsAllDelete()
[USER CODE SHOULD NOT REFERENCE THIS CLASS]
#define SB_LIBRARY_MANAGER_SHUTDOWN_TOPIC
PRUnicharAdaptor(PRUnichar const **aCharArray, PRUint32 aLength)
#define CACHE_HASHTABLE_SIZE
#define NS_FINAL_UI_STARTUP_OBSERVER_ID
PR_STATIC_CALLBACK(PRBool) FindElementCallback(void *aElement
NS_IMPL_THREADSAFE_ISUPPORTS5(sbLocalDatabaseSortInvalidateJob, nsIClassInfo, sbIJobProgress, nsIRunnable, sbIMediaListEnumerationListener, nsIObserver)
static PRUint32 const BATCH_READ_SIZE
function succeeded(ch, cx, status, data)
PRUint64 nsString_ToUint64(const nsAString &str, nsresult *rv)
static nsString MediaItemsFtsAllInsert()
Generic interface for exposing long running jobs to the UI.
static nsString PropertiesTableInsert()
nsString Get(const nsAString &aKey, const nsAString &aDefault=SBVoidString())
NS_IMETHOD RunInBatchMode(sbIMediaListBatchCallback *aCallback, nsISupports *aUserData)
static const int SecondaryPropertyBindCount
static const PRUint32 sStaticPropertyCount
static nsresult SB_GetTopLevelPropertyColumnType(const nsAString &aProperty, PRUint32 &aColumnType)
virtual ~sbLocalDatabaseSortInvalidateJob()
static nsresult SB_GetTopLevelPropertyColumn(const nsAString &aProperty, nsAString &aColumnName)
DirtyPropertyEnumerator(sbLocalDatabasePropertyCache *aCache, sbLocalDatabaseResourcePropertyBag *aBag, sbIDatabaseQuery *aQuery, PRUint32 aMediaItemID, PRBool aIsLibrary)
static nsString PropertiesInsert()
const unsigned short STATUS_SUCCEEDED
Constant indicating that the job has completed.
static PRBool SB_IsTopLevelProperty(PRUint32 aPropertyDBID)
Simple class to make sure we notify listeners that a batch operation has completed every time they ar...
static nsString LibraryMediaItemsPropertiesSelect()
#define SB_PROPERTYMANAGER_CONTRACTID
const unsigned short STATUS_RUNNING
Constant indicating that the job is active.
PRBool GetPropertyID(PRUint32 aPropertyDBID, nsAString &aPropertyID)
nsresult Init(sbLocalDatabaseLibrary *aLibrary, const nsAString &aLibraryResourceGUID)
NS_IMPL_THREADSAFE_ISUPPORTS2(sbLocalDatabasePropertyCache, sbILocalDatabasePropertyCache, nsIObserver) sbLocalDatabasePropertyCache
const PRUint32 SB_COLUMN_TYPE_TEXT
PRInt32 IndexOf(nsAString const &aItemToFind) const
Songbird Thread Pool Service.
static nsString PropertiesSelect()
nsString LibraryMediaItemSelect()
#define NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID
nsTArray< nsString > mGUIDs
EnumDirtyProps(nsUint32HashKey *aKey, void *aClosure)
const NS_TIMER_CALLBACK_TOPIC
nsString MediaItemSelect()
const PRUint32 SB_COLUMN_TYPE_INTEGER
NS_IMETHOD GetLength(PRUint32 *aLength)
nsresult Process(PRUint32 aDirtyPropertyKey)
nsString operator[](PRUint32 aIndex) const
nsTArray< PRUint32 > mIDs
Songbird String Bundle Definitions.
#define SORTINVALIDATE_TIMER_PERIOD
Number of milliseconds between sbIJobProgress notifications for sbLocalDatabaseSortInvalidateJob.
nsresult Init(sbLocalDatabasePropertyCache *aPropCache, sbLocalDatabaseLibrary *aLibrary)
[USER CODE SHOULD NOT REFERENCE THIS CLASS]
inst dpDiv empty().append(this._generateHTML(inst)).find('iframe.ui-datepicker-cover').css(
static nsString SecondaryPropertySelect()
StringArrayEnumerator prototype hasMore
PRBool RemoveElement(nsAString const &aItemToRemove)
#define SB_LOCALDATABASE_CACHE_FLUSH_DELAY
Number of milliseconds after the last write to force a cache write.
NS_IMETHOD EnumerateAllItems(sbIMediaListEnumerationListener *aEnumerationListener, PRUint16 aEnumerationType)
An object responsible for executing SQL queries on the database.
Implemented to receive notifications from sbIJobProgress interfaces.
static sbStaticProperty sStaticProperties[]
static PRUint32 const CACHE_SIZE
restoreHistoryPrecursor aCount
nsresult SetProperties(nsIArray *aProperties)
~sbLocalDatabasePropertyCache()
const unsigned short STATUS_FAILED
Constant indicating that the job has completed with errors.
nsresult CreateSecondarySortValue(sbILocalDatabaseResourcePropertyBag *aBag, PRUint32 aPropertyDBID, nsAString &_retval)
nsresult InvalidateSortDataComplete()
_getSelectedPageStyle s i
nsresult PutValue(PRUint32 aPropertyID, const nsAString &aValue)
#define SB_UNUSED_IN_RELEASE(decl)
const SB_LIBRARY_MANAGER_BEFORE_SHUTDOWN_TOPIC
friend class sbLocalDatabaseResourcePropertyBag
_updateTextAndScrollDataForFrame aData
nsresult GetDirtyForInvalidation(std::set< PRUint32 > &aDirty)
Songbird Database Object Definition.