# How to guarantee a guarantee

It's not obvious at the first glance, but there are only two ways of how a guarantee can be provided:

1. reserve desired amount in advance
2. limit consumers to keep some amount free

The first way has the followong disadvantages:

Reservation is impossible for certain resources
such as CPU time, disk or network bandwidth and similar can not be just reserved as their amount instantly increases;
Reserved amount is essentially a limit, but much more strict
cutting off X megabytes from RAM implies that all the rest groups are limited in their RAM consumption;
Reservation reduces containers density
if one wants to run some identical containers, each requiring 100Mb on 1Gb system, reservations can be done for only 10 containers, and starting the 11th is impossible.

On the other hand, limiting of containers can provide guarantees for them as well.

# Providing a guarantee through limiting

The idea of getting a guarantee is simple:

if any group ${\displaystyle g_{i}}$ requires a ${\displaystyle G_{i}}$ units of resource from ${\displaystyle R}$ units available then limiting all the rest groups with ${\displaystyle R-G_{i}}$ units provides a desired guarantee

For ${\displaystyle N}$ groups in the system this implies solving a linear equation set to get limits ${\displaystyle L_{i}}$ like this:

${\displaystyle {\begin{cases}L_{2}+L_{3}+\ldots +L_{N}=R-G_{1}\\L_{1}+L_{3}+\ldots +L_{N}=R-G_{2}\\\ldots \\L_{1}+L_{2}+\ldots +L_{N-1}=R-G_{N}\\\end{cases}}}$

In a matrix form this looks like

${\displaystyle AL=G\;}$

where

${\displaystyle A={\begin{bmatrix}0&1&1&\cdots &1&1\\1&0&1&\cdots &1&1\\&&\cdots \\1&1&1&\cdots &1&0\\\end{bmatrix}},L={\begin{bmatrix}L_{1}\\L_{2}\\\vdots \\L_{N}\end{bmatrix}},G={\begin{bmatrix}R-G_{1}\\R-G_{2}\\\vdots \\R-G_{N}\end{bmatrix}}}$

and thus the solution is

${\displaystyle L=A^{-1}G\;}$

Skipping boring calculations, the reverse matrix ${\displaystyle A^{-1}\;}$ is

${\displaystyle A^{-1}={\frac {1}{N-1}}\left(A-(N-2)E\right)}$

This solutions looks huge, but the ${\displaystyle L}$ vector is calculated in ${\displaystyle O(N)}$ time:

void calculate_limits(int N, int *g, int *l)
{
int sum;
int i;

if (N == 1) {
l[0] = R;
return;
}

sum = 0;
for (i = 0; i < N; i++)
sum += R - g[i];
for (i = 0; i < N; i++)
l[i] = (sum - (R - g[i]) - (N - 2) * (R - g[i]))/(N - 1);
}