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

Reply via email to