/*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2011 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include "cache.h"
+#pragma mark -
+#pragma mark SCDynamicStore "cache"
+
+
+static Boolean use_cache = FALSE;
+
+static CFMutableDictionaryRef cached_keys = NULL;
+static CFMutableDictionaryRef cached_set = NULL;
+static CFMutableArrayRef cached_removals = NULL;
+static CFMutableArrayRef cached_notifys = NULL;
+
+
+static void
+cache_open(void)
+{
+ if (use_cache) {
+ // if we are already using the cache
+ cache_close();
+ }
+
+ cached_keys = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ cached_set = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ cached_removals = CFArrayCreateMutable(NULL,
+ 0,
+ &kCFTypeArrayCallBacks);
+ cached_notifys = CFArrayCreateMutable(NULL,
+ 0,
+ &kCFTypeArrayCallBacks);
+
+ use_cache = TRUE;
+ return;
+}
+
+
+static CFPropertyListRef
+cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+ CFPropertyListRef value;
+
+ value = CFDictionaryGetValue(cached_set, key);
+ if (value) {
+ // if we have "set" a new value
+ return (CFRetain(value));
+ }
+
+ if (CFArrayContainsValue(cached_removals,
+ CFRangeMake(0, CFArrayGetCount(cached_removals)),
+ key)) {
+ // if we have "removed" the key
+ _SCErrorSet(kSCStatusNoKey);
+ return NULL;
+ }
+
+ value = CFDictionaryGetValue(cached_keys, key);
+ if (value) {
+ // if we have a cached value
+ return (CFRetain(value));
+ }
+
+ value = SCDynamicStoreCopyValue(store, key);
+ if (value) {
+ CFDictionarySetValue(cached_keys, key, value);
+ }
+
+ return value;
+}
+
+
+static void
+cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
+{
+ CFIndex i;
+
+ i = CFArrayGetFirstIndexOfValue(cached_removals,
+ CFRangeMake(0, CFArrayGetCount(cached_removals)),
+ key);
+ if (i != kCFNotFound) {
+ // if previously "removed"
+ CFArrayRemoveValueAtIndex(cached_removals, i);
+ }
+
+ CFDictionarySetValue(cached_set, key, value);
+
+ return;
+}
+
+static void
+cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
+{
+ CFDictionaryRemoveValue(cached_set, key);
+
+ if (!CFArrayContainsValue(cached_removals,
+ CFRangeMake(0, CFArrayGetCount(cached_removals)),
+ key)) {
+ CFArrayAppendValue(cached_removals, key);
+ }
+
+ return;
+}
+
+
+static void
+cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+ if (!CFArrayContainsValue(cached_notifys,
+ CFRangeMake(0, CFArrayGetCount(cached_notifys)),
+ key)) {
+ CFArrayAppendValue(cached_notifys, key);
+ }
+
+ return;
+}
+
+
+static void
+cache_write(SCDynamicStoreRef store)
+{
+ if ((CFDictionaryGetCount(cached_set) > 0) ||
+ (CFArrayGetCount(cached_removals) > 0) ||
+ (CFArrayGetCount(cached_notifys) > 0)) {
+ if (!SCDynamicStoreSetMultiple(store,
+ cached_set,
+ cached_removals,
+ cached_notifys)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ }
+
+ return;
+}
+
+
+__private_extern__
+void
+cache_close(void)
+{
+ if (!use_cache) {
+ return;
+ }
+
+ CFRelease(cached_keys);
+ CFRelease(cached_set);
+ CFRelease(cached_removals);
+ CFRelease(cached_notifys);
+
+ use_cache = FALSE;
+ return;
+}
+
+
+#pragma mark -
+#pragma mark SCDynamicStore operations
+
+
+__private_extern__
+void
+do_block(int argc, char **argv)
+{
+ Boolean enable = FALSE;
+
+ if (argc >= 1) {
+ if ((strcasecmp(argv[0], "begin") == 0) ||
+ (strcasecmp(argv[0], "start") == 0) ||
+ (strcasecmp(argv[0], "on" ) == 0) ||
+ (strcasecmp(argv[0], "1" ) == 0)) {
+ enable = TRUE;
+ } else if ((strcasecmp(argv[0], "end" ) == 0) ||
+ (strcasecmp(argv[0], "stop" ) == 0) ||
+ (strcasecmp(argv[0], "off" ) == 0) ||
+ (strcasecmp(argv[0], "0" ) == 0)) {
+ enable = FALSE;
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
+ return;
+ }
+ } else {
+ enable = !use_cache; // toggle
+ }
+
+ if (enable) {
+ // begin block of SCDynamicStore operations
+ if (use_cache) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusLocked));
+ return;
+ }
+
+ SCPrint(TRUE, stdout, CFSTR("Begin block of SCDynamicStore operations\n"));
+
+ cache_open();
+ } else {
+ CFIndex n;
+
+ // end block of SCDynamicStore operations
+ if (!use_cache) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNeedLock));
+ return;
+ }
+
+ n = CFDictionaryGetCount(cached_keys) +
+ CFArrayGetCount(cached_removals) +
+ CFArrayGetCount(cached_notifys);
+ SCPrint(TRUE, stdout,
+ CFSTR("End block of SCDynamicStore operations%s\n"),
+ (n > 0) ? ", posting changes" : "");
+ if (n > 0) {
+ cache_write(store);
+ }
+ cache_close();
+ }
+
+ return;
+}
+
+
static CFComparisonResult
sort_keys(const void *p1, const void *p2, void *context) {
CFStringRef key1 = (CFStringRef)p1;
}
+#define N_QUICK 64
+
+
__private_extern__
void
do_list(int argc, char **argv)
if (list == NULL) {
if (SCError() != kSCStatusOK) {
SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ return;
} else {
+ if (!use_cache) {
SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
+ return;
+ } else {
+ CFIndex n;
+
+ n = CFDictionaryGetCount(cached_set);
+ if (n > 0) {
+ const void * cachedKeys_q[N_QUICK];
+ const void ** cachedKeys = cachedKeys_q;
+
+ if (n > (CFIndex)(sizeof(cachedKeys_q) / sizeof(CFStringRef))) {
+ cachedKeys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
+ }
+ CFDictionaryGetKeysAndValues(cached_set, cachedKeys, NULL);
+ list = CFArrayCreate(NULL, cachedKeys, n, &kCFTypeArrayCallBacks);
+ if (cachedKeys != cachedKeys_q) {
+ CFAllocatorDeallocate(NULL, cachedKeys);
+ }
+ } else {
+ SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
+ return;
+ }
+ }
}
- return;
+ } else if (use_cache &&
+ ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0))) {
+ SCPrint(TRUE, stdout,
+ CFSTR(" Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n"));
}
listCnt = CFArrayGetCount(list);
key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
if (argc < 2) {
- if (!SCDynamicStoreAddValue(store, key, value)) {
- SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ if (!use_cache) {
+ if (!SCDynamicStoreAddValue(store, key, value)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ } else {
+ CFTypeRef val;
+
+ val = cache_SCDynamicStoreCopyValue(store, key);
+ if (val != NULL) {
+ CFRelease(val);
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists));
+ } else {
+ cache_SCDynamicStoreSetValue(store, key, value);
+ }
}
} else {
- if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
- SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ if (!use_cache) {
+ if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ } else {
+ CFTypeRef val;
+
+ val = cache_SCDynamicStoreCopyValue(store, key);
+ if (val != NULL) {
+ CFRelease(val);
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists));
+ } else {
+ if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ } else {
+ // and save the temp value in the cache too!
+ cache_SCDynamicStoreSetValue(store, key, value);
+ }
+ }
}
}
CFPropertyListRef newValue;
key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
- newValue = SCDynamicStoreCopyValue(store, key);
+ if (!use_cache) {
+ newValue = SCDynamicStoreCopyValue(store, key);
+ } else {
+ newValue = cache_SCDynamicStoreCopyValue(store, key);
+ }
CFRelease(key);
if (newValue == NULL) {
SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
CFStringRef key;
key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
- if (!SCDynamicStoreSetValue(store, key, value)) {
- SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ if (!use_cache) {
+ if (!SCDynamicStoreSetValue(store, key, value)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ } else {
+ cache_SCDynamicStoreSetValue(store, key, value);
}
CFRelease(key);
return;
key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
if (argc == 1) {
- newValue = SCDynamicStoreCopyValue(store, key);
+ if (!use_cache) {
+ newValue = SCDynamicStoreCopyValue(store, key);
+ } else {
+ newValue = cache_SCDynamicStoreCopyValue(store, key);
+ }
} else {
CFArrayRef patterns;
patterns = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
- newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns);
+ if (!use_cache) {
+ newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns);
+ } else {
+ CFArrayRef keys;
+ CFMutableDictionaryRef newDict;
+
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ keys = SCDynamicStoreCopyKeyList(store, key);
+ if (keys != NULL) {
+ CFIndex i;
+ CFIndex n;
+
+ n = CFArrayGetCount(keys);
+ for (i = 0; i < n; i++) {
+ CFStringRef storeKey;
+ CFTypeRef storeVal;
+
+ storeKey = CFArrayGetValueAtIndex(keys, i);
+ storeVal = cache_SCDynamicStoreCopyValue(store, storeKey);
+ if (storeVal != NULL) {
+ CFDictionarySetValue(newDict, storeKey, storeVal);
+ CFRelease(storeVal);
+ }
+ }
+ CFRelease(keys);
+ }
+
+ if ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0)) {
+ SCPrint(TRUE, stdout, CFSTR(" Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n"));
+ }
+
+ newValue = newDict;
+ }
CFRelease(patterns);
}
CFStringRef key;
key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
- if (!SCDynamicStoreRemoveValue(store, key)) {
- SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ if (!use_cache) {
+ if (!SCDynamicStoreRemoveValue(store, key)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ } else {
+ cache_SCDynamicStoreRemoveValue(store, key);
}
CFRelease(key);
return;
CFStringRef key;
key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
- if (!SCDynamicStoreNotifyValue(store, key)) {
- SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
- }
- CFRelease(key);
- return;
-}
-
-
-__private_extern__
-void
-do_touch(int argc, char **argv)
-{
- CFStringRef key;
-
- key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
- if (!SCDynamicStoreTouchValue(store, key)) {
- SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ if (!use_cache) {
+ if (!SCDynamicStoreNotifyValue(store, key)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ } else {
+ cache_SCDynamicStoreNotifyValue(store, key);
}
CFRelease(key);
return;