commit
55da600433
|
@ -14,6 +14,12 @@ import (
|
||||||
"github.com/thejerf/suture"
|
"github.com/thejerf/suture"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minNegCache = 60 // seconds
|
||||||
|
maxNegCache = 3600 // seconds
|
||||||
|
maxDeviceAge = 7 * 86400 // one week, in seconds
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lruSize = 10240
|
lruSize = 10240
|
||||||
limitAvg = 5
|
limitAvg = 5
|
||||||
|
|
|
@ -4,6 +4,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
@ -100,7 +101,7 @@ func postgresCompile(db *sql.DB) (map[string]*sql.Stmt, error) {
|
||||||
stmts := map[string]string{
|
stmts := map[string]string{
|
||||||
"cleanAddress": "DELETE FROM Addresses WHERE Seen < now() - '2 hour'::INTERVAL",
|
"cleanAddress": "DELETE FROM Addresses WHERE Seen < now() - '2 hour'::INTERVAL",
|
||||||
"cleanRelay": "DELETE FROM Relays WHERE Seen < now() - '2 hour'::INTERVAL",
|
"cleanRelay": "DELETE FROM Relays WHERE Seen < now() - '2 hour'::INTERVAL",
|
||||||
"cleanDevice": "DELETE FROM Devices WHERE Seen < now() - '24 hour'::INTERVAL",
|
"cleanDevice": fmt.Sprintf("DELETE FROM Devices WHERE Seen < now() - '%d hour'::INTERVAL", maxDeviceAge/3600),
|
||||||
"countAddress": "SELECT count(*) FROM Addresses",
|
"countAddress": "SELECT count(*) FROM Addresses",
|
||||||
"countDevice": "SELECT count(*) FROM Devices",
|
"countDevice": "SELECT count(*) FROM Devices",
|
||||||
"countRelay": "SELECT count(*) FROM Relays",
|
"countRelay": "SELECT count(*) FROM Relays",
|
||||||
|
@ -109,6 +110,7 @@ func postgresCompile(db *sql.DB) (map[string]*sql.Stmt, error) {
|
||||||
"insertDevice": "INSERT INTO Devices (DeviceID, Seen) VALUES ($1, now())",
|
"insertDevice": "INSERT INTO Devices (DeviceID, Seen) VALUES ($1, now())",
|
||||||
"selectAddress": "SELECT Address FROM Addresses WHERE DeviceID=$1 AND Seen > now() - '1 hour'::INTERVAL ORDER BY random() LIMIT 16",
|
"selectAddress": "SELECT Address FROM Addresses WHERE DeviceID=$1 AND Seen > now() - '1 hour'::INTERVAL ORDER BY random() LIMIT 16",
|
||||||
"selectRelay": "SELECT Address, Latency FROM Relays WHERE DeviceID=$1 AND Seen > now() - '1 hour'::INTERVAL ORDER BY random() LIMIT 16",
|
"selectRelay": "SELECT Address, Latency FROM Relays WHERE DeviceID=$1 AND Seen > now() - '1 hour'::INTERVAL ORDER BY random() LIMIT 16",
|
||||||
|
"selectDevice": "SELECT Seen FROM Devices WHERE DeviceID=$1",
|
||||||
"updateAddress": "UPDATE Addresses SET Seen=now() WHERE DeviceID=$1 AND Address=$2",
|
"updateAddress": "UPDATE Addresses SET Seen=now() WHERE DeviceID=$1 AND Address=$2",
|
||||||
"updateDevice": "UPDATE Devices SET Seen=now() WHERE DeviceID=$1",
|
"updateDevice": "UPDATE Devices SET Seen=now() WHERE DeviceID=$1",
|
||||||
"deleteRelay": "DELETE FROM Relays WHERE DeviceID=$1",
|
"deleteRelay": "DELETE FROM Relays WHERE DeviceID=$1",
|
||||||
|
|
|
@ -4,6 +4,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/cznic/ql"
|
"github.com/cznic/ql"
|
||||||
|
@ -71,7 +72,7 @@ func qlCompile(db *sql.DB) (map[string]*sql.Stmt, error) {
|
||||||
stmts := map[string]string{
|
stmts := map[string]string{
|
||||||
"cleanAddress": `DELETE FROM Addresses WHERE Seen < now() - duration("2h")`,
|
"cleanAddress": `DELETE FROM Addresses WHERE Seen < now() - duration("2h")`,
|
||||||
"cleanRelay": `DELETE FROM Relays WHERE Seen < now() - duration("2h")`,
|
"cleanRelay": `DELETE FROM Relays WHERE Seen < now() - duration("2h")`,
|
||||||
"cleanDevice": `DELETE FROM Devices WHERE Seen < now() - duration("24h")`,
|
"cleanDevice": fmt.Sprintf(`DELETE FROM Devices WHERE Seen < now() - duration("%dh")`, maxDeviceAge/3600),
|
||||||
"countAddress": "SELECT count(*) FROM Addresses",
|
"countAddress": "SELECT count(*) FROM Addresses",
|
||||||
"countDevice": "SELECT count(*) FROM Devices",
|
"countDevice": "SELECT count(*) FROM Devices",
|
||||||
"countRelay": "SELECT count(*) FROM Relays",
|
"countRelay": "SELECT count(*) FROM Relays",
|
||||||
|
@ -80,6 +81,7 @@ func qlCompile(db *sql.DB) (map[string]*sql.Stmt, error) {
|
||||||
"insertDevice": "INSERT INTO Devices (DeviceID, Seen) VALUES ($1, now())",
|
"insertDevice": "INSERT INTO Devices (DeviceID, Seen) VALUES ($1, now())",
|
||||||
"selectAddress": `SELECT Address from Addresses WHERE DeviceID==$1 AND Seen > now() - duration("1h") LIMIT 16`,
|
"selectAddress": `SELECT Address from Addresses WHERE DeviceID==$1 AND Seen > now() - duration("1h") LIMIT 16`,
|
||||||
"selectRelay": `SELECT Address, Latency from Relays WHERE DeviceID==$1 AND Seen > now() - duration("1h") LIMIT 16`,
|
"selectRelay": `SELECT Address, Latency from Relays WHERE DeviceID==$1 AND Seen > now() - duration("1h") LIMIT 16`,
|
||||||
|
"selectDevice": "SELECT Seen FROM Devices WHERE DeviceID==$1",
|
||||||
"updateAddress": "UPDATE Addresses Seen=now() WHERE DeviceID==$1 AND Address==$2",
|
"updateAddress": "UPDATE Addresses Seen=now() WHERE DeviceID==$1 AND Address==$2",
|
||||||
"updateDevice": "UPDATE Devices Seen=now() WHERE DeviceID==$1",
|
"updateDevice": "UPDATE Devices Seen=now() WHERE DeviceID==$1",
|
||||||
"deleteRelay": "DELETE FROM Relays WHERE DeviceID==$1",
|
"deleteRelay": "DELETE FROM Relays WHERE DeviceID==$1",
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ type querysrv struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type announcement struct {
|
type announcement struct {
|
||||||
|
Seen time.Time
|
||||||
Direct []string `json:"direct"`
|
Direct []string `json:"direct"`
|
||||||
Relays []annRelay `json:"relays"`
|
Relays []annRelay `json:"relays"`
|
||||||
}
|
}
|
||||||
|
@ -57,6 +59,22 @@ func (s *safeCache) Add(key string, val interface{}) {
|
||||||
s.mut.Unlock()
|
s.mut.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func negCacheFor(lastSeen time.Time) int {
|
||||||
|
since := time.Since(lastSeen).Seconds()
|
||||||
|
if since >= maxDeviceAge {
|
||||||
|
return maxNegCache
|
||||||
|
}
|
||||||
|
if since < 0 {
|
||||||
|
// That's weird
|
||||||
|
return minNegCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a value linearly scaled from minNegCache (at zero seconds ago)
|
||||||
|
// to maxNegCache (at maxDeviceAge seconds ago).
|
||||||
|
r := since / maxDeviceAge
|
||||||
|
return int(minNegCache + r*(maxNegCache-minNegCache))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *querysrv) Serve() {
|
func (s *querysrv) Serve() {
|
||||||
s.limiter = &safeCache{
|
s.limiter = &safeCache{
|
||||||
Cache: lru.New(lruSize),
|
Cache: lru.New(lruSize),
|
||||||
|
@ -158,6 +176,18 @@ func (s *querysrv) handleGET(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
var ann announcement
|
var ann announcement
|
||||||
|
|
||||||
|
ann.Seen, err = s.getDeviceSeen(deviceID)
|
||||||
|
negCache := strconv.Itoa(negCacheFor(ann.Seen))
|
||||||
|
w.Header().Set("Retry-After", negCache)
|
||||||
|
w.Header().Set("Cache-Control", "public, max-age="+negCache)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// The device is not in the database.
|
||||||
|
globalStats.Query()
|
||||||
|
http.Error(w, "Not Found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ann.Direct, err = s.getAddresses(deviceID)
|
ann.Direct, err = s.getAddresses(deviceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("getAddresses:", err)
|
log.Println("getAddresses:", err)
|
||||||
|
@ -385,6 +415,15 @@ func (s *querysrv) getAddresses(device protocol.DeviceID) ([]string, error) {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *querysrv) getDeviceSeen(device protocol.DeviceID) (time.Time, error) {
|
||||||
|
row := s.prep["selectDevice"].QueryRow(device.String())
|
||||||
|
var seen time.Time
|
||||||
|
if err := row.Scan(&seen); err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
return seen, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *querysrv) getRelays(device protocol.DeviceID) ([]annRelay, error) {
|
func (s *querysrv) getRelays(device protocol.DeviceID) ([]annRelay, error) {
|
||||||
rows, err := s.prep["selectRelay"].Query(device.String())
|
rows, err := s.prep["selectRelay"].Query(device.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user