zap_leaf.c revision c5608ce59546d1bc2e7c57e495af756f09c68d27
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* The 512-byte leaf is broken into 32 16-byte chunks.
* chunk number n means l_chunk[n], even though the header precedes it.
* the names are stored null-terminated.
*/
#include <sys/zfs_context.h>
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
/* half the (current) minimum block size */
#define LEAF_HASH(l, h) \
((ZAP_LEAF_HASH_NUMENTRIES(l)-1) & \
static void
zap_memset(void *a, int c, size_t n)
{
char *cp = a;
*cp++ = c;
}
static void
{
switch (len) {
case 1:
return;
case 2:
return;
case 4:
return;
case 8:
return;
}
ASSERT(!"bad int len");
}
static uint64_t
{
switch (len) {
case 1:
case 2:
case 4:
case 8:
}
ASSERT(!"bad int len");
return (0xFEEDFACEDEADBEEFULL);
}
void
{
int i;
zap_leaf_t l;
for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(&l); i++)
for (i = 0; i < ZAP_LEAF_NUMCHUNKS(&l); i++) {
struct zap_leaf_entry *le;
case ZAP_CHUNK_ENTRY:
break;
case ZAP_CHUNK_FREE:
break;
case ZAP_CHUNK_ARRAY:
/* la_array doesn't need swapping */
break;
default:
ASSERT(!"bad leaf type");
}
}
}
void
{
int i;
for (i = 0; i < ZAP_LEAF_NUMCHUNKS(l); i++) {
}
}
/*
* Routines which manipulate leaf chunks (l_chunk[]).
*/
static uint16_t
{
int chunk;
return (chunk);
}
static void
{
}
/*
* Routines which manipulate leaf arrays (zap_leaf_array type chunks).
*/
static uint16_t
int integer_size, int num_integers)
{
int byten = 0;
int len = num_integers;
while (len > 0) {
int i;
for (i = 0; i < ZAP_LEAF_ARRAY_BYTES; i++) {
if (byten == 0)
value <<= 8;
if (++byten == integer_size) {
byten = 0;
buf += integer_size;
if (--len == 0)
break;
}
}
}
return (chunk_head);
}
static void
{
zap_leaf_chunk_free(l, chunk);
}
}
/* array_len and buf_len are in integers, not bytes */
static void
char *buf)
{
int byten = 0;
/* Fast path for one 8-byte integer */
return;
}
/* Fast path for an array of 1-byte integers (eg. the entry name) */
struct zap_leaf_array *la =
}
return;
}
while (len > 0) {
int i;
for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) {
byten++;
if (byten == array_int_len) {
byten = 0;
len--;
if (len == 0)
return;
buf += buf_int_len;
}
}
}
}
/*
* Only to be used on 8-bit arrays.
* array_len is actual len in bytes (not encoded le_value_length).
* buf is null-terminated.
*/
static int
{
int bseen = 0;
break;
}
}
/*
* Routines which manipulate leaf entries.
*/
int
{
struct zap_leaf_entry *le;
for (chunkp = LEAF_HASH_ENTPTR(l, h);
continue;
return (0);
}
}
return (ENOENT);
}
/* Return (h1,cd1 >= h2,cd2) */
int
{
struct zap_leaf_entry *le;
}
}
}
}
int
{
struct zap_leaf_entry *le =
return (EINVAL);
return (EOVERFLOW);
return (0);
}
int
{
struct zap_leaf_entry *le =
return (EOVERFLOW);
return (0);
}
int
{
int delta_chunks;
return (EAGAIN);
/*
* We should search other chained leaves (via
* zap_entry_remove,create?) otherwise returning EAGAIN will
* just send us into an infinite loop if we have to chain
* another leaf block, rather than being able to split this
* block.
*/
le->le_value_chunk =
return (0);
}
void
{
struct zap_leaf_entry *le;
}
int
{
struct zap_leaf_entry *le;
int numchunks;
if (numchunks > ZAP_LEAF_NUMCHUNKS(l))
return (E2BIG);
for (chunk = *LEAF_HASH_ENTPTR(l, h);
break;
}
}
/* If this cd is not in use, we are good. */
break;
}
/* If we tried all the cd's, we lose. */
return (ENOSPC);
}
return (EAGAIN);
/* make the entry */
chunk = zap_leaf_chunk_alloc(l);
le->le_value_chunk =
/* link it into the hash chain */
chunkp = LEAF_HASH_ENTPTR(l, h);
return (0);
}
/*
* Routines for transferring entries between leafs.
*/
static void
{
}
static uint16_t
{
struct zap_leaf_array *nla =
struct zap_leaf_array *la =
zap_leaf_chunk_free(l, chunk);
}
return (new_chunk);
}
static void
{
zap_leaf_chunk_free(l, entry);
}
/*
* Transfer the entries whose hash prefix ends in 1 to the new leaf.
*/
void
{
int i;
/* set new prefix and prefix_len */
/* break existing hash chains */
/*
* Transfer entries whose hash bit 'bit' is set to nl; rehash
* the remaining entries
*
* NB: We could find entries via the hashtable instead. That
* would be O(hashents+numents) rather than O(numblks+numents),
* but this accesses memory more sequentially, and when we're
* called, the block is usually pretty full.
*/
for (i = 0; i < ZAP_LEAF_NUMCHUNKS(l); i++) {
continue;
zap_leaf_transfer_entry(l, i, nl);
else
zap_leaf_rehash_entry(l, i);
}
}
void
{
int i, n;
zs->zs_leafs_with_2n_pointers[n]++;
zs->zs_blocks_with_n5_entries[n]++;
zs->zs_blocks_n_tenths_full[n]++;
for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(l); i++) {
int nentries = 0;
struct zap_leaf_entry *le =
ZAP_LEAF_ENTRY(l, chunk);
le->le_int_size);
zs->zs_entries_using_n_chunks[n]++;
nentries++;
}
n = nentries;
zs->zs_buckets_with_n_entries[n]++;
}
}