pc_hash_t *pc_hash_create_min(pc_pool_t *pool, int min_items) { pc_hash_t *result = pc_alloc(pool, sizeof(*result)); result->count = 0; result->pool = pool; if (min_items > 1000000000) result->twins_index = TWINS_COUNT - 1; else { /* Scale up MIN_ITEMS based on our desired initial load factor */ if (min_items > 10000000) { min_items = (min_items / INITIAL_LOAD) * 100; result->twins_index = TWIN_MIN_10MIL; } else { min_items = (min_items * 100) / INITIAL_LOAD; result->twins_index = 0; } while (twins[result->twins_index] < min_items && result->twins_index < TWINS_COUNT - 1) ++result->twins_index; } result->alloc = twins[result->twins_index] + 2; /* higher of the pair! */ result->slots = pc_alloc(pool, result->alloc * sizeof(*result->slots)); pc_hash_clear(result); return result; }
static void maybe_grow(pc_hash_t *hash) { int threshold; int alloc; struct pc_hslot_s *slots; if (hash->twins_index == TWINS_COUNT - 1) return; if (hash->alloc < 10000000) threshold = (hash->alloc * MAX_LOAD_PERCENT) / 100; else threshold = (hash->alloc / 100) * MAX_LOAD_PERCENT; if (hash->count + 1 < threshold) return; alloc = twins[++hash->twins_index] + 2; /* the higher of the pair! */ slots = pc_alloc(hash->pool, alloc * sizeof(*slots)); memset(slots, 0, alloc * sizeof(*slots)); copy_items(hash, slots, alloc); /* ### free old hash->slots */ hash->alloc = alloc; hash->slots = slots; }
pc_hiter_t *pc_hiter_begin(const pc_hash_t *hash, pc_pool_t *pool) { pc_hiter_t *result = pc_alloc(pool, sizeof(*result)); result->current = hash->slots; result->last = &hash->slots[hash->alloc]; if (result->current->key == NULL || result->current->key == SLOT_DELETED) return pc_hiter_next(result); return result; }
pc_error_t *pc_address_lookup(pc_hash_t **addresses, const char *name, int port, int flags, pc_pool_t *pool) { char portbuf[6]; struct addrinfo hints = { 0 }; struct addrinfo *results; struct addrinfo *scan; int rv; if (port <= 0 || port > 65535) return pc_error_create_pm(pool, PC_ERR_BAD_PARAM, "port number out of range"); snprintf(portbuf, sizeof(portbuf), "%d", port); /* ### these are the wrong hints for now, but let's just get started */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; rv = getaddrinfo(name, portbuf, &hints, &results); if (rv != 0) { const char *msg = gai_strerror(rv); return pc_error_create_pm(pool, PC_ERR_ADDRESS_LOOKUP, msg); } *addresses = pc_hash_create(pool); for (scan = results; scan != NULL; scan = scan->ai_next) { /* Can the returned address fit into our structure? ### this is probably bogus and needs some research. */ if (scan->ai_addrlen <= sizeof(((pc_address_t *)0)->a.inet)) { pc_address_t *addr = pc_alloc(pool, sizeof(*addr)); const char *readable; memcpy(&addr->a.inet, scan->ai_addr, scan->ai_addrlen); readable = pc_address_readable(addr, pool); pc_hash_sets(*addresses, readable, addr); } } freeaddrinfo(results); return PC_NO_ERROR; }
static read_buffer_t * get_read_buffer(struct pc__channel_ctx_s *cctx) { read_buffer_t *rb = cctx->avail; if (rb == NULL) { rb = pc_alloc(cctx->pool, sizeof(*rb) + READ_BUFFER_SIZE); rb->buf = (char *)rb + sizeof(*rb); rb->len = READ_BUFFER_SIZE; return rb; } cctx->avail = rb->next; return rb; }
static void get_iovec(struct iovec **result_iov, int *result_iovcnt, pc_channel_t *channel) { int iovcnt = channel->pending_iovcnt; char *buf = channel->pending_buf; assert(channel->pending_iov != NULL && iovcnt > 0); /* The simplest case: we can directly use PENDING_IOV because we don't need to adjust the first iovec for PENDING_BUF. */ if (buf == NULL || buf == channel->pending_iov[0].iov_base) { *result_iov = channel->pending_iov; *result_iovcnt = iovcnt; return; } /* The first iovec must be adjusted, so we need to copy it into our pre-allocated scratch area, or onto the heap. */ if (iovcnt <= INTERNAL_IOVEC_COUNT) { *result_iov = &channel->ctx->cctx->scratch_iov[0]; *result_iovcnt = iovcnt; } else { *result_iov = pc_alloc(channel->ctx->cctx->callback_scratch, iovcnt * sizeof(**result_iov)); *result_iovcnt = iovcnt; } memcpy(*result_iov, channel->pending_iov, iovcnt * sizeof(**result_iov)); (*result_iov)[0].iov_base = buf; (*result_iov)[0].iov_len = (channel->pending_iov[0].iov_len - (buf - (char *)channel->pending_iov[0].iov_base)); }