]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Update comments in the R-Tree module in preparation for some big changes.
authordrh <drh@noemail.net>
Fri, 11 Apr 2014 16:14:54 +0000 (16:14 +0000)
committerdrh <drh@noemail.net>
Fri, 11 Apr 2014 16:14:54 +0000 (16:14 +0000)
Add an "rtree" performance test to speedtest1.

FossilOrigin-Name: 20a73ec0b2f56609a4504052e198e32803d30207

ext/rtree/rtree.c
manifest
manifest.uuid
test/speedtest1.c

index cefb9a8b2a81ca089ee8436b2bb34b3586fed6e0..2034ff693f5d91934a5f0932df9857a7cc66df77 100644 (file)
 #include "sqlite3rtree.h"
 typedef sqlite3_int64 i64;
 typedef unsigned char u8;
+typedef unsigned short u16;
 typedef unsigned int u32;
 #endif
 
@@ -135,7 +136,7 @@ typedef union RtreeCoord RtreeCoord;
 ** ever contain very many entries, so a fixed number of buckets is 
 ** used.
 */
-#define HASHSIZE 128
+#define HASHSIZE 97
 
 /* The xBestIndex method of this virtual table requires an estimate of
 ** the number of rows in the virtual table to calculate the costs of
@@ -151,15 +152,15 @@ typedef union RtreeCoord RtreeCoord;
 ** An rtree virtual-table object.
 */
 struct Rtree {
-  sqlite3_vtab base;
+  sqlite3_vtab base;          /* Base class.  Must be first */
   sqlite3 *db;                /* Host database connection */
   int iNodeSize;              /* Size in bytes of each node in the node table */
-  int nDim;                   /* Number of dimensions */
-  int nBytesPerCell;          /* Bytes consumed per cell */
+  u8 nDim;                    /* Number of dimensions */
+  u8 eCoordType;              /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
+  u8 nBytesPerCell;           /* Bytes consumed per cell */
   int iDepth;                 /* Current depth of the r-tree structure */
   char *zDb;                  /* Name of database containing r-tree table */
   char *zName;                /* Name of r-tree table */ 
-  RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ 
   int nBusy;                  /* Current number of users of this structure */
   i64 nRowEst;                /* Estimated number of rows in this table */
 
@@ -186,10 +187,10 @@ struct Rtree {
   sqlite3_stmt *pWriteParent;
   sqlite3_stmt *pDeleteParent;
 
-  int eCoordType;
+  RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ 
 };
 
-/* Possible values for eCoordType: */
+/* Possible values for Rtree.eCoordType: */
 #define RTREE_COORD_REAL32 0
 #define RTREE_COORD_INT32  1
 
@@ -232,7 +233,7 @@ struct Rtree {
 ** An rtree cursor object.
 */
 struct RtreeCursor {
-  sqlite3_vtab_cursor base;
+  sqlite3_vtab_cursor base;         /* Base class.  Must be first */
   RtreeNode *pNode;                 /* Node cursor is currently pointing at */
   int iCell;                        /* Index of current cell in pNode */
   int iStrategy;                    /* Copy of idxNum search parameter */
@@ -240,9 +241,13 @@ struct RtreeCursor {
   RtreeConstraint *aConstraint;     /* Search constraints. */
 };
 
+/*
+** A coordinate can be either a floating point number or a integer.  All
+** coordinates within a single R-Tree are always of the same time.
+*/
 union RtreeCoord {
-  RtreeValue f;
-  int i;
+  RtreeValue f;      /* Floating point value */
+  int i;             /* Integer value */
 };
 
 /*
@@ -284,21 +289,23 @@ struct RtreeConstraint {
 ** An rtree structure node.
 */
 struct RtreeNode {
-  RtreeNode *pParent;               /* Parent node */
-  i64 iNode;
-  int nRef;
-  int isDirty;
-  u8 *zData;
-  RtreeNode *pNext;                 /* Next node in this hash chain */
+  RtreeNode *pParent;          /* Parent node */
+  i64 iNode;                   /* The node number */
+  int nRef;                    /* Number of references to this node */
+  int isDirty;                 /* True if the node needs to be written to disk */
+  u8 *zData;                   /* Content of the node, as should be on disk */
+  RtreeNode *pNext;            /* Next node in this hash collision chain */
 };
+
+/* Return the number of cells in a node  */
 #define NCELL(pNode) readInt16(&(pNode)->zData[2])
 
 /* 
-** Structure to store a deserialized rtree record.
+** A single cell from a node, deserialized
 */
 struct RtreeCell {
-  i64 iRowid;
-  RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];
+  i64 iRowid;                                 /* Node or entry ID */
+  RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];  /* Bounding box coordinates */
 };
 
 
@@ -426,10 +433,7 @@ static void nodeZero(Rtree *pRtree, RtreeNode *p){
 ** in the Rtree.aHash table.
 */
 static int nodeHash(i64 iNode){
-  return (
-    (iNode>>56) ^ (iNode>>48) ^ (iNode>>40) ^ (iNode>>32) ^ 
-    (iNode>>24) ^ (iNode>>16) ^ (iNode>> 8) ^ (iNode>> 0)
-  ) % HASHSIZE;
+  return iNode % HASHSIZE;
 }
 
 /*
@@ -489,8 +493,7 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
 /*
 ** Obtain a reference to an r-tree node.
 */
-static int
-nodeAcquire(
+static int nodeAcquire(
   Rtree *pRtree,             /* R-tree structure */
   i64 iNode,                 /* Node number to load */
   RtreeNode *pParent,        /* Either the parent node or NULL */
@@ -579,10 +582,10 @@ nodeAcquire(
 ** Overwrite cell iCell of node pNode with the contents of pCell.
 */
 static void nodeOverwriteCell(
-  Rtree *pRtree, 
-  RtreeNode *pNode,  
-  RtreeCell *pCell, 
-  int iCell
+  Rtree *pRtree,             /* The overall R-Tree */
+  RtreeNode *pNode,          /* The node into which the cell is to be written */
+  RtreeCell *pCell,          /* The cell to write */
+  int iCell                  /* Index into pNode into which pCell is written */
 ){
   int ii;
   u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
@@ -594,7 +597,7 @@ static void nodeOverwriteCell(
 }
 
 /*
-** Remove cell the cell with index iCell from node pNode.
+** Remove the cell with index iCell from node pNode.
 */
 static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){
   u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
@@ -611,11 +614,10 @@ static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){
 **
 ** If there is not enough free space in pNode, return SQLITE_FULL.
 */
-static int
-nodeInsertCell(
-  Rtree *pRtree, 
-  RtreeNode *pNode, 
-  RtreeCell *pCell 
+static int nodeInsertCell(
+  Rtree *pRtree,                /* The overall R-Tree */
+  RtreeNode *pNode,             /* Write new cell into this node */
+  RtreeCell *pCell              /* The cell to be inserted */
 ){
   int nCell;                    /* Current number of cells in pNode */
   int nMaxCell;                 /* Maximum number of cells for pNode */
@@ -636,8 +638,7 @@ nodeInsertCell(
 /*
 ** If the node is dirty, write it out to the database.
 */
-static int
-nodeWrite(Rtree *pRtree, RtreeNode *pNode){
+static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){
   int rc = SQLITE_OK;
   if( pNode->isDirty ){
     sqlite3_stmt *p = pRtree->pWriteNode;
@@ -662,8 +663,7 @@ nodeWrite(Rtree *pRtree, RtreeNode *pNode){
 ** Release a reference to a node. If the node is dirty and the reference
 ** count drops to zero, the node data is written to the database.
 */
-static int
-nodeRelease(Rtree *pRtree, RtreeNode *pNode){
+static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){
   int rc = SQLITE_OK;
   if( pNode ){
     assert( pNode->nRef>0 );
@@ -691,9 +691,9 @@ nodeRelease(Rtree *pRtree, RtreeNode *pNode){
 ** an internal node, then the 64-bit integer is a child page number.
 */
 static i64 nodeGetRowid(
-  Rtree *pRtree, 
-  RtreeNode *pNode, 
-  int iCell
+  Rtree *pRtree,       /* The overall R-Tree */
+  RtreeNode *pNode,    /* The node from which to extract the ID */
+  int iCell            /* The cell index from which to extract the ID */
 ){
   assert( iCell<NCELL(pNode) );
   return readInt64(&pNode->zData[4 + pRtree->nBytesPerCell*iCell]);
@@ -703,11 +703,11 @@ static i64 nodeGetRowid(
 ** Return coordinate iCoord from cell iCell in node pNode.
 */
 static void nodeGetCoord(
-  Rtree *pRtree, 
-  RtreeNode *pNode, 
-  int iCell,
-  int iCoord,
-  RtreeCoord *pCoord           /* Space to write result to */
+  Rtree *pRtree,               /* The overall R-Tree */
+  RtreeNode *pNode,            /* The node from which to extract a coordinate */
+  int iCell,                   /* The index of the cell within the node */
+  int iCoord,                  /* Which coordinate to extract */
+  RtreeCoord *pCoord           /* OUT: Space to write result to */
 ){
   readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
 }
@@ -717,10 +717,10 @@ static void nodeGetCoord(
 ** to by pCell with the results.
 */
 static void nodeGetCell(
-  Rtree *pRtree, 
-  RtreeNode *pNode, 
-  int iCell,
-  RtreeCell *pCell
+  Rtree *pRtree,               /* The overall R-Tree */
+  RtreeNode *pNode,            /* The node containing the cell to be read */
+  int iCell,                   /* Index of the cell within the node */
+  RtreeCell *pCell             /* OUT: Write the cell contents here */
 ){
   int ii;
   pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
index 0602716bed0ca59ef81a201b23dbe7ae9645514c..1a7e491bc34b559f89f4f61e12352cc420158bab 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\sall\srecent\schanges\sfrom\strunk,\nincluding\sthe\sfix\sfor\sthe\sOP_SCopy-vs-OP_Copy\sproblem.
-D 2014-04-03T16:35:33.203
+C Update\scomments\sin\sthe\sR-Tree\smodule\sin\spreparation\sfor\ssome\sbig\schanges.\nAdd\san\s"rtree"\sperformance\stest\sto\sspeedtest1.
+D 2014-04-11T16:14:54.092
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in e4ee6d36cdf6136aee0158675a3b24dd3bf31a5a
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -120,7 +120,7 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
 F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
 F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/rtree.c 2d9f95da404d850474e628c720c5ce15d29b47de
+F ext/rtree/rtree.c 043f16a6c3f823c760657b975f2ff1de7fe5c197
 F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
 F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
@@ -840,7 +840,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
 F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
-F test/speedtest1.c 90446861e566a9965a8d005381a3c964ff333646
+F test/speedtest1.c 3e06b48e8c578eaa61a01e8c7c4d8734c9dd3776
 F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
 F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
 F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
@@ -1174,7 +1174,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P fc8ca1a87e7127bd28f32fd809aec3e24355fbfa d5513dfa23baa0b0a095aaf17d19aacd30dcef61
-R 507e4fb477cf51261d2563e52f7cfa77
+P 9515c8344a6743bbb0c6a6e49fb79fb3139090df
+R 57f2249bba89c44cd5839664eafe6658
+T *branch * rtree-enhancements
+T *sym-rtree-enhancements *
+T -sym-sessions *
 U drh
-Z a91c37323943563a6d3bfb60a104e003
+Z bdd5cbefa0a4dcc9a9cc6ed610b85f71
index 7a0e457ea730c2ad8afcfd9806d05cd2a68f62bc..d8135897dd1029a63ad8b27483533ec2dea68748 100644 (file)
@@ -1 +1 @@
-9515c8344a6743bbb0c6a6e49fb79fb3139090df
\ No newline at end of file
+20a73ec0b2f56609a4504052e198e32803d30207
\ No newline at end of file
index 28c24e0885a1a45e05ececbd11b8034463b3d186..a32f12f92349ba5d4c509e632b13c9b46ad3bae6 100644 (file)
@@ -931,6 +931,98 @@ void testset_cte(void){
 
 }
 
+/* Generate two numbers between 1 and mx.  The first number is less than
+** the second.  Usually the numbers are near each other but can sometimes
+** be far apart.
+*/
+static void twoCoords(
+  unsigned mx,                      /* Range of 1..mx */
+  unsigned *pX0, unsigned *pX1      /* OUT: write results here */
+){
+  unsigned d, x0, x1, span;
+
+  span = mx/100 + 1;
+  if( speedtest1_random()%3==0 ) span *= 3;
+  if( speedtest1_random()%17==0 ) span = mx - 5;
+  d = speedtest1_random()%span + 1;
+  x0 = speedtest1_random()%(mx-d) + 1;
+  x1 = x0 + d;
+  *pX0 = x0;
+  *pX1 = x1;
+}
+
+/*
+** A testset for the R-Tree virtual table
+*/
+void testset_rtree(void){
+  unsigned i, n;
+  unsigned mxCoord;
+  unsigned x0, x1, y0, y1, z0, z1;
+
+  mxCoord = g.szTest*600;
+  n = g.szTest*100;
+  speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
+  speedtest1_exec("BEGIN");
+  speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
+  speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)"
+                     "VALUES(?1,?2,?3,?4,?5,?6,?7)");
+  for(i=1; i<=n; i++){
+    twoCoords(mxCoord, &x0, &x1);
+    twoCoords(mxCoord, &y0, &y1);
+    twoCoords(mxCoord, &z0, &z1);
+    sqlite3_bind_int(g.pStmt, 1, i);
+    sqlite3_bind_int(g.pStmt, 2, x0);
+    sqlite3_bind_int(g.pStmt, 3, x1);
+    sqlite3_bind_int(g.pStmt, 4, y0);
+    sqlite3_bind_int(g.pStmt, 5, y1);
+    sqlite3_bind_int(g.pStmt, 6, z0);
+    sqlite3_bind_int(g.pStmt, 7, z1);
+    speedtest1_run();
+  }
+  speedtest1_exec("COMMIT");
+  speedtest1_end_test();
+
+  n = g.szTest*20;
+  speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
+  speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
+  for(i=0; i<mxCoord; i+=(mxCoord/n)){
+    sqlite3_bind_int(g.pStmt, 1, i);
+    sqlite3_bind_int(g.pStmt, 2, i+mxCoord/n);
+    speedtest1_run();
+  }
+  speedtest1_end_test();
+
+  n = g.szTest*20;
+  speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
+  speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
+  for(i=0; i<mxCoord; i+=(mxCoord/n)){
+    sqlite3_bind_int(g.pStmt, 1, i);
+    sqlite3_bind_int(g.pStmt, 2, i+mxCoord/n);
+    speedtest1_run();
+  }
+  speedtest1_end_test();
+
+  n = g.szTest*80;
+  speedtest1_begin_test(130, "%d three-dimensional intersect box queries", n);
+  speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x1>=?1 AND x0<=?2"
+                     " AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2");
+  for(i=0; i<mxCoord; i+=(mxCoord/n)){
+    sqlite3_bind_int(g.pStmt, 1, i);
+    sqlite3_bind_int(g.pStmt, 2, i+mxCoord/n);
+    speedtest1_run();
+  }
+  speedtest1_end_test();
+
+  n = g.szTest*100;
+  speedtest1_begin_test(140, "%d rowid queries", n);
+  speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1");
+  for(i=1; i<=n; i++){
+    sqlite3_bind_int(g.pStmt, 1, i);
+    speedtest1_run();
+  }
+  speedtest1_end_test();
+}
+
 /*
 ** A testset used for debugging speedtest1 itself.
 */
@@ -1141,8 +1233,11 @@ int main(int argc, char **argv){
     testset_debug1();
   }else if( strcmp(zTSet,"cte")==0 ){
     testset_cte();
+  }else if( strcmp(zTSet,"rtree")==0 ){
+    testset_rtree();
   }else{
-    fatal_error("unknown testset: \"%s\"\n", zTSet);
+    fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n",
+                 zTSet);
   }
   speedtest1_final();