Author: rfm
Date: Tue Apr 28 13:47:23 2015
New Revision: 38461
URL: http://svn.gna.org/viewcvs/gnustep?rev=38461&view=rev
Log:
performance tweaks
Modified:
libs/sqlclient/trunk/ChangeLog
libs/sqlclient/trunk/Postgres.m
libs/sqlclient/trunk/SQLClient.h
libs/sqlclient/trunk/SQLClient.m
libs/sqlclient/trunk/testPostgres.m
Modified: libs/sqlclient/trunk/ChangeLog
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/ChangeLog?rev=38461&r1=38460&r2=38461&view=diff
==============================================================================
--- libs/sqlclient/trunk/ChangeLog (original)
+++ libs/sqlclient/trunk/ChangeLog Tue Apr 28 13:47:23 2015
@@ -1,3 +1,13 @@
+2015-04-28 Richard Frith-Macdonald <[email protected]>
+
+ * SQLClient.h:
+ * SQLClient.m:
+ * Postgres.m:
+ Deprecate trtansaction merging.
+ Rewrite SQLRecord concrete class to use a new SQLRecordKeys object
+ shared between all the records produced by a query (as a performance
+ enhancement for large queries).
+
2015-04-15 Richard Frith-Macdonald <[email protected]>
* Postgres.m: notifications are posted in main thread.
Modified: libs/sqlclient/trunk/Postgres.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/Postgres.m?rev=38461&r1=38460&r2=38461&view=diff
==============================================================================
--- libs/sqlclient/trunk/Postgres.m (original)
+++ libs/sqlclient/trunk/Postgres.m Tue Apr 28 13:47:23 2015
@@ -772,6 +772,7 @@
int ftype[fieldCount];
int fmod[fieldCount];
int fformat[fieldCount];
+ SQLRecordKeys *k = nil;
int i;
for (i = 0; i < fieldCount; i++)
@@ -816,9 +817,25 @@
}
values[j] = v;
}
- record = [rtype newWithValues: values
- keys: keys
- count: fieldCount];
+ if (nil == k)
+ {
+ /* We don't have keys information, so use the
+ * constructor where we list keys and, if the
+ * resulting record provides keys information
+ * on the first record, we save it for later.
+ */
+ record = [rtype newWithValues: values
+ keys: keys
+ count: fieldCount];
+ if (0 == i)
+ {
+ k = [record keys];
+ }
+ }
+ else
+ {
+ record = [rtype newWithValues: values keys: k];
+ }
[records addObject: record];
[record release];
}
Modified: libs/sqlclient/trunk/SQLClient.h
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.h?rev=38461&r1=38460&r2=38461&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.h (original)
+++ libs/sqlclient/trunk/SQLClient.h Tue Apr 28 13:47:23 2015
@@ -208,6 +208,36 @@
#define SQLCLIENT_PRIVATE @private
#endif
+/** This class is used to hold key information for a set of SQLRecord
+ * objects produced by a single query.
+ */
+@interface SQLRecordKeys : NSObject
+{
+ NSUInteger count; // Number of keys
+ NSArray *order; // Keys in order
+ NSMapTable *map; // Key to index
+ NSMapTable *low; // lowercase map
+}
+
+/** Returns the number of keys in the receiver.
+ */
+- (NSUInteger) count;
+
+/** Returns the index of the object with the specified key,
+ * or NSNotFound if there is no such key.
+ */
+- (NSUInteger) indexForKey: (NSString*)key;
+
+/** Initialiser
+ */
+- (id) initWithKeys: (NSString**)keys count: (NSUInteger)c;
+
+/** Returns an array containing the record field names in order.
+ */
+- (NSArray*) order;
+
+@end
+
/**
* <p>An enhanced array to represent a record returned from a query.
* You should <em>NOT</em> try to create instances of this class
@@ -239,6 +269,17 @@
count: (unsigned int)c;
/**
+ * Create a new SQLRecord containing the specified fields.<br />
+ * NB. The values and keys are <em>retained</em> by the record rather
+ * than being copied.<br />
+ * A nil value is represented by [NSNull null].<br />
+ * This constructor will be used for subsequent records after the first
+ * in a query iff the first record created returns a non-nil result when
+ * sent the -keys method.
+ */
++ (id) newWithValues: (id*)v keys: (SQLRecordKeys*)k;
+
+/**
* Returns an array containing the names of all the fields in the record.
*/
- (NSArray*) allKeys;
@@ -266,9 +307,15 @@
- (void) getObjects: (id*)buf;
/** <override-subclass />
- * Returns the key at the specified indes.<br />
+ * Returns the key at the specified index.<br />
*/
- (NSString*) keyAtIndex: (NSUInteger)index;
+
+/** Returns the keys used by this record.
+ * The abstract class returns nil, so subclasses should override if
+ * they wish to make use of the +newWithValues:keys: method.
+ */
+- (SQLRecordKeys*) keys;
/** <override-subclass />
* Returns the object at the specified indes.<br />
@@ -1791,35 +1838,10 @@
*/
- (void) reset;
-/** <p>Use this method to enable merging of statemements subsequently added
- * or appended to the receiver. The history argument specifies how many
- * of the most recent statements in the transaction should be checked for
- * merging in a new statement, with a value of zero meaning that no
- * merging is done.<br />
- * Returns the previous setting for the transaction.
- * </p>
- * <p>You may use this feature with an insert statement of the form:<br />
- * INSERT INTO table (fieldnames) VALUES (values);<br />
- * For databases which support multiline inserts such that they can be
- * merged into something of the form:
- * INSERT INTO table (fieldnames) VALUES (values1),(values2),...;
- * </p>
- * <p>Or may use this with an update or delete statement of the form:<br />
- * command table SET settings WHERE condition;<br />
- * So that statements may be merged into:<br />
- * command table SET settings WHERE (condition1) OR (condition2) OR ...;
- * </p>
- * If no opportunity for merging is found, the new statement is simply
- * added to the transaction.<br />
- * Caveats:<br />
- * 1. databases may not actually support multiline insert.<br />
- * 2. Merging is done only if the statement up to the string 'VALUES'
- * (for insert) or 'WHERE' (for update) matches.<br />
- * 3. Merging into any of the last N statements (where N is greater than 1)
- * may of course change the order of statements in the transaction,
- * so care must be taken not to use this feature where that might matter.<br />
- * 4. This is a simple text match rather than sql syntactic analysis,
- * so it's possible to confuse the process with complex statements.
+/** <p>DEPRECATED ... merging of statments is quite database specific and
+ * also much better done by hand rather than trying to rely on anything
+ * automatic.
+ * </p>
*/
- (uint8_t) setMerge: (uint8_t)history;
Modified: libs/sqlclient/trunk/SQLClient.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/SQLClient.m?rev=38461&r1=38460&r2=38461&view=diff
==============================================================================
--- libs/sqlclient/trunk/SQLClient.m (original)
+++ libs/sqlclient/trunk/SQLClient.m Tue Apr 28 13:47:23 2015
@@ -73,6 +73,9 @@
NSString * const SQLClientDidDisconnectNotification
= @"SQLClientDidDisconnectNotification";
+static unsigned int classDebugging = 0;
+static NSTimeInterval classDuration = -1;
+
static NSNull *null = nil;
static NSArray *queryModes = nil;
static NSThread *mainThread = nil;
@@ -82,9 +85,76 @@
static Class NSSetClass = Nil;
static Class SQLClientClass = Nil;
+@implementation SQLRecordKeys
+
+- (NSUInteger) count
+{
+ return count;
+}
+
+- (void) dealloc
+{
+ if (nil != order) [order release];
+ if (nil != map) [map release];
+ if (nil != low) [low release];
+ [super dealloc];
+}
+
+- (NSUInteger) indexForKey: (NSString*)key
+{
+ NSUInteger c;
+
+ c = (NSUInteger)NSMapGet(map, key);
+ if (c > 0)
+ {
+ return c - 1;
+ }
+ key = [key lowercaseString];
+ c = (NSUInteger)NSMapGet(low, key);
+ if (c > 0)
+ {
+ if (classDebugging > 0)
+ {
+ NSLog(@"[SQLRecordKeys-indexForKey:] lowercase '%@'", key);
+ }
+ return c - 1;
+ }
+ return NSNotFound;
+}
+
+- (id) initWithKeys: (NSString**)keys count: (NSUInteger)c
+{
+ if (nil != (self = [super init]))
+ {
+ count = c;
+ order = [[NSArray alloc] initWithObjects: keys count: c];
+ map = NSCreateMapTable(NSObjectMapKeyCallBacks,
+ NSIntegerMapValueCallBacks, count);
+ low = NSCreateMapTable(NSObjectMapKeyCallBacks,
+ NSIntegerMapValueCallBacks, count);
+ for (c = 1; c <= count; c++)
+ {
+ NSString *k = keys[c-1];
+
+ NSMapInsert(map, (void*)k, (void*)c);
+ k = [k lowercaseString];
+ NSMapInsert(low, (void*)k, (void*)c);
+ }
+ }
+ return self;
+}
+
+- (NSArray*) order
+{
+ return order;
+}
+@end
+
+
@interface _ConcreteSQLRecord : SQLRecord
{
- unsigned count;
+ SQLRecordKeys *keys;
+ NSUInteger count; // Must be last
}
@end
@@ -132,6 +202,11 @@
return [rClass newWithValues: v keys: k count: c];
}
++ (id) newWithValues: (id*)v keys: (SQLRecordKeys*)k
+{
+ return [rClass newWithValues: v keys: k];
+}
+
- (NSArray*) allKeys
{
NSUInteger count = [self count];
@@ -186,7 +261,7 @@
- (void) getKeys: (id*)buf
{
- unsigned i = [self count];
+ NSUInteger i = [self count];
while (i-- > 0)
{
@@ -196,7 +271,7 @@
- (void) getObjects: (id*)buf
{
- unsigned i = [self count];
+ NSUInteger i = [self count];
while (i-- > 0)
{
@@ -214,6 +289,11 @@
- (NSString*) keyAtIndex: (NSUInteger)index
{
SUBCLASS_RESPONSIBILITY
+ return nil;
+}
+
+- (SQLRecordKeys*) keys
+{
return nil;
}
@@ -354,59 +434,68 @@
@implementation _ConcreteSQLRecord
++ (id) newWithValues: (id*)v keys: (SQLRecordKeys*)k
+{
+ id *ptr;
+ _ConcreteSQLRecord *r;
+ NSUInteger c;
+
+ c = [k count];
+ r = (_ConcreteSQLRecord*)NSAllocateObject(self,
+ c*sizeof(id), NSDefaultMallocZone());
+ r->count = c;
+ r->keys = [k retain];
+ ptr = (id*)(((void*)&(r->count)) + sizeof(r->count));
+ while (c-- > 0)
+ {
+ if (nil == v[c])
+ {
+ ptr[c] = [null retain];
+ }
+ else
+ {
+ ptr[c] = [v[c] retain];
+ }
+ }
+ return r;
+}
+
+ (id) newWithValues: (id*)v keys: (NSString**)k count: (unsigned int)c
{
+ SQLRecordKeys *o;
+ _ConcreteSQLRecord *r;
+
+ o = [[SQLRecordKeys alloc] initWithKeys: k count: c];
+ r = [self newWithValues: v keys: o];
+ [o release];
+ return r;
+}
+
+- (NSArray*) allKeys
+{
+ return [keys order];
+}
+
+- (id) copyWithZone: (NSZone*)z
+{
+ return [self retain];
+}
+
+- (NSUInteger) count
+{
+ return count;
+}
+
+- (void) dealloc
+{
id *ptr;
- _ConcreteSQLRecord *r;
- unsigned pos;
-
- r = (_ConcreteSQLRecord*)NSAllocateObject(self,
- c*2*sizeof(id), NSDefaultMallocZone());
- r->count = c;
- ptr = ((void*)&(r->count)) + sizeof(r->count);
- for (pos = 0; pos < c; pos++)
- {
- if (v[pos] == nil)
- {
- ptr[pos] = [null retain];
- }
- else
- {
- ptr[pos] = [v[pos] retain];
- }
- ptr[pos + c] = [k[pos] retain];
- }
- return r;
-}
-
-- (NSArray*) allKeys
-{
- id *ptr;
-
- ptr = ((void*)&count) + sizeof(count);
- return [NSArray arrayWithObjects: &ptr[count] count: count];
-}
-
-- (id) copyWithZone: (NSZone*)z
-{
- return [self retain];
-}
-
-- (NSUInteger) count
-{
- return count;
-}
-
-- (void) dealloc
-{
- id *ptr;
- unsigned pos;
-
- ptr = ((void*)&count) + sizeof(count);
+ NSUInteger pos;
+
+ [keys release];
+ ptr = (id*)(((void*)&count) + sizeof(count));
for (pos = 0; pos < count; pos++)
{
[ptr[pos] release]; ptr[pos] = nil;
- [ptr[count + pos] release]; ptr[count + pos] = nil;
}
[super dealloc];
}
@@ -414,37 +503,31 @@
- (NSMutableDictionary*) dictionary
{
NSMutableDictionary *d;
- unsigned pos;
+ NSUInteger pos;
+ NSArray *k = [keys order];
id *ptr;
- ptr = ((void*)&count) + sizeof(count);
+ ptr = (id*)(((void*)&count) + sizeof(count));
d = [NSMutableDictionary dictionaryWithCapacity: count];
for (pos = 0; pos < count; pos++)
{
- [d setObject: ptr[pos] forKey: [ptr[pos + count] lowercaseString]];
+ [d setObject: ptr[pos]
+ forKey: [[k objectAtIndex: pos] lowercaseString]];
}
return d;
}
- (void) getKeys: (id*)buf
{
+ [[keys order] getObjects: buf];
+}
+
+- (void) getObjects: (id*)buf
+{
id *ptr;
- unsigned pos;
-
- ptr = ((void*)&count) + sizeof(count);
- ptr += count; // Step past objects to keys.
- for (pos = 0; pos < count; pos++)
- {
- buf[pos] = ptr[pos];
- }
-}
-
-- (void) getObjects: (id*)buf
-{
- id *ptr;
- unsigned pos;
-
- ptr = ((void*)&count) + sizeof(count);
+ NSUInteger pos;
+
+ ptr = (id*)(((void*)&count) + sizeof(count));
for (pos = 0; pos < count; pos++)
{
buf[pos] = ptr[pos];
@@ -460,6 +543,16 @@
- (NSString*) keyAtIndex: (NSUInteger)pos
{
+ return [[keys order] objectAtIndex: pos];
+}
+
+- (SQLRecordKeys*) keys
+{
+ return keys;
+}
+
+- (id) objectAtIndex: (NSUInteger)pos
+{
id *ptr;
if (pos >= count)
@@ -467,61 +560,41 @@
[NSException raise: NSRangeException
format: @"Array index too large"];
}
- ptr = ((void*)&count) + sizeof(count);
- ptr += count;
+ ptr = (id*)(((void*)&count) + sizeof(count));
return ptr[pos];
}
-- (id) objectAtIndex: (NSUInteger)pos
-{
- id *ptr;
-
- if (pos >= count)
+- (id) objectForKey: (NSString*)key
+{
+ NSUInteger pos = [keys indexForKey: key];
+
+ if (NSNotFound == pos)
+ {
+ return nil;
+ }
+ else
+ {
+ id *ptr;
+
+ ptr = (id*)(((void*)&count) + sizeof(count));
+ return ptr[pos];
+ }
+}
+
+- (void) replaceObjectAtIndex: (NSUInteger)index withObject: (id)anObject
+{
+ id *ptr;
+
+ if (index >= count)
{
[NSException raise: NSRangeException
format: @"Array index too large"];
}
- ptr = ((void*)&count) + sizeof(count);
- return ptr[pos];
-}
-
-- (id) objectForKey: (NSString*)key
-{
- id *ptr;
- unsigned int pos;
-
- ptr = ((void*)&count) + sizeof(count);
- for (pos = 0; pos < count; pos++)
- {
- if ([key isEqualToString: ptr[pos + count]] == YES)
- {
- return ptr[pos];
- }
- }
- for (pos = 0; pos < count; pos++)
- {
- if ([key caseInsensitiveCompare: ptr[pos + count]] == NSOrderedSame)
- {
- return ptr[pos];
- }
- }
- return nil;
-}
-
-- (void) replaceObjectAtIndex: (NSUInteger)index withObject: (id)anObject
-{
- id *ptr;
-
- if (index >= count)
- {
- [NSException raise: NSRangeException
- format: @"Array index too large"];
- }
if (anObject == nil)
{
anObject = null;
}
- ptr = ((void*)&count) + sizeof(count);
+ ptr = (id*)(((void*)&count) + sizeof(count));
ptr += index;
[anObject retain];
[*ptr release];
@@ -531,35 +604,25 @@
- (void) setObject: (id)anObject forKey: (NSString*)aKey
{
id *ptr;
- unsigned int pos;
+ NSUInteger pos;
if (anObject == nil)
{
anObject = null;
}
- ptr = ((void*)&count) + sizeof(count);
- for (pos = 0; pos < count; pos++)
- {
- if ([aKey isEqualToString: ptr[pos + count]] == YES)
- {
- [anObject retain];
- [ptr[pos] release];
- ptr[pos] = anObject;
- return;
- }
- }
- for (pos = 0; pos < count; pos++)
- {
- if ([aKey caseInsensitiveCompare: ptr[pos + count]] == NSOrderedSame)
- {
- [anObject retain];
- [ptr[pos] release];
- ptr[pos] = anObject;
- return;
- }
- }
- [NSException raise: NSInvalidArgumentException
- format: @"Bad key (%@) in -setObject:forKey:", aKey];
+ ptr = (id*)(((void*)&count) + sizeof(count));
+ pos = [keys indexForKey: aKey];
+ if (NSNotFound == pos)
+ {
+ [NSException raise: NSInvalidArgumentException
+ format: @"Bad key (%@) in -setObject:forKey:", aKey];
+ }
+ else
+ {
+ [anObject retain];
+ [ptr[pos] release];
+ ptr[pos] = anObject;
+ }
}
- (NSUInteger) sizeInBytes: (NSMutableSet*)exclude
@@ -574,7 +637,7 @@
NSUInteger pos;
id *ptr;
- ptr = ((void*)&count) + sizeof(count);
+ ptr = (id*)(((void*)&count) + sizeof(count));
for (pos = 0; pos < count; pos++)
{
size += [ptr[pos] sizeInBytes: exclude];
@@ -604,9 +667,6 @@
NSString *SQLUniqueException = @"SQLUniqueException";
@implementation SQLClient (Logging)
-
-static unsigned int classDebugging = 0;
-static NSTimeInterval classDuration = -1;
+ (unsigned int) debugging
{
Modified: libs/sqlclient/trunk/testPostgres.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/sqlclient/trunk/testPostgres.m?rev=38461&r1=38460&r2=38461&view=diff
==============================================================================
--- libs/sqlclient/trunk/testPostgres.m (original)
+++ libs/sqlclient/trunk/testPostgres.m Tue Apr 28 13:47:23 2015
@@ -367,9 +367,10 @@
{
NSLog(@"Retrieved non-latin does not match saved string");
}
- if ([[record objectForKey: @"k"] isEqual: oddChars] == NO)
- {
- NSLog(@"Retrieved odd chars does not match saved string");
+ id o = [[record objectForKey: @"k"] stringByTrimmingSpaces];
+ if ([o isEqual: oddChars] == NO)
+ {
+ NSLog(@"Retrieved odd chars (%@) does not match saved string
(%@)", o, oddChars);
}
}
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs