-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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) { | ||
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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you avoid double-checked locking? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; |
There was a problem hiding this comment.
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?