1d4afb5ceSopenharmony_ci /* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci * 24d4afb5ceSopenharmony_ci * The functions allow 25d4afb5ceSopenharmony_ci * 26d4afb5ceSopenharmony_ci * - collecting a concordance of strings from one or more files (eg, a 27d4afb5ceSopenharmony_ci * directory of files) into a single in-memory, lac-backed trie; 28d4afb5ceSopenharmony_ci * 29d4afb5ceSopenharmony_ci * - to optimize and serialize the in-memory trie to an fd; 30d4afb5ceSopenharmony_ci * 31d4afb5ceSopenharmony_ci * - to very quickly report any instances of a string in any of the files 32d4afb5ceSopenharmony_ci * indexed by the trie, by a seeking around a serialized trie fd, without 33d4afb5ceSopenharmony_ci * having to load it all in memory 34d4afb5ceSopenharmony_ci */ 35d4afb5ceSopenharmony_ci 36d4afb5ceSopenharmony_ci#include "private-lib-core.h" 37d4afb5ceSopenharmony_ci#include "private-lib-misc-fts.h" 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci#include <stdio.h> 40d4afb5ceSopenharmony_ci#include <string.h> 41d4afb5ceSopenharmony_ci#include <assert.h> 42d4afb5ceSopenharmony_ci#include <fcntl.h> 43d4afb5ceSopenharmony_ci#include <errno.h> 44d4afb5ceSopenharmony_ci#include <sys/types.h> 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_cistruct lws_fts_entry; 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_ci/* notice these are stored in t->lwsac_input_head which has input file scope */ 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_cistruct lws_fts_filepath { 51d4afb5ceSopenharmony_ci struct lws_fts_filepath *next; 52d4afb5ceSopenharmony_ci struct lws_fts_filepath *prev; 53d4afb5ceSopenharmony_ci char filepath[256]; 54d4afb5ceSopenharmony_ci jg2_file_offset ofs; 55d4afb5ceSopenharmony_ci jg2_file_offset line_table_ofs; 56d4afb5ceSopenharmony_ci int filepath_len; 57d4afb5ceSopenharmony_ci int file_index; 58d4afb5ceSopenharmony_ci int total_lines; 59d4afb5ceSopenharmony_ci int priority; 60d4afb5ceSopenharmony_ci}; 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci/* notice these are stored in t->lwsac_input_head which has input file scope */ 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_cistruct lws_fts_lines { 65d4afb5ceSopenharmony_ci struct lws_fts_lines *lines_next; 66d4afb5ceSopenharmony_ci /* 67d4afb5ceSopenharmony_ci * amount of line numbers needs to meet average count for best 68d4afb5ceSopenharmony_ci * efficiency. 69d4afb5ceSopenharmony_ci * 70d4afb5ceSopenharmony_ci * Line numbers are stored in VLI format since if we don't, around half 71d4afb5ceSopenharmony_ci * the total lac allocation consists of struct lws_fts_lines... 72d4afb5ceSopenharmony_ci * size chosen to maintain 8-byte struct alignment 73d4afb5ceSopenharmony_ci */ 74d4afb5ceSopenharmony_ci uint8_t vli[119]; 75d4afb5ceSopenharmony_ci char count; 76d4afb5ceSopenharmony_ci}; 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci/* this represents the instances of a symbol inside a given filepath */ 79d4afb5ceSopenharmony_ci 80d4afb5ceSopenharmony_cistruct lws_fts_instance_file { 81d4afb5ceSopenharmony_ci /* linked-list of tifs generated for current file */ 82d4afb5ceSopenharmony_ci struct lws_fts_instance_file *inst_file_next; 83d4afb5ceSopenharmony_ci struct lws_fts_entry *owner; 84d4afb5ceSopenharmony_ci struct lws_fts_lines *lines_list, *lines_tail; 85d4afb5ceSopenharmony_ci uint32_t file_index; 86d4afb5ceSopenharmony_ci uint32_t total; 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci /* 89d4afb5ceSopenharmony_ci * optimization for the common case there's only 1 - ~3 matches, so we 90d4afb5ceSopenharmony_ci * don't have to allocate any lws_fts_lines struct 91d4afb5ceSopenharmony_ci * 92d4afb5ceSopenharmony_ci * Using 8 bytes total for this maintains 8-byte struct alignment... 93d4afb5ceSopenharmony_ci */ 94d4afb5ceSopenharmony_ci 95d4afb5ceSopenharmony_ci uint8_t vli[7]; 96d4afb5ceSopenharmony_ci char count; 97d4afb5ceSopenharmony_ci}; 98d4afb5ceSopenharmony_ci 99d4afb5ceSopenharmony_ci/* 100d4afb5ceSopenharmony_ci * this is the main trie in-memory allocation object 101d4afb5ceSopenharmony_ci */ 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_cistruct lws_fts_entry { 104d4afb5ceSopenharmony_ci struct lws_fts_entry *parent; 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_ci struct lws_fts_entry *child_list; 107d4afb5ceSopenharmony_ci struct lws_fts_entry *sibling; 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_ci /* 110d4afb5ceSopenharmony_ci * care... this points to content in t->lwsac_input_head, it goes 111d4afb5ceSopenharmony_ci * out of scope when the input file being indexed completes 112d4afb5ceSopenharmony_ci */ 113d4afb5ceSopenharmony_ci struct lws_fts_instance_file *inst_file_list; 114d4afb5ceSopenharmony_ci 115d4afb5ceSopenharmony_ci jg2_file_offset ofs_last_inst_file; 116d4afb5ceSopenharmony_ci 117d4afb5ceSopenharmony_ci char *suffix; /* suffix string or NULL if one char (in .c) */ 118d4afb5ceSopenharmony_ci jg2_file_offset ofs; 119d4afb5ceSopenharmony_ci uint32_t child_count; 120d4afb5ceSopenharmony_ci uint32_t instance_count; 121d4afb5ceSopenharmony_ci uint32_t agg_inst_count; 122d4afb5ceSopenharmony_ci uint32_t agg_child_count; 123d4afb5ceSopenharmony_ci uint32_t suffix_len; 124d4afb5ceSopenharmony_ci unsigned char c; 125d4afb5ceSopenharmony_ci}; 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_ci/* there's only one of these per trie file */ 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_cistruct lws_fts { 130d4afb5ceSopenharmony_ci struct lwsac *lwsac_head; 131d4afb5ceSopenharmony_ci struct lwsac *lwsac_input_head; 132d4afb5ceSopenharmony_ci struct lws_fts_entry *root; 133d4afb5ceSopenharmony_ci struct lws_fts_filepath *filepath_list; 134d4afb5ceSopenharmony_ci struct lws_fts_filepath *fp; 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci struct lws_fts_entry *parser; 137d4afb5ceSopenharmony_ci struct lws_fts_entry *root_lookup[256]; 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci /* 140d4afb5ceSopenharmony_ci * head of linked-list of tifs generated for current file 141d4afb5ceSopenharmony_ci * care... this points to content in t->lwsac_input_head 142d4afb5ceSopenharmony_ci */ 143d4afb5ceSopenharmony_ci struct lws_fts_instance_file *tif_list; 144d4afb5ceSopenharmony_ci 145d4afb5ceSopenharmony_ci jg2_file_offset c; /* length of output file so far */ 146d4afb5ceSopenharmony_ci 147d4afb5ceSopenharmony_ci uint64_t agg_trie_creation_us; 148d4afb5ceSopenharmony_ci uint64_t agg_raw_input; 149d4afb5ceSopenharmony_ci uint64_t worst_lwsac_input_size; 150d4afb5ceSopenharmony_ci int last_file_index; 151d4afb5ceSopenharmony_ci int chars_in_line; 152d4afb5ceSopenharmony_ci jg2_file_offset last_block_len_ofs; 153d4afb5ceSopenharmony_ci int line_number; 154d4afb5ceSopenharmony_ci int lines_in_unsealed_linetable; 155d4afb5ceSopenharmony_ci int next_file_index; 156d4afb5ceSopenharmony_ci int count_entries; 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci int fd; 159d4afb5ceSopenharmony_ci unsigned int agg_pos; 160d4afb5ceSopenharmony_ci unsigned int str_match_pos; 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci unsigned char aggregate; 163d4afb5ceSopenharmony_ci unsigned char agg[128]; 164d4afb5ceSopenharmony_ci}; 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci/* since the kernel case allocates >300MB, no point keeping this too low */ 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci#define TRIE_LWSAC_BLOCK_SIZE (1024 * 1024) 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci#define spill(margin, force) \ 171d4afb5ceSopenharmony_ci if (bp && ((uint32_t)bp >= (sizeof(buf) - (size_t)(margin)) || (force))) { \ 172d4afb5ceSopenharmony_ci if ((int)write(t->fd, buf, (size_t)bp) != bp) { \ 173d4afb5ceSopenharmony_ci lwsl_err("%s: write %d failed (%d)\n", __func__, \ 174d4afb5ceSopenharmony_ci bp, errno); \ 175d4afb5ceSopenharmony_ci return 1; \ 176d4afb5ceSopenharmony_ci } \ 177d4afb5ceSopenharmony_ci t->c += (unsigned int)bp; \ 178d4afb5ceSopenharmony_ci bp = 0; \ 179d4afb5ceSopenharmony_ci } 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_cistatic int 182d4afb5ceSopenharmony_cig32(unsigned char *b, uint32_t d) 183d4afb5ceSopenharmony_ci{ 184d4afb5ceSopenharmony_ci *b++ = (uint8_t)((d >> 24) & 0xff); 185d4afb5ceSopenharmony_ci *b++ = (uint8_t)((d >> 16) & 0xff); 186d4afb5ceSopenharmony_ci *b++ = (uint8_t)((d >> 8) & 0xff); 187d4afb5ceSopenharmony_ci *b = (uint8_t)(d & 0xff); 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci return 4; 190d4afb5ceSopenharmony_ci} 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_cistatic int 193d4afb5ceSopenharmony_cig16(unsigned char *b, int d) 194d4afb5ceSopenharmony_ci{ 195d4afb5ceSopenharmony_ci *b++ = (uint8_t)((d >> 8) & 0xff); 196d4afb5ceSopenharmony_ci *b = (uint8_t)(d & 0xff); 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_ci return 2; 199d4afb5ceSopenharmony_ci} 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_cistatic int 202d4afb5ceSopenharmony_ciwq32(unsigned char *b, uint32_t d) 203d4afb5ceSopenharmony_ci{ 204d4afb5ceSopenharmony_ci unsigned char *ob = b; 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci if (d > (1 << 28) - 1) 207d4afb5ceSopenharmony_ci *b++ = (uint8_t)(((d >> 28) | 0x80) & 0xff); 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci if (d > (1 << 21) - 1) 210d4afb5ceSopenharmony_ci *b++ = (uint8_t)(((d >> 21) | 0x80) & 0xff); 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci if (d > (1 << 14) - 1) 213d4afb5ceSopenharmony_ci *b++ = (uint8_t)(((d >> 14) | 0x80) & 0xff); 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci if (d > (1 << 7) - 1) 216d4afb5ceSopenharmony_ci *b++ = (uint8_t)(((d >> 7) | 0x80) & 0xff); 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci *b++ = (uint8_t)(d & 0x7f); 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci return lws_ptr_diff(b, ob); 221d4afb5ceSopenharmony_ci} 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci/* read a VLI, return the number of bytes used */ 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ciint 227d4afb5ceSopenharmony_cirq32(unsigned char *b, uint32_t *d) 228d4afb5ceSopenharmony_ci{ 229d4afb5ceSopenharmony_ci unsigned char *ob = b; 230d4afb5ceSopenharmony_ci uint32_t t = 0; 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_ci t = *b & 0x7f; 233d4afb5ceSopenharmony_ci if (*(b++) & 0x80) { 234d4afb5ceSopenharmony_ci t = (t << 7) | (*b & 0x7f); 235d4afb5ceSopenharmony_ci if (*(b++) & 0x80) { 236d4afb5ceSopenharmony_ci t = (t << 7) | (*b & 0x7f); 237d4afb5ceSopenharmony_ci if (*(b++) & 0x80) { 238d4afb5ceSopenharmony_ci t = (t << 7) | (*b & 0x7f); 239d4afb5ceSopenharmony_ci if (*(b++) & 0x80) { 240d4afb5ceSopenharmony_ci t = (t << 7) | (*b & 0x7f); 241d4afb5ceSopenharmony_ci b++; 242d4afb5ceSopenharmony_ci } 243d4afb5ceSopenharmony_ci } 244d4afb5ceSopenharmony_ci } 245d4afb5ceSopenharmony_ci } 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci *d = t; 248d4afb5ceSopenharmony_ci 249d4afb5ceSopenharmony_ci return (int)(b - ob); 250d4afb5ceSopenharmony_ci} 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_cistruct lws_fts * 253d4afb5ceSopenharmony_cilws_fts_create(int fd) 254d4afb5ceSopenharmony_ci{ 255d4afb5ceSopenharmony_ci struct lws_fts *t; 256d4afb5ceSopenharmony_ci struct lwsac *lwsac_head = NULL; 257d4afb5ceSopenharmony_ci unsigned char buf[TRIE_FILE_HDR_SIZE]; 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci t = lwsac_use(&lwsac_head, sizeof(*t), TRIE_LWSAC_BLOCK_SIZE); 260d4afb5ceSopenharmony_ci if (!t) 261d4afb5ceSopenharmony_ci return NULL; 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci memset(t, 0, sizeof(*t)); 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ci t->fd = fd; 266d4afb5ceSopenharmony_ci t->lwsac_head = lwsac_head; 267d4afb5ceSopenharmony_ci t->root = lwsac_use(&lwsac_head, sizeof(*t->root), 268d4afb5ceSopenharmony_ci TRIE_LWSAC_BLOCK_SIZE); 269d4afb5ceSopenharmony_ci if (!t->root) 270d4afb5ceSopenharmony_ci goto unwind; 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci memset(t->root, 0, sizeof(*t->root)); 273d4afb5ceSopenharmony_ci t->parser = t->root; 274d4afb5ceSopenharmony_ci t->last_file_index = -1; 275d4afb5ceSopenharmony_ci t->line_number = 1; 276d4afb5ceSopenharmony_ci t->filepath_list = NULL; 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci memset(t->root_lookup, 0, sizeof(*t->root_lookup)); 279d4afb5ceSopenharmony_ci 280d4afb5ceSopenharmony_ci /* write the header */ 281d4afb5ceSopenharmony_ci 282d4afb5ceSopenharmony_ci buf[0] = 0xca; 283d4afb5ceSopenharmony_ci buf[1] = 0x7a; 284d4afb5ceSopenharmony_ci buf[2] = 0x5f; 285d4afb5ceSopenharmony_ci buf[3] = 0x75; 286d4afb5ceSopenharmony_ci 287d4afb5ceSopenharmony_ci /* (these are filled in with correct data at the end) */ 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci /* file offset to root trie entry */ 290d4afb5ceSopenharmony_ci g32(&buf[4], 0); 291d4afb5ceSopenharmony_ci /* file length when it was created */ 292d4afb5ceSopenharmony_ci g32(&buf[8], 0); 293d4afb5ceSopenharmony_ci /* fileoffset to the filepath table */ 294d4afb5ceSopenharmony_ci g32(&buf[0xc], 0); 295d4afb5ceSopenharmony_ci /* count of filepaths */ 296d4afb5ceSopenharmony_ci g32(&buf[0x10], 0); 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci if (write(t->fd, buf, TRIE_FILE_HDR_SIZE) != TRIE_FILE_HDR_SIZE) { 299d4afb5ceSopenharmony_ci lwsl_err("%s: trie header write failed\n", __func__); 300d4afb5ceSopenharmony_ci goto unwind; 301d4afb5ceSopenharmony_ci } 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci t->c = TRIE_FILE_HDR_SIZE; 304d4afb5ceSopenharmony_ci 305d4afb5ceSopenharmony_ci return t; 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_ciunwind: 308d4afb5ceSopenharmony_ci lwsac_free(&lwsac_head); 309d4afb5ceSopenharmony_ci 310d4afb5ceSopenharmony_ci return NULL; 311d4afb5ceSopenharmony_ci} 312d4afb5ceSopenharmony_ci 313d4afb5ceSopenharmony_civoid 314d4afb5ceSopenharmony_cilws_fts_destroy(struct lws_fts **trie) 315d4afb5ceSopenharmony_ci{ 316d4afb5ceSopenharmony_ci struct lwsac *lwsac_head = (*trie)->lwsac_head; 317d4afb5ceSopenharmony_ci lwsac_free(&(*trie)->lwsac_input_head); 318d4afb5ceSopenharmony_ci lwsac_free(&lwsac_head); 319d4afb5ceSopenharmony_ci *trie = NULL; 320d4afb5ceSopenharmony_ci} 321d4afb5ceSopenharmony_ci 322d4afb5ceSopenharmony_ciint 323d4afb5ceSopenharmony_cilws_fts_file_index(struct lws_fts *t, const char *filepath, int filepath_len, 324d4afb5ceSopenharmony_ci int priority) 325d4afb5ceSopenharmony_ci{ 326d4afb5ceSopenharmony_ci struct lws_fts_filepath *fp = t->filepath_list; 327d4afb5ceSopenharmony_ci#if 0 328d4afb5ceSopenharmony_ci while (fp) { 329d4afb5ceSopenharmony_ci if (fp->filepath_len == filepath_len && 330d4afb5ceSopenharmony_ci !strcmp(fp->filepath, filepath)) 331d4afb5ceSopenharmony_ci return fp->file_index; 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci fp = fp->next; 334d4afb5ceSopenharmony_ci } 335d4afb5ceSopenharmony_ci#endif 336d4afb5ceSopenharmony_ci fp = lwsac_use(&t->lwsac_head, sizeof(*fp), TRIE_LWSAC_BLOCK_SIZE); 337d4afb5ceSopenharmony_ci if (!fp) 338d4afb5ceSopenharmony_ci return -1; 339d4afb5ceSopenharmony_ci 340d4afb5ceSopenharmony_ci fp->next = t->filepath_list; 341d4afb5ceSopenharmony_ci t->filepath_list = fp; 342d4afb5ceSopenharmony_ci strncpy(fp->filepath, filepath, sizeof(fp->filepath) - 1); 343d4afb5ceSopenharmony_ci fp->filepath[sizeof(fp->filepath) - 1] = '\0'; 344d4afb5ceSopenharmony_ci fp->filepath_len = filepath_len; 345d4afb5ceSopenharmony_ci fp->file_index = t->next_file_index++; 346d4afb5ceSopenharmony_ci fp->line_table_ofs = t->c; 347d4afb5ceSopenharmony_ci fp->priority = priority; 348d4afb5ceSopenharmony_ci fp->total_lines = 0; 349d4afb5ceSopenharmony_ci t->fp = fp; 350d4afb5ceSopenharmony_ci 351d4afb5ceSopenharmony_ci return fp->file_index; 352d4afb5ceSopenharmony_ci} 353d4afb5ceSopenharmony_ci 354d4afb5ceSopenharmony_cistatic struct lws_fts_entry * 355d4afb5ceSopenharmony_cilws_fts_entry_child_add(struct lws_fts *t, unsigned char c, 356d4afb5ceSopenharmony_ci struct lws_fts_entry *parent) 357d4afb5ceSopenharmony_ci{ 358d4afb5ceSopenharmony_ci struct lws_fts_entry *e, **pe; 359d4afb5ceSopenharmony_ci 360d4afb5ceSopenharmony_ci e = lwsac_use(&t->lwsac_head, sizeof(*e), TRIE_LWSAC_BLOCK_SIZE); 361d4afb5ceSopenharmony_ci if (!e) 362d4afb5ceSopenharmony_ci return NULL; 363d4afb5ceSopenharmony_ci 364d4afb5ceSopenharmony_ci memset(e, 0, sizeof(*e)); 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ci e->c = c; 367d4afb5ceSopenharmony_ci parent->child_count++; 368d4afb5ceSopenharmony_ci e->parent = parent; 369d4afb5ceSopenharmony_ci t->count_entries++; 370d4afb5ceSopenharmony_ci 371d4afb5ceSopenharmony_ci /* keep the parent child list in ascending sort order for c */ 372d4afb5ceSopenharmony_ci 373d4afb5ceSopenharmony_ci pe = &parent->child_list; 374d4afb5ceSopenharmony_ci while (*pe) { 375d4afb5ceSopenharmony_ci assert((*pe)->parent == parent); 376d4afb5ceSopenharmony_ci if ((*pe)->c > c) { 377d4afb5ceSopenharmony_ci /* add it before */ 378d4afb5ceSopenharmony_ci e->sibling = *pe; 379d4afb5ceSopenharmony_ci *pe = e; 380d4afb5ceSopenharmony_ci break; 381d4afb5ceSopenharmony_ci } 382d4afb5ceSopenharmony_ci pe = &(*pe)->sibling; 383d4afb5ceSopenharmony_ci } 384d4afb5ceSopenharmony_ci 385d4afb5ceSopenharmony_ci if (!*pe) { 386d4afb5ceSopenharmony_ci /* add it at the end */ 387d4afb5ceSopenharmony_ci e->sibling = NULL; 388d4afb5ceSopenharmony_ci *pe = e; 389d4afb5ceSopenharmony_ci } 390d4afb5ceSopenharmony_ci 391d4afb5ceSopenharmony_ci return e; 392d4afb5ceSopenharmony_ci} 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_cistatic int 395d4afb5ceSopenharmony_cifinalize_per_input(struct lws_fts *t) 396d4afb5ceSopenharmony_ci{ 397d4afb5ceSopenharmony_ci struct lws_fts_instance_file *tif; 398d4afb5ceSopenharmony_ci unsigned char buf[8192]; 399d4afb5ceSopenharmony_ci uint64_t lwsac_input_size; 400d4afb5ceSopenharmony_ci jg2_file_offset temp; 401d4afb5ceSopenharmony_ci int bp = 0; 402d4afb5ceSopenharmony_ci 403d4afb5ceSopenharmony_ci bp += g16(&buf[bp], 0); 404d4afb5ceSopenharmony_ci bp += g16(&buf[bp], 0); 405d4afb5ceSopenharmony_ci bp += g32(&buf[bp], 0); 406d4afb5ceSopenharmony_ci if ((int)write(t->fd, buf, (size_t)bp) != bp) 407d4afb5ceSopenharmony_ci return 1; 408d4afb5ceSopenharmony_ci t->c += (unsigned int)bp; 409d4afb5ceSopenharmony_ci bp = 0; 410d4afb5ceSopenharmony_ci 411d4afb5ceSopenharmony_ci /* 412d4afb5ceSopenharmony_ci * Write the generated file index + instances (if any) 413d4afb5ceSopenharmony_ci * 414d4afb5ceSopenharmony_ci * Notice the next same-parent file instance fileoffset list is 415d4afb5ceSopenharmony_ci * backwards, so it does not require seeks to fill in. The first 416d4afb5ceSopenharmony_ci * entry has 0 but the second entry points to the first entry (whose 417d4afb5ceSopenharmony_ci * fileoffset is known). 418d4afb5ceSopenharmony_ci * 419d4afb5ceSopenharmony_ci * After all the file instance structs are finalized, 420d4afb5ceSopenharmony_ci * .ofs_last_inst_file contains the fileoffset of that child's tif 421d4afb5ceSopenharmony_ci * list head in the file. 422d4afb5ceSopenharmony_ci * 423d4afb5ceSopenharmony_ci * The file instances are written to disk in the order that the files 424d4afb5ceSopenharmony_ci * were indexed, along with their prev pointers inline. 425d4afb5ceSopenharmony_ci */ 426d4afb5ceSopenharmony_ci 427d4afb5ceSopenharmony_ci tif = t->tif_list; 428d4afb5ceSopenharmony_ci while (tif) { 429d4afb5ceSopenharmony_ci struct lws_fts_lines *i; 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci spill((3 * MAX_VLI) + tif->count, 0); 432d4afb5ceSopenharmony_ci 433d4afb5ceSopenharmony_ci temp = tif->owner->ofs_last_inst_file; 434d4afb5ceSopenharmony_ci if (tif->total) 435d4afb5ceSopenharmony_ci tif->owner->ofs_last_inst_file = t->c + (unsigned int)bp; 436d4afb5ceSopenharmony_ci 437d4afb5ceSopenharmony_ci assert(!temp || (temp > TRIE_FILE_HDR_SIZE && temp < t->c)); 438d4afb5ceSopenharmony_ci 439d4afb5ceSopenharmony_ci /* fileoffset of prev instance file for this entry, or 0 */ 440d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], temp); 441d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], tif->file_index); 442d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], tif->total); 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_ci /* remove any pointers into this disposable lac footprint */ 445d4afb5ceSopenharmony_ci tif->owner->inst_file_list = NULL; 446d4afb5ceSopenharmony_ci 447d4afb5ceSopenharmony_ci memcpy(&buf[bp], &tif->vli, (size_t)tif->count); 448d4afb5ceSopenharmony_ci bp += tif->count; 449d4afb5ceSopenharmony_ci 450d4afb5ceSopenharmony_ci i = tif->lines_list; 451d4afb5ceSopenharmony_ci while (i) { 452d4afb5ceSopenharmony_ci spill(i->count, 0); 453d4afb5ceSopenharmony_ci memcpy(&buf[bp], &i->vli, (size_t)i->count); 454d4afb5ceSopenharmony_ci bp += i->count; 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci i = i->lines_next; 457d4afb5ceSopenharmony_ci } 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci tif = tif->inst_file_next; 460d4afb5ceSopenharmony_ci } 461d4afb5ceSopenharmony_ci 462d4afb5ceSopenharmony_ci spill(0, 1); 463d4afb5ceSopenharmony_ci 464d4afb5ceSopenharmony_ci assert(lseek(t->fd, 0, SEEK_END) == (off_t)t->c); 465d4afb5ceSopenharmony_ci 466d4afb5ceSopenharmony_ci if (t->lwsac_input_head) { 467d4afb5ceSopenharmony_ci lwsac_input_size = lwsac_total_alloc(t->lwsac_input_head); 468d4afb5ceSopenharmony_ci if (lwsac_input_size > t->worst_lwsac_input_size) 469d4afb5ceSopenharmony_ci t->worst_lwsac_input_size = lwsac_input_size; 470d4afb5ceSopenharmony_ci } 471d4afb5ceSopenharmony_ci 472d4afb5ceSopenharmony_ci /* 473d4afb5ceSopenharmony_ci * those per-file allocations are all on a separate lac so we can 474d4afb5ceSopenharmony_ci * free it cleanly afterwards 475d4afb5ceSopenharmony_ci */ 476d4afb5ceSopenharmony_ci lwsac_free(&t->lwsac_input_head); 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ci /* and lose the pointer into the deallocated lac */ 479d4afb5ceSopenharmony_ci t->tif_list = NULL; 480d4afb5ceSopenharmony_ci 481d4afb5ceSopenharmony_ci return 0; 482d4afb5ceSopenharmony_ci} 483d4afb5ceSopenharmony_ci 484d4afb5ceSopenharmony_ci/* 485d4afb5ceSopenharmony_ci * 0 = punctuation, whitespace, brackets etc 486d4afb5ceSopenharmony_ci * 1 = character inside symbol set 487d4afb5ceSopenharmony_ci * 2 = upper-case character inside symbol set 488d4afb5ceSopenharmony_ci */ 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_cistatic char classify[] = { 491d4afb5ceSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 492d4afb5ceSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 493d4afb5ceSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 494d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 495d4afb5ceSopenharmony_ci 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 496d4afb5ceSopenharmony_ci 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, //1, 497d4afb5ceSopenharmony_ci 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 498d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 499d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 500d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 501d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 502d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 503d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 504d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 505d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 506d4afb5ceSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 507d4afb5ceSopenharmony_ci}; 508d4afb5ceSopenharmony_ci 509d4afb5ceSopenharmony_ci#if 0 510d4afb5ceSopenharmony_cistatic const char * 511d4afb5ceSopenharmony_ciname_entry(struct lws_fts_entry *e1, char *s, int len) 512d4afb5ceSopenharmony_ci{ 513d4afb5ceSopenharmony_ci struct lws_fts_entry *e2; 514d4afb5ceSopenharmony_ci int n = len; 515d4afb5ceSopenharmony_ci 516d4afb5ceSopenharmony_ci s[--n] = '\0'; 517d4afb5ceSopenharmony_ci 518d4afb5ceSopenharmony_ci e2 = e1; 519d4afb5ceSopenharmony_ci while (e2) { 520d4afb5ceSopenharmony_ci if (e2->suffix) { 521d4afb5ceSopenharmony_ci if ((int)e2->suffix_len < n) { 522d4afb5ceSopenharmony_ci n -= e2->suffix_len; 523d4afb5ceSopenharmony_ci memcpy(&s[n], e2->suffix, e2->suffix_len); 524d4afb5ceSopenharmony_ci } 525d4afb5ceSopenharmony_ci } else { 526d4afb5ceSopenharmony_ci n--; 527d4afb5ceSopenharmony_ci s[n] = e2->c; 528d4afb5ceSopenharmony_ci } 529d4afb5ceSopenharmony_ci 530d4afb5ceSopenharmony_ci e2 = e2->parent; 531d4afb5ceSopenharmony_ci } 532d4afb5ceSopenharmony_ci 533d4afb5ceSopenharmony_ci return &s[n + 1]; 534d4afb5ceSopenharmony_ci} 535d4afb5ceSopenharmony_ci#endif 536d4afb5ceSopenharmony_ci 537d4afb5ceSopenharmony_ci/* 538d4afb5ceSopenharmony_ci * as we parse the input, we create a line length table for the file index. 539d4afb5ceSopenharmony_ci * Only the file header has been written before we start doing this. 540d4afb5ceSopenharmony_ci */ 541d4afb5ceSopenharmony_ci 542d4afb5ceSopenharmony_ciint 543d4afb5ceSopenharmony_cilws_fts_fill(struct lws_fts *t, uint32_t file_index, const char *buf, 544d4afb5ceSopenharmony_ci size_t len) 545d4afb5ceSopenharmony_ci{ 546d4afb5ceSopenharmony_ci unsigned long long tf = (unsigned long long)lws_now_usecs(); 547d4afb5ceSopenharmony_ci unsigned char c, linetable[256], vlibuf[8]; 548d4afb5ceSopenharmony_ci struct lws_fts_entry *e, *e1, *dcl; 549d4afb5ceSopenharmony_ci struct lws_fts_instance_file *tif; 550d4afb5ceSopenharmony_ci int bp = 0, sline, chars, m; 551d4afb5ceSopenharmony_ci char *osuff, skipline = 0; 552d4afb5ceSopenharmony_ci struct lws_fts_lines *tl; 553d4afb5ceSopenharmony_ci unsigned int olen, n; 554d4afb5ceSopenharmony_ci off_t lbh; 555d4afb5ceSopenharmony_ci 556d4afb5ceSopenharmony_ci if ((int)file_index != t->last_file_index) { 557d4afb5ceSopenharmony_ci if (t->last_file_index >= 0) 558d4afb5ceSopenharmony_ci finalize_per_input(t); 559d4afb5ceSopenharmony_ci t->last_file_index = (int)file_index; 560d4afb5ceSopenharmony_ci t->line_number = 1; 561d4afb5ceSopenharmony_ci t->chars_in_line = 0; 562d4afb5ceSopenharmony_ci t->lines_in_unsealed_linetable = 0; 563d4afb5ceSopenharmony_ci } 564d4afb5ceSopenharmony_ci 565d4afb5ceSopenharmony_ci t->agg_raw_input += len; 566d4afb5ceSopenharmony_ci 567d4afb5ceSopenharmony_ciresume: 568d4afb5ceSopenharmony_ci 569d4afb5ceSopenharmony_ci chars = 0; 570d4afb5ceSopenharmony_ci lbh = (off_t)t->c; 571d4afb5ceSopenharmony_ci sline = t->line_number; 572d4afb5ceSopenharmony_ci bp += g16(&linetable[bp], 0); 573d4afb5ceSopenharmony_ci bp += g16(&linetable[bp], 0); 574d4afb5ceSopenharmony_ci bp += g32(&linetable[bp], 0); 575d4afb5ceSopenharmony_ci 576d4afb5ceSopenharmony_ci while (len) { 577d4afb5ceSopenharmony_ci char go_around = 0; 578d4afb5ceSopenharmony_ci 579d4afb5ceSopenharmony_ci if (t->lines_in_unsealed_linetable >= LWS_FTS_LINES_PER_CHUNK) 580d4afb5ceSopenharmony_ci break; 581d4afb5ceSopenharmony_ci 582d4afb5ceSopenharmony_ci len--; 583d4afb5ceSopenharmony_ci 584d4afb5ceSopenharmony_ci c = (unsigned char)*buf++; 585d4afb5ceSopenharmony_ci t->chars_in_line++; 586d4afb5ceSopenharmony_ci if (c == '\n') { 587d4afb5ceSopenharmony_ci skipline = 0; 588d4afb5ceSopenharmony_ci t->filepath_list->total_lines++; 589d4afb5ceSopenharmony_ci t->lines_in_unsealed_linetable++; 590d4afb5ceSopenharmony_ci t->line_number++; 591d4afb5ceSopenharmony_ci 592d4afb5ceSopenharmony_ci bp += wq32(&linetable[bp], (uint32_t)t->chars_in_line); 593d4afb5ceSopenharmony_ci if ((unsigned int)bp > sizeof(linetable) - 6) { 594d4afb5ceSopenharmony_ci if ((int)write(t->fd, linetable, (unsigned int)bp) != bp) { 595d4afb5ceSopenharmony_ci lwsl_err("%s: linetable write failed\n", 596d4afb5ceSopenharmony_ci __func__); 597d4afb5ceSopenharmony_ci return 1; 598d4afb5ceSopenharmony_ci } 599d4afb5ceSopenharmony_ci t->c += (unsigned int)bp; 600d4afb5ceSopenharmony_ci bp = 0; 601d4afb5ceSopenharmony_ci // assert(lseek(t->fd, 0, SEEK_END) == t->c); 602d4afb5ceSopenharmony_ci } 603d4afb5ceSopenharmony_ci 604d4afb5ceSopenharmony_ci chars += t->chars_in_line; 605d4afb5ceSopenharmony_ci t->chars_in_line = 0; 606d4afb5ceSopenharmony_ci 607d4afb5ceSopenharmony_ci /* 608d4afb5ceSopenharmony_ci * Detect overlength lines and skip them (eg, BASE64 609d4afb5ceSopenharmony_ci * in css etc) 610d4afb5ceSopenharmony_ci */ 611d4afb5ceSopenharmony_ci 612d4afb5ceSopenharmony_ci if (len > 200) { 613d4afb5ceSopenharmony_ci n = 0; 614d4afb5ceSopenharmony_ci m = 0; 615d4afb5ceSopenharmony_ci while (n < 200 && m < 80 && buf[n] != '\n') { 616d4afb5ceSopenharmony_ci if (buf[n] == ' ' || buf[n] == '\t') 617d4afb5ceSopenharmony_ci m = 0; 618d4afb5ceSopenharmony_ci n++; 619d4afb5ceSopenharmony_ci m++; 620d4afb5ceSopenharmony_ci } 621d4afb5ceSopenharmony_ci 622d4afb5ceSopenharmony_ci /* 80 lines no whitespace, or >=200-char line */ 623d4afb5ceSopenharmony_ci 624d4afb5ceSopenharmony_ci if (m == 80 || n == 200) 625d4afb5ceSopenharmony_ci skipline = 1; 626d4afb5ceSopenharmony_ci } 627d4afb5ceSopenharmony_ci 628d4afb5ceSopenharmony_ci goto seal; 629d4afb5ceSopenharmony_ci } 630d4afb5ceSopenharmony_ci if (skipline) 631d4afb5ceSopenharmony_ci continue; 632d4afb5ceSopenharmony_ci 633d4afb5ceSopenharmony_ci m = classify[(int)c]; 634d4afb5ceSopenharmony_ci if (!m) 635d4afb5ceSopenharmony_ci goto seal; 636d4afb5ceSopenharmony_ci if (m == 2) 637d4afb5ceSopenharmony_ci c = (unsigned char)((char)c + 'a' - 'A'); 638d4afb5ceSopenharmony_ci 639d4afb5ceSopenharmony_ci if (t->aggregate) { 640d4afb5ceSopenharmony_ci 641d4afb5ceSopenharmony_ci /* 642d4afb5ceSopenharmony_ci * We created a trie entry for an earlier char in this 643d4afb5ceSopenharmony_ci * symbol already. So we know at the moment, any 644d4afb5ceSopenharmony_ci * further chars in the symbol are the only children. 645d4afb5ceSopenharmony_ci * 646d4afb5ceSopenharmony_ci * Aggregate them and add them as a string suffix to 647d4afb5ceSopenharmony_ci * the trie symbol at the end (when we know how much to 648d4afb5ceSopenharmony_ci * allocate). 649d4afb5ceSopenharmony_ci */ 650d4afb5ceSopenharmony_ci 651d4afb5ceSopenharmony_ci if (t->agg_pos < sizeof(t->agg) - 1) 652d4afb5ceSopenharmony_ci /* symbol is not too long to stash */ 653d4afb5ceSopenharmony_ci t->agg[t->agg_pos++] = c; 654d4afb5ceSopenharmony_ci 655d4afb5ceSopenharmony_ci continue; 656d4afb5ceSopenharmony_ci } 657d4afb5ceSopenharmony_ci 658d4afb5ceSopenharmony_ci if (t->str_match_pos) { 659d4afb5ceSopenharmony_ci go_around = 1; 660d4afb5ceSopenharmony_ci goto seal; 661d4afb5ceSopenharmony_ci } 662d4afb5ceSopenharmony_ci 663d4afb5ceSopenharmony_ci /* zeroth-iteration child matching */ 664d4afb5ceSopenharmony_ci 665d4afb5ceSopenharmony_ci if (t->parser == t->root) { 666d4afb5ceSopenharmony_ci e = t->root_lookup[(int)c]; 667d4afb5ceSopenharmony_ci if (e) { 668d4afb5ceSopenharmony_ci t->parser = e; 669d4afb5ceSopenharmony_ci continue; 670d4afb5ceSopenharmony_ci } 671d4afb5ceSopenharmony_ci } else { 672d4afb5ceSopenharmony_ci 673d4afb5ceSopenharmony_ci /* look for the char amongst the children */ 674d4afb5ceSopenharmony_ci 675d4afb5ceSopenharmony_ci e = t->parser->child_list; 676d4afb5ceSopenharmony_ci while (e) { 677d4afb5ceSopenharmony_ci 678d4afb5ceSopenharmony_ci /* since they're alpha ordered... */ 679d4afb5ceSopenharmony_ci if (e->c > c) { 680d4afb5ceSopenharmony_ci e = NULL; 681d4afb5ceSopenharmony_ci break; 682d4afb5ceSopenharmony_ci } 683d4afb5ceSopenharmony_ci if (e->c == c) { 684d4afb5ceSopenharmony_ci t->parser = e; 685d4afb5ceSopenharmony_ci 686d4afb5ceSopenharmony_ci if (e->suffix) 687d4afb5ceSopenharmony_ci t->str_match_pos = 1; 688d4afb5ceSopenharmony_ci 689d4afb5ceSopenharmony_ci break; 690d4afb5ceSopenharmony_ci } 691d4afb5ceSopenharmony_ci 692d4afb5ceSopenharmony_ci e = e->sibling; 693d4afb5ceSopenharmony_ci } 694d4afb5ceSopenharmony_ci 695d4afb5ceSopenharmony_ci if (e) 696d4afb5ceSopenharmony_ci continue; 697d4afb5ceSopenharmony_ci } 698d4afb5ceSopenharmony_ci 699d4afb5ceSopenharmony_ci /* 700d4afb5ceSopenharmony_ci * we are blazing a new trail, add a new child representing 701d4afb5ceSopenharmony_ci * the whole suffix that couldn't be matched until now. 702d4afb5ceSopenharmony_ci */ 703d4afb5ceSopenharmony_ci 704d4afb5ceSopenharmony_ci e = lws_fts_entry_child_add(t, c, t->parser); 705d4afb5ceSopenharmony_ci if (!e) { 706d4afb5ceSopenharmony_ci lwsl_err("%s: lws_fts_entry_child_add failed\n", 707d4afb5ceSopenharmony_ci __func__); 708d4afb5ceSopenharmony_ci return 1; 709d4afb5ceSopenharmony_ci } 710d4afb5ceSopenharmony_ci 711d4afb5ceSopenharmony_ci /* if it's the root node, keep the root_lookup table in sync */ 712d4afb5ceSopenharmony_ci 713d4afb5ceSopenharmony_ci if (t->parser == t->root) 714d4afb5ceSopenharmony_ci t->root_lookup[(int)c] = e; 715d4afb5ceSopenharmony_ci 716d4afb5ceSopenharmony_ci /* follow the new path */ 717d4afb5ceSopenharmony_ci t->parser = e; 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci { 720d4afb5ceSopenharmony_ci struct lws_fts_entry **pe = &e->child_list; 721d4afb5ceSopenharmony_ci while (*pe) { 722d4afb5ceSopenharmony_ci assert((*pe)->parent == e); 723d4afb5ceSopenharmony_ci 724d4afb5ceSopenharmony_ci pe = &(*pe)->sibling; 725d4afb5ceSopenharmony_ci } 726d4afb5ceSopenharmony_ci } 727d4afb5ceSopenharmony_ci 728d4afb5ceSopenharmony_ci /* 729d4afb5ceSopenharmony_ci * If there are any more symbol characters coming, just 730d4afb5ceSopenharmony_ci * create a suffix string on t->parser instead of what must 731d4afb5ceSopenharmony_ci * currently be single-child nodes, since we just created e 732d4afb5ceSopenharmony_ci * as a child with a single character due to no existing match 733d4afb5ceSopenharmony_ci * on that single character... so if no match on 'h' with this 734d4afb5ceSopenharmony_ci * guy's parent, we created e that matches on the single char 735d4afb5ceSopenharmony_ci * 'h'. If the symbol continues ... 'a' 'p' 'p' 'y', then 736d4afb5ceSopenharmony_ci * instead of creating singleton child nodes under e, 737d4afb5ceSopenharmony_ci * modify e to match on the whole string suffix "happy". 738d4afb5ceSopenharmony_ci * 739d4afb5ceSopenharmony_ci * If later "hoppy" appears, we will remove the suffix on e, 740d4afb5ceSopenharmony_ci * so it reverts to a char match for 'h', add singleton children 741d4afb5ceSopenharmony_ci * for 'a' and 'o', and attach a "ppy" suffix child to each of 742d4afb5ceSopenharmony_ci * those. 743d4afb5ceSopenharmony_ci * 744d4afb5ceSopenharmony_ci * We want to do this so we don't have to allocate trie entries 745d4afb5ceSopenharmony_ci * for every char in the string to save memory and consequently 746d4afb5ceSopenharmony_ci * time. 747d4afb5ceSopenharmony_ci * 748d4afb5ceSopenharmony_ci * Don't try this optimization if the parent is the root node... 749d4afb5ceSopenharmony_ci * it's not compatible with it's root_lookup table and it's 750d4afb5ceSopenharmony_ci * highly likely children off the root entry are going to have 751d4afb5ceSopenharmony_ci * to be fragmented. 752d4afb5ceSopenharmony_ci */ 753d4afb5ceSopenharmony_ci 754d4afb5ceSopenharmony_ci if (e->parent != t->root) { 755d4afb5ceSopenharmony_ci t->aggregate = 1; 756d4afb5ceSopenharmony_ci t->agg_pos = 0; 757d4afb5ceSopenharmony_ci } 758d4afb5ceSopenharmony_ci 759d4afb5ceSopenharmony_ci continue; 760d4afb5ceSopenharmony_ci 761d4afb5ceSopenharmony_ciseal: 762d4afb5ceSopenharmony_ci if (t->str_match_pos) { 763d4afb5ceSopenharmony_ci 764d4afb5ceSopenharmony_ci /* 765d4afb5ceSopenharmony_ci * We're partway through matching an elaborated string 766d4afb5ceSopenharmony_ci * on a child, not just a character. String matches 767d4afb5ceSopenharmony_ci * only exist when we met a child entry that only had 768d4afb5ceSopenharmony_ci * one path until now... so we had an 'h', and the 769d4afb5ceSopenharmony_ci * only child had a string "hello". 770d4afb5ceSopenharmony_ci * 771d4afb5ceSopenharmony_ci * We are following the right path and will not need 772d4afb5ceSopenharmony_ci * to back up, but we may find as we go we have the 773d4afb5ceSopenharmony_ci * first instance of a second child path, eg, "help". 774d4afb5ceSopenharmony_ci * 775d4afb5ceSopenharmony_ci * When we get to the 'p', we have to split what was 776d4afb5ceSopenharmony_ci * the only string option "hello" into "hel" and then 777d4afb5ceSopenharmony_ci * two child entries, for "lo" and 'p'. 778d4afb5ceSopenharmony_ci */ 779d4afb5ceSopenharmony_ci 780d4afb5ceSopenharmony_ci if (c == t->parser->suffix[t->str_match_pos++]) { 781d4afb5ceSopenharmony_ci if (t->str_match_pos < t->parser->suffix_len) 782d4afb5ceSopenharmony_ci continue; 783d4afb5ceSopenharmony_ci 784d4afb5ceSopenharmony_ci /* 785d4afb5ceSopenharmony_ci * We simply matched everything, continue 786d4afb5ceSopenharmony_ci * parsing normally from this trie entry. 787d4afb5ceSopenharmony_ci */ 788d4afb5ceSopenharmony_ci 789d4afb5ceSopenharmony_ci t->str_match_pos = 0; 790d4afb5ceSopenharmony_ci continue; 791d4afb5ceSopenharmony_ci } 792d4afb5ceSopenharmony_ci 793d4afb5ceSopenharmony_ci /* 794d4afb5ceSopenharmony_ci * So... we hit a mismatch somewhere... it means we 795d4afb5ceSopenharmony_ci * have to split this string entry. 796d4afb5ceSopenharmony_ci * 797d4afb5ceSopenharmony_ci * We know the first char actually matched in order to 798d4afb5ceSopenharmony_ci * start down this road. So for the current trie entry, 799d4afb5ceSopenharmony_ci * we need to truncate his suffix at the char before 800d4afb5ceSopenharmony_ci * this mismatched one, where we diverged (if the 801d4afb5ceSopenharmony_ci * second char, simply remove the suffix string from the 802d4afb5ceSopenharmony_ci * current trie entry to turn it back to a 1-char match) 803d4afb5ceSopenharmony_ci * 804d4afb5ceSopenharmony_ci * The original entry, which becomes the lhs post-split, 805d4afb5ceSopenharmony_ci * is t->parser. 806d4afb5ceSopenharmony_ci */ 807d4afb5ceSopenharmony_ci 808d4afb5ceSopenharmony_ci olen = t->parser->suffix_len; 809d4afb5ceSopenharmony_ci osuff = t->parser->suffix; 810d4afb5ceSopenharmony_ci 811d4afb5ceSopenharmony_ci if (t->str_match_pos == 2) 812d4afb5ceSopenharmony_ci t->parser->suffix = NULL; 813d4afb5ceSopenharmony_ci else 814d4afb5ceSopenharmony_ci t->parser->suffix_len = t->str_match_pos - 1; 815d4afb5ceSopenharmony_ci 816d4afb5ceSopenharmony_ci /* 817d4afb5ceSopenharmony_ci * Then we need to create a new child trie entry that 818d4afb5ceSopenharmony_ci * represents the remainder of the original string 819d4afb5ceSopenharmony_ci * path that we didn't match. For the "hello" / 820d4afb5ceSopenharmony_ci * "help" case, this guy will have "lo". 821d4afb5ceSopenharmony_ci * 822d4afb5ceSopenharmony_ci * Any instances or children (not siblings...) that were 823d4afb5ceSopenharmony_ci * attached to the original trie entry must be detached 824d4afb5ceSopenharmony_ci * first and then migrate to this new guy that completes 825d4afb5ceSopenharmony_ci * the original string. 826d4afb5ceSopenharmony_ci */ 827d4afb5ceSopenharmony_ci 828d4afb5ceSopenharmony_ci dcl = t->parser->child_list; 829d4afb5ceSopenharmony_ci m = (int)t->parser->child_count; 830d4afb5ceSopenharmony_ci 831d4afb5ceSopenharmony_ci t->parser->child_list = NULL; 832d4afb5ceSopenharmony_ci t->parser->child_count = 0; 833d4afb5ceSopenharmony_ci 834d4afb5ceSopenharmony_ci e = lws_fts_entry_child_add(t, (unsigned char) 835d4afb5ceSopenharmony_ci osuff[t->str_match_pos - 1], t->parser); 836d4afb5ceSopenharmony_ci if (!e) { 837d4afb5ceSopenharmony_ci lwsl_err("%s: lws_fts_entry_child_add fail1\n", 838d4afb5ceSopenharmony_ci __func__); 839d4afb5ceSopenharmony_ci return 1; 840d4afb5ceSopenharmony_ci } 841d4afb5ceSopenharmony_ci 842d4afb5ceSopenharmony_ci e->child_list = dcl; 843d4afb5ceSopenharmony_ci e->child_count = (uint32_t)m; 844d4afb5ceSopenharmony_ci /* 845d4afb5ceSopenharmony_ci * any children we took over must point to us as the 846d4afb5ceSopenharmony_ci * parent now they appear on our child list 847d4afb5ceSopenharmony_ci */ 848d4afb5ceSopenharmony_ci e1 = e->child_list; 849d4afb5ceSopenharmony_ci while (e1) { 850d4afb5ceSopenharmony_ci e1->parent = e; 851d4afb5ceSopenharmony_ci e1 = e1->sibling; 852d4afb5ceSopenharmony_ci } 853d4afb5ceSopenharmony_ci 854d4afb5ceSopenharmony_ci /* 855d4afb5ceSopenharmony_ci * We detached any children, gave them to the new guy 856d4afb5ceSopenharmony_ci * and replaced them with just our new guy 857d4afb5ceSopenharmony_ci */ 858d4afb5ceSopenharmony_ci t->parser->child_count = 1; 859d4afb5ceSopenharmony_ci t->parser->child_list = e; 860d4afb5ceSopenharmony_ci 861d4afb5ceSopenharmony_ci /* 862d4afb5ceSopenharmony_ci * any instances that belonged to the original entry we 863d4afb5ceSopenharmony_ci * are splitting now must be reassigned to the end 864d4afb5ceSopenharmony_ci * part 865d4afb5ceSopenharmony_ci */ 866d4afb5ceSopenharmony_ci 867d4afb5ceSopenharmony_ci e->inst_file_list = t->parser->inst_file_list; 868d4afb5ceSopenharmony_ci if (e->inst_file_list) 869d4afb5ceSopenharmony_ci e->inst_file_list->owner = e; 870d4afb5ceSopenharmony_ci t->parser->inst_file_list = NULL; 871d4afb5ceSopenharmony_ci e->instance_count = t->parser->instance_count; 872d4afb5ceSopenharmony_ci t->parser->instance_count = 0; 873d4afb5ceSopenharmony_ci 874d4afb5ceSopenharmony_ci e->ofs_last_inst_file = t->parser->ofs_last_inst_file; 875d4afb5ceSopenharmony_ci t->parser->ofs_last_inst_file = 0; 876d4afb5ceSopenharmony_ci 877d4afb5ceSopenharmony_ci if (t->str_match_pos != olen) { 878d4afb5ceSopenharmony_ci /* we diverged partway */ 879d4afb5ceSopenharmony_ci e->suffix = &osuff[t->str_match_pos - 1]; 880d4afb5ceSopenharmony_ci e->suffix_len = olen - (t->str_match_pos - 1); 881d4afb5ceSopenharmony_ci } 882d4afb5ceSopenharmony_ci 883d4afb5ceSopenharmony_ci /* 884d4afb5ceSopenharmony_ci * if the current char is a terminal, skip creating a 885d4afb5ceSopenharmony_ci * new way forward. 886d4afb5ceSopenharmony_ci */ 887d4afb5ceSopenharmony_ci 888d4afb5ceSopenharmony_ci if (classify[(int)c]) { 889d4afb5ceSopenharmony_ci 890d4afb5ceSopenharmony_ci /* 891d4afb5ceSopenharmony_ci * Lastly we need to create a new child trie 892d4afb5ceSopenharmony_ci * entry that represents the new way forward 893d4afb5ceSopenharmony_ci * from the point that we diverged. For the 894d4afb5ceSopenharmony_ci * "hello" / "help" case, this guy will start 895d4afb5ceSopenharmony_ci * as a child of "hel" with the single 896d4afb5ceSopenharmony_ci * character match 'p'. 897d4afb5ceSopenharmony_ci * 898d4afb5ceSopenharmony_ci * Since he becomes the current parser context, 899d4afb5ceSopenharmony_ci * more symbol characters may be coming to make 900d4afb5ceSopenharmony_ci * him into, eg, "helping", in which case he 901d4afb5ceSopenharmony_ci * will acquire a suffix eventually of "ping" 902d4afb5ceSopenharmony_ci * via the aggregation stuff 903d4afb5ceSopenharmony_ci */ 904d4afb5ceSopenharmony_ci 905d4afb5ceSopenharmony_ci e = lws_fts_entry_child_add(t, c, t->parser); 906d4afb5ceSopenharmony_ci if (!e) { 907d4afb5ceSopenharmony_ci lwsl_err("%s: child_add fail2\n", 908d4afb5ceSopenharmony_ci __func__); 909d4afb5ceSopenharmony_ci return 1; 910d4afb5ceSopenharmony_ci } 911d4afb5ceSopenharmony_ci } 912d4afb5ceSopenharmony_ci 913d4afb5ceSopenharmony_ci /* go on following this path */ 914d4afb5ceSopenharmony_ci t->parser = e; 915d4afb5ceSopenharmony_ci 916d4afb5ceSopenharmony_ci t->aggregate = 1; 917d4afb5ceSopenharmony_ci t->agg_pos = 0; 918d4afb5ceSopenharmony_ci 919d4afb5ceSopenharmony_ci t->str_match_pos = 0; 920d4afb5ceSopenharmony_ci 921d4afb5ceSopenharmony_ci if (go_around) 922d4afb5ceSopenharmony_ci continue; 923d4afb5ceSopenharmony_ci 924d4afb5ceSopenharmony_ci /* this is intended to be a seal */ 925d4afb5ceSopenharmony_ci } 926d4afb5ceSopenharmony_ci 927d4afb5ceSopenharmony_ci 928d4afb5ceSopenharmony_ci /* end of token */ 929d4afb5ceSopenharmony_ci 930d4afb5ceSopenharmony_ci if (t->aggregate && t->agg_pos) { 931d4afb5ceSopenharmony_ci 932d4afb5ceSopenharmony_ci /* if nothing in agg[]: leave as single char match */ 933d4afb5ceSopenharmony_ci 934d4afb5ceSopenharmony_ci /* otherwise copy out the symbol aggregation */ 935d4afb5ceSopenharmony_ci t->parser->suffix = lwsac_use(&t->lwsac_head, 936d4afb5ceSopenharmony_ci t->agg_pos + 1, 937d4afb5ceSopenharmony_ci TRIE_LWSAC_BLOCK_SIZE); 938d4afb5ceSopenharmony_ci if (!t->parser->suffix) { 939d4afb5ceSopenharmony_ci lwsl_err("%s: lac for suffix failed\n", 940d4afb5ceSopenharmony_ci __func__); 941d4afb5ceSopenharmony_ci return 1; 942d4afb5ceSopenharmony_ci } 943d4afb5ceSopenharmony_ci 944d4afb5ceSopenharmony_ci /* add the first char at the beginning */ 945d4afb5ceSopenharmony_ci *t->parser->suffix = (char)t->parser->c; 946d4afb5ceSopenharmony_ci /* and then add the agg buffer stuff */ 947d4afb5ceSopenharmony_ci memcpy(t->parser->suffix + 1, t->agg, t->agg_pos); 948d4afb5ceSopenharmony_ci t->parser->suffix_len = t->agg_pos + 1; 949d4afb5ceSopenharmony_ci } 950d4afb5ceSopenharmony_ci t->aggregate = 0; 951d4afb5ceSopenharmony_ci 952d4afb5ceSopenharmony_ci if (t->parser == t->root) /* multiple terminal chars */ 953d4afb5ceSopenharmony_ci continue; 954d4afb5ceSopenharmony_ci 955d4afb5ceSopenharmony_ci if (!t->parser->inst_file_list || 956d4afb5ceSopenharmony_ci t->parser->inst_file_list->file_index != file_index) { 957d4afb5ceSopenharmony_ci tif = lwsac_use(&t->lwsac_input_head, sizeof(*tif), 958d4afb5ceSopenharmony_ci TRIE_LWSAC_BLOCK_SIZE); 959d4afb5ceSopenharmony_ci if (!tif) { 960d4afb5ceSopenharmony_ci lwsl_err("%s: lac for tif failed\n", 961d4afb5ceSopenharmony_ci __func__); 962d4afb5ceSopenharmony_ci return 1; 963d4afb5ceSopenharmony_ci } 964d4afb5ceSopenharmony_ci 965d4afb5ceSopenharmony_ci tif->file_index = file_index; 966d4afb5ceSopenharmony_ci tif->owner = t->parser; 967d4afb5ceSopenharmony_ci tif->lines_list = NULL; 968d4afb5ceSopenharmony_ci tif->lines_tail = NULL; 969d4afb5ceSopenharmony_ci tif->total = 0; 970d4afb5ceSopenharmony_ci tif->count = 0; 971d4afb5ceSopenharmony_ci tif->inst_file_next = t->tif_list; 972d4afb5ceSopenharmony_ci t->tif_list = tif; 973d4afb5ceSopenharmony_ci 974d4afb5ceSopenharmony_ci t->parser->inst_file_list = tif; 975d4afb5ceSopenharmony_ci } 976d4afb5ceSopenharmony_ci 977d4afb5ceSopenharmony_ci /* 978d4afb5ceSopenharmony_ci * A naive allocation strategy for this leads to 50% of the 979d4afb5ceSopenharmony_ci * total inmem lac allocation being for line numbers... 980d4afb5ceSopenharmony_ci * 981d4afb5ceSopenharmony_ci * It's mainly solved by only holding the instance and line 982d4afb5ceSopenharmony_ci * number tables for the duration of a file being input, as soon 983d4afb5ceSopenharmony_ci * as one input file is finished it is written to disk. 984d4afb5ceSopenharmony_ci * 985d4afb5ceSopenharmony_ci * For the common case of 1 - ~3 matches the line number are 986d4afb5ceSopenharmony_ci * stored in a small VLI array inside the filepath inst. If the 987d4afb5ceSopenharmony_ci * next one won't fit, it allocates a line number struct with 988d4afb5ceSopenharmony_ci * more vli space and continues chaining those if needed. 989d4afb5ceSopenharmony_ci */ 990d4afb5ceSopenharmony_ci 991d4afb5ceSopenharmony_ci n = (unsigned int)wq32(vlibuf, (uint32_t)t->line_number); 992d4afb5ceSopenharmony_ci tif = t->parser->inst_file_list; 993d4afb5ceSopenharmony_ci 994d4afb5ceSopenharmony_ci if (!tif->lines_list) { 995d4afb5ceSopenharmony_ci /* we are still trying to use the file inst vli */ 996d4afb5ceSopenharmony_ci if (LWS_ARRAY_SIZE(tif->vli) - (size_t)tif->count >= n) { 997d4afb5ceSopenharmony_ci tif->count = (char)((char)tif->count + (char)wq32(tif->vli + tif->count, 998d4afb5ceSopenharmony_ci (uint32_t)t->line_number)); 999d4afb5ceSopenharmony_ci goto after; 1000d4afb5ceSopenharmony_ci } 1001d4afb5ceSopenharmony_ci /* we are going to have to allocate */ 1002d4afb5ceSopenharmony_ci } 1003d4afb5ceSopenharmony_ci 1004d4afb5ceSopenharmony_ci /* can we add to an existing line numbers struct? */ 1005d4afb5ceSopenharmony_ci if (tif->lines_tail && 1006d4afb5ceSopenharmony_ci LWS_ARRAY_SIZE(tif->lines_tail->vli) - 1007d4afb5ceSopenharmony_ci (unsigned char)tif->lines_tail->count >= n) { 1008d4afb5ceSopenharmony_ci tif->lines_tail->count = (char)((char)tif->lines_tail->count + (char)wq32(tif->lines_tail->vli + 1009d4afb5ceSopenharmony_ci tif->lines_tail->count, 1010d4afb5ceSopenharmony_ci (uint32_t)t->line_number)); 1011d4afb5ceSopenharmony_ci goto after; 1012d4afb5ceSopenharmony_ci } 1013d4afb5ceSopenharmony_ci 1014d4afb5ceSopenharmony_ci /* either no existing line numbers struct at tail, or full */ 1015d4afb5ceSopenharmony_ci 1016d4afb5ceSopenharmony_ci /* have to create a(nother) line numbers struct */ 1017d4afb5ceSopenharmony_ci tl = lwsac_use(&t->lwsac_input_head, sizeof(*tl), 1018d4afb5ceSopenharmony_ci TRIE_LWSAC_BLOCK_SIZE); 1019d4afb5ceSopenharmony_ci if (!tl) { 1020d4afb5ceSopenharmony_ci lwsl_err("%s: lac for tl failed\n", __func__); 1021d4afb5ceSopenharmony_ci return 1; 1022d4afb5ceSopenharmony_ci } 1023d4afb5ceSopenharmony_ci tl->lines_next = NULL; 1024d4afb5ceSopenharmony_ci if (tif->lines_tail) 1025d4afb5ceSopenharmony_ci tif->lines_tail->lines_next = tl; 1026d4afb5ceSopenharmony_ci 1027d4afb5ceSopenharmony_ci tif->lines_tail = tl; 1028d4afb5ceSopenharmony_ci if (!tif->lines_list) 1029d4afb5ceSopenharmony_ci tif->lines_list = tl; 1030d4afb5ceSopenharmony_ci 1031d4afb5ceSopenharmony_ci tl->count = (char)wq32(tl->vli, (uint32_t)t->line_number); 1032d4afb5ceSopenharmony_ciafter: 1033d4afb5ceSopenharmony_ci tif->total++; 1034d4afb5ceSopenharmony_ci#if 0 1035d4afb5ceSopenharmony_ci { 1036d4afb5ceSopenharmony_ci char s[128]; 1037d4afb5ceSopenharmony_ci const char *ne = name_entry(t->parser, s, sizeof(s)); 1038d4afb5ceSopenharmony_ci 1039d4afb5ceSopenharmony_ci if (!strcmp(ne, "describ")) { 1040d4afb5ceSopenharmony_ci lwsl_err(" %s %d\n", ne, t->str_match_pos); 1041d4afb5ceSopenharmony_ci write(1, buf - 10, 20); 1042d4afb5ceSopenharmony_ci } 1043d4afb5ceSopenharmony_ci } 1044d4afb5ceSopenharmony_ci#endif 1045d4afb5ceSopenharmony_ci t->parser->instance_count++; 1046d4afb5ceSopenharmony_ci t->parser = t->root; 1047d4afb5ceSopenharmony_ci t->str_match_pos = 0; 1048d4afb5ceSopenharmony_ci } 1049d4afb5ceSopenharmony_ci 1050d4afb5ceSopenharmony_ci /* seal off the line length table block */ 1051d4afb5ceSopenharmony_ci 1052d4afb5ceSopenharmony_ci if (bp) { 1053d4afb5ceSopenharmony_ci if ((int)write(t->fd, linetable, (size_t)bp) != bp) 1054d4afb5ceSopenharmony_ci return 1; 1055d4afb5ceSopenharmony_ci t->c += (unsigned int)bp; 1056d4afb5ceSopenharmony_ci bp = 0; 1057d4afb5ceSopenharmony_ci } 1058d4afb5ceSopenharmony_ci 1059d4afb5ceSopenharmony_ci if (lseek(t->fd, lbh, SEEK_SET) < 0) { 1060d4afb5ceSopenharmony_ci lwsl_err("%s: seek to 0x%llx failed\n", __func__, 1061d4afb5ceSopenharmony_ci (unsigned long long)lbh); 1062d4afb5ceSopenharmony_ci return 1; 1063d4afb5ceSopenharmony_ci } 1064d4afb5ceSopenharmony_ci 1065d4afb5ceSopenharmony_ci g16(linetable, (uint16_t)(t->c - (jg2_file_offset)lbh)); 1066d4afb5ceSopenharmony_ci g16(linetable + 2, (uint16_t)(t->line_number - sline)); 1067d4afb5ceSopenharmony_ci g32(linetable + 4, (uint32_t)chars); 1068d4afb5ceSopenharmony_ci if ((int)write(t->fd, linetable, 8) != 8) { 1069d4afb5ceSopenharmony_ci lwsl_err("%s: write linetable header failed\n", __func__); 1070d4afb5ceSopenharmony_ci return 1; 1071d4afb5ceSopenharmony_ci } 1072d4afb5ceSopenharmony_ci 1073d4afb5ceSopenharmony_ci assert(lseek(t->fd, 0, SEEK_END) == (off_t)t->c); 1074d4afb5ceSopenharmony_ci 1075d4afb5ceSopenharmony_ci if (lseek(t->fd, (off_t)t->c, SEEK_SET) < 0) { 1076d4afb5ceSopenharmony_ci lwsl_err("%s: end seek failed\n", __func__); 1077d4afb5ceSopenharmony_ci return 1; 1078d4afb5ceSopenharmony_ci } 1079d4afb5ceSopenharmony_ci 1080d4afb5ceSopenharmony_ci bp = 0; 1081d4afb5ceSopenharmony_ci 1082d4afb5ceSopenharmony_ci if (len) { 1083d4afb5ceSopenharmony_ci t->lines_in_unsealed_linetable = 0; 1084d4afb5ceSopenharmony_ci goto resume; 1085d4afb5ceSopenharmony_ci } 1086d4afb5ceSopenharmony_ci 1087d4afb5ceSopenharmony_ci /* dump the collected per-input instance and line data, and free it */ 1088d4afb5ceSopenharmony_ci 1089d4afb5ceSopenharmony_ci t->agg_trie_creation_us += (uint64_t)((uint64_t)lws_now_usecs() - tf); 1090d4afb5ceSopenharmony_ci 1091d4afb5ceSopenharmony_ci return 0; 1092d4afb5ceSopenharmony_ci} 1093d4afb5ceSopenharmony_ci 1094d4afb5ceSopenharmony_ci/* refer to ./README.md */ 1095d4afb5ceSopenharmony_ci 1096d4afb5ceSopenharmony_ciint 1097d4afb5ceSopenharmony_cilws_fts_serialize(struct lws_fts *t) 1098d4afb5ceSopenharmony_ci{ 1099d4afb5ceSopenharmony_ci struct lws_fts_filepath *fp = t->filepath_list, *ofp; 1100d4afb5ceSopenharmony_ci unsigned long long tf = (unsigned long long)lws_now_usecs(); 1101d4afb5ceSopenharmony_ci struct lws_fts_entry *e, *e1, *s[256]; 1102d4afb5ceSopenharmony_ci unsigned char buf[8192], stasis; 1103d4afb5ceSopenharmony_ci int n, bp, sp = 0, do_parent; 1104d4afb5ceSopenharmony_ci 1105d4afb5ceSopenharmony_ci (void)tf; 1106d4afb5ceSopenharmony_ci finalize_per_input(t); 1107d4afb5ceSopenharmony_ci 1108d4afb5ceSopenharmony_ci /* 1109d4afb5ceSopenharmony_ci * Compute aggregated instance counts (parents should know the total 1110d4afb5ceSopenharmony_ci * number of instances below each child path) 1111d4afb5ceSopenharmony_ci * 1112d4afb5ceSopenharmony_ci * 1113d4afb5ceSopenharmony_ci * If we have 1114d4afb5ceSopenharmony_ci * 1115d4afb5ceSopenharmony_ci * (root) -> (c1) -> (c2) 1116d4afb5ceSopenharmony_ci * -> (c3) 1117d4afb5ceSopenharmony_ci * 1118d4afb5ceSopenharmony_ci * we need to visit the nodes in the order 1119d4afb5ceSopenharmony_ci * 1120d4afb5ceSopenharmony_ci * c2, c1, c3, root 1121d4afb5ceSopenharmony_ci */ 1122d4afb5ceSopenharmony_ci 1123d4afb5ceSopenharmony_ci sp = 0; 1124d4afb5ceSopenharmony_ci s[0] = t->root; 1125d4afb5ceSopenharmony_ci do_parent = 0; 1126d4afb5ceSopenharmony_ci while (sp >= 0) { 1127d4afb5ceSopenharmony_ci int n; 1128d4afb5ceSopenharmony_ci 1129d4afb5ceSopenharmony_ci /* aggregate in every antecedent */ 1130d4afb5ceSopenharmony_ci 1131d4afb5ceSopenharmony_ci for (n = 0; n <= sp; n++) { 1132d4afb5ceSopenharmony_ci s[n]->agg_inst_count += s[sp]->instance_count; 1133d4afb5ceSopenharmony_ci s[n]->agg_child_count += s[sp]->child_count; 1134d4afb5ceSopenharmony_ci } 1135d4afb5ceSopenharmony_ci 1136d4afb5ceSopenharmony_ci /* handle any children before the parent */ 1137d4afb5ceSopenharmony_ci 1138d4afb5ceSopenharmony_ci if (s[sp]->child_list) { 1139d4afb5ceSopenharmony_ci if (sp + 1 == LWS_ARRAY_SIZE(s)) { 1140d4afb5ceSopenharmony_ci lwsl_err("Stack too deep\n"); 1141d4afb5ceSopenharmony_ci 1142d4afb5ceSopenharmony_ci goto bail; 1143d4afb5ceSopenharmony_ci } 1144d4afb5ceSopenharmony_ci 1145d4afb5ceSopenharmony_ci s[sp + 1] = s[sp]->child_list; 1146d4afb5ceSopenharmony_ci sp++; 1147d4afb5ceSopenharmony_ci continue; 1148d4afb5ceSopenharmony_ci } 1149d4afb5ceSopenharmony_ci 1150d4afb5ceSopenharmony_ci do { 1151d4afb5ceSopenharmony_ci if (s[sp]->sibling) { 1152d4afb5ceSopenharmony_ci s[sp] = s[sp]->sibling; 1153d4afb5ceSopenharmony_ci break; 1154d4afb5ceSopenharmony_ci } else 1155d4afb5ceSopenharmony_ci sp--; 1156d4afb5ceSopenharmony_ci } while (sp >= 0); 1157d4afb5ceSopenharmony_ci } 1158d4afb5ceSopenharmony_ci 1159d4afb5ceSopenharmony_ci /* dump the filepaths and set prev */ 1160d4afb5ceSopenharmony_ci 1161d4afb5ceSopenharmony_ci fp = t->filepath_list; 1162d4afb5ceSopenharmony_ci ofp = NULL; 1163d4afb5ceSopenharmony_ci bp = 0; 1164d4afb5ceSopenharmony_ci while (fp) { 1165d4afb5ceSopenharmony_ci 1166d4afb5ceSopenharmony_ci fp->ofs = t->c + (unsigned int)bp; 1167d4afb5ceSopenharmony_ci n = (int)strlen(fp->filepath); 1168d4afb5ceSopenharmony_ci spill(15 + n, 0); 1169d4afb5ceSopenharmony_ci 1170d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], fp->line_table_ofs); 1171d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], (uint32_t)fp->total_lines); 1172d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], (uint32_t)n); 1173d4afb5ceSopenharmony_ci memcpy(&buf[bp], fp->filepath, (unsigned int)n); 1174d4afb5ceSopenharmony_ci bp += n; 1175d4afb5ceSopenharmony_ci 1176d4afb5ceSopenharmony_ci fp->prev = ofp; 1177d4afb5ceSopenharmony_ci ofp = fp; 1178d4afb5ceSopenharmony_ci fp = fp->next; 1179d4afb5ceSopenharmony_ci } 1180d4afb5ceSopenharmony_ci 1181d4afb5ceSopenharmony_ci spill(0, 1); 1182d4afb5ceSopenharmony_ci 1183d4afb5ceSopenharmony_ci /* record the fileoffset of the filepath map and filepath count */ 1184d4afb5ceSopenharmony_ci 1185d4afb5ceSopenharmony_ci if (lseek(t->fd, 0xc, SEEK_SET) < 0) 1186d4afb5ceSopenharmony_ci goto bail_seek; 1187d4afb5ceSopenharmony_ci 1188d4afb5ceSopenharmony_ci g32(buf, t->c + (unsigned int)bp); 1189d4afb5ceSopenharmony_ci g32(buf + 4, (uint32_t)t->next_file_index); 1190d4afb5ceSopenharmony_ci if ((int)write(t->fd, buf, 8) != 8) 1191d4afb5ceSopenharmony_ci goto bail; 1192d4afb5ceSopenharmony_ci 1193d4afb5ceSopenharmony_ci if (lseek(t->fd, (off_t)(t->c + (unsigned int)bp), SEEK_SET) < 0) 1194d4afb5ceSopenharmony_ci goto bail_seek; 1195d4afb5ceSopenharmony_ci 1196d4afb5ceSopenharmony_ci /* dump the filepath map, starting from index 0, which is at the tail */ 1197d4afb5ceSopenharmony_ci 1198d4afb5ceSopenharmony_ci fp = ofp; 1199d4afb5ceSopenharmony_ci bp = 0; 1200d4afb5ceSopenharmony_ci while (fp) { 1201d4afb5ceSopenharmony_ci spill(5, 0); 1202d4afb5ceSopenharmony_ci g32(buf + bp, fp->ofs); 1203d4afb5ceSopenharmony_ci bp += 4; 1204d4afb5ceSopenharmony_ci fp = fp->prev; 1205d4afb5ceSopenharmony_ci } 1206d4afb5ceSopenharmony_ci spill(0, 1); 1207d4afb5ceSopenharmony_ci 1208d4afb5ceSopenharmony_ci /* 1209d4afb5ceSopenharmony_ci * The trie entries in reverse order... because of the reversal, we have 1210d4afb5ceSopenharmony_ci * always written children first, and marked them with their file offset 1211d4afb5ceSopenharmony_ci * before we come to refer to them. 1212d4afb5ceSopenharmony_ci */ 1213d4afb5ceSopenharmony_ci 1214d4afb5ceSopenharmony_ci bp = 0; 1215d4afb5ceSopenharmony_ci sp = 0; 1216d4afb5ceSopenharmony_ci s[0] = t->root; 1217d4afb5ceSopenharmony_ci do_parent = 0; 1218d4afb5ceSopenharmony_ci while (s[sp]) { 1219d4afb5ceSopenharmony_ci 1220d4afb5ceSopenharmony_ci /* handle any children before the parent */ 1221d4afb5ceSopenharmony_ci 1222d4afb5ceSopenharmony_ci if (!do_parent && s[sp]->child_list) { 1223d4afb5ceSopenharmony_ci 1224d4afb5ceSopenharmony_ci if (sp + 1 == LWS_ARRAY_SIZE(s)) { 1225d4afb5ceSopenharmony_ci lwsl_err("Stack too deep\n"); 1226d4afb5ceSopenharmony_ci 1227d4afb5ceSopenharmony_ci goto bail; 1228d4afb5ceSopenharmony_ci } 1229d4afb5ceSopenharmony_ci 1230d4afb5ceSopenharmony_ci s[sp + 1] = s[sp]->child_list; 1231d4afb5ceSopenharmony_ci sp++; 1232d4afb5ceSopenharmony_ci continue; 1233d4afb5ceSopenharmony_ci } 1234d4afb5ceSopenharmony_ci 1235d4afb5ceSopenharmony_ci /* leaf nodes with no children */ 1236d4afb5ceSopenharmony_ci 1237d4afb5ceSopenharmony_ci e = s[sp]; 1238d4afb5ceSopenharmony_ci e->ofs = t->c + (unsigned int)bp; 1239d4afb5ceSopenharmony_ci 1240d4afb5ceSopenharmony_ci /* write the trie entry header */ 1241d4afb5ceSopenharmony_ci 1242d4afb5ceSopenharmony_ci spill((3 * MAX_VLI), 0); 1243d4afb5ceSopenharmony_ci 1244d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e->ofs_last_inst_file); 1245d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e->child_count); 1246d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e->instance_count); 1247d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e->agg_inst_count); 1248d4afb5ceSopenharmony_ci 1249d4afb5ceSopenharmony_ci /* sort the children in order of highest aggregate hits first */ 1250d4afb5ceSopenharmony_ci 1251d4afb5ceSopenharmony_ci do { 1252d4afb5ceSopenharmony_ci struct lws_fts_entry **pe, *te1, *te2; 1253d4afb5ceSopenharmony_ci 1254d4afb5ceSopenharmony_ci stasis = 1; 1255d4afb5ceSopenharmony_ci 1256d4afb5ceSopenharmony_ci /* bubble sort keeps going until nothing changed */ 1257d4afb5ceSopenharmony_ci 1258d4afb5ceSopenharmony_ci pe = &e->child_list; 1259d4afb5ceSopenharmony_ci while (*pe) { 1260d4afb5ceSopenharmony_ci 1261d4afb5ceSopenharmony_ci te1 = *pe; 1262d4afb5ceSopenharmony_ci te2 = te1->sibling; 1263d4afb5ceSopenharmony_ci 1264d4afb5ceSopenharmony_ci if (te2 && te1->agg_inst_count < 1265d4afb5ceSopenharmony_ci te2->agg_inst_count) { 1266d4afb5ceSopenharmony_ci stasis = 0; 1267d4afb5ceSopenharmony_ci 1268d4afb5ceSopenharmony_ci *pe = te2; 1269d4afb5ceSopenharmony_ci te1->sibling = te2->sibling; 1270d4afb5ceSopenharmony_ci te2->sibling = te1; 1271d4afb5ceSopenharmony_ci } 1272d4afb5ceSopenharmony_ci 1273d4afb5ceSopenharmony_ci pe = &(*pe)->sibling; 1274d4afb5ceSopenharmony_ci } 1275d4afb5ceSopenharmony_ci 1276d4afb5ceSopenharmony_ci } while (!stasis); 1277d4afb5ceSopenharmony_ci 1278d4afb5ceSopenharmony_ci /* write the children */ 1279d4afb5ceSopenharmony_ci 1280d4afb5ceSopenharmony_ci e1 = e->child_list; 1281d4afb5ceSopenharmony_ci while (e1) { 1282d4afb5ceSopenharmony_ci spill((5 * MAX_VLI) + e1->suffix_len + 1, 0); 1283d4afb5ceSopenharmony_ci 1284d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e1->ofs); 1285d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e1->instance_count); 1286d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e1->agg_inst_count); 1287d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e1->agg_child_count); 1288d4afb5ceSopenharmony_ci 1289d4afb5ceSopenharmony_ci if (e1->suffix) { /* string */ 1290d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], e1->suffix_len); 1291d4afb5ceSopenharmony_ci memmove(&buf[bp], e1->suffix, e1->suffix_len); 1292d4afb5ceSopenharmony_ci bp += (int)e1->suffix_len; 1293d4afb5ceSopenharmony_ci } else { /* char */ 1294d4afb5ceSopenharmony_ci bp += wq32(&buf[bp], 1); 1295d4afb5ceSopenharmony_ci buf[bp++] = e1->c; 1296d4afb5ceSopenharmony_ci } 1297d4afb5ceSopenharmony_ci#if 0 1298d4afb5ceSopenharmony_ci if (e1->suffix && e1->suffix_len == 3 && 1299d4afb5ceSopenharmony_ci !memcmp(e1->suffix, "cri", 3)) { 1300d4afb5ceSopenharmony_ci struct lws_fts_entry *e2; 1301d4afb5ceSopenharmony_ci 1302d4afb5ceSopenharmony_ci e2 = e1; 1303d4afb5ceSopenharmony_ci while (e2){ 1304d4afb5ceSopenharmony_ci if (e2->suffix) 1305d4afb5ceSopenharmony_ci lwsl_notice("%s\n", e2->suffix); 1306d4afb5ceSopenharmony_ci else 1307d4afb5ceSopenharmony_ci lwsl_notice("%c\n", e2->c); 1308d4afb5ceSopenharmony_ci 1309d4afb5ceSopenharmony_ci e2 = e2->parent; 1310d4afb5ceSopenharmony_ci } 1311d4afb5ceSopenharmony_ci 1312d4afb5ceSopenharmony_ci lwsl_err("*** %c CRI inst %d ch %d\n", e1->parent->c, 1313d4afb5ceSopenharmony_ci e1->instance_count, e1->child_count); 1314d4afb5ceSopenharmony_ci } 1315d4afb5ceSopenharmony_ci#endif 1316d4afb5ceSopenharmony_ci e1 = e1->sibling; 1317d4afb5ceSopenharmony_ci } 1318d4afb5ceSopenharmony_ci 1319d4afb5ceSopenharmony_ci /* if there are siblings, do those next */ 1320d4afb5ceSopenharmony_ci 1321d4afb5ceSopenharmony_ci if (do_parent) { 1322d4afb5ceSopenharmony_ci do_parent = 0; 1323d4afb5ceSopenharmony_ci sp--; 1324d4afb5ceSopenharmony_ci } 1325d4afb5ceSopenharmony_ci 1326d4afb5ceSopenharmony_ci if (s[sp]->sibling) 1327d4afb5ceSopenharmony_ci s[sp] = s[sp]->sibling; 1328d4afb5ceSopenharmony_ci else { 1329d4afb5ceSopenharmony_ci /* if there are no siblings, do the parent */ 1330d4afb5ceSopenharmony_ci do_parent = 1; 1331d4afb5ceSopenharmony_ci s[sp] = s[sp]->parent; 1332d4afb5ceSopenharmony_ci } 1333d4afb5ceSopenharmony_ci } 1334d4afb5ceSopenharmony_ci 1335d4afb5ceSopenharmony_ci spill(0, 1); 1336d4afb5ceSopenharmony_ci 1337d4afb5ceSopenharmony_ci assert(lseek(t->fd, 0, SEEK_END) == (off_t)t->c); 1338d4afb5ceSopenharmony_ci 1339d4afb5ceSopenharmony_ci /* drop the correct root trie offset + file length into the header */ 1340d4afb5ceSopenharmony_ci 1341d4afb5ceSopenharmony_ci if (lseek(t->fd, 4, SEEK_SET) < 0) { 1342d4afb5ceSopenharmony_ci lwsl_err("%s: unable to seek\n", __func__); 1343d4afb5ceSopenharmony_ci 1344d4afb5ceSopenharmony_ci goto bail; 1345d4afb5ceSopenharmony_ci } 1346d4afb5ceSopenharmony_ci 1347d4afb5ceSopenharmony_ci g32(buf, t->root->ofs); 1348d4afb5ceSopenharmony_ci g32(buf + 4, t->c); 1349d4afb5ceSopenharmony_ci if (write(t->fd, buf, 0x8) != 0x8) 1350d4afb5ceSopenharmony_ci goto bail; 1351d4afb5ceSopenharmony_ci 1352d4afb5ceSopenharmony_ci lwsl_notice("%s: index %d files (%uMiB) cpu time %dms, " 1353d4afb5ceSopenharmony_ci "alloc: %dKiB + %dKiB, " 1354d4afb5ceSopenharmony_ci "serialize: %dms, file: %dKiB\n", __func__, 1355d4afb5ceSopenharmony_ci t->next_file_index, 1356d4afb5ceSopenharmony_ci (int)(t->agg_raw_input / (1024 * 1024)), 1357d4afb5ceSopenharmony_ci (int)(t->agg_trie_creation_us / 1000), 1358d4afb5ceSopenharmony_ci (int)(lwsac_total_alloc(t->lwsac_head) / 1024), 1359d4afb5ceSopenharmony_ci (int)(t->worst_lwsac_input_size / 1024), 1360d4afb5ceSopenharmony_ci (int)(((uint64_t)lws_now_usecs() - tf) / 1000), 1361d4afb5ceSopenharmony_ci (int)(t->c / 1024)); 1362d4afb5ceSopenharmony_ci 1363d4afb5ceSopenharmony_ci return 0; 1364d4afb5ceSopenharmony_ci 1365d4afb5ceSopenharmony_cibail_seek: 1366d4afb5ceSopenharmony_ci lwsl_err("%s: problem seekings\n", __func__); 1367d4afb5ceSopenharmony_ci 1368d4afb5ceSopenharmony_cibail: 1369d4afb5ceSopenharmony_ci return 1; 1370d4afb5ceSopenharmony_ci} 1371d4afb5ceSopenharmony_ci 1372d4afb5ceSopenharmony_ci 1373