/*
* Copyright (c) 2003-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: resource.c,v 1.26 2006/03/29 18:37:18 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "qmgr.h"
#include "log.h"
/*
** QM_COMP_RESOURCE -- compute total resource usage
** result stored in qmgr_ctx->qmgr_total_usage
**
** Parameters:
** qmgr_ctx -- QMGR context
** locktype -- kind of locking
**
** Returns:
** usual sm_error code
**
** Called by:
** qss_control()
** qss_unthrottle()
**
** Locking:
** qmgr_ctx is locked/unlocked as requested by locktype
** check unlocking! XXX
**
** Last code review: 2005-04-21 23:54:01
** Last code change:
*/
sm_ret_T
qm_comp_resource(qmgr_ctx_P qmgr_ctx, thr_lock_T locktype)
{
sm_ret_T ret;
int r;
uint u;
uint total, sum;
SM_IS_QMGR_CTX(qmgr_ctx);
ret = SM_SUCCESS;
if (thr_lock_it(locktype))
{
r = pthread_mutex_lock(&qmgr_ctx->qmgr_mutex);
SM_LOCK_OK(r);
if (r != 0)
{
QM_LEV_DPRINTFC(QDC_RSRC, 0, (QM_DEBFP, "sev=ERROR, func=qm_comp_resource, lock=%d\n", r));
return sm_error_temp(SM_EM_Q, r);
}
}
ret = cdb_fs_getfree(qmgr_ctx->qmgr_cdb_fsctx,
&qmgr_ctx->qmgr_cdb_kbfree);
QM_LEV_DPRINTFC(QDC_RSRC, 3, (QM_DEBFP, "func=qm_comp_resource, cdb_kbfree=%lu, ret=%r\n", qmgr_ctx->qmgr_cdb_kbfree, ret));
if (sm_is_success(ret))
{
qmgr_ctx->qmgr_usage[QMGR_RFL_CDB_I] =
DISK_USAGE(qmgr_ctx->qmgr_cdb_kbfree, qmgr_ctx);
QMGR_SET_USE_MAX(QMGR_RFL_CDB_I);
}
ret = edb_fs_getfree(qmgr_ctx->qmgr_edb_fsctx,
&qmgr_ctx->qmgr_edb_kbfree);
QM_LEV_DPRINTFC(QDC_RSRC, 3, (QM_DEBFP, "func=qm_comp_resource, edb_kbfree=%lu, ret=%r\n", qmgr_ctx->qmgr_edb_kbfree, ret));
if (sm_is_success(ret))
{
qmgr_ctx->qmgr_usage[QMGR_RFL_EDB_I] =
DISK_USAGE(qmgr_ctx->qmgr_edb_kbfree, qmgr_ctx);
QMGR_SET_USE_MAX(QMGR_RFL_EDB_I);
}
ret = ibdb_fs_getfree(qmgr_ctx->qmgr_ibdb,
&qmgr_ctx->qmgr_ibdb_kbfree);
QM_LEV_DPRINTFC(QDC_RSRC, 3, (QM_DEBFP, "func=qm_comp_resource, ibdb_kbfree=%lu, ret=%r\n", qmgr_ctx->qmgr_ibdb_kbfree, ret));
if (sm_is_success(ret))
{
qmgr_ctx->qmgr_usage[QMGR_RFL_IBD_I] =
DISK_USAGE(qmgr_ctx->qmgr_ibdb_kbfree, qmgr_ctx);
QMGR_SET_USE_MAX(QMGR_RFL_IBD_I);
}
total = QMGR_R_USE_NONE;
sum = 0;
for (u = 0; u <= QMGR_RFL_LAST_I; u++)
{
if (qmgr_ctx->qmgr_usage[u] >= qmgr_ctx->qmgr_upper[u])
{
total = QMGR_R_USE_FULL;
break;
}
if (qmgr_ctx->qmgr_usage[u] > qmgr_ctx->qmgr_lower[u])
{
sum += 100 *
(qmgr_ctx->qmgr_usage[u]
- qmgr_ctx->qmgr_lower[u]) /
(qmgr_ctx->qmgr_upper[u]
- qmgr_ctx->qmgr_lower[u]);
}
}
if (total == QMGR_R_USE_NONE)
total = sum / (QMGR_RFL_LAST_I + 1);
qmgr_ctx->qmgr_total_usage = total;
if (thr_unl_always(locktype))
{
r = pthread_mutex_unlock(&qmgr_ctx->qmgr_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_Q, r);
}
return ret;
}
/*
** QM_RESOURCE -- change resource usage
**
** Parameters:
** qmgr_ctx -- QMGR context
** direction -- up/down/any direction
** use -- fullness of cache/DB/resource (0..100)
** resource -- which resource?
**
** Returns:
** usual sm_error code
**
** Locking:
** qmgr_ctx is locked here (additional parameter in case a caller
** has a lock on qmgr_ctx?)
**
** Last code review: 2005-04-23 21:52:26
** Last code change:
*/
sm_ret_T
qm_resource(qmgr_ctx_P qmgr_ctx, int direction, uint use, uint resource)
{
sm_ret_T ret;
int r;
SM_IS_QMGR_CTX(qmgr_ctx);
SM_REQUIRE(resource <= QMGR_RFL_LAST_I);
ret = SM_SUCCESS;
QM_LEV_DPRINTFC(QDC_RSRC, 6, (QM_DEBFP, "func=qm_resource, dir=%d, use=%u, resource=%u, flags=%#x\n", direction, use, resource, qmgr_ctx->qmgr_rflags));
r = pthread_mutex_lock(&qmgr_ctx->qmgr_mutex);
SM_LOCK_OK(r);
if (r != 0)
{
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_CONTROL, QM_LMOD_CONTROL,
SM_LOG_CRIT, 4,
"sev=CRIT, func=qm_resource, lock=%d", r);
return sm_error_temp(SM_EM_Q, r);
}
/*
** Throttle the system iff
** - asked for and
** - the use of the resource exceeds the upper threshold and
** - the use of the resource exceeds the last recorded usage
**
** else unthrottle the system iff
** - asked for and
** - the use of the resource is below the lower threshold and
** - the use of the resource is below the last recorded usage and
** - the resource is flagged as being exceeded
**
** in that case unthrottle the SMTPS servers iff
** - there is no resource shortage at all
*/
if (qmgr_is_throttle(direction)
&& use > qmgr_ctx->qmgr_upper[resource]
&& use > qmgr_ctx->qmgr_usage[resource])
{
QMGR_SET_RFLAG_I(qmgr_ctx, resource);
QM_LEV_DPRINTFC(QDC_RSRC, 2, (QM_DEBFP, "func=qm_resource, status=throttle, use=%u, resource=%d, flags=%#x\n", use, resource, qmgr_ctx->qmgr_rflags));
}
else if (qmgr_is_un_throttle(direction)
&& use < qmgr_ctx->qmgr_lower[resource]
&& use < qmgr_ctx->qmgr_usage[resource]
&& QMGR_IS_RFLAG_I(qmgr_ctx, resource)
)
{
QMGR_CLR_RFLAG_I(qmgr_ctx, resource);
QM_LEV_DPRINTFC(QDC_RSRC, 2, (QM_DEBFP, "func=qm_resource, status=unthrottle, use=%u,resource=%d, flags=%#x\n", use, resource, qmgr_ctx->qmgr_rflags));
if (QMGR_RFL_IS_NO_RSR(qmgr_ctx))
{
sm_log_write(qmgr_ctx->qmgr_lctx,
QM_LCAT_CONTROL, QM_LMOD_CONTROL,
SM_LOG_INFO, 9,
"sev=INFO, func=qm_resource, status=unthrottle, use=%u, resource=%d, flags=%#x"
, use, resource, qmgr_ctx->qmgr_rflags);
ret = qss_wakeup(qmgr_ctx, THR_NO_LOCK);
if (sm_is_err(ret))
QM_LEV_DPRINTFC(QDC_RSRC, 1, (QM_DEBFP, "sev=ERROR, func=qm_resource, qss_wakeup=%r\n", ret));
}
}
qmgr_ctx->qmgr_usage[resource] = use;
QMGR_SET_USE_MAX(resource);
r = pthread_mutex_unlock(&qmgr_ctx->qmgr_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_Q, r);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1