4
\$\begingroup\$

Uptime is a very important metric, as we all know, so we'd like to measure the uptime since our service was first launched. The SLA specifies an uptime of a certain number of nines, such as 3 nines for at least 99.9% uptime, or 1 nine for at least 90% uptime, and you're wondering if you've actually met the SLA or not. Since you know the service went down last friday night when someone pushed to production, and since this is basically standard practice here, you figure there's no need for your code to handle 100% uptime as a special case.

Everytime a server stops or starts, Nagios sends you an email. The service in question has some level of fault tolerance, so only m servers have to be online for the service to be available. You just wrote a quick script to extract the important information from these emails. Now it's time for the fun part, and you're in the mood for golfing.

Your task is to write a program or function that analyzes the input, figures out the uptime, and prints the largest integer number of nines achieved by the service.

Input:

  • The number of servers required to be running for the service to be considered online: m > 0.

  • Followed by at least one line, one for each server. Each line contains start/stop times for that server. Since we've measured this since the service was launched, the first number is the time the server started the first time. The second time is a stop time, the third another start time etc.

  • No single server is ever started and stopped at the same time.

  • This means that if the server is currently running, you haven't gotten an email about it shutting down yet, so the number of numbers on that line would be odd.

  • The lines are sorted, but the ordering between different lines is not enforced.

  • The input is EOF-terminated. The last character of the input will be \n followed by EOF (ctrl+D).

  • The time starts at time 0 and ends at the last recorded start/stop of a single server, since that's all the information we have so far. This can be done by adding max(last number on each line) to the end of all odd-length lines.

  • Time is discrete.

  • All input numbers are guaranteed to fit inside a 32bit integer.

  • The service will never have 100% uptime.

  • If you would like to add an integer telling you how many servers there are, you may do so. You may also add an integer in the beginning of each server line telling you how many measurements there are for that server. See example in first testcase. You may also use whatever native format you'd like.

Output:
The output consists of a single integer; the highest number of nines that you can guarantee you had in hindsight, i.e. 3 for at least 99.9% uptime or 4 for at least 99.99% uptime.

Testcases:

First:

1
0 5 8 10
0 1 7

-> 1

First, with counts (if you prefer that):

1 2
4 0 5 8 10
3 0 1 7

-> 1

Second:

1
0 999 1001 2000

-> 3

Third:

3
0 42

-> 0

Reference implementation: (Python 2)

"""
Slow and huge, but useful for checking smaller inputs.

input: m, followed by n lines of start and stop times, all servers are turned off in the beginning, all numbers fit inside 32bit signed integers, counts are optional
output: number of nines of uptime

example:
1
0 5 8 9
0 1 7
parsed:
1st node: on 0:5, 7:9
2nd node: on 0:1, 6:9
at least one server is running during:
0:5, 7:9
known time interval: 0:9, only timestep 6 is down, so 90% uptime during the part we can see.
output:
1

"""

import sys


def rangeify(l):
    res = []
    for i in range(0, len(l), 2):
        res += range(l[i], l[i + 1] + 1)
    return res


def parse():
    m = input()
    lines = [map(int, x.split()) for x in sys.stdin.read().split("\n")[:-1]]
    if not lines:
        return [], m
    top = max(map(max, lines))
    nlines = [x + [top] if len(x) % 2 else x for x in lines]

    n2lines = map(rangeify, nlines)
    return n2lines, m


def flatten(ls):
    res = []
    for l in ls:
        res += l
    return sorted(res)


def join(ups):
    res = {}
    for up in ups:
        if up not in res:
            res[up] = 0
        res[up] += 1
    return res


def bin(ups, m):
    res = []
    for up in range(max(ups)+1):
        res += [up in ups and ups[up] >= m]
    return res


def nines(a):
    s = ("%.15f" % a)[2:]
    s2 = s.lstrip("9")
    return len(s) - len(s2)


def solve(l, m):
    if len(l) < m:
        return nines(0)
    b = bin(join(flatten(l)), m)
    return nines(sum(b) / float(len(b)))


print solve(*parse())
\$\endgroup\$
5
  • 1
    \$\begingroup\$ A few nitpicks: 1) EOF is not an actual byte in a stream - it's a signal from the I/O library back to the code to inform you that the end of file has been reached. 2) This challenge would be a lot better if you were more flexible with the input format (allowing lists/arrays and such instead of requiring string parsing, which detracts from the actual challenge). You should post challenges in the Sandbox to get feedback before posting on Main. \$\endgroup\$
    – user45941
    May 24, 2016 at 19:57
  • \$\begingroup\$ Thought I'd avoided the cumbersome I/O format by allowing lengths to be inserted, but no. Added clarification allowing any native input format. Thanks @Mego \$\endgroup\$ May 24, 2016 at 20:00
  • \$\begingroup\$ The first test case only computes to 80% uptime when I try. \$\endgroup\$
    – Neil
    May 24, 2016 at 23:40
  • \$\begingroup\$ @Neil you're trying to figure out the maximum possible uptime. If a service goes down at 12:00 you of course assume that this is 12:00:59, as that might actually have been the case. \$\endgroup\$ Jun 23, 2016 at 10:15
  • \$\begingroup\$ Ah, so the time ranges include the whole stop minute? I hadn't understood that before. I've updated my answer appropriately. \$\endgroup\$
    – Neil
    Jun 23, 2016 at 12:40

2 Answers 2

1
\$\begingroup\$

Pyth - 26 bytes

/`.Omgsm%lf<dTk2.QQeSs.Q`9

Try it online here.

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 161 bytes

(m,a)=>a.map(b=>b.map(n=>l=n>l?n:l),l=0)|a.map(b=>c.map((_,i)=>{k=b[j]==i;j+=k;n^=k;c[i]+=n|k},j=n=0),c=Array(++l).fill(0))|Math.log10(l/c.filter(n=>n<m).length)

Accepts an integer representing the minimum number of concurrent servers and an array of arrays representing the start and stop times of each server. Edit: Now uses inclusive ranges, so correctly returns 1 for the first example.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.