|  | /* | 
|  | * Copyright 2013 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. | 
|  | */ | 
|  |  | 
|  | // Author: morlovich@google.com (Maksim Orlovich) | 
|  | // | 
|  | // This contains some utilities that make it easier to work | 
|  | // with the property cache. | 
|  |  | 
|  | #ifndef NET_INSTAWEB_REWRITER_PUBLIC_PROPERTY_CACHE_UTIL_H_ | 
|  | #define NET_INSTAWEB_REWRITER_PUBLIC_PROPERTY_CACHE_UTIL_H_ | 
|  |  | 
|  | #include "net/instaweb/rewriter/public/rewrite_driver.h" | 
|  | #include "net/instaweb/rewriter/public/server_context.h" | 
|  | #include "net/instaweb/util/public/property_cache.h" | 
|  | #include "pagespeed/kernel/base/basictypes.h" | 
|  | #include "pagespeed/kernel/base/proto_util.h" | 
|  | #include "pagespeed/kernel/base/scoped_ptr.h" | 
|  | #include "pagespeed/kernel/base/string.h" | 
|  | #include "pagespeed/kernel/base/string_util.h" | 
|  |  | 
|  | namespace net_instaweb { | 
|  |  | 
|  | enum PropertyCacheDecodeResult { | 
|  | kPropertyCacheDecodeNotFound,  // includes property cache not being enabled. | 
|  | kPropertyCacheDecodeExpired, | 
|  | kPropertyCacheDecodeParseError, | 
|  | kPropertyCacheDecodeOk | 
|  | }; | 
|  |  | 
|  | // Returns PropertyValue object for given cohort and property name, | 
|  | // setting *status and returning NULL if any errors were found. | 
|  | const PropertyValue* DecodeFromPropertyCacheHelper( | 
|  | const PropertyCache* cache, | 
|  | AbstractPropertyPage* page, | 
|  | const PropertyCache::Cohort* cohort, | 
|  | StringPiece property_name, | 
|  | int64 cache_ttl_ms, | 
|  | PropertyCacheDecodeResult* status); | 
|  |  | 
|  | // Decodes a protobuf of type T from the property named 'property_name' in the | 
|  | // cohort 'cohort_name' in the given property cache, and makes sure it has not | 
|  | // exceeded its TTL of 'cache_ttl_ms' (a value of -1 will disable this check). | 
|  | // | 
|  | // *status will denote the decoding state; if it's kPropertyCacheDecodeOk | 
|  | // then a pointer to a freshly allocated decoded proto is returned; otherwise | 
|  | // NULL is returned. | 
|  | template<typename T> | 
|  | T* DecodeFromPropertyCache(const PropertyCache* cache, | 
|  | AbstractPropertyPage* page, | 
|  | const PropertyCache::Cohort* cohort, | 
|  | StringPiece property_name, | 
|  | int64 cache_ttl_ms, | 
|  | PropertyCacheDecodeResult* status) { | 
|  | const PropertyValue* property_value = | 
|  | DecodeFromPropertyCacheHelper(cache, page, cohort, property_name, | 
|  | cache_ttl_ms, status); | 
|  | if (property_value == NULL) { | 
|  | // *status set by helper | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | scoped_ptr<T> result(new T); | 
|  | ArrayInputStream input(property_value->value().data(), | 
|  | property_value->value().size()); | 
|  | if (!result->ParseFromZeroCopyStream(&input)) { | 
|  | *status = kPropertyCacheDecodeParseError; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | *status = kPropertyCacheDecodeOk; | 
|  | return result.release(); | 
|  | } | 
|  |  | 
|  | // Wrapper version of the above function that gets the property cache and the | 
|  | // property page from the given driver. | 
|  | template<typename T> | 
|  | T* DecodeFromPropertyCache(RewriteDriver* driver, | 
|  | const PropertyCache::Cohort* cohort, | 
|  | StringPiece property_name, | 
|  | int64 cache_ttl_ms, | 
|  | PropertyCacheDecodeResult* status) { | 
|  | return DecodeFromPropertyCache<T>( | 
|  | driver->server_context()->page_property_cache(), | 
|  | driver->property_page(), | 
|  | cohort, | 
|  | property_name, | 
|  | cache_ttl_ms, | 
|  | status); | 
|  | } | 
|  |  | 
|  | enum PropertyCacheUpdateResult { | 
|  | kPropertyCacheUpdateNotFound,  // can't find existing value to update | 
|  | kPropertyCacheUpdateEncodeError, | 
|  | kPropertyCacheUpdateOk | 
|  | }; | 
|  |  | 
|  | PropertyCacheUpdateResult UpdateInPropertyCache( | 
|  | const protobuf::MessageLite& value, | 
|  | const PropertyCache::Cohort* cohort, | 
|  | StringPiece property_name, | 
|  | bool write_cohort, | 
|  | AbstractPropertyPage* page); | 
|  |  | 
|  | // Updates the property 'property_name' in cohort 'cohort_name' of the property | 
|  | // cache managed by the rewrite driver with the new value of the proto T. | 
|  | // If 'write_cohort' is true, will also additionally write out the cohort | 
|  | // to the cache backing. | 
|  | inline PropertyCacheUpdateResult UpdateInPropertyCache( | 
|  | const protobuf::MessageLite& value, RewriteDriver* driver, | 
|  | const PropertyCache::Cohort* cohort, StringPiece property_name, | 
|  | bool write_cohort) { | 
|  | AbstractPropertyPage* page = driver->property_page(); | 
|  | return UpdateInPropertyCache( | 
|  | value, cohort, property_name, write_cohort, page); | 
|  | } | 
|  |  | 
|  | }  // namespace net_instaweb | 
|  |  | 
|  | #endif  // NET_INSTAWEB_REWRITER_PUBLIC_PROPERTY_CACHE_UTIL_H_ |