| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- package main
- import (
- // "bufio"
- "encoding/gob"
- "io"
- "log"
- "os"
- "sync"
- )
- const saveQueueLength = 1000
- type URLStore struct {
- urls map[string]string
- mu sync.RWMutex
- save chan record
- }
- type record struct {
- Key, URL string
- }
- func NewURLStore(filename string) *URLStore {
- s := &URLStore{
- urls: make(map[string]string),
- save: make(chan record, saveQueueLength),
- }
- if err := s.load(filename); err != nil {
- log.Println("Error loading URLStore:", err)
- }
- go s.saveLoop(filename)
- return s
- }
- func (s *URLStore) Get(key string) string {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return s.urls[key]
- }
- func (s *URLStore) Set(key, url string) bool {
- s.mu.Lock()
- defer s.mu.Unlock()
- if _, present := s.urls[key]; present {
- return false
- }
- s.urls[key] = url
- return true
- }
- func (s *URLStore) Count() int {
- s.mu.RLock()
- defer s.mu.RUnlock()
- return len(s.urls)
- }
- func (s *URLStore) Put(url string) string {
- for {
- key := genKey(s.Count())
- if ok := s.Set(key, url); ok {
- s.save <- record{key, url}
- return key
- }
- }
- panic("shouldn't get here")
- }
- func (s *URLStore) load(filename string) error {
- f, err := os.Open(filename)
- if err != nil {
- log.Println("Error opening URLStore:", err)
- return err
- }
- defer f.Close()
- // buffered reading:
- // b := bufio.NewReader(f)
- // d := gob.NewDecoder(b)
- d := gob.NewDecoder(f)
- for err == nil {
- var r record
- if err = d.Decode(&r); err == nil {
- s.Set(r.Key, r.URL)
- }
- }
- if err == io.EOF {
- return nil
- }
- // error occurred:
- log.Println("Error decoding URLStore:", err) // map hasn't been read correctly
- return err
- }
- func (s *URLStore) saveLoop(filename string) {
- f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
- if err != nil {
- log.Fatal("Error opening URLStore: ", err)
- }
- defer f.Close()
- e := gob.NewEncoder(f)
- // buffered encoding:
- // b := bufio.NewWriter(f)
- // e := gob.NewEncoder(b)
- // defer b.Flush()
- for {
- r := <-s.save // takes a record from the channel
- if err := e.Encode(r); err != nil {
- log.Println("Error saving to URLStore: ", err)
- }
- }
- }
|