func handler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	// [START intro_2]
	// Create an Item
	item := &memcache.Item{
		Key:   "lyric",
		Value: []byte("Oh, give me a home"),
	}
	// Add the item to the memcache, if the key does not already exist
	if err := memcache.Add(ctx, item); err == memcache.ErrNotStored {
		log.Infof(ctx, "item with key %q already exists", item.Key)
	} else if err != nil {
		log.Errorf(ctx, "error adding item: %v", err)
	}

	// Change the Value of the item
	item.Value = []byte("Where the buffalo roam")
	// Set the item, unconditionally
	if err := memcache.Set(ctx, item); err != nil {
		log.Errorf(ctx, "error setting item: %v", err)
	}

	// Get the item from the memcache
	if item, err := memcache.Get(ctx, "lyric"); err == memcache.ErrCacheMiss {
		log.Infof(ctx, "item not in the cache")
	} else if err != nil {
		log.Errorf(ctx, "error getting item: %v", err)
	} else {
		log.Infof(ctx, "the lyric is %q", item.Value)
	}
	// [END intro_2]

}
Example #2
0
// create a message
func handleIndex(res http.ResponseWriter, req *http.Request) {
	ctx := appengine.NewContext(req)

	// form submit
	if req.Method == "POST" {
		msg := req.FormValue("message")
		secretKey := generatePassword()
		encryptedMessage := encrypt(msg, secretKey)

		messageKey, _ := uuid.NewV4()
		// store the message in memcache
		item := &memcache.Item{
			Key:   messageKey.String(),
			Value: []byte(encryptedMessage),
		}
		err := memcache.Add(ctx, item)
		if err != nil {
			http.Error(res, err.Error(), 500)
			return
		}
		io.WriteString(res, `<!DOCTYPE html>
<html>
  <head>

  </head>
  <body>
    Here is your self-destructing secret message ID:
    <a href="/msg/`+messageKey.String()+`?secret=`+fmt.Sprintf("%x", secretKey)+`">`+messageKey.String()+`</a>
    Send it to Peter Graves.
    <p>The encrypted message:</p>
    <p>`+encryptedMessage+`</p>
  </body>
</html>`)
	} else {

		// render the form
		io.WriteString(res, `<!DOCTYPE html>
  <html>
    <head>

    </head>
    <body>
      <form method="POST">
        <label>Message:
          <textarea name="message"></textarea>
        </label><br>
        <input type="submit">
      </form>
    </body>
  </html>`)
	}

}
Example #3
0
File: main.go Project: golang/gddo
func servePresentation(w http.ResponseWriter, r *http.Request) error {
	ctx := appengine.NewContext(r)
	importPath := r.URL.Path[1:]

	item, err := memcache.Get(ctx, importPath)
	if err == nil {
		writeHTMLHeader(w, 200)
		w.Write(item.Value)
		return nil
	} else if err != memcache.ErrCacheMiss {
		log.Errorf(ctx, "Could not get item from Memcache: %v", err)
	}

	log.Infof(ctx, "Fetching presentation %s.", importPath)
	pres, err := getPresentation(httpClient(r), importPath)
	if err != nil {
		return err
	}
	parser := &present.Context{
		ReadFile: func(name string) ([]byte, error) {
			if p, ok := pres.Files[name]; ok {
				return p, nil
			}
			return nil, presFileNotFoundError(name)
		},
	}
	doc, err := parser.Parse(bytes.NewReader(pres.Files[pres.Filename]), pres.Filename, 0)
	if err != nil {
		return err
	}

	var buf bytes.Buffer
	if err := renderPresentation(&buf, importPath, doc); err != nil {
		return err
	}

	if err := memcache.Add(ctx, &memcache.Item{
		Key:        importPath,
		Value:      buf.Bytes(),
		Expiration: time.Hour,
	}); err != nil {
		log.Errorf(ctx, "Could not cache presentation %s: %v", importPath, err)
		return nil
	}

	writeHTMLHeader(w, 200)
	_, err = w.Write(buf.Bytes())
	return err
}
Example #4
0
// create a message
func index(res http.ResponseWriter, req *http.Request) {
	ctx := appengine.NewContext(req)

	// form submit
	if req.Method == "POST" {
		msg := req.FormValue("message")
		key, _ := uuid.NewV4()
		// store the message in memcache
		item := &memcache.Item{
			Key:   key.String(),
			Value: []byte(msg),
		}
		err := memcache.Add(ctx, item)
		if err != nil {
			http.Error(res, err.Error(), 500)
			return
		}
		io.WriteString(res, `<!DOCTYPE html>
<html>
  <head>

  </head>
  <body>
    Here is your self-destructing secret message ID:
    <a href="/msg/`+key.String()+`">`+key.String()+`</a>
  </body>
</html>`)
	} else {

		// render the form
		io.WriteString(res, `<!DOCTYPE html>
  <html>
    <head>

    </head>
    <body>
      <form method="POST">
        <label>Message:
          <textarea name="message"></textarea>
        </label><br>
        <input type="submit">
      </form>
    </body>
  </html>`)
	}

}
Example #5
0
func TestPresentationCacheHit(t *testing.T) {
	do(t, "GET", "/"+importPath, func(r *http.Request) {
		cachedPresentation := "<div>My Presentation</div>"

		c := appengine.NewContext(r)
		memcache.Add(c, &memcache.Item{
			Key:        importPath,
			Value:      []byte(cachedPresentation),
			Expiration: time.Hour,
		})

		w := httptest.NewRecorder()
		handlerFunc(serveRoot).ServeHTTP(w, r)

		if w.Code != http.StatusOK {
			t.Fatalf("expected status: %d, got: %d", http.StatusOK, w.Code)
		}

		if w.Body.String() != cachedPresentation {
			t.Fatal("response does not matched cached presentation")
		}
	})
}
Example #6
0
// McacheSet is a generic memcache saving function.
// It takes scalars as well as structs.
//
// Integers and strings   are put into the memcache Value []byte
// structs			      are put into the memcache *Object* - using memcache.JSON
// Todo: types WrapString and WrapInt should be handled like string/int
//
// Scalars are tentatively saved using the CAS (compare and save) methods
func McacheSet(c context.Context, skey string, str_int_struct interface{}) {

	var err error
	var val string

	tMold := reflect.TypeOf(str_int_struct)
	stMold := tMold.Name()                     // strangely this is empty
	stMold = fmt.Sprintf("%T", str_int_struct) // unlike this

	if stMold != "int" &&
		stMold != "string" &&
		stMold != "dsu.WrapInt" &&
		stMold != "dsu.WrapString" &&
		stMold != "*filesys.fs" &&
		stMold != "*filesys.fso" {
		// struct - save it with JSON encoder
		if ll > 2 {
			aelog.Infof(c, "%v", stMold)
		}
		n := tMold.NumField()
		_ = n
		miPut := &memcache.Item{
			Key:        skey,
			Value:      []byte(tMold.Name()), // sadly - value is ignored
			Object:     &str_int_struct,
			Expiration: 3600 * time.Second,
		}
		memcache.JSON.Set(c, miPut)
		if ll > 2 {
			aelog.Infof(c, "mcache set obj key %v[%s]  - err %v", skey, stMold, err)
		}

	} else {
		// scalar value - save it
		switch chamaeleon := str_int_struct.(type) {
		default:
			panic(fmt.Sprintf("only string or int - instead: -%T", str_int_struct))
		case nil:
			val = ""
		case WrapString:
			val = chamaeleon.S
		case string:
			val = chamaeleon
		case int:
			val = util.Itos(chamaeleon)
		case WrapInt:
			val = util.Itos(chamaeleon.I)
		}

		/*
			This is a Compare and Set (CAS) implementation of "set".
			It implements optimistic locking.

			We fetch the item first, then modify it, then put it back.
			We rely on the hidden "casID" of the memcache item,
				to detect intermittent changes by competitors.

			Biggest downside is the additional roundtrip for the fetch.
			Second downside: We should implement a retry after failure.
				Instead I resorted to a simple "SET"

			Upside: Prevention of race conditions.
				But race conditions only matter if newval = f(oldval)
				Otherwise last one wins should apply anyway.

		*/

		maxTries := 3

		miCas, eget := memcache.Get(c, skey) // compare and swap

		for i := 0; i <= maxTries; i++ {

			if i == maxTries {
				panic(fmt.Sprintf("memcache set CAS failed after %v attempts", maxTries))
			}

			var eput error
			var putMode = ""
			if eget != memcache.ErrCacheMiss {
				putMode = "CAS"
				miCas.Value = []byte(val)
				eput = memcache.CompareAndSwap(c, miCas)
			} else {
				putMode = "ADD"
				miCas := &memcache.Item{
					Key:   skey,
					Value: []byte(val),
				}
				eput = memcache.Add(c, miCas)
			}

			if eput == memcache.ErrCASConflict {
				aelog.Errorf(c, "\t memcache CAS  FAILED - concurrent update?")
				// we brutally fallback to set():
				miCas := &memcache.Item{
					Key:   skey,
					Value: []byte(val),
				}
				eset := memcache.Set(c, miCas)
				if ll > 2 {
					aelog.Infof(c, "%v", eset)
				}
				time.Sleep(10 * time.Millisecond)
				continue
			}
			if eput == memcache.ErrNotStored {
				aelog.Errorf(c, "\t memcache save FAILED - no idea why it would")
				time.Sleep(10 * time.Millisecond)
				continue
			}
			if ll > 2 {
				aelog.Infof(c, "mcache set scalar %v[%T]=%v - mode %v - eget/eput: %v/%v",
					skey, str_int_struct, val, putMode, eget, eput)
			}
			break
		}

	}

}