You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2010/05/17 06:23:42 UTC

svn commit: r944963 - in /trafficserver/traffic/trunk/proxy: Makefile.am StatAPITypes.cc StatAPITypes.h StatSystemV2.cc StatSystemV2.h api/ts/InkAPIPrivateIOCore.h http2/HttpSM.h

Author: zwoop
Date: Mon May 17 04:23:42 2010
New Revision: 944963

URL: http://svn.apache.org/viewvc?rev=944963&view=rev
Log:
TS-157: Added four missing files, and also renamed StatTypes to StatAPITypes, to avoid reusing a filename that is already used in proxy/mgmt2/stats/. If someone objects, please feel free to rename these files again, I just find it confusing having two very similar files with the same names in two different directories.

Added:
    trafficserver/traffic/trunk/proxy/StatAPITypes.cc
    trafficserver/traffic/trunk/proxy/StatAPITypes.h
    trafficserver/traffic/trunk/proxy/StatSystemV2.cc
    trafficserver/traffic/trunk/proxy/StatSystemV2.h
Modified:
    trafficserver/traffic/trunk/proxy/Makefile.am
    trafficserver/traffic/trunk/proxy/api/ts/InkAPIPrivateIOCore.h
    trafficserver/traffic/trunk/proxy/http2/HttpSM.h

Modified: trafficserver/traffic/trunk/proxy/Makefile.am
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/Makefile.am?rev=944963&r1=944962&r2=944963&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/Makefile.am (original)
+++ trafficserver/traffic/trunk/proxy/Makefile.am Mon May 17 04:23:42 2010
@@ -144,7 +144,7 @@ traffic_server_SOURCES = \
   StatSystem.cc \
   StatSystem.h \
   StatSystemV2.cc \
-  StatTypes.cc \
+  StatAPITypes.cc \
   TestHook.cc \
   Transform.cc \
   Transform.h \
@@ -194,7 +194,7 @@ traffic_logcat_LDADD = \
   ControlMatcher.o CacheControl.o  \
   StatSystem.o \
   StatSystemV2.o \
-  StatTypes.o \
+  StatAPITypes.o \
   CacheInspectorAllow.o \
   ReverseProxy.o \
   ProxyConfig.o \
@@ -257,7 +257,7 @@ traffic_logstats_LDADD = \
   CacheControl.o  \
   StatSystem.o \
   StatSystemV2.o \
-  StatTypes.o \
+  StatAPITypes.o \
   CacheInspectorAllow.o \
   ReverseProxy.o \
   ProxyConfig.o \
@@ -321,7 +321,7 @@ traffic_sac_LDADD = \
   CacheControl.o \
   StatSystem.o \
   StatSystemV2.o \
-  StatTypes.o \
+  StatAPITypes.o \
   CacheInspectorAllow.o \
   ReverseProxy.o \
   ProxyConfig.o \
@@ -388,7 +388,7 @@ libTrafficServerStandalone_a_SOURCES = \
   StatPages.cc \
   StatSystem.cc \
   StatSystemV2.cc \
-  StatTypes.cc \
+  StatAPITypes.cc \
   AbstractBuffer.cc \
   Initialize.cc
 

