Ventosus
Ventosus

Reputation: 449

store multiple values in maps

problem: Store both an IP address as well as a time to a counter. something like this

ip, time, count

and then i would like to be able to increment the count for each ip:

ip++

in my map, and then on a given interval, i would like to iterate all keys and find the keys with a time stamp older than N minutes.

I need this to make sure i don't "forget" a key in memory if for some reason, client disconnect and i dont delete the key properly.

http://play.golang.org/p/RiWWOCARq7

Question: How do i add a time stamp to every IP address i store in my map. Also i need this be be used across multiple go routines

Im new to both programming and Golang, so if this is not even the correct approach, if anyone could point me in the right direction, i would appreciate it.

Upvotes: 5

Views: 17001

Answers (3)

Matt Harrison
Matt Harrison

Reputation: 13567

It sounds like you need a struct. A map is for storing a collection where all the keys are of one type and all the elements are of another (or the same type).

For grouping a collection of variables of different data types, that are related, use a struct

e.g.

type IPCounter struct {
    ip    string
    time  time.Time
    count int
}

Here's some sample code that creates one of these objects and increments the count:

package main

import (
    "fmt"
    "time"
)

type IPAddressCounter struct {
    ip    string
    time  time.Time
    count int
}

func (i *IPAddressCounter) IncrementCount() {
    i.count++
}

func makeCounter(ip string) IPAddressCounter {
    return IPAddressCounter{
        ip:   ip,
        time: time.Now(),
    }
}

func main() {
    mapOfIPCounters := make(map[string]IPAddressCounter)

    mapOfIPCounters["192.168.1.1"] = makeCounter("192.168.1.1")
    mapOfIPCounters["192.168.1.2"] = makeCounter("192.168.1.2")
    mapOfIPCounters["192.168.1.3"] = makeCounter("192.168.1.3")

    for key, value := range mapOfIPCounters {
        value.IncrementCount()
        mapOfIPCounters[key] = value

        fmt.Println("The counter for "+key+" is", mapOfIPCounters[key].count)
    }

}

Upvotes: 2

peterSO
peterSO

Reputation: 166598

For example,

package main

import (
    "sync"
    "time"
)

type IPCounter struct {
    IPAddr string
    Time   time.Time
    Count  int
}

type ipCounterMap struct {
    counters map[string]IPCounter
    mutex    sync.RWMutex
}

var ipCounters = ipCounterMap{counters: make(map[string]IPCounter)}

// Get IP address counter
func Counter(ipAddr string) IPCounter {
    ipCounters.mutex.RLock()
    defer ipCounters.mutex.RUnlock()
    counter, found := ipCounters.counters[ipAddr]
    if !found {
        counter.IPAddr = ipAddr
    }
    return counter
}

// Increment IP address counter
func Incr(ipAddr string) {
    now := time.Now().UTC()
    ipCounters.mutex.Lock()
    defer ipCounters.mutex.Unlock()
    counter, found := ipCounters.counters[ipAddr]
    if !found {
        counter.IPAddr = ipAddr
    }
    counter.Time = now
    counter.Count++
    ipCounters.counters[ipAddr] = counter
}

// Delete IP address counter
func Delete(ipAddr string) {
    ipCounters.mutex.Lock()
    defer ipCounters.mutex.Unlock()
    delete(ipCounters.counters, ipAddr)
}

// Get old IP address counters old durations ago
func OldIPCounters(old time.Duration) []IPCounter {
    var counters []IPCounter
    oldTime := time.Now().UTC().Add(-old)
    ipCounters.mutex.RLock()
    defer ipCounters.mutex.RUnlock()
    for _, counter := range ipCounters.counters {
        if counter.Time.Before(oldTime) {
            counters = append(counters, counter)
        }
    }
    return counters
}

func main() {}

Upvotes: 11

David Budworth
David Budworth

Reputation: 11626

You probably want a map of ip -> struct { ip, counter, lastTime } that way, you can look up the counter by ip and then update it

var Counters = map[string]*Counter{}

type Counter struct {
    ip       string
    count    int
    lastTime time.Time
}

Here's a working example on Play http://play.golang.org/p/TlCTc_4iq5

Adding the find older than is simply range over the values of the map comparing to now and do something when it's old enough.

Upvotes: 5

Related Questions