void * node_map( nh_t nh ) { nix_t nix; u_char_t *p; #ifdef NODECHK register u_char_t hkp; register u_char_t hdlgen; register u_char_t nodegen; register u_char_t nodeunq; #endif /* NODECHK */ ASSERT( nh != NH_NULL ); /* convert the handle into an index */ #ifdef NODECHK hdlgen = HDLGETGEN( nh ); nix = HDLGETNIX( nh ); #else /* NODECHK */ nix = ( nix_t )nh; #endif /* NODECHK */ ASSERT( nix <= NIX_MAX ); /* map in */ p = 0; /* keep lint happy */ win_map( NIX2OFF( nix ), ( void ** )&p ); if (p == NULL) return NULL; #ifdef NODECHK hkp = *( p + node_hdrp->nh_nodehkix ); nodegen = HKPGETGEN( hkp ); nodeunq = HKPGETUNQ( hkp ); ASSERT( nodegen == hdlgen ); ASSERT( nodeunq != NODEUNQFREE ); ASSERT( nodeunq == NODEUNQALCD ); #endif /* NODECHK */ return ( void * )p; }
void win_map( segix_t segix, void **pp ) { off64_t segoff; win_t *winp; CRITICAL_BEGIN(); #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK, "win_map(segix=%u,addr=%p)\n", segix, pp); #endif /* resize the array if necessary */ if ( segix >= tranp->t_segmaplen ) win_segmap_resize( segix ); /* see if segment already mapped. if ref cnt zero, * remove from LRU list. */ winp = tranp->t_segmap[segix]; if ( winp ) { #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK, "win_map(): requested segment already mapped\n"); #endif if ( winp->w_refcnt == 0 ) { ASSERT( tranp->t_lruheadp ); ASSERT( tranp->t_lrutailp ); if ( tranp->t_lruheadp == winp ) { if ( tranp->t_lrutailp == winp ) { tranp->t_lruheadp = 0; tranp->t_lrutailp = 0; } else { tranp->t_lruheadp = winp->w_nextp; tranp->t_lruheadp->w_prevp = 0; } } else { if ( tranp->t_lrutailp == winp ) { tranp->t_lrutailp = winp->w_prevp; tranp->t_lrutailp->w_nextp = 0; } else { winp->w_prevp->w_nextp = winp->w_nextp; winp->w_nextp->w_prevp = winp->w_prevp; } } winp->w_prevp = 0; winp->w_nextp = 0; } else { ASSERT( ! winp->w_prevp ); ASSERT( ! winp->w_nextp ); } winp->w_refcnt++; *pp = winp->w_p; CRITICAL_END(); return; } /* Allocate a new descriptor if we haven't yet hit the maximum, * otherwise reuse any descriptor on the LRU list. */ if ( tranp->t_wincnt < tranp->t_winmax ) { #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK, "win_map(): create a new window\n"); #endif winp = ( win_t * )calloc( 1, sizeof( win_t )); ASSERT( winp ); tranp->t_wincnt++; } else if ( tranp->t_lruheadp ) { /* REFERENCED */ intgen_t rval; #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK, "win_map(): get head from lru freelist & unmap\n"); #endif ASSERT( tranp->t_lrutailp ); winp = tranp->t_lruheadp; tranp->t_lruheadp = winp->w_nextp; if ( tranp->t_lruheadp ) { tranp->t_lruheadp->w_prevp = 0; } else { tranp->t_lrutailp = 0; } tranp->t_segmap[winp->w_segix] = NULL; rval = munmap( winp->w_p, tranp->t_segsz ); ASSERT( ! rval ); memset( ( void * )winp, 0, sizeof( win_t )); } else { ASSERT( tranp->t_wincnt == tranp->t_winmax ); *pp = NULL; CRITICAL_END(); mlog( MLOG_NORMAL | MLOG_WARNING, _( "all map windows in use. Check virtual memory limits\n")); return; } /* calculate offset of segment */ segoff = segix * ( off64_t )tranp->t_segsz; /* map the window */ ASSERT( tranp->t_segsz >= 1 ); ASSERT( tranp->t_firstoff <= OFF64MAX - segoff - ( off64_t )tranp->t_segsz + 1ll ); ASSERT( ! ( tranp->t_segsz % pgsz )); ASSERT( ! ( ( tranp->t_firstoff + segoff ) % ( off64_t )pgsz )); #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE | MLOG_NOLOCK, "win_map(): mmap segment at %lld, size = %llu\n", ( off64_t )( tranp->t_firstoff + segoff ), tranp->t_segsz); #endif tranp->t_winmmaps++; winp->w_p = mmap_autogrow( tranp->t_segsz, tranp->t_fd, ( off64_t )( tranp->t_firstoff + segoff )); if ( winp->w_p == (void *)-1 ) { int error = errno; mlog( MLOG_NORMAL | MLOG_ERROR, _( "win_map(): unable to map a node segment of size %d at %d: %s\n"), tranp->t_segsz, tranp->t_firstoff + segoff, strerror( error )); tranp->t_wincnt--; tranp->t_winmax--; CRITICAL_END(); free(winp); if (error == ENOMEM && tranp->t_lruheadp) { mlog( MLOG_NORMAL | MLOG_ERROR, _("win_map(): try to select a different win_t\n")); win_map(segix, pp); return; } *pp = NULL; return; } winp->w_segix = segix; ASSERT( winp->w_refcnt == 0 ); winp->w_refcnt++; tranp->t_segmap[winp->w_segix] = winp; *pp = winp->w_p; CRITICAL_END(); }
nh_t node_alloc( void ) { nix_t nix; u_char_t *p; nh_t nh; register nix_t *linkagep; #ifdef NODECHK register u_char_t *hkpp; register u_char_t gen; register u_char_t unq; #endif /* NODECHK */ /* if free list is depleted, map in a new window at the * end of backing store. put all nodes on free list. * initialize the gen count to the node index, and the unique * pattern to the free pattern. */ if ( node_hdrp->nh_freenix == NIX_NULL ) { nix_t virgbegnix; /* abs. nix of first node in virg seg */ nix_t virgendnix; /* abs. nix of next node after last */ nix_t sacrcnt; /* how many virgins to put on free list */ nix_t sacrnix; ASSERT( node_hdrp->nh_virgrelnix < ( nix_t )node_hdrp->nh_nodesperseg ); virgbegnix = OFF2NIX( node_hdrp->nh_virgsegreloff ) + node_hdrp->nh_virgrelnix; virgendnix = OFF2NIX( ( node_hdrp->nh_virgsegreloff + ( off64_t )node_hdrp->nh_segsz ) ); #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE, "node_alloc(): create freelist - " "virg_begin=%lld virg_end=%lld\n", virgbegnix, virgendnix); #endif ASSERT( virgendnix > virgbegnix ); sacrcnt = min( VIRGSACRMAX, virgendnix - virgbegnix ); ASSERT( sacrcnt >= 1 ); p = 0; /* keep lint happy */ win_map( NIX2OFF( virgbegnix ), ( void ** )&p ); if (p == NULL) return NH_NULL; node_hdrp->nh_freenix = virgbegnix; for ( sacrnix = virgbegnix ; sacrnix < virgbegnix + sacrcnt - 1 ; p += node_hdrp->nh_nodesz, sacrnix++ ) { linkagep = ( nix_t * )p; *linkagep = sacrnix + 1; #ifdef NODECHK hkpp = p + node_hdrp->nh_nodehkix; gen = ( u_char_t )sacrnix; *hkpp = ( u_char_t )HKPMKHKP( ( size_t )gen, NODEUNQFREE ); #endif /* NODECHK */ } linkagep = ( nix_t * )p; *linkagep = NIX_NULL; #ifdef NODECHK hkpp = p + node_hdrp->nh_nodehkix; gen = ( u_char_t )sacrnix; *hkpp = HKPMKHKP( gen, NODEUNQFREE ); #endif /* NODECHK */ node_hdrp->nh_virgrelnix += sacrcnt; win_unmap( node_hdrp->nh_virgsegreloff, ( void ** )&p ); if ( node_hdrp->nh_virgrelnix >= ( nix_t )node_hdrp->nh_nodesperseg ) { intgen_t rval; ASSERT( node_hdrp->nh_virgrelnix == ( nix_t )node_hdrp->nh_nodesperseg ); ASSERT( node_hdrp->nh_virgsegreloff <= OFF64MAX - ( off64_t )node_hdrp->nh_segsz ); #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE, "node_alloc(): runout of nodes for freelist in " "this segment - nodes used = %lld\n", node_hdrp->nh_virgrelnix); #endif node_hdrp->nh_virgsegreloff += ( off64_t )node_hdrp->nh_segsz; node_hdrp->nh_virgrelnix = 0; mlog( MLOG_DEBUG, "pre-growing new node array segment at %lld " "size %lld\n", node_hdrp->nh_firstsegoff + node_hdrp->nh_virgsegreloff + ( off64_t )node_hdrp->nh_segsz, ( off64_t )node_hdrp->nh_segsz ); rval = ftruncate64( node_fd, node_hdrp->nh_firstsegoff + node_hdrp->nh_virgsegreloff + ( off64_t )node_hdrp->nh_segsz ); if ( rval ) { mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, _( "unable to autogrow node segment %llu: " "%s (%d)\n"), node_hdrp->nh_virgsegreloff / ( off64_t )node_hdrp->nh_segsz, strerror( errno ), errno ); } } } /* map in window containing node at top of free list, * and adjust free list. */ nix = node_hdrp->nh_freenix; #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE, "node_alloc(): win_map(%llu) and get head from node freelist\n", NIX2OFF(nix)); #endif win_map( NIX2OFF( nix ), ( void ** )&p ); if (p == NULL) return NH_NULL; #ifdef NODECHK hkpp = p + node_hdrp->nh_nodehkix; unq = HKPGETUNQ( *hkpp ); ASSERT( unq != NODEUNQALCD ); ASSERT( unq == NODEUNQFREE ); #endif /* NODECHK */ linkagep = ( nix_t * )p; node_hdrp->nh_freenix = *linkagep; /* clean the node */ memset( ( void * )p, 0, node_hdrp->nh_nodesz ); /* build a handle for node */ ASSERT( nix <= NIX_MAX ); #ifdef NODECHK hkpp = p + ( int )node_hdrp->nh_nodehkix; gen = ( u_char_t )( HKPGETGEN( *p ) + ( u_char_t )1 ); nh = HDLMKHDL( gen, nix ); *hkpp = HKPMKHKP( gen, NODEUNQALCD ); #else /* NODECHK */ nh = ( nh_t )nix; #endif /* NODECHK */ /* unmap window */ #ifdef TREE_DEBUG mlog(MLOG_DEBUG | MLOG_TREE, "node_alloc(): win_unmap(%llu)\n", NIX2OFF(nix)); #endif win_unmap( NIX2OFF( nix ), ( void ** )&p ); return nh; }