Added: trafficserver/traffic/trunk/proxy/StatAPITypes.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/StatAPITypes.cc?rev=944963&view=auto
==============================================================================
--- trafficserver/traffic/trunk/proxy/StatAPITypes.cc (added)
+++ trafficserver/traffic/trunk/proxy/StatAPITypes.cc Mon May 17 04:23:42 2010
@@ -0,0 +1,89 @@
+/** @file
+
+    A brief file description
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+/***************************************************************************
+ Stat types
+
+ ***************************************************************************/
+
+#include "api/ts/ts.h"
+#include "StatAPITypes.h"
+#include "StatSystemV2.h"
+
+long long HistogramStats::get_bucket(long long theNumber)
+{
+    // theNumber == 0 : bucket = 0
+    // theNumber == 1 : bucket = 1
+    // theNumber >= 2 && theNumber < 4 : bucket = 2
+    // theNumber >= 4 && theNumber < 8: bucket = 3
+    // and so on
+
+    int PowerOf2Counter = 0;
+
+    if (theNumber == 0) {
+        return 0;
+    }
+    if(theNumber == 1) {
+        return 1;
+    }
+
+    // count the number in question down as we count up a power of 2
+    while (theNumber > 1) {
+        PowerOf2Counter++;
+        
+        // reduce number by a factor of 2 two
+        theNumber >>= 1;
+    }
+
+    return PowerOf2Counter + 1;
+}
+
+void HistogramStats::init(const std::string &stat_prefix, long long max_stat)
+{
+    long long max_bucket = get_bucket(max_stat);
+
+    buckets.resize(max_bucket + 2);
+    StatSystemV2::registerStat((stat_prefix + "." + "0").c_str(), &buckets[0]);
+    for(long long bucket = 0; bucket <= max_bucket; bucket++) {
+        std::ostringstream stat_name;
+        stat_name << stat_prefix << "." << (1<<bucket);
+        StatSystemV2::registerStat(stat_name.str().c_str(), &buckets[bucket+1]);
+    }
+}
+
+void HistogramStats::inc(long long stat_val)
+{
+    long long num_buckets = buckets.size();
+    if(!num_buckets) {
+        return;
+    }
+    
+    long long bucket = get_bucket(stat_val);
+   
+    if(bucket >= num_buckets) {
+        StatSystemV2::increment(buckets[num_buckets-1]);
+    }
+    else {
+        StatSystemV2::increment(buckets[bucket]);
+    }
+}

Added: trafficserver/traffic/trunk/proxy/StatAPITypes.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/StatAPITypes.h?rev=944963&view=auto
==============================================================================
--- trafficserver/traffic/trunk/proxy/StatAPITypes.h (added)
+++ trafficserver/traffic/trunk/proxy/StatAPITypes.h Mon May 17 04:23:42 2010
@@ -0,0 +1,49 @@
+/** @file
+
+    A brief file description
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+/***************************************************************************
+ Stat types
+
+ ***************************************************************************/
+
+#ifndef STAT_TYPES_V2_H
+#define STAT_TYPES_V2_H
+
+#include <string>
+#include <vector>
+#include "inktomi++.h"
+
+class HistogramStats
+{
+public:
+    HistogramStats() { }
+    HistogramStats(const std::string &stat_prefix, long long max_stat) { init(stat_prefix, max_stat); }
+    void init(const std::string &stat_prefix, long long max_stat);
+    void inc(long long stat_val);
+    long long get_bucket(long long theNumber);
+private:
+    std::vector<uint32_t> buckets;
+};
+
+#endif // STAT_TYPES
+

