prior to returning results.
The adapter uses offsets to enable positional in-
dexes. To find the id corresponding to a positional
index, the adapter performs a query with all filters,
sort orders and an offset equal to that of the positional
index. Due to the limitations on the maximum size
of the offset, the Adapter cannot determine the key
corresponding to a positional index in one query for
indexes larger than 1000. In these cases, the Adapter
uses cursors to step trough each chiliad until a cursor
is obtained for the chiliad in which the index resides.
For example the positional index 1200 would require
the Adapter to first perform a query to find the cur-
sor for the 1000th entity, and subsequently perform a
query with an offset of 200 using that cursor.
3.5 Counting
Vaadin Containers can be queried for the number of
contained items. The size method returns the num-
ber of items. If no filters are applied, the size method
returns the full amount. If filters are applied, the
amount of items matched by the combination of fil-
ters is returned.
Counting the amount of entities matched by a
query is supported by the Datastore, but grows lin-
early in time and is therefore not scalable to large
quantities.
To avoid counting items using queries to the Data-
store when no filters are applied, we store the amount
of items as metadata in the Datastore. This enables
us to determine the size merely by fetching the en-
tity containing the metadata. The metadata is transac-
tionally updated for each add and remove of an item.
This introduces additional overhead to adds and re-
moves but was deemed justifiable in extent to GAE’s
methodology of prioritizing fast reads over writes.
As each combination of filters has its own amount
of items, we do not store the size as metadata when
filters are applied.
4 CACHING PROXY
Our attempted solution to improving latency is a
proxy which a cache consisting of two levels: local
memory and Memcache, with a modular design al-
lowing for more levels to be added.
4.1 Memcache and Local Memory
The GAE platform provides an implementation of
Memcache for caching data. The implementation
uses the standard Memcache API and stored data is
global to the entire application. We use Memcache as
the middle level in our cache hierarchy.
Furthermore, static variables are stored in mem-
ory on server instances between sessions in GAE. The
top level uses this to cache data with a very fast access
speed. The stored data is local to each server. There
is no guarantee to which server instance a particu-
lar request will go (Sanderson, 2009), however in a
cache application context, a request arriving at a new
instance can simply be thought of as a cache miss.
The adapter fetches data in chunks from the Data-
store, enabling preloading. There are performance
benefits from preloading data to UI components, such
as a table, since data is accessed spatially. The chunk
size and life time of data can be specified for each of
the cache levels.
The slower but global Memcache can be config-
ured to bring in larger chunks of data with longer life
time while the local memory level works on smaller
pieces that are refreshed at a higher pace. Since there
could be an arbitrary amount of combinations of ap-
plied filters, we allow the users to decide if positional
indexes should cached when filters are applied.
The implementation for the local memory level
essentially consists of customized linked hash maps.
The size method is extensively used by Vaadin com-
ponents such as Table. To further reduce the latency
of this method, we allow sizes to be cached in the
local memory level. As the conceptual size varies
depending on which filters are applied, the user can
choose whether to cache sizes when filters are ap-
plied. If specified, one size will be cached for each
filter combination. To ensure thread safety, each oper-
ation that changes data in the hash maps uses a Reen-
trant lock for read and write operations.
To customize the memory usage of the local mem-
ory level, maximum capacity for positional indexes,
items and sizes can be specified separately. An up-
date strategy can be chosen for discarding data once
the maximum capacity is reached. We support Least
Recently Used and First In First Out.
4.2 Caching Indexes
One of the biggest challenges for the cache is that the
Vaadin interface does not simply work on key-value
basis but relies on positional indexes to retrieve the
keys. Only caching keys-items would give little per-
formance benefit as querying the Datastore would still
be necessary to determine the positional indexes.
In our implementation we cache both key-item
pairs and positional index-key pairs. Each set of posi-
tional indexes is uniquely identified by its sort orders
and filters. Since the positional indexes vary depend-
CLOSER 2011 - International Conference on Cloud Computing and Services Science
414