~ubuntu-branches/ubuntu/oneiric/squid3/oneiric-security

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "config.h"
#include "globals.h"
#include "TextException.h"
#include "SquidTime.h"
#include "HttpRequest.h" /* for alLogformatHasAdaptToken */
#include "adaptation/Config.h"
#include "adaptation/History.h"

/// impossible services value to identify unset theNextServices
const static char *TheNullServices = ",null,";

Adaptation::History::Entry::Entry(const String &serviceId, const timeval &when):
        service(serviceId), start(when), theRptm(-1), retried(false)
{
}

Adaptation::History::Entry::Entry():
        start(current_time), theRptm(-1), retried(false)
{
}

void Adaptation::History::Entry::stop()
{
    // theRptm may already be set if the access log entry has already been made
    (void)rptm(); // will cache result in theRptm if not set already
}

int Adaptation::History::Entry::rptm()
{
    if (theRptm < 0)
        theRptm = tvSubMsec(start, current_time);
    return theRptm;
}


Adaptation::History::History(): theNextServices(TheNullServices)
{
}

int Adaptation::History::recordXactStart(const String &serviceId, const timeval &when, bool retrying)
{
    // the history will be empty on retries if it was enabled after the failure
    if (retrying && !theEntries.empty())
        theEntries.back().retried = true;

    theEntries.push_back(Adaptation::History::Entry(serviceId, when));
    return theEntries.size() - 1; // record position becomes history ID
}

void Adaptation::History::recordXactFinish(int hid)
{
    Must(0 <= hid && hid < static_cast<int>(theEntries.size()));
    theEntries[hid].stop();
}

void Adaptation::History::allLogString(const char *serviceId, String &s)
{
    s="";
    bool prevWasRetried = false;
    // XXX: Fix Vector<> so that we can use const_iterator here
    typedef Adaptation::History::Entries::iterator ECI;
    for (ECI i = theEntries.begin(); i != theEntries.end(); ++i) {
        // TODO: here and below, optimize service ID comparison?
        if (!serviceId || i->service == serviceId) {
            if (s.size() > 0) // not the first logged time, must delimit
                s.append(prevWasRetried ? "+" : ",");

            char buf[64];
            snprintf(buf, sizeof(buf), "%d", i->rptm());
            s.append(buf);

            // continue; we may have two identical services (e.g., for retries)
        }
        prevWasRetried = i->retried;
    }
}

void Adaptation::History::sumLogString(const char *serviceId, String &s)
{
    s="";
    int retriedRptm = 0; // sum of rptm times of retried transactions
    typedef Adaptation::History::Entries::iterator ECI;
    for (ECI i = theEntries.begin(); i != theEntries.end(); ++i) {
        if (i->retried) { // do not log retried xact but accumulate their time
            retriedRptm += i->rptm();
        } else if (!serviceId || i->service == serviceId) {
            if (s.size() > 0) // not the first logged time, must delimit
                s.append(",");

            char buf[64];
            snprintf(buf, sizeof(buf), "%d", retriedRptm + i->rptm());
            s.append(buf);

            // continue; we may have two identical services (e.g., for retries)
        }

        if (!i->retried)
            retriedRptm = 0;
    }

    // the last transaction is never retried or it would not be the last
    Must(!retriedRptm);
}

void Adaptation::History::updateXxRecord(const char *name, const String &value)
{
    theXxName = name;
    theXxValue = value;
}

bool Adaptation::History::getXxRecord(String &name, String &value) const
{
    if (theXxName.size() <= 0)
        return false;

    name = theXxName;
    value = theXxValue;
    return true;
}

void Adaptation::History::updateNextServices(const String &services)
{
    if (theNextServices != TheNullServices)
        debugs(93,3, HERE << "old services: " << theNextServices);
    debugs(93,3, HERE << "new services: " << services);
    Must(services != TheNullServices);
    theNextServices = services;
}

bool Adaptation::History::extractNextServices(String &value)
{
    if (theNextServices == TheNullServices)
        return false;

    value = theNextServices;
    theNextServices = TheNullServices; // prevents resetting the plan twice
    return true;
}