The Tiny HTM Library
src/tree.c
Go to the documentation of this file.
00001 
00009 #include "tinyhtm/tree.h"
00010 
00011 #include <errno.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <sys/types.h>
00015 #include <sys/stat.h>
00016 #include <sys/mman.h>
00017 #include <fcntl.h>
00018 #include <unistd.h>
00019 
00020 #include "tinyhtm/varint.h"
00021 
00022 #ifdef __cplusplus
00023 extern "C" {
00024 #endif
00025 
00026 
00027 enum htm_errcode htm_tree_init(struct htm_tree *tree,
00028                                const char * const treefile,
00029                                const char * const datafile)
00030 {
00031     struct stat sb;
00032     const unsigned char *s;
00033     uint64_t off, count;
00034     int i;
00035     const size_t pagesz =  (size_t) sysconf(_SC_PAGESIZE);
00036     enum htm_errcode err = HTM_OK;
00037 
00038     /* set defaults */
00039     tree->leafthresh = 0;
00040     tree->count = 0;
00041     for (i = 0; i < 8; ++i) {
00042         tree->root[i] = NULL;
00043     }
00044     tree->entries = (const struct htm_tree_entry *) MAP_FAILED;
00045     tree->index = (const void *) MAP_FAILED;
00046     tree->indexsz = 0;
00047     tree->datasz = 0;
00048     tree->indexfd = -1;
00049     tree->datafd = -1;
00050 
00051     /* check inputs */
00052     if (tree == NULL || datafile == NULL) {
00053         return HTM_ENULLPTR;
00054     }
00055     if (stat(datafile, &sb) != 0) {
00056         return HTM_EIO;
00057     }
00058     if (sb.st_size % sizeof(struct htm_tree_entry) != 0 || sb.st_size == 0) {
00059         return HTM_EINV;
00060     }
00061     count = (uint64_t) sb.st_size / sizeof(struct htm_tree_entry);
00062 
00063     /* memory map datafile */
00064     tree->datasz = (size_t) sb.st_size;
00065     if (tree->datasz % pagesz != 0) {
00066         tree->datasz += pagesz - tree->datasz % pagesz;
00067     }
00068     tree->datafd = open(datafile, O_RDONLY);
00069     if (tree->datafd == -1) {
00070         err = HTM_EIO;
00071         goto cleanup;
00072     }
00073     tree->entries = (const struct htm_tree_entry *) mmap(
00074         NULL, tree->datasz, PROT_READ, MAP_SHARED | MAP_NORESERVE,
00075         tree->datafd, 0);
00076     if ((void *) tree->entries == MAP_FAILED) {
00077         err = HTM_EMMAN;
00078         goto cleanup;
00079     }
00080     if (madvise((void *) tree->entries, tree->datasz, MADV_RANDOM) != 0) {
00081         err = HTM_EMMAN;
00082         goto cleanup;
00083     }
00084 
00085     /* memory map treefile (if there is one) */
00086     if (treefile == NULL) {
00087         tree->count = count;
00088         return HTM_OK;
00089     }
00090     if (stat(treefile, &sb) != 0) {
00091         err = HTM_EIO;
00092         goto cleanup;
00093     }
00094     tree->indexsz = (size_t) sb.st_size;
00095     if (tree->indexsz % pagesz != 0) {
00096         tree->indexsz += pagesz - tree->indexsz % pagesz;
00097     }
00098     tree->indexfd = open(treefile, O_RDONLY);
00099     if (tree->indexfd == -1) {
00100         err = HTM_EIO;
00101         goto cleanup;
00102     }
00103     tree->index = (const void *) mmap(
00104         NULL, tree->indexsz, PROT_READ, MAP_SHARED | MAP_NORESERVE,
00105         tree->indexfd, 0);
00106     if ((void *) tree->index == MAP_FAILED) {
00107         err = HTM_EMMAN;
00108         goto cleanup;
00109     }
00110     if (madvise((void *) tree->index, tree->indexsz, MADV_RANDOM) != 0) {
00111         err = HTM_EMMAN;
00112         goto cleanup;
00113     }
00114 
00115     /* parse tree file header */
00116     s = (const unsigned char *) tree->index;
00117     tree->leafthresh = htm_varint_decode(s);
00118     s += 1 + htm_varint_nfollow(*s);
00119     tree->count = htm_varint_decode(s);
00120     s += 1 + htm_varint_nfollow(*s);
00121     if (tree->count != count) {
00122         /* tree index point count does not agree with data file */
00123         err = HTM_ETREE;
00124         goto cleanup;
00125     }
00126     for (i = 0; i < 8; ++i) {
00127         off = htm_varint_decode(s);
00128         s += 1 + htm_varint_nfollow(*s);
00129         if (off == 0) {
00130             tree->root[i] = NULL;
00131         } else {
00132             tree->root[i] = s + (off - 1);
00133         }
00134     }
00135     if (s - (const unsigned char *) tree->index >= sb.st_size) {
00136         /* header overflowed tree file size */
00137         err = HTM_ETREE;
00138         goto cleanup;
00139     }
00140     return HTM_OK;
00141 
00142 cleanup:
00143     htm_tree_destroy(tree);
00144     return err;
00145 }
00146 
00147 
00148 void htm_tree_destroy(struct htm_tree *tree)
00149 {
00150     int i;
00151     if (tree == NULL) {
00152         return;
00153     }
00154     /* unmap and close data file */
00155     if ((void *) tree->entries != MAP_FAILED) {
00156         munmap((void *)tree->entries, tree->datasz);
00157         tree->entries = (const struct htm_tree_entry *) MAP_FAILED;
00158     }
00159     tree->datasz = 0;
00160     if (tree->datafd != -1) {
00161         close(tree->datafd);
00162         tree->datafd = -1;
00163     }
00164     /* unmap and close tree file */
00165     if (tree->index != MAP_FAILED) {
00166         munmap((void *)tree->index, tree->indexsz);
00167         tree->index = (const void *) MAP_FAILED;
00168     }
00169     tree->indexsz = 0;
00170     if (tree->indexfd != -1) {
00171         close(tree->indexfd);
00172         tree->indexfd = - 1;
00173     }
00174     /* set remaining fields to default values */
00175     tree->leafthresh = 0;
00176     tree->count = 0;
00177     for (i = 0; i < 8; ++i) {
00178         tree->root[i] = NULL;
00179     }
00180 }
00181 
00182 
00183 enum htm_errcode htm_tree_lock(struct htm_tree *tree, size_t datathresh)
00184 {
00185     if (tree == NULL) {
00186         return HTM_ENULLPTR;
00187     }
00188     if (tree->indexfd != -1) {
00189         if (mlock(tree->index, tree->indexsz) != 0) {
00190             return HTM_ENOMEM;
00191         }
00192     }
00193     if (tree->datasz <= datathresh) {
00194         if (mlock(tree->entries, tree->datasz) != 0) {
00195             return HTM_ENOMEM;
00196         }
00197     }
00198     return HTM_OK;
00199 }
00200 
00201 
00202 int64_t htm_tree_s2circle_scan(const struct htm_tree *tree,
00203                                const struct htm_v3 *center,
00204                                double radius,
00205                                enum htm_errcode *err)
00206 {
00207     double dist2;
00208     int64_t count;
00209     uint64_t i;
00210 
00211     if (tree == NULL || center == NULL) {
00212         if (err != NULL) {
00213             *err = HTM_ENULLPTR;
00214         }
00215         return -1;
00216     }
00217     if (radius < 0.0) {
00218         return 0;
00219     } else if (radius >= 180.0) {
00220         return (int64_t) tree->count;
00221     }
00222     dist2 = sin(radius * 0.5 * HTM_RAD_PER_DEG);
00223     dist2 = 4.0 * dist2 * dist2;
00224     count = 0;
00225     for (i = 0, count = 0; i < tree->count; ++i) {
00226         if (htm_v3_dist2(center, &tree->entries[i].v) <= dist2) {
00227             ++count;
00228         }
00229     }
00230     return count;
00231 }
00232 
00233 
00234 int64_t htm_tree_s2ellipse_scan(const struct htm_tree *tree,
00235                                 const struct htm_s2ellipse *ellipse,
00236                                 enum htm_errcode *err)
00237 {
00238     int64_t count;
00239     uint64_t i;
00240 
00241     if (tree == NULL || ellipse == NULL) {
00242         if (err != NULL) {
00243             *err = HTM_ENULLPTR;
00244         }
00245         return -1;
00246     }
00247     count = 0;
00248     for (i = 0, count = 0; i < tree->count; ++i) {
00249         if (htm_s2ellipse_cv3(ellipse, &tree->entries[i].v) != 0) {
00250             ++count;
00251         }
00252     }
00253     return count;
00254 }
00255 
00256 
00257 int64_t htm_tree_s2cpoly_scan(const struct htm_tree *tree,
00258                               const struct htm_s2cpoly *poly,
00259                               enum htm_errcode *err)
00260 {
00261     int64_t count;
00262     uint64_t i;
00263 
00264     if (tree == NULL || poly == NULL) {
00265         if (err != NULL) {
00266             *err = HTM_ENULLPTR;
00267         }
00268         return -1;
00269     }
00270     count = 0;
00271     for (i = 0, count = 0; i < tree->count; ++i) {
00272         if (htm_s2cpoly_cv3(poly, &tree->entries[i].v) != 0) {
00273             ++count;
00274         }
00275     }
00276     return count;
00277 }
00278 
00279 
00280 #ifdef __cplusplus
00281 }
00282 #endif
00283