The Tiny HTM Library
|
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