1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-03 04:22:09 +03:00

r11266: Speed up loading smb.conf for large numbers of share definitions. The problem

was a O(n^2) loop: Whenever a service definition was found, we linearly
searched the already loaded share definitions, the patch adds an internal tdb
for this. For a smb.conf with 2000 shares this speeds up loading by about a
factor of 50.

Might be a fix for bug #1117.

Thanks to Michael Adam <ma@sernet.de>,

Volker
(This used to be commit d07343e0c4)
This commit is contained in:
Volker Lendecke
2005-10-23 16:29:02 +00:00
committed by Gerald (Jerry) Carter
parent cef9443a87
commit 4e9bc2ec5c

View File

@ -73,7 +73,7 @@ extern enum protocol_types Protocol;
#endif
/* some helpful bits */
#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && ServicePtrs[(i)]->valid)
#define LP_SNUM_OK(i) (((i) >= 0) && ((i) < iNumServices) && (ServicePtrs != NULL) && ServicePtrs[(i)]->valid)
#define VALID(i) (ServicePtrs != NULL && ServicePtrs[i]->valid)
int keepalive = DEFAULT_KEEPALIVE;
@ -587,6 +587,9 @@ static service sDefault = {
static service **ServicePtrs = NULL;
static int iNumServices = 0;
static int iServiceIndex = 0;
static TDB_CONTEXT *ServiceHash;
static int *invalid_services = NULL;
static int num_invalid_services = 0;
static BOOL bInGlobalSection = True;
static BOOL bGlobalOnly = False;
static int server_role;
@ -2037,6 +2040,9 @@ static BOOL service_ok(int iService);
static BOOL do_parameter(const char *pszParmName, const char *pszParmValue);
static BOOL do_section(const char *pszSectionName);
static void init_copymap(service * pservice);
static BOOL hash_a_service(const char *name, int number);
static void free_service_byindex(int iService);
static char * canonicalize_servicename(const char *name);
/* This is a helper function for parametrical options support. */
/* It returns a pointer to parametrical option value if it exists or NULL otherwise */
@ -2329,6 +2335,26 @@ static void free_service(service *pservice)
ZERO_STRUCTP(pservice);
}
/***************************************************************************
remove a service indexed in the ServicePtrs array from the ServiceHash
and free the dynamically allocated parts
***************************************************************************/
static void free_service_byindex(int idx)
{
if (!LP_SNUM_OK(idx)) {
return;
}
ServicePtrs[idx]->valid = False;
invalid_services[num_invalid_services++] = idx;
if (ServicePtrs[idx]->szService) {
tdb_delete_bystring(ServiceHash, ServicePtrs[idx]->szService);
}
free_service(ServicePtrs[idx]);
}
/***************************************************************************
Add a new service to the services array initialising it with the given
service.
@ -2364,32 +2390,41 @@ static int add_a_service(const service *pservice, const char *name)
}
/* find an invalid one */
for (i = 0; i < iNumServices; i++)
if (!ServicePtrs[i]->valid)
break;
i = iNumServices;
if (num_invalid_services > 0) {
i = invalid_services[--num_invalid_services];
}
/* if not, then create one */
if (i == iNumServices) {
service **tsp;
int *tinvalid;
tsp = SMB_REALLOC_ARRAY(ServicePtrs, service *, num_to_alloc);
if (!tsp) {
if (tsp == NULL) {
DEBUG(0,("add_a_service: failed to enlarge ServicePtrs!\n"));
return (-1);
}
else {
ServicePtrs = tsp;
ServicePtrs[iNumServices] = SMB_MALLOC_P(service);
}
ServicePtrs = tsp;
ServicePtrs[iNumServices] = SMB_MALLOC_P(service);
if (!ServicePtrs[iNumServices]) {
DEBUG(0,("add_a_service: out of memory!\n"));
return (-1);
}
iNumServices++;
} else
free_service(ServicePtrs[i]);
/* enlarge invalid_services here for now... */
tinvalid = SMB_REALLOC_ARRAY(invalid_services, int,
num_to_alloc);
if (tinvalid == NULL) {
DEBUG(0,("add_a_service: failed to enlarge "
"invalid_services!\n"));
return (-1);
}
invalid_services = tinvalid;
} else {
free_service_byindex(i);
}
ServicePtrs[i]->valid = True;
@ -2400,10 +2435,57 @@ static int add_a_service(const service *pservice, const char *name)
DEBUG(8,("add_a_service: Creating snum = %d for %s\n",
i, ServicePtrs[i]->szService));
if (!hash_a_service(ServicePtrs[i]->szService, i)) {
return (-1);
}
return (i);
}
/***************************************************************************
Convert a string to uppercase and remove whitespaces.
***************************************************************************/
static char *canonicalize_servicename(const char *src)
{
static fstring canon; /* is fstring large enough? */
int dst_idx = 0;
for (; *src != '\0'; src++) {
if (isspace(*src)) {
continue;
}
if (dst_idx == sizeof(canon) - 1) {
return NULL;
}
canon[dst_idx++] = toupper(*src);
}
canon[dst_idx] = '\0';
return canon;
}
/***************************************************************************
Add a name/index pair for the services array to the hash table.
***************************************************************************/
static BOOL hash_a_service(const char *name, int idx)
{
if (ServiceHash == NULL) {
DEBUG(10,("hash_a_service: creating tdb servicehash\n"));
ServiceHash = tdb_open("servicehash", 1031, TDB_INTERNAL,
(O_RDWR|O_CREAT), 0644);
if (ServiceHash == NULL) {
DEBUG(0,("hash_a_service: open tdb servicehash failed!\n"));
return False;
}
}
DEBUG(10,("hash_a_service: hashing index %d for service name %s\n",
idx, name));
tdb_store_int32(ServiceHash, canonicalize_servicename(name), idx);
return True;
}
/***************************************************************************
Add a new home service, with the specified home directory, defaults coming
from service ifrom.
@ -2636,16 +2718,20 @@ Find a service by name. Otherwise works like get_service.
static int getservicebyname(const char *pszServiceName, service * pserviceDest)
{
int iService;
int iService = -1;
for (iService = iNumServices - 1; iService >= 0; iService--)
if (VALID(iService) &&
strwicmp(ServicePtrs[iService]->szService, pszServiceName) == 0) {
if (pserviceDest != NULL)
copy_service(pserviceDest, ServicePtrs[iService], NULL);
break;
if (ServiceHash != NULL) {
iService = tdb_fetch_int32(ServiceHash,
canonicalize_servicename(pszServiceName));
if (LP_SNUM_OK(iService)) {
if (pserviceDest != NULL) {
copy_service(pserviceDest,
ServicePtrs[iService], NULL);
}
} else {
iService = -1;
}
}
return (iService);
}
@ -3916,8 +4002,7 @@ void lp_killunused(BOOL (*snumused) (int))
continue;
if (!snumused || !snumused(i)) {
ServicePtrs[i]->valid = False;
free_service(ServicePtrs[i]);
free_service_byindex(i);
}
}
}
@ -3929,8 +4014,7 @@ void lp_killunused(BOOL (*snumused) (int))
void lp_killservice(int iServiceIn)
{
if (VALID(iServiceIn)) {
ServicePtrs[iServiceIn]->valid = False;
free_service(ServicePtrs[iServiceIn]);
free_service_byindex(iServiceIn);
}
}
@ -4346,6 +4430,7 @@ BOOL lp_preferred_master(void)
void lp_remove_service(int snum)
{
ServicePtrs[snum]->valid = False;
invalid_services[num_invalid_services++] = snum;
}
/*******************************************************************