|
|
@@ -39,29 +39,47 @@ type hostStats struct {
|
|
|
numBytesReceived int64
|
|
|
}
|
|
|
|
|
|
-func newHostStats() *hostStats {
|
|
|
- return &hostStats{}
|
|
|
+// AccumulatedStats holds the Psiphon Server API status request data for a
|
|
|
+// given server. To accommodate status requests that may fail, and be retried,
|
|
|
+// the TakeOutStatsForServer/PutBackStatsForServer procedure allows the requester
|
|
|
+// to check out stats for reporting and merge back stats for a later retry.
|
|
|
+type AccumulatedStats struct {
|
|
|
+ hostnameToStats map[string]*hostStats
|
|
|
}
|
|
|
|
|
|
-// ServerStats holds per-server stats.
|
|
|
-type ServerStats struct {
|
|
|
- hostnameToStats map[string]*hostStats
|
|
|
- totalBytesSent int64
|
|
|
- totalBytesReceived int64
|
|
|
-}
|
|
|
+// GetStatsForStatusRequest summarizes AccumulatedStats data as
|
|
|
+// required for the Psiphon Server API status request.
|
|
|
+func (stats AccumulatedStats) GetStatsForStatusRequest() (map[string]int64, int64) {
|
|
|
+
|
|
|
+ hostBytes := make(map[string]int64)
|
|
|
+ bytesTransferred := int64(0)
|
|
|
|
|
|
-func newServerStats() *ServerStats {
|
|
|
- return &ServerStats{
|
|
|
- hostnameToStats: make(map[string]*hostStats),
|
|
|
+ for hostname, hostStats := range stats.hostnameToStats {
|
|
|
+ totalBytes := hostStats.numBytesReceived + hostStats.numBytesSent
|
|
|
+ bytesTransferred += totalBytes
|
|
|
+ hostBytes[hostname] = totalBytes
|
|
|
}
|
|
|
+
|
|
|
+ return hostBytes, bytesTransferred
|
|
|
+}
|
|
|
+
|
|
|
+// serverStats holds per-server stats.
|
|
|
+// accumulatedStats data is payload for the Psiphon status request
|
|
|
+// which is accessed via TakeOut/PutBack.
|
|
|
+// recentBytes data is for tunnel monitoring which is accessed via
|
|
|
+// ReportRecentBytesTransferredForServer.
|
|
|
+type serverStats struct {
|
|
|
+ accumulatedStats *AccumulatedStats
|
|
|
+ recentBytesSent int64
|
|
|
+ recentBytesReceived int64
|
|
|
}
|
|
|
|
|
|
// allStats is the root object that holds stats for all servers and all hosts,
|
|
|
// as well as the mutex to access them.
|
|
|
var allStats = struct {
|
|
|
statsMutex sync.RWMutex
|
|
|
- serverIDtoStats map[string]*ServerStats
|
|
|
-}{serverIDtoStats: make(map[string]*ServerStats)}
|
|
|
+ serverIDtoStats map[string]*serverStats
|
|
|
+}{serverIDtoStats: make(map[string]*serverStats)}
|
|
|
|
|
|
// statsUpdate contains new stats counts to be aggregated.
|
|
|
type statsUpdate struct {
|
|
|
@@ -72,10 +90,9 @@ type statsUpdate struct {
|
|
|
}
|
|
|
|
|
|
// recordStats makes sure the given stats update is added to the global
|
|
|
-// collection. Guaranteed to not block.
|
|
|
-// Callers of this function should assume that it "takes control" of the
|
|
|
-// statsUpdate object.
|
|
|
-func recordStat(stat *statsUpdate) {
|
|
|
+// collection. recentBytes are not adjusted when isPutBack is true,
|
|
|
+// as recentBytes aren't subject to TakeOut/PutBack.
|
|
|
+func recordStat(stat *statsUpdate, isPutBack bool) {
|
|
|
allStats.statsMutex.Lock()
|
|
|
defer allStats.statsMutex.Unlock()
|
|
|
|
|
|
@@ -85,42 +102,31 @@ func recordStat(stat *statsUpdate) {
|
|
|
|
|
|
storedServerStats := allStats.serverIDtoStats[stat.serverID]
|
|
|
if storedServerStats == nil {
|
|
|
- storedServerStats = newServerStats()
|
|
|
+ storedServerStats = &serverStats{
|
|
|
+ accumulatedStats: &AccumulatedStats{
|
|
|
+ hostnameToStats: make(map[string]*hostStats)}}
|
|
|
allStats.serverIDtoStats[stat.serverID] = storedServerStats
|
|
|
}
|
|
|
|
|
|
- storedHostStats := storedServerStats.hostnameToStats[stat.hostname]
|
|
|
+ storedHostStats := storedServerStats.accumulatedStats.hostnameToStats[stat.hostname]
|
|
|
if storedHostStats == nil {
|
|
|
- storedHostStats = newHostStats()
|
|
|
- storedServerStats.hostnameToStats[stat.hostname] = storedHostStats
|
|
|
+ storedHostStats = &hostStats{}
|
|
|
+ storedServerStats.accumulatedStats.hostnameToStats[stat.hostname] = storedHostStats
|
|
|
}
|
|
|
|
|
|
- storedServerStats.totalBytesSent += stat.numBytesSent
|
|
|
- storedServerStats.totalBytesReceived += stat.numBytesReceived
|
|
|
-
|
|
|
storedHostStats.numBytesSent += stat.numBytesSent
|
|
|
storedHostStats.numBytesReceived += stat.numBytesReceived
|
|
|
|
|
|
- //fmt.Println("server:", stat.serverID, "host:", stat.hostname, "sent:", storedHostStats.numBytesSent, "received:", storedHostStats.numBytesReceived)
|
|
|
-}
|
|
|
-
|
|
|
-func (serverStats ServerStats) GetStatsForReporting() (map[string]int64, int64) {
|
|
|
-
|
|
|
- hostBytes := make(map[string]int64)
|
|
|
- bytesTransferred := int64(0)
|
|
|
-
|
|
|
- for hostname, hostStats := range serverStats.hostnameToStats {
|
|
|
- totalBytes := hostStats.numBytesReceived + hostStats.numBytesSent
|
|
|
- bytesTransferred += totalBytes
|
|
|
- hostBytes[hostname] = totalBytes
|
|
|
+ if !isPutBack {
|
|
|
+ storedServerStats.recentBytesSent += stat.numBytesSent
|
|
|
+ storedServerStats.recentBytesReceived += stat.numBytesReceived
|
|
|
}
|
|
|
-
|
|
|
- return hostBytes, bytesTransferred
|
|
|
}
|
|
|
|
|
|
-// GetBytesTransferredForServer returns total bytes sent and received since
|
|
|
-// the last call to GetBytesTransferredForServer.
|
|
|
-func GetBytesTransferredForServer(serverID string) (sent, received int64) {
|
|
|
+// ReportRecentBytesTransferredForServer returns bytes sent and received since
|
|
|
+// the last call to ReportRecentBytesTransferredForServer. The accumulated sent
|
|
|
+// and received are reset to 0 by this call.
|
|
|
+func ReportRecentBytesTransferredForServer(serverID string) (sent, received int64) {
|
|
|
allStats.statsMutex.Lock()
|
|
|
defer allStats.statsMutex.Unlock()
|
|
|
|
|
|
@@ -130,37 +136,47 @@ func GetBytesTransferredForServer(serverID string) (sent, received int64) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- sent = stats.totalBytesSent
|
|
|
- received = stats.totalBytesReceived
|
|
|
+ sent = stats.recentBytesSent
|
|
|
+ received = stats.recentBytesReceived
|
|
|
|
|
|
- stats.totalBytesSent = 0
|
|
|
- stats.totalBytesReceived = 0
|
|
|
+ stats.recentBytesSent = 0
|
|
|
+ stats.recentBytesReceived = 0
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-// GetForServer returns the server stats for the given server.
|
|
|
-func GetForServer(serverID string) (serverStats *ServerStats) {
|
|
|
+// TakeOutStatsForServer borrows the AccumulatedStats for the specified
|
|
|
+// server. When we fail to report these stats, resubmit them with
|
|
|
+// PutBackStatsForServer. Stats will continue to be accumulated between
|
|
|
+// TakeOut and PutBack calls. The recentBytes values are unaffected by
|
|
|
+// TakeOut/PutBack. Returns empty stats if the serverID is not found.
|
|
|
+func TakeOutStatsForServer(serverID string) (accumulatedStats *AccumulatedStats) {
|
|
|
allStats.statsMutex.Lock()
|
|
|
defer allStats.statsMutex.Unlock()
|
|
|
|
|
|
- serverStats = allStats.serverIDtoStats[serverID]
|
|
|
- if serverStats == nil {
|
|
|
- serverStats = newServerStats()
|
|
|
+ newAccumulatedStats := &AccumulatedStats{
|
|
|
+ hostnameToStats: make(map[string]*hostStats)}
|
|
|
+
|
|
|
+ serverStats := allStats.serverIDtoStats[serverID]
|
|
|
+ if serverStats != nil {
|
|
|
+ accumulatedStats = serverStats.accumulatedStats
|
|
|
+ serverStats.accumulatedStats = newAccumulatedStats
|
|
|
+ } else {
|
|
|
+ accumulatedStats = newAccumulatedStats
|
|
|
}
|
|
|
- delete(allStats.serverIDtoStats, serverID)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
-// PutBack re-adds a set of server stats to the collection.
|
|
|
-func PutBack(serverID string, serverStats *ServerStats) {
|
|
|
- for hostname, hoststats := range serverStats.hostnameToStats {
|
|
|
+// PutBackStatsForServer re-adds a set of server stats to the collection.
|
|
|
+func PutBackStatsForServer(serverID string, accumulatedStats *AccumulatedStats) {
|
|
|
+ for hostname, hoststats := range accumulatedStats.hostnameToStats {
|
|
|
recordStat(
|
|
|
&statsUpdate{
|
|
|
serverID: serverID,
|
|
|
hostname: hostname,
|
|
|
numBytesSent: hoststats.numBytesSent,
|
|
|
numBytesReceived: hoststats.numBytesReceived,
|
|
|
- })
|
|
|
+ },
|
|
|
+ true)
|
|
|
}
|
|
|
}
|