Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added memcache sample #4

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions memcache/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>

<groupId>com.google.appengine.samples.memcache</groupId>
<artifactId>memcache</artifactId>

<properties>
<appengine.app.version>1</appengine.app.version>
<appengine.version>1.9.18</appengine.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<prerequisites>
<maven>3.1.0</maven>
</prerequisites>

<dependencies>
<!-- Compile/runtime dependencies -->
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>${appengine.version}</version>
</dependency>
</dependencies>

<build>
<!-- for hot reload of the web application-->
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>display-dependency-updates</goal>
<goal>display-plugin-updates</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>3.1</version>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<archiveClasses>true</archiveClasses>
<webResources>
<!-- in order to interpolate version from pom into appengine-web.xml -->
<resource>
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
<filtering>true</filtering>
<targetPath>WEB-INF</targetPath>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.15</version>
<executions>
<execution>
<id>checkstyle</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<failOnViolation>true</failOnViolation>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* Copyright 2015 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.google.appengine.samples.memcache;

import com.google.appengine.api.memcache.AsyncMemcacheService;
import com.google.appengine.api.memcache.ErrorHandlers;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.utils.FutureWrapper;

import java.util.Map;
import java.util.concurrent.Future;
import java.util.logging.Level;

/**
* Example asynchronous usage of App Engine Memcache.
* AsyncMemcache wraps a "slow" map with the memcache service.
*/
public class AsyncMemcache {

/**
* the backing map for the memcache.
*/
private Map<String, byte[]> map;

/**
* Singleton App Engine Memcache service.
*/
private static AsyncMemcacheService asyncCache = null;

/**
* a Lock to ensure that asyncCache is a threadsafe singleton.
*/
private static final Object MEMCACHE_LOCK = new Object();

/**
* @param slowMap a Map<String, byte[]> for which retrieval is quite expensive
*/
public AsyncMemcache(final Map<String, byte[]> slowMap) {
this.map = slowMap;
}

/**
* @param key the String key used for lookup
* @return a Future<byte[]> which can be used to retrieve the value
**/
public final Future<byte[]> get(final String key) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this methodwrapper is overkill for the entry-level document and also slowMap here is not apealing to me (I assume some RPCs for slow operation).

Is it possible to just keep the current style in the snippet?

return new FutureWrapper<Object, byte[]>(asyncCache.get(key)) {

@Override
protected Throwable convertException(final Throwable arg0) {
return arg0;
}

@Override
protected byte[] wrap(final Object arg0) throws Exception {
byte[] value = (byte[]) arg0;
if (arg0 == null) {
value = map.get(key);
asyncCache.put(key, arg0);
}
return value;
}
};
}
/**
* @return this instances singleton asyncCache service.
*/
public final AsyncMemcacheService getService() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you avoid double-checked locking?
I think you can just use static block to initialize the service.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would still need to synchronize for it to be threadsafe but it might clean it up a little.

EDIT: nevemind misunderstood your comment. Will update.

if (asyncCache == null) {
synchronized (MEMCACHE_LOCK) {
if (asyncCache == null) {
asyncCache = MemcacheServiceFactory.getAsyncMemcacheService();
asyncCache.setErrorHandler(
ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
}
}
}
return asyncCache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* Copyright 2015 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.google.appengine.samples.memcache;

import com.google.appengine.api.memcache.ErrorHandlers;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;

import java.util.Map;
import java.util.logging.Level;

/**
* Example synchronous usage of App Engine Memcache.
* SyncMemcache wraps a "slow" map with the memcache service.
*/
public class SyncMemcache {

/**
* the backing map for the memcache.
*/
private Map<String, byte[]> map;

/**
* Singleton App Engine Memcache service.
*/
private static MemcacheService syncCache = null;

/**
* a Lock to ensure that syncCache is a threadsafe singleton.
*/
private static final Object MEMCACHE_LOCK = new Object();

/**
* @param slowMap a Map<String, byte[]> for which retrieval is quite expensive
*/

/**
* @param slowMap a Map<String, byte[]> for which retrieval is quite expensive
*/
public SyncMemcache(final Map<String, byte[]> slowMap) {
this.map = slowMap;
}

/**
* @param key the String key used for lookup
* @return a byte[] representing the stored value
**/
public final byte[] get(final String key) {
byte[] value = (byte[]) syncCache.get(key);
if (value == null) {
value = map.get(key);
syncCache.put(key, value);
}
return value;
}

/**
* @return this instances singleton syncCache service.
*/
public final MemcacheService getService() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

if (syncCache == null) {
synchronized (MEMCACHE_LOCK) {
if (syncCache == null) {
syncCache = MemcacheServiceFactory.getMemcacheService();
syncCache.setErrorHandler(
ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
}
}
}
return syncCache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* Copyright 2015 Google Inc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this code supposed to teach developers? @elibixby, nm. I just saw your comment. I'll look at it again.


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.google.appengine.samples.memcache;

import com.google.appengine.api.memcache.ErrorHandlers;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;

import java.util.logging.Level;

/**
* Example synchronous usage of App Engine Memcache.
* SyncMemcache wraps a "slow" map with the memcache service.
*/
public class ThreadsafeMemcacheUpdater {

/**
* class wrapper for byte[] -> byte[] update function.
*/
public abstract class Updater {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No concrete class?


/**
* @param value byte[] the old value
* @return byte[] the new value
*/
public abstract byte[] update(byte[] value);

}

/**
* Singleton App Engine Memcache service.
*/
private static MemcacheService syncCache = null;

/**
* a Lock to ensure that syncCache is a threadsafe singleton.
*/
private static final Object MEMCACHE_LOCK = new Object();

/**
* Empty constructor.
*/
public ThreadsafeMemcacheUpdater() {
}

/**
* @param key the String identifying which value to update
* @param update an Update wrapper which represents the function to apply
* @return boolean indicating if the value was successfully updated
*/
public final boolean update(final String key, final Updater update) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I still don't know how to use this class. Can you show me an example usage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was an attempt to create a more flexible wrapper, but I'm not sure I ended up simplifying things at all. I'll provide a concrete example instead.

MemcacheService.IdentifiableValue oldValue = syncCache.getIdentifiable(key);
if (oldValue == null) {
syncCache.put(key, update.update(null));
return true;
} else {
return syncCache.putIfUntouched(key,
oldValue,
update.update((byte[]) oldValue.getValue()));
}
}


/**
* @return this instances singleton syncCache service.
*/
public final MemcacheService getService() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

if (syncCache == null) {
synchronized (MEMCACHE_LOCK) {
if (syncCache == null) {
syncCache = MemcacheServiceFactory.getMemcacheService();
syncCache.setErrorHandler(
ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
}
}
}
return syncCache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

/**
* Sample usage of the App Engine Memcache service.
*/
package com.google.appengine.samples.memcache;
Loading