/** * Given a player dbref (For use with viewing permissions for attrs, etc), * list of keys, list of strings it maps to (sortkey()-style), * # of keys+strings and a list type info, build an array of * s_rec structures representing each item. * \param player the player executing the sort. * \param keys the array of items to sort. * \param strs If non-NULL, these are what to sort <keys> using. * \param n Number of items in <keys> and <strs> * \param lti List Type Info describing how it's sorted and built. * \retval A pointer to the first s_rec of an <n> s_rec array. */ s_rec * slist_build(dbref player, char *keys[], char *strs[], int n, ListTypeInfo * lti) { int i; s_rec *sp; sort_order = lti->sort_order; sp = mush_calloc(n, sizeof(s_rec), "do_gensort"); for (i = 0; i < n; i++) { /* Elements are 0 by default thanks to calloc. Only need to touch those that need other values. */ sp[i].val = keys[i]; if (strs) sp[i].ptr = strs[i]; if (lti->flags & IS_DB) { sp[i].db = parse_objid(keys[i]); if (!RealGoodObject(sp[i].db)) sp[i].db = NOTHING; } genrecord(&sp[i], player, lti); } return sp; }
/** Return a list of all available locks * \param buff the buffer * \param bp a pointer to the current position in the buffer. * \param name if not NULL, only show locks with this prefix */ void list_locks(char *buff, char **bp, const char *name) { lock_list **locks, *lk; bool first = 1; int nlocks = 0, n; locks = mush_calloc(htab_locks.entries, sizeof(lock_list), "lock.list"); for (lk = hash_firstentry(&htab_locks); lk; lk = hash_nextentry(&htab_locks)) { /* Skip those that don't match */ if (name && !string_prefix(lk->type, name)) continue; locks[nlocks++] = lk; } qsort(locks, nlocks, sizeof lk, lock_compare); for (n = 0; n < nlocks; n += 1) { if (first) { first = 0; } else { safe_chr(' ', buff, bp); } safe_str(strupper(locks[n]->type), buff, bp); } mush_free(locks, "lock.list"); }
/** Initialize a hashtable. * \param htab pointer to hash table to initialize. * \param size size of hashtable. */ void hash_init(HASHTAB *htab, int size, void (*free_data) (void *)) { size = next_prime_after(size); htab->last_index = -1; htab->free_data = free_data; htab->hashsize = size; htab->hashfunc_offset = 0; htab->entries = 0; htab->buckets = mush_calloc(size, sizeof(struct hash_bucket), "hash.buckets"); }
/** Resize a hash table. * \param htab pointer to hashtable. * \param primesize new size. * \param hashindex Index of first hash function to use */ static bool real_hash_resize(HASHTAB *htab, int newsize, int hashfunc_offset) { HASHENT *oldarr; int oldsize, oldoffset, i; /* Massive overkill here */ if (resize_calls > 150) { fputs("Ooops. Too many attempts to resize a hash table.\n", stderr); return false; } /* If all possible hash function combos have been exhausted, grow the array */ if (hashfunc_offset == first_offset) { int newersize = next_prime_after(floor(newsize * 1.15)); first_offset = -1; return real_hash_resize(htab, newersize, hashfunc_offset); } resize_calls += 1; /* Save the old data we need */ oldsize = htab->hashsize; oldoffset = htab->hashfunc_offset; oldarr = htab->buckets; htab->buckets = mush_calloc(newsize, sizeof(struct hash_bucket), "hash.buckets"); htab->hashsize = newsize; htab->hashfunc_offset = hashfunc_offset; for (i = 0; i < oldsize; i++) { if (oldarr[i].key) { if (!hash_insert(htab, oldarr[i].key, oldarr[i].keylen, oldarr[i].data)) { /* Couldn't fit an element in. Try with different hash functions. */ mush_free(htab->buckets, "hash.buckets"); htab->buckets = oldarr; htab->hashsize = oldsize; htab->hashfunc_offset = oldoffset; if (first_offset == -1) first_offset = hashfunc_offset; return real_hash_resize(htab, newsize, (hashfunc_offset + 1) % NHASH_MOD); } } } mush_free(oldarr, "hash.buckets"); return true; }
/** * Given a string description of a sort type, generate and return a * ListTypeInfo that can be passed to slist_* functions. * \param sort_type A string describing a sort type. * \retval ListTypeInfo containing all generating and comparison information * needed. */ ListTypeInfo * get_list_type_info(SortType sort_type) { int i, len; char *ptr = NULL; ListTypeInfo *lti; /* i is either the right one or the default, so we return it anyway. */ lti = mush_calloc(1, sizeof(ListTypeInfo), "list_type_info"); lti->sort_order = ASCENDING; if (*sort_type == '-') { lti->sort_order = DESCENDING; sort_type++; } if (!sort_type) { /* Advance i to the default */ for (i = 0; ltypelist[i].name; i++) ; } else if ((ptr = strchr(sort_type, ':'))) { len = ptr - sort_type; ptr += 1; if (!*ptr) ptr = NULL; for (i = 0; ltypelist[i].name && strncasecmp(ltypelist[i].name, sort_type, len); i++) ; } else { for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, sort_type); i++) ; } lti->name = ltypelist[i].name; if (ptr) { lti->attrname = mush_strdup(ptr, "list_type_info_attrname"); } else { lti->attrname = NULL; } lti->make_record = ltypelist[i].make_record; lti->sorter = ltypelist[i].sorter; lti->flags = ltypelist[i].flags; return lti; }
/** Migrate some number of chunks. * The requested amount is only a guideline; the actual amount * migrated will be more or less due to always migrating all the * attributes, locks, and mail on any given object together. * \param amount the suggested number of attributes to migrate. */ static void migrate_stuff(int amount) { static int start_obj = 0; static chunk_reference_t **refs = NULL; static int refs_size = 0; int end_obj; int actual; ATTR *aptr; lock_list *lptr; MAIL *mp; if (db_top == 0) return; end_obj = start_obj; actual = 0; do { for (aptr = List(end_obj); aptr; aptr = AL_NEXT(aptr)) if (aptr->data != NULL_CHUNK_REFERENCE) actual++; for (lptr = Locks(end_obj); lptr; lptr = L_NEXT(lptr)) if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) actual++; if (IsPlayer(end_obj)) { for (mp = find_exact_starting_point(end_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) actual++; } end_obj = (end_obj + 1) % db_top; } while (actual < amount && end_obj != start_obj); if (actual == 0) return; if (!refs || actual > refs_size) { if (refs) mush_free(refs, "migration reference array"); refs = mush_calloc(actual, sizeof(chunk_reference_t *), "migration reference array"); refs_size = actual; if (!refs) mush_panic("Could not allocate migration reference array"); } #ifdef DEBUG_MIGRATE do_rawlog(LT_TRACE, "Migrate asked %d, actual objects #%d to #%d for %d", amount, start_obj, (end_obj + db_top - 1) % db_top, actual); #endif actual = 0; do { for (aptr = List(start_obj); aptr; aptr = AL_NEXT(aptr)) if (aptr->data != NULL_CHUNK_REFERENCE) { refs[actual] = &(aptr->data); actual++; } for (lptr = Locks(start_obj); lptr; lptr = L_NEXT(lptr)) if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) { refs[actual] = &(lptr->key); actual++; } if (IsPlayer(start_obj)) { for (mp = find_exact_starting_point(start_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) { refs[actual] = &(mp->msgid); actual++; } } start_obj = (start_obj + 1) % db_top; } while (start_obj != end_obj); chunk_migration(actual, refs); }