Added: trafficserver/traffic/trunk/proxy/StatSystemV2.cc
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/StatSystemV2.cc?rev=944963&view=auto
==============================================================================
--- trafficserver/traffic/trunk/proxy/StatSystemV2.cc (added)
+++ trafficserver/traffic/trunk/proxy/StatSystemV2.cc Mon May 17 04:23:42 2010
@@ -0,0 +1,564 @@
+/** @file
+
+    A brief file description
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+#include "StatSystemV2.h"
+#include "P_EventSystem.h"
+#include "Log.h"
+#include <iostream>
+
+extern struct EventProcessor eventProcessor;
+
+std::map<std::string, uint32_t> StatSystemV2::stat_name_to_num;
+std::vector< std::pair<std::string, INK64> > StatSystemV2::global_stats;
+uint32_t StatSystemV2::MAX_STATS_ALLOWED = 500000;
+uint32_t StatSystemV2::NUM_STATS_ESTIMATE = 5000;
+static INKMutex statsMutex = INKMutexCreate();
+
+void StatSystemV2::incrementGlobal(uint32_t stat_num, INK64 stat_val)
+{
+    if(stat_num >= global_stats.size()) {
+        Debug("http", "Cannot incrementing stat %u as it is greater than global_stats size", stat_num);
+        return;
+    }
+    Debug("http", "Incrementing stat %u %s %ld", stat_num, global_stats[stat_num].first.c_str(), stat_val);
+    global_stats[stat_num].second += stat_val;
+}
+
+bool StatSystemV2::increment(uint32_t stat_num, INK64 stat_val)
+{
+    if(stat_num >= MAX_STATS_ALLOWED) {
+        return false;
+    }
+   
+    EThread *t = this_ethread(); 
+    // stat_num starts at 0
+    if(t->thread_stats.size() < (unsigned int)stat_num+1) {
+        if (INKMutexLock(t->thread_stats_mutex) != INK_SUCCESS) {
+            return false;
+        }
+        t->thread_stats.resize(stat_num+1, 0);
+        INKMutexUnlock(t->thread_stats_mutex);
+    }
+    t->thread_stats[stat_num] += stat_val;
+    return true;
+}
+
+bool StatSystemV2::increment(const char *stat_name, INK64 stat_val)
+{
+    uint32_t stat_num;
+    if(!getStatNum(stat_name, stat_num)) {
+        return false;
+    }
+    return increment(stat_num, stat_val);
+}
+
+bool StatSystemV2::get(uint32_t stat_num, INK64 *stat_val)
+{
+    // Get stat lock
+    if (INKMutexLock(statsMutex) != INK_SUCCESS) {
+        return false;
+    }
+
+    if(stat_num >= global_stats.size()) {
+        INKMutexUnlock(statsMutex);
+        return false;
+    }
+    
+    *stat_val = global_stats[stat_num].second;
+    INKMutexUnlock(statsMutex);
+    
+    return true;
+}
+
+bool StatSystemV2::get(const char *stat_name, INK64 *stat_val)
+{
+    // Get value of stat with name == stat_name
+    // Returns value from the global stats map. does not walk threads 
+    uint32_t stat_num;
+    if(!getStatNum(stat_name, stat_num)) {
+        return false;
+    }
+    return get(stat_num, stat_val);
+}
+
+bool StatSystemV2::get_current(uint32_t stat_num, INK64 *stat_val)
+{
+    // Returns current value of stat. Walks all threads
+    
+    *stat_val = 0;
+    // Collect stat from all threads
+    for(int i =0; i < eventProcessor.n_ethreads; i++) {
+        EThread *t = eventProcessor.all_ethreads[i];
+        if (INKMutexLock(t->thread_stats_mutex) != INK_SUCCESS) {
+            return false;
+        }
+
+        if(t->thread_stats.size() > stat_num) { 
+            *stat_val += t->thread_stats[stat_num];
+        }
+        INKMutexUnlock(t->thread_stats_mutex);
+    }
+    return true;
+}
+
+bool StatSystemV2::get_current(const char *stat_name, INK64 *stat_val)
+{
+    uint32_t stat_num;
+    if(!getStatNum(stat_name, stat_num)) {
+        return false;
+    }
+    return get_current(stat_num, stat_val);
+}
+
+bool StatSystemV2::registerStat(const char *stat_name, uint32_t *stat_num)
+{
+    if(!stat_num ) {
+        return false;
+    }
+    
+    // Get stat lock
+    if (INKMutexLock(statsMutex) != INK_SUCCESS) {
+        *stat_num = MAX_STATS_ALLOWED;
+        return false;
+    }
+
+    // Check if stat is already registered
+    std::map<std::string, uint32_t>::const_iterator stat_name_it = stat_name_to_num.find(stat_name);
+    if(stat_name_it != stat_name_to_num.end()) {
+        *stat_num = stat_name_it->second;
+        INKMutexUnlock(statsMutex);
+        return true;
+    }
+
+    // Check to see if limit for max allowed stats was hit
+    if(global_stats.size() == MAX_STATS_ALLOWED) {
+        INKMutexUnlock(statsMutex);
+        *stat_num = MAX_STATS_ALLOWED;
+        return false;
+    }
+
+    global_stats.push_back(std::make_pair(stat_name, 0));
+    *stat_num = global_stats.size() - 1;
+    stat_name_to_num[stat_name] = *stat_num;
+    Debug("http", "Registered stat : %s %u", global_stats[*stat_num].first.c_str(), *stat_num); 
+    INKMutexUnlock(statsMutex);
+    return true;
+}
+
+void StatSystemV2::setMaxStatsAllowed(uint32_t max_stats_allowed)
+{
+    MAX_STATS_ALLOWED = max_stats_allowed;
+}
+
+void StatSystemV2::setNumStatsEstimate(uint32_t num_stats_estimate)
+{
+    if(num_stats_estimate < MAX_STATS_ALLOWED)
+        NUM_STATS_ESTIMATE = num_stats_estimate;
+    else
+        NUM_STATS_ESTIMATE = MAX_STATS_ALLOWED;
+}
+
+void StatSystemV2::init()
+{
+    if (INKMutexLock(statsMutex) != INK_SUCCESS) {
+        return;
+    }
+
+    // Resize thread_stats vector in each thread to NUM_STATS_ESTIMATE
+    for(int i =0; i < eventProcessor.n_ethreads; i++) {
+        EThread *t = eventProcessor.all_ethreads[i];
+        INKMutexLock(t->thread_stats_mutex);
+        t->thread_stats.resize(NUM_STATS_ESTIMATE);
+        INKMutexUnlock(t->thread_stats_mutex);
+    }
+    
+    INKMutexUnlock(statsMutex);    
+}
+
+void StatSystemV2::clear()
+{
+    for(std::vector< std::pair<std::string, INK64> >::iterator it = StatSystemV2::global_stats.begin();
+            it != StatSystemV2::global_stats.end(); it++) {
+        it->second = 0;
+    }
+}
+
+void StatSystemV2::collect()
+{
+    if (INKMutexLock(statsMutex) != INK_SUCCESS) {
+        return;
+    }
+
+    StatSystemV2::clear();
+    for(int i =0; i < eventProcessor.n_ethreads; i++) {
+        EThread *t = eventProcessor.all_ethreads[i];
+
+        // Lock thread stats to prevent resizing on increment
+        INKMutexLock(t->thread_stats_mutex);
+        int i = 0;
+        for(std::vector<INK64>::iterator it = t->thread_stats.begin();
+            it != t->thread_stats.end(); it++, i++) {
+            if(*it != 0) {
+                incrementGlobal(i, *it);
+            }
+        }
+        
+        // Release thread stats
+        INKMutexUnlock(t->thread_stats_mutex);
+    }
+    INKMutexUnlock(statsMutex);
+}
+
+bool StatSystemV2::getStatNum(const char *stat_name, uint32_t &stat_num)
+{
+    // Get stat lock
+    if (INKMutexLock(statsMutex) != INK_SUCCESS) {
+        return false;
+    }
+
+    // Get stat num and release lock
+    std::map<std::string, uint32_t>::const_iterator stat_name_it = stat_name_to_num.find(stat_name);
+    if(stat_name_it == stat_name_to_num.end()) {
+        INKMutexUnlock(statsMutex);
+        return false;
+    }
+
+    stat_num = stat_name_it->second;
+    INKMutexUnlock(statsMutex);
+    return true;
+}
+
+static INKThread statsCommandThread;
+static int MAX_STAT_NAME_LENGTH = 512;
+int StatCollectorContinuation::mainEvent(int event, Event * e)
+{
+    StatSystemV2::collect();
+    return EVENT_CONT;
+}
+
+int StatCollectorContinuation::doWrite(int fd, const char* buf, size_t towrite) {
+    int written = -1;
+    while(fd && buf && towrite > 0) {
+        if ((written = write(fd, buf, towrite)) < 0) {
+            if (errno == EINTR || errno == EAGAIN) {
+                written = 0;
+            } else {
+                Debug("http", "Failed write on stats connection");
+                return -1;
+            }
+        } else if (written == 0) { //closed
+            return -1;
+        }
+        towrite -= written;
+        buf += written;
+    }
+    
+    return 0;
+}
+
+//------------------------------------------------------------------------------
+void StatCollectorContinuation::print_stats(std::stringstream &printbuf) {
+   printbuf <<  "Cache stats: \n"
+                "-----------------------------------------------------------------------------\n";
+
+  printbuf << "TIME " << _startTime <<"\n";
+  if (INKMutexLock(statsMutex) == INK_SUCCESS) {
+      for(std::vector< std::pair<std::string, INK64> >::const_iterator it = StatSystemV2::global_stats.begin();
+          it != StatSystemV2::global_stats.end(); it++) {
+          if(it->second != 0 ) {
+              printbuf << "STAT " << it->first << " " << it->second << "\n";
+          }
+      }
+      INKMutexUnlock(statsMutex);
+  }
+  printbuf << "END\n";
+}
+
+void StatCollectorContinuation::print_stat(const char *stat_name, std::stringstream &printbuf, bool current) {
+    // Print only non zero stats
+    INK64 stat_val = 0;
+    bool stat_get_status;
+    if(current) {
+        stat_get_status = StatSystemV2::get_current(stat_name, &stat_val);
+    }
+    else {
+        stat_get_status = StatSystemV2::get(stat_name, &stat_val);
+    }
+    
+    if(stat_get_status && stat_val != 0) {
+        printbuf << "STAT " << stat_name << " " << stat_val << "\n";
+    }
+}
+
+void StatCollectorContinuation::print_stats(const std::vector<std::string> &stat_names, std::stringstream &printbuf, bool current) {
+  printbuf << "TIME " << _startTime <<"\n";
+    for(std::vector<std::string>::const_iterator it = stat_names.begin();
+        it != stat_names.end();
+        it++) {
+        print_stat(it->c_str(), printbuf, current);
+    }
+   printbuf << "END\n";
+}
+
+void
+StatCollectorContinuation::get_stats_with_prefix(const std::string &stat_prefix, std::vector<std::string> &stat_names)
+{
+    if (INKMutexLock(statsMutex) != INK_SUCCESS) {
+        return;
+    }
+
+    // Get all stats which start with stat_prefix
+    for(std::vector< std::pair<std::string, INK64> >::const_iterator it = StatSystemV2::global_stats.begin();
+        it != StatSystemV2::global_stats.end(); it++) {
+        size_t found = it->first.find(stat_prefix);
+        if(found == 0) {
+            stat_names.push_back(it->first);
+        }
+    }    
+    INKMutexUnlock(statsMutex);
+}
+
+int
+StatCollectorContinuation::getCommand(int fd, char *buf, int buf_size)
+{
+    int n, rc;
+    char c = '\0';
+    double time_left = _readTimeout*1000 + _readTimeoutUSecs/1000;
+    
+    for (n = 1; n < buf_size && time_left > 0; n++) {
+        struct timeval start, stop;
+        gettimeofday(&start, NULL);
+        if ((rc = read(fd, &c, 1)) == 1) {
+            *buf++ = c;
+            if (c == '\n') {
+                break;
+            }
+        } else if (rc == 0) {
+            if (n == 1)
+                return 0; // EOF, no data read
+            else
+                break; // EOF, read some data
+        } else if(rc < 0) {
+            if (errno != EINTR && errno != EAGAIN) {
+                Debug("http", "Failed read on stats connection");
+                return -1;
+            }
+        }
+        
+        gettimeofday(&stop, NULL);
+        double time_elapsed = (stop.tv_sec - start.tv_sec)*1000 + (stop.tv_usec - start.tv_usec)/1000;
+        time_left = time_left - time_elapsed;
+    }
+
+    if(time_left <= 0) {
+    // Timeout. Client took too long to send a command. Close client connection
+        return -1;
+    }
+    
+    *buf = '\0'; // null-terminate
+    return n;
+}
+
+//------------------------------------------------------------------------------
+// Handles a command port client connection
+void* StatCollectorContinuation::commandLoop(void *data) {
+    // static const char cmdPrompt[] = "STATS : ";
+    static const char cmdUnrec[] = "Unrecognized command.\r\n";
+    static const char cmdHelp[] = "Valid commands are: \r\n"
+        "  stats - Print stats which have been collected.\r\n"
+        "  stats_current - Print stats after forcing a collect\r\n"
+        "  stat (<stat_name> )* - Print values for stats that are specified. Does not collect\r\n"
+        "  stat_current (<stat_name> )* - Print values for stats that are specified after collecting from all threads\r\n"
+        "  help - Prints this message.\r\n"
+        "  quit - Close this connection.\r\n"
+        ;
+    int client_sock, readbytes;
+    char readbuf[1024];
+    
+    if (!data) return 0;
+    client_sock = *(static_cast<int*>(data));
+    while(1){
+        if((readbytes = getCommand(client_sock, readbuf, sizeof(readbuf))) <= 0) {
+            break;
+        }
+
+        if(strstr(readbuf, "stats_current") == readbuf) {
+            // Force a collect before printing out the stats
+            StatSystemV2::collect();
+            std::stringstream printbuf;
+            print_stats(printbuf);
+            if (doWrite(client_sock, printbuf.str().c_str(), printbuf.str().length())) {
+                //failed write, break to close connection
+                break;
+            }
+        }
+        else if (strstr(readbuf, "stats") == readbuf) {
+            std::stringstream printbuf;
+            print_stats(printbuf);
+            if (doWrite(client_sock, printbuf.str().c_str(), printbuf.str().length())) {
+                    //failed write, break to close connection
+                break;
+            }
+        }
+        else if (strstr(readbuf, "stat ") == readbuf || strstr(readbuf, "stat_current ") == readbuf) {
+            std::vector<std::string> stats;
+            char stat_name[MAX_STAT_NAME_LENGTH];
+            bzero(stat_name, MAX_STAT_NAME_LENGTH);
+            int next;
+            char *start = readbuf;
+
+            // determine if collection has to be forced or not
+            bool get_current = false;
+            if(strstr(readbuf, "stat ") == readbuf)
+                start += strlen("stat ");
+            else {
+                start += strlen("stat_current ");
+                get_current = true;
+            }
+            
+            while(sscanf(start, "%s%n", stat_name, &next) == 1)
+            {
+                // Prefix support
+                char *prefix_end = strchr(start, '*');
+                if(prefix_end != NULL) {
+                    std::string prefix;
+                    prefix.assign(start, prefix_end-start);
+                    // Get all stats with the prefix
+                    get_stats_with_prefix(prefix, stats);
+                }
+                else {
+                    stats.push_back(stat_name);
+                }
+                bzero(stat_name, MAX_STAT_NAME_LENGTH);
+                start+=next;
+            }
+            std::stringstream printbuf;
+            
+            print_stats(stats, printbuf, get_current);
+            if (doWrite(client_sock, printbuf.str().c_str(), printbuf.str().length())) {
+                //failed write, break to close connection
+                break;
+            }
+        }
+        else if (strstr(readbuf, "help") == readbuf) {
+            if (doWrite(client_sock, cmdHelp, sizeof(cmdHelp)-1)) {
+                //failed write, break to close connection
+                break;
+            }
+        } else if (strstr(readbuf, "quit") == readbuf) {
+            break;
+        } else {
+            if (doWrite(client_sock, cmdUnrec, sizeof(cmdUnrec)-1) ||
+                doWrite(client_sock, cmdHelp, sizeof(cmdHelp)-1)) {
+                //failed write, break to close connection
+                break;
+            }
+        }
+    } // END while loop
+    
+    if (shutdown(client_sock, SHUT_RDWR) < 0) {
+        Debug("http", "Failed shutdown on stats connection");
+    }
+    
+    if (close(client_sock) < 0) {
+        Debug("http", "Failed close on stats connection");
+    }
+    
+    return 0;
+}
+    
+//------------------------------------------------------------------------------
+// Creates a socket for command port and listens for connection requests
+void* StatCollectorContinuation::commandListen(void *data) {
+    // This is single-threaded and using blocking sockets for now,
+    // so there can be only one client at a time...
+    // non-blocking socket with poll/epoll can be added later if needed
+    
+    int listen_sock, client_sock;
+    struct  sockaddr_in listen_addr;
+    int reuseaddr = 1;
+    int port;
+    
+    if (!data) return 0;
+    port = *(static_cast<int*>(data));
+    
+    if (port < 1 || port > 65535) return 0;
+    
+    if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        Debug("Could not create listening socket for stats : %d %s", errno, strerror(errno));
+        return 0;
+    }
+    
+    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
+    
+    memset(&listen_addr, 0, sizeof(listen_addr));
+    listen_addr.sin_port = htons(port);
+    listen_addr.sin_family = AF_INET;
+    listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    
+    if (bind(listen_sock, (struct sockaddr *) &listen_addr, sizeof(listen_addr)) < 0) {
+        Debug("http", "Could not bind stat socket : %d %s", errno, strerror(errno));
+        return 0;
+    }
+    
+    if (listen(listen_sock, 8) < 0) {
+        Debug("http", "Failed to listen on stats port : %d %s", errno, strerror(errno));
+        return 0;
+    }
+    
+    while(1) {
+        
+        if ((client_sock = accept(listen_sock, NULL, NULL)) < 0 ) {
+            Debug("http", "Failed to accept on stats port : %d %s", errno, strerror(errno));
+            if (errno == ECONNABORTED || errno == EPROTO)
+                continue;
+            else //something unexpected, bail
+                return 0;
+        }
+        
+        INKThreadCreate(commandLoop, &client_sock);
+    }
+}
+
+int StatCollectorContinuation::_statCommandPort = 8091;
+time_t StatCollectorContinuation::_startTime = time(NULL);
+int StatCollectorContinuation::_readTimeout = 600;
+long StatCollectorContinuation::_readTimeoutUSecs = 0;
+
+void StatCollectorContinuation::setStatCommandPort(int port)
+{
+    _statCommandPort = port;
+}
+
+void StatCollectorContinuation::setReadTimeout(int secs, long usecs)
+{
+    _readTimeout = secs;
+    _readTimeoutUSecs = usecs;
+}
+
+StatCollectorContinuation::StatCollectorContinuation() : Continuation(NULL)
+{
+    Debug("http", "YTS start time : %b64d", StatCollectorContinuation::_startTime);
+    SET_HANDLER(&StatCollectorContinuation::mainEvent);
+    statsCommandThread = INKThreadCreate(commandListen, &_statCommandPort);
+}

Added: trafficserver/traffic/trunk/proxy/StatSystemV2.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/StatSystemV2.h?rev=944963&view=auto
==============================================================================
--- trafficserver/traffic/trunk/proxy/StatSystemV2.h (added)
+++ trafficserver/traffic/trunk/proxy/StatSystemV2.h Mon May 17 04:23:42 2010
@@ -0,0 +1,100 @@
+/** @file
+
+    A brief file description
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+*/
+
+/***************************************************************************
+ Stats
+
+ ***************************************************************************/
+
+#ifndef STAT_SYSTEM_V2_H
+#define STAT_SYSTEM_V2_H
+
+#include <map>
+#include <string>
+#include <vector>
+#include <utility>
+#include <sstream>
+#include "api/ts/ts.h"
+
+#include "I_EventSystem.h"
+
+class Event;
+
+class StatSystemV2
+{
+public:
+    static bool increment(uint32_t stat_num, INK64 stat_val = 1);
+    static bool increment(const char *stat_name, INK64 stat_val = 1);
+    static bool get(uint32_t stat_num, INK64 *stat_val);
+    static bool get(const char *stat_name, INK64 *stat_val);
+    static bool get_current(uint32_t stat_num, INK64 *stat_val);
+    static bool get_current(const char *stat_name, INK64 *stat_val);
+    
+    static bool registerStat(const char *stat_name, uint32_t *stat_num);
+    static void setMaxStatsAllowed(uint32_t max_stats_allowed);
+    static void setNumStatsEstimate(uint32_t num_stats_estimate);
+    static void init();
+    
+private:
+    // These must be called after acquiring a lock
+    // Since these are private, only methods in StatCollectorContinuation can call them
+    static void incrementGlobal(uint32_t stat_num, INK64 stat_val = 1);
+    static void clear();
+    static void collect();
+
+    static bool getStatNum(const char *stat_name, uint32_t &stat_num);
+    static std::map<std::string, uint32_t> stat_name_to_num;
+    static std::vector< std::pair<std::string, INK64> > global_stats;
+    static uint32_t MAX_STATS_ALLOWED;
+    static uint32_t NUM_STATS_ESTIMATE;
+
+    friend class StatCollectorContinuation;
+};
+
+class StatCollectorContinuation : public Continuation
+{
+public:
+    StatCollectorContinuation();
+    static void setStatCommandPort(int port);
+    static void setReadTimeout(int secs = 1, long usecs = 0);
+    
+private:
+    int mainEvent(int event, Event *e);
+    static int doWrite(int fd, const char* buf, size_t towrite);
+    static void print_stats(std::stringstream &printbuf);
+    static void print_stat(const char *stat_name, std::stringstream &printbuf, bool current = false);
+    static void print_stats(const std::vector<std::string> &stat_names, std::stringstream &printbuf, bool current = false);
+    static void get_stats_with_prefix(const std::string &stat_prefix, std::vector<std::string> &stat_names);
+    static void *commandLoop(void *data);
+    static void *commandListen(void *data);
+    static int getCommand(int fd, char *buf, int buf_size);
+
+    // member variables
+    static int _statCommandPort;
+    static time_t _startTime;
+    static int _readTimeout;
+    static long _readTimeoutUSecs;
+};
+
+#endif // STAT_SYSTEM_V2
+

