CUBRID Engine  latest
file_hash.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * file_hash.c: file hashing implementation
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <stddef.h>
31 #if defined (WINDOWS)
32 #include <io.h>
33 #endif
34 
35 #include "utility.h"
36 #include "error_manager.h"
37 #include "file_hash.h"
38 #include "filesys_temp.hpp"
39 #include "memory_alloc.h"
40 #include "object_representation.h"
41 
42 #include "message_catalog.h"
43 
44 #if defined (WINDOWS)
45 #include "porting.h"
46 #endif
47 
48 #define ISPOWER2(x) (((x) & (x-1)) == 0)
49 
50 static OID null_oid;
51 static int null_int;
52 
53 
54 /*
55  * A Table of Prime Numbers
56  *
57  * Some prime numbers which were picked randomly. This table contains more
58  * smaller prime numbers. For example, between 1000 and 2000, we include
59  * only prime numbers that are farther than 50 units. And above 2000, we
60  * include prime numbers that are farther in 100 units.
61  *
62  * NOTE: if x is a prime number, the n is prime if
63  * X**(n-1) mod n == 1
64  */
65 
66 #define NPRIMES 100
67 
68 static int fh_Primes[NPRIMES] = {
69  11, 23, 37, 53, 67, 79, 97, 109, 127, 149,
70  167, 191, 211, 227, 251, 269, 293, 311, 331, 349,
71  367, 389, 409, 431, 449, 467, 487, 509, 541, 563,
72  587, 607, 631, 653, 673, 521, 541, 557, 569, 587,
73  599, 613, 641, 673, 701, 727, 751, 787, 821, 853,
74  881, 907, 941, 977, 1039, 1087, 1129, 1171, 1212, 1259,
75  1301, 1361, 1409, 1471, 1523, 1579, 1637, 1693, 1747, 1777,
76  1823, 1867, 1913, 1973, 2017, 2129, 2237, 2339, 2441, 2543,
77  2647, 2749, 2851, 2953, 3061, 3163, 3271, 3373, 3491, 3593,
78  3697, 3803, 3907, 4013, 4177, 4337, 4493, 4649, 4801, 4957
79 };
80 
81 
82 static int fh_calculate_htsize (int htsize);
83 static FH_PAGE_HDR *fh_fetch_page (FH_TABLE * ht, int page);
84 static FH_PAGE_HDR *fh_read_page (FH_TABLE * ht, int page);
85 static FH_PAGE_HDR *fh_write_page (FH_TABLE * ht, FH_PAGE_HDR * pg_hdr);
86 static void fh_bitset (FH_TABLE * ht, int page);
87 static int fh_bittest (FH_TABLE * ht, int page);
88 
89 /*
90  * fh_calculate_htsize - find a good size for a hash table
91  * return: htsize..
92  * htsize(in): Desired hash table size
93  * Note:
94  * A prime number is the best size for a hash table, unfortunately prime
95  * numbers are difficult to find. If the given htsize, falls among the
96  * prime numbers known by this module, a close prime number to
97  * the given htsize value is returned, otherwise, a power of two
98  * is returned.
99  */
100 static int
102 {
103  int left, right, middle; /* Indices for binary search */
104 
105  /* Can we get a prime number ? */
106  if (htsize > fh_Primes[NPRIMES - 1])
107  {
108  /* Use a prower of two */
109  if (!ISPOWER2 (htsize))
110  {
111  /* Turn off some bits but the left most one */
112  while (!ISPOWER2 (htsize))
113  {
114  htsize = htsize & (htsize - 1);
115  }
116  htsize = htsize << 1;
117  }
118  }
119  else
120  {
121  /* We can assign a primary number, ... Binary search */
122  for (left = 0, right = NPRIMES - 1; left <= right;)
123  {
124  /* get the middle record */
125  middle = CEIL_PTVDIV ((left + right), 2);
126  if (htsize == fh_Primes[middle])
127  {
128  break;
129  }
130  else if (htsize > fh_Primes[middle])
131  {
132  left = middle + 1;
133  }
134  else
135  {
136  right = middle - 1;
137  }
138  }
139  htsize = fh_Primes[middle];
140  }
141  return htsize;
142 }
143 
144 
145 /*
146  * fh_create - create a new file hash table
147  * return: hash table handle
148  * name(in): Name of hash table
149  * est_size(in): Estimated number of entries
150  * page_size(in): Number of bytes per cached hash entry page
151  * cached_pages(in): Number of entry pages to cache
152  * hash_filename(in): pathname of the hash file
153  * key_type(in): Type of key
154  * data_size(in): Number of bytes of data per entry
155  * hfun(in): Hash function
156  * cmpfun(): Key comparison function
157  * Note:
158  * The estimated number of entries for the hash table is adjusted in order
159  * to obtain certain favorable circumstances when the table is created.
160  * hfun must return an integer between 0 and table_size - 1. cmpfun must
161  * return true if key1 == key2, otherwise, false.
162  */
163 FH_TABLE *
164 fh_create (const char *name, int est_size, int page_size, int cached_pages, const char *hash_filename,
165  FH_KEY_TYPE key_type, int data_size, HASH_FUNC hfun, CMP_FUNC cmpfun)
166 {
167  FH_TABLE *ht; /* Hash table information */
168  FH_PAGE_HDR *pg_hdr; /* Entries of hash table */
169  int size;
170  int n;
171  int entry_size;
172 
173  OR_PUT_NULL_OID (&null_oid);
174  null_int = -1;
175 
176  /* Validate arguments */
177  switch (key_type)
178  {
179  case FH_OID_KEY:
180  entry_size = data_size + offsetof (FH_INFO, fh_oidk_data) + offsetof (FH_ENTRY, info);
181  break;
182  case FH_INT_KEY:
183  entry_size = data_size + offsetof (FH_INFO, fh_intk_data) + offsetof (FH_ENTRY, info);
184  break;
185  default:
186  /*
187  * this should be calling er_set
188  * fprintf(stderr, "Invalid key type\n");
189  */
190  return NULL;
191  }
192 
193  if (page_size < entry_size)
194  {
195  /*
196  * should be calling er_set
197  * fprintf(stderr, "Invalid page_size\n");
198  */
199  return NULL;
200  }
201 
202  /* Allocate the header information for hash table */
203  if ((ht = (FH_TABLE *) malloc (DB_SIZEOF (FH_TABLE))) == NULL)
204  {
205  return NULL;
206  }
207  memset (ht, 0, DB_SIZEOF (FH_TABLE));
208 
209  /* Get a good number of entries for hash table */
210  if (est_size <= 0)
211  {
212  est_size = 2;
213  }
214  est_size = fh_calculate_htsize (est_size);
215 
216  /* Open the hash file */
217  if (!hash_filename || hash_filename[0] == '\0')
218  {
219  auto[filename, filedes] = filesys::open_temp_filedes ("fhash_");
220  close (filedes);
221  ht->hash_filename = strdup (filename.c_str ());
222  }
223  else
224  {
225  ht->hash_filename = strdup (hash_filename);
226  }
227  if (ht->hash_filename == NULL)
228  {
229  fh_destroy (ht);
230  return NULL;
231  }
232 #if defined(SOLARIS) || defined(AIX) || (defined(I386) && defined(LINUX)) || (defined(HPUX) && (_LFS64_LARGEFILE == 1))
233  ht->fd = open64 (ht->hash_filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
234 #else
235  ht->fd = open (ht->hash_filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
236 #endif
237  if (ht->fd < 0)
238  {
240  fh_destroy (ht);
241  return NULL;
242  }
243 
244  /* Allocate the page bitmap */
245  ht->page_size = page_size;
246  ht->data_size = data_size;
247  ht->entry_size = entry_size;
248  ht->entries_per_page = page_size / entry_size;
249  ht->overflow = est_size + 1;
250  ht->bitmap_size = (ht->overflow / ht->entries_per_page + 7) / 8;
251  ht->bitmap = (char *) malloc (ht->bitmap_size);
252  if (ht->bitmap == NULL)
253  {
254  fh_destroy (ht);
255  return NULL;
256  }
257  memset (ht->bitmap, 0, ht->bitmap_size);
258 
259  /* Allocate the cached page headers */
260  size = cached_pages * DB_SIZEOF (FH_PAGE_HDR);
261  if ((pg_hdr = (FH_PAGE_HDR *) malloc (size)) == NULL)
262  {
263  fh_destroy (ht);
264  return NULL;
265  }
266  ht->pg_hdr = ht->pg_hdr_alloc = pg_hdr;
267  memset (ht->pg_hdr, 0, size);
268 
269  /*
270  * Allocate the cached pages and fill in the page headers and
271  * initialize each of the hash entries
272  */
273  for (n = 0; n < cached_pages; n++, pg_hdr++)
274  {
275  pg_hdr->next = pg_hdr + 1;
276  pg_hdr->prev = pg_hdr - 1;
277  if ((pg_hdr->fh_entries = (FH_ENTRY *) malloc (page_size)) == NULL)
278  {
279  fh_destroy (ht);
280  return NULL;
281  }
282  memset ((char *) pg_hdr->fh_entries, 0, page_size);
283  pg_hdr->page = INVALID_FILE_POS;
284  }
285  pg_hdr--;
286  pg_hdr->next = NULL;
287  ht->pg_hdr->prev = NULL;
288 
289  ht->pg_hdr_last = pg_hdr;
290  ht->pg_hdr_free = ht->pg_hdr;
291  ht->hfun = hfun;
292  ht->cmpfun = cmpfun;
293  ht->name = name;
294  ht->size = est_size;
296  ht->nentries = 0;
297  ht->ncollisions = 0;
298  ht->key_type = key_type;
299 
300  return ht;
301 }
302 
303 
304 /*
305  * fh_destroy - destroy the given hash table
306  * return: void
307  * ht(out): Hash table (set as a side effect)
308  */
309 void
311 {
312  FH_PAGE_HDR *pg_hdr; /* Entries of hash table */
313 
314  for (pg_hdr = ht->pg_hdr; pg_hdr; pg_hdr = pg_hdr->next)
315  {
316  if (pg_hdr->fh_entries)
317  {
318  free_and_init (pg_hdr->fh_entries);
319  }
320  }
321  if (ht->pg_hdr_alloc)
322  {
324  }
325 
326  if (ht->fd > 0)
327  {
328  close (ht->fd);
329  unlink (ht->hash_filename);
330  }
331  if (ht->hash_filename)
332  {
334  }
335  if (ht->bitmap)
336  {
337  free_and_init (ht->bitmap);
338  }
339  free_and_init (ht);
340  return;
341 }
342 
343 
344 /*
345  * fh_get - Find the entry in hash table whose key is the value of the
346  * given key and return the data associated with the key.
347  * return: NO_ERROR or error code
348  * ht(in): Hash table
349  * key(in): Hashing key
350  * data(out): pointer to data or NULL if not found
351  */
352 int
353 fh_get (FH_TABLE * ht, FH_KEY key, FH_DATA * data)
354 {
355  int hash;
356  FH_FILE_POS pos;
357  int page_no;
358  int entry_no;
359  FH_ENTRY *entry;
360  FH_PAGE_HDR *pg_hdr;
361  char *ptr;
362 
363  /*
364  * Hash the key and make sure that the return value is between 0 and size
365  * of hash table
366  */
367  hash = (*ht->hfun) (key, ht->size);
368  if (hash < 0)
369  {
370  hash = -hash;
371  }
372  if (hash >= ht->size)
373  {
374  hash = hash % ht->size;
375  }
376 
377  /* Determine the page & entry in the hash file */
378  pos = hash;
379 
380  while (pos != INVALID_FILE_POS)
381  {
382  page_no = pos / ht->entries_per_page;
383  entry_no = pos % ht->entries_per_page;
384 
385  /* fetch the page */
386  if ((pg_hdr = fh_fetch_page (ht, page_no)) == NULL)
387  {
388  *data = NULL;
389  return ER_GENERIC_ERROR;
390  }
391 
392  /* Determine if the entry has the key */
393  ptr = (char *) pg_hdr->fh_entries;
394  ptr += entry_no * ht->entry_size;
395  entry = (FH_ENTRY *) ptr;
396  switch (ht->key_type)
397  {
398  case FH_OID_KEY:
399  /* If the entry is null, the key doesn't exist */
400  if ((*ht->cmpfun) (&entry->info.fh_oidk_key, &null_oid))
401  {
402  *data = NULL;
403  return ER_GENERIC_ERROR;
404  }
405  if ((*ht->cmpfun) (&entry->info.fh_oidk_key, key))
406  {
407  *data = &entry->info.fh_oidk_data;
408  return NO_ERROR;
409  }
410  break;
411  case FH_INT_KEY:
412  /* If the entry is null, the key doesn't exist */
413  if ((*ht->cmpfun) (&entry->info.fh_intk_key, &null_int))
414  {
415  *data = NULL;
416  return ER_GENERIC_ERROR;
417  }
418  if ((*ht->cmpfun) (&entry->info.fh_intk_key, key))
419  {
420  *data = &entry->info.fh_intk_data;
421  return NO_ERROR;
422  }
423  break;
424  default:
425  *data = NULL;
426  return ER_GENERIC_ERROR;
427  }
428  pos = entry->next;
429  }
430  *data = NULL;
431  return ER_GENERIC_ERROR;
432 }
433 
434 
435 /*
436  * fh_put - insert an entry into a hash table
437  * return: NO_ERROR or ER_GENERIC_ERROR
438  * ht(in/out): Hash table
439  * key(in): Hashing key
440  * data(in): Data associated with hashing key
441  * Note:
442  * If the key already exists, the new entry replaces the old one.
443  *
444  * The key and data are copied.
445  * The user must be aware, that changes to the key and value are
446  * not reflected in the hash table.
447  */
448 int
449 fh_put (FH_TABLE * ht, FH_KEY key, FH_DATA data)
450 {
451  int hash;
452  FH_FILE_POS pos;
453  int page_no;
454  int entry_no;
455  FH_ENTRY *entry = NULL;
456  FH_PAGE_HDR *pg_hdr;
457  char *ptr;
458 
459  /*
460  * Hash the key and make sure that the return value is between 0 and size
461  * of hash table
462  */
463  hash = (*ht->hfun) (key, ht->size);
464  if (hash < 0)
465  {
466  hash = -hash;
467  }
468  if (hash >= ht->size)
469  {
470  hash = hash % ht->size;
471  }
472 
473  /* Determine the page & entry in the hash file */
474  pos = hash;
475 
476  do
477  {
478  page_no = pos / ht->entries_per_page;
479  entry_no = pos % ht->entries_per_page;
480 
481  /* fetch the page */
482  if ((pg_hdr = fh_fetch_page (ht, page_no)) == NULL)
483  {
484  return ER_GENERIC_ERROR;
485  }
486 
487  /* Determine if the entry has the key */
488  ptr = (char *) pg_hdr->fh_entries;
489  ptr += entry_no * ht->entry_size;
490  entry = (FH_ENTRY *) ptr;
491  switch (ht->key_type)
492  {
493  case FH_OID_KEY:
494  /* If the entry is null, the key doesn't exist */
495  if ((*ht->cmpfun) (&entry->info.fh_oidk_key, &null_oid))
496  {
497  goto use_entry;
498  }
499  if ((*ht->cmpfun) (&entry->info.fh_oidk_key, key))
500  {
501  memcpy (&entry->info.fh_oidk_data, (char *) data, ht->data_size);
502  return NO_ERROR;
503  }
504  break;
505  case FH_INT_KEY:
506  if ((*ht->cmpfun) (&entry->info.fh_intk_key, &null_int))
507  {
508  goto use_entry;
509  }
510  if ((*ht->cmpfun) (&entry->info.fh_intk_key, key))
511  {
512  memcpy (&entry->info.fh_intk_data, (char *) data, ht->data_size);
513  return NO_ERROR;
514  }
515  break;
516  default:
517  return ER_GENERIC_ERROR;
518  }
519  pos = entry->next;
520  }
521  while (pos != INVALID_FILE_POS);
522 
523  /* This is a new entry, and the last entry examined is not available */
524  entry->next = ht->overflow;
525  /* fetch the overflow page */
526  page_no = ht->overflow / ht->entries_per_page;
527  if ((pg_hdr = fh_fetch_page (ht, page_no)) == NULL)
528  {
529  return ER_GENERIC_ERROR;
530  }
531  entry_no = ht->overflow % ht->entries_per_page;
532  ptr = (char *) pg_hdr->fh_entries;
533  ptr += entry_no * ht->entry_size;
534  entry = (FH_ENTRY *) ptr;
535  ++ht->overflow;
536  ++ht->ncollisions;
537 
538  /* This is a new entry, and the last entry examined is available */
539 use_entry:
540  ++ht->nentries;
541  switch (ht->key_type)
542  {
543  case FH_OID_KEY:
544  entry->info.fh_oidk_key.volid = ((OID *) key)->volid;
545  entry->info.fh_oidk_key.pageid = ((OID *) key)->pageid;
546  entry->info.fh_oidk_key.slotid = ((OID *) key)->slotid;
547  memcpy (&entry->info.fh_oidk_data, (char *) data, ht->data_size);
548  break;
549  case FH_INT_KEY:
550  entry->info.fh_intk_key = *(int *) key;
551  memcpy (&entry->info.fh_intk_data, (char *) data, ht->data_size);
552  break;
553  default:
554  return ER_GENERIC_ERROR;
555  }
556  entry->next = INVALID_FILE_POS;
557  return NO_ERROR;
558 }
559 
560 
561 /*
562  * fh_fetch_page - fetch a page from the hash file to the cache
563  * return: page header pointer if the page exists, or if there is enough
564  * disk space to create a new page. otherwise, it returns NULL.
565  * ht(in/out): Hash table
566  * page(in): Page desired
567  *
568  * Note:
569  * Determine if the page is already in the cache. If so, then
570  * return its page header. Otherwise, select the least recently
571  * used page, write it the the hash file and fetch the desired
572  * page. The page found or fetched becomes the most recently
573  * used page.
574  */
575 static FH_PAGE_HDR *
576 fh_fetch_page (FH_TABLE * ht, int page)
577 {
578  FH_PAGE_HDR *pg_hdr;
579 
580  /* Search for the page in the cache */
581  for (pg_hdr = ht->pg_hdr; pg_hdr; pg_hdr = pg_hdr->next)
582  {
583  /* The page is in the cache. */
584  if (pg_hdr->page == (unsigned int) page)
585  {
586  break;
587  }
588  }
589 
590  /* If the page is not in the cache, get it from the hash file */
591  if (pg_hdr == NULL)
592  {
593  if ((pg_hdr = fh_read_page (ht, page)) == NULL)
594  {
595  return NULL;
596  }
597  }
598 
599  /*
600  * If the page is the least recently used, make the previous page
601  * the least recently used.
602  */
603  if ((ht->pg_hdr_last == pg_hdr) && (ht->cached_pages > 1))
604  {
605  ht->pg_hdr_last = pg_hdr->prev;
606  }
607  /*
608  * If the page is the most recently used, do nothing.
609  * Otherwise, make the page the most recently used.
610  */
611  if (ht->pg_hdr != pg_hdr)
612  {
613  pg_hdr->prev->next = pg_hdr->next;
614  if (pg_hdr->next)
615  {
616  pg_hdr->next->prev = pg_hdr->prev;
617  }
618  pg_hdr->next = ht->pg_hdr;
619  ht->pg_hdr->prev = pg_hdr;
620  pg_hdr->prev = NULL;
621  ht->pg_hdr = pg_hdr;
622  }
623  return pg_hdr;
624 }
625 
626 
627 /*
628  * fh_read_page - read a page from the hash file to the cache
629  * return: page header pointer if the page exists, or if there is enough
630  * disk space to create a new page. otherwise, it returns NULL.
631  * ht(in/out): Hash table
632  * page(in): Page desired
633  *
634  * Note:
635  * Determine if a free page is in the cache. If so, use it.
636  * Otherwise, write the least recently used page to the hash
637  * file and use its page slot to read in the desired page.
638  * If the desired page has never been written, initialize it to
639  * contain all unused entries.
640  */
641 static FH_PAGE_HDR *
642 fh_read_page (FH_TABLE * ht, int page)
643 {
644  FH_PAGE_HDR *pg_hdr;
645 #if defined(SOLARIS) || defined(AIX) || (defined(HPUX) && (_LFS64_LARGEFILE == 1))
646  off64_t offset;
647 #elif defined(I386) && defined(LINUX)
648  __off64_t offset;
649 #elif defined(WINDOWS)
650  __int64 offset;
651 #else
652  int offset;
653 #endif
654  int n;
655 
656  /*
657  * If a free page exists, use it. Since pages are not freed, free
658  * pages only exist after initialization until they are used. Thus
659  * the next page after the first free page is the next free page.
660  */
661  if (ht->pg_hdr_free)
662  {
663  pg_hdr = ht->pg_hdr_free;
664  ht->pg_hdr_free = ht->pg_hdr_free->next;
665  }
666  /* Use the least recently page slot. Write out the page first. */
667  else
668  {
669  if (fh_write_page (ht, ht->pg_hdr_last) == NULL)
670  {
671  return NULL;
672  }
673  pg_hdr = ht->pg_hdr_last;
674  }
675 
676  /* If the page has never been written, initialize a new page */
677  if (fh_bittest (ht, page) == 0)
678  {
679  FH_ENTRY *entry;
680  int i;
681  char *ptr;
682 
683  for (i = 0, entry = pg_hdr->fh_entries; i < ht->entries_per_page; ++i)
684  {
685  switch (ht->key_type)
686  {
687  case FH_OID_KEY:
688  COPY_OID (&entry->info.fh_oidk_key, &null_oid);
689  break;
690  case FH_INT_KEY:
691  entry->info.fh_intk_key = null_int;
692  break;
693  default:
694  return NULL;
695  }
696  entry->next = INVALID_FILE_POS;
697  ptr = (char *) entry;
698  ptr += ht->entry_size;
699  entry = (FH_ENTRY *) ptr;
700  }
701  pg_hdr->page = page;
702  return pg_hdr;
703  }
704 
705  /* Seek to the page location and read it. */
706 #if defined(SOLARIS) || defined(AIX) || (defined(HPUX) && (_LFS64_LARGEFILE == 1))
707  offset = lseek64 (ht->fd, ((off64_t) page) * ht->page_size, SEEK_SET);
708 #elif defined(I386) && defined(LINUX)
709  offset = lseek64 (ht->fd, ((__off64_t) page) * ht->page_size, SEEK_SET);
710 #elif defined(WINDOWS)
711  offset = _lseeki64 (ht->fd, ((__int64) page) * ht->page_size, SEEK_SET);
712 #else
713  offset = lseek (ht->fd, page * ht->page_size, SEEK_SET);
714 #endif
715  if (offset < 0)
716  {
717  return NULL;
718  }
719  n = read (ht->fd, pg_hdr->fh_entries, ht->page_size);
720  if (n != ht->page_size)
721  {
722  return NULL;
723  }
724 
725  pg_hdr->page = page;
726  return pg_hdr;
727 }
728 
729 
730 /*
731  * fh_write_page - write a page from the cache to the hash file
732  * return: page header pointer if the write is successful otherwise, it
733  * returns NULL.
734  * ht(in/out): Hash table
735  * pg_hdr(in): Page header of page to write
736  */
737 static FH_PAGE_HDR *
739 {
740 #if defined(SOLARIS) || defined(AIX) || (defined(HPUX) && (_LFS64_LARGEFILE == 1))
741  off64_t offset;
742 #elif defined(I386) && defined(LINUX)
743  __off64_t offset;
744 #elif defined(WINDOWS)
745  __int64 offset;
746 #else
747  int offset;
748 #endif
749  int n;
750 
751  /* Seek to the page location and write it. */
752 #if defined(SOLARIS) || defined(AIX) || (defined(HPUX) && (_LFS64_LARGEFILE == 1))
753  offset = lseek64 (ht->fd, ((off64_t) pg_hdr->page) * ht->page_size, SEEK_SET);
754 #elif defined(I386) && defined(LINUX)
755  offset = lseek64 (ht->fd, ((__off64_t) pg_hdr->page) * ht->page_size, SEEK_SET);
756 #elif defined(WINDOWS)
757  offset = _lseeki64 (ht->fd, ((__int64) pg_hdr->page) * ht->page_size, SEEK_SET);
758 #else
759  offset = lseek (ht->fd, pg_hdr->page * ht->page_size, SEEK_SET);
760 #endif
761  if (offset < 0)
762  {
763  return NULL;
764  }
765  n = write (ht->fd, pg_hdr->fh_entries, ht->page_size);
766  if (n != ht->page_size)
767  {
768  return NULL;
769  }
770  fh_bitset (ht, pg_hdr->page);
771  return pg_hdr;
772 }
773 
774 
775 /*
776  * fh_bitset - set a bit corresponding to a page in the hash file page bitmap
777  * return: void
778  * ht(in/out): Hash table
779  * page(in): Page to set the bit for
780  *
781  * Note:
782  * The bit is assumed to exist since bits are tested before being set and
783  * fh_bittest allocates a location for bits that don't exist.
784  */
785 static void
786 fh_bitset (FH_TABLE * ht, int page)
787 {
788  int byte;
789  int bit;
790 
791  byte = page / 8;
792  bit = page % 8;
793  ht->bitmap[byte] |= 1 << bit;
794 }
795 
796 
797 /*
798  * fh_bittest - test a bit corresponding to a page in the hash file page bitmap
799  * return: 1/0
800  * ht(in): Hash table
801  * page(in): Page to test for
802  */
803 static int
804 fh_bittest (FH_TABLE * ht, int page)
805 {
806  int byte;
807  int bit;
808 
809  byte = page / 8;
810  if (byte + 1 > ht->bitmap_size)
811  {
812  ht->bitmap = (char *) realloc (ht->bitmap, byte + 1);
813  if (ht->bitmap == NULL)
814  {
815  perror ("SYSTEM ERROR");
816  exit (1);
817  }
818  memset (&ht->bitmap[ht->bitmap_size], 0, byte + 1 - ht->bitmap_size);
819  ht->bitmap_size = byte + 1;
820  return 0;
821  }
822  bit = page % 8;
823  return ht->bitmap[byte] & 1 << bit;
824 }
825 
826 
827 /*
828  * fh_dump - dump the hash table header structure
829  * return: void
830  * ht(in): Hash table
831  */
832 void
834 {
835  static char oid_string[] = "OID";
836  static char int_string[] = "INT";
837 
843  ht->entry_size);
845  ht->entries_per_page);
847  ht->cached_pages);
849  ht->nentries);
851  ht->ncollisions);
853  ht->hash_filename);
855  ht->overflow);
857  ht->key_type == FH_OID_KEY ? oid_string : int_string);
859  (unsigned long) (unsigned long long) ht->pg_hdr);
861  (unsigned long) (unsigned long long) ht->pg_hdr_last);
863  (unsigned long) (unsigned long long) ht->pg_hdr_free);
865  (unsigned long) (unsigned long long) ht->bitmap);
867  ht->bitmap_size);
868 }
void fh_dump(FH_TABLE *ht)
Definition: file_hash.c:833
char * hash_filename
Definition: unloaddb.c:55
FH_INFO info
Definition: file_hash.h:63
int page_size
Definition: unloaddb.c:52
static OID null_oid
Definition: file_hash.c:50
int entries_per_page
Definition: file_hash.h:100
#define NO_ERROR
Definition: error_code.h:46
unsigned int FH_FILE_POS
Definition: file_hash.h:56
int nentries
Definition: file_hash.h:103
FH_TABLE * fh_create(const char *name, int est_size, int page_size, int cached_pages, const char *hash_filename, FH_KEY_TYPE key_type, int data_size, HASH_FUNC hfun, CMP_FUNC cmpfun)
Definition: file_hash.c:164
int data_size
Definition: file_hash.h:98
static FH_PAGE_HDR * fh_read_page(FH_TABLE *ht, int page)
Definition: file_hash.c:642
FH_FILE_POS next
Definition: file_hash.h:62
int cached_pages
Definition: file_hash.h:101
static int fh_calculate_htsize(int htsize)
Definition: file_hash.c:101
static int fh_Primes[NPRIMES]
Definition: file_hash.c:68
int fd
Definition: file_hash.h:106
#define ISPOWER2(x)
Definition: file_hash.c:48
#define COPY_OID(dest_oid_ptr, src_oid_ptr)
Definition: oid.h:63
FH_KEY_TYPE key_type
Definition: file_hash.h:107
static FH_PAGE_HDR * fh_write_page(FH_TABLE *ht, FH_PAGE_HDR *pg_hdr)
Definition: file_hash.c:738
#define OR_PUT_NULL_OID(ptr)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
struct fh_page_hdr * next
Definition: file_hash.h:71
FH_KEY_TYPE
Definition: file_hash.h:80
int fh_get(FH_TABLE *ht, FH_KEY key, FH_DATA *data)
Definition: file_hash.c:353
CMP_FUNC cmpfun
Definition: file_hash.h:90
#define DB_SIZEOF(val)
Definition: memory_alloc.h:54
FH_PAGE_HDR * pg_hdr
Definition: file_hash.h:92
#define NULL
Definition: freelistheap.h:34
static FH_PAGE_HDR * fh_fetch_page(FH_TABLE *ht, int page)
Definition: file_hash.c:576
#define NPRIMES
Definition: file_hash.c:66
FH_PAGE_HDR * pg_hdr_alloc
Definition: file_hash.h:95
FH_FILE_POS overflow
Definition: file_hash.h:102
#define CEIL_PTVDIV(dividend, divisor)
Definition: memory_alloc.h:50
int bitmap_size
Definition: file_hash.h:109
struct fh_entry * fh_entries
Definition: file_hash.h:73
int entry_size
Definition: file_hash.h:99
static int fh_bittest(FH_TABLE *ht, int page)
Definition: file_hash.c:804
void fh_destroy(FH_TABLE *ht)
Definition: file_hash.c:310
int size
Definition: file_hash.h:96
HASH_FUNC hfun
Definition: file_hash.h:89
static int null_int
Definition: file_hash.c:51
void * FH_KEY
Definition: file_hash.h:112
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define fh_intk_data
Definition: file_hash.h:54
unsigned int(* HASH_FUNC)(const void *info, unsigned int htsize)
Definition: file_hash.h:77
int64_t est_size
Definition: unloaddb.c:54
int cached_pages
Definition: unloaddb.c:53
const char * name
Definition: file_hash.h:91
static void fh_bitset(FH_TABLE *ht, int page)
Definition: file_hash.c:786
#define fh_oidk_data
Definition: file_hash.h:52
int i
Definition: dynamic_load.c:954
char * msgcat_message(int cat_id, int set_id, int msg_id)
int fh_put(FH_TABLE *ht, FH_KEY key, FH_DATA data)
Definition: file_hash.c:449
int ncollisions
Definition: file_hash.h:104
int page_size
Definition: file_hash.h:97
char * strdup(const char *str)
Definition: porting.c:901
int(* CMP_FUNC)(const void *key1, const void *key2)
Definition: file_hash.h:78
FH_PAGE_HDR * pg_hdr_last
Definition: file_hash.h:93
FH_FILE_POS page
Definition: file_hash.h:74
char * hash_filename
Definition: file_hash.h:105
Definition: file_hash.h:60
void * FH_DATA
Definition: file_hash.h:113
struct fh_page_hdr * prev
Definition: file_hash.h:72
#define INVALID_FILE_POS
Definition: file_hash.h:57
char * bitmap
Definition: file_hash.h:108
std::pair< std::string, int > open_temp_filedes(const char *prefix, int flags=0)
FH_PAGE_HDR * pg_hdr_free
Definition: file_hash.h:94
#define MSGCAT_CATALOG_UTILS