Modified: trafficserver/traffic/trunk/proxy/api/ts/InkAPIPrivateIOCore.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/api/ts/InkAPIPrivateIOCore.h?rev=944963&r1=944962&r2=944963&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/api/ts/InkAPIPrivateIOCore.h (original)
+++ trafficserver/traffic/trunk/proxy/api/ts/InkAPIPrivateIOCore.h Mon May 17 04:23:42 2010
@@ -36,7 +36,7 @@
 
 #include <string>
 #include <vector>
-#include "StatTypes.h"
+#include "StatAPITypes.h"
 
 enum INKContInternalMagic_t
 {

Modified: trafficserver/traffic/trunk/proxy/http2/HttpSM.h
URL: http://svn.apache.org/viewvc/trafficserver/traffic/trunk/proxy/http2/HttpSM.h?rev=944963&r1=944962&r2=944963&view=diff
==============================================================================
--- trafficserver/traffic/trunk/proxy/http2/HttpSM.h (original)
+++ trafficserver/traffic/trunk/proxy/http2/HttpSM.h Mon May 17 04:23:42 2010
@@ -40,7 +40,7 @@
 #include "HttpTunnel.h"
 #include "InkAPIInternal.h"
 #include "StatSystem.h"
-#include "StatTypes.h"
+#include "StatAPITypes.h"
 #include "HttpClientSession.h"
 //#include "AuthHttpAdapter.h"