blob: 604309050b76de788e24e487c057d57b29771ee8 [file] [log] [blame]
/*
* Copyright 2016 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)
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_DEPENDENCY_TRACKER_H_
#define NET_INSTAWEB_REWRITER_PUBLIC_DEPENDENCY_TRACKER_H_
#include <memory>
#include "net/instaweb/rewriter/dependencies.pb.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/thread_annotations.h"
namespace net_instaweb {
class AbstractMutex;
class RewriteDriver;
class ServerContext;
// Helper for keeping track of what resources a page depends on --- it helps
// decode information saved in property cache, and to assemble information
// collected from the actual page to update it.
//
// The Register/Report methods are thread-safe.
// TODO(morlovich): Might need merging strategy for stability.
class DependencyTracker {
public:
// Note: you must also call SetServerContext on this before operation.
explicit DependencyTracker(RewriteDriver* driver);
~DependencyTracker();
// This needs to be called to help initialize locking.
void SetServerContext(ServerContext* server_context);
// Must be called when parsing pages, after pcache has read in.
void Start();
// Must be called after the last flush window has been processed, so we
// know no further processing.
void FinishedParsing();
// Notices the tracker that some filter may be trying to compute a dependency
// asynchronously. This returns an ID which should then be passed to
// ReportDependencyCandidate();
int RegisterDependencyCandidate();
// Reports result of a dependency computation. You must call
// ReportDependencyCandidate() for every RegisterDependencyCandidate()
// call, but it can report that the lead didn't checkout by setting dep to
// nullptr.
//
// 'id' must be the result of the corresponding RegisterDependencyCandidate()
// call.
// 'dep' is the dependency summary for the resource in question, and may be
// nullptr if there doesn't seem to be something we want to push there
// (e.g. it got removed due to combining). *dep will be copied in,
// so only needs to be alive for the duration of the call.
void ReportDependencyCandidate(int id, const Dependency* dep);
// This is temporary, nicer API coming later.
const Dependencies* read_in_info() const { return read_in_info_.get(); }
private:
void Clear() LOCKS_EXCLUDED(mutex_);
void ClearLockHeld() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void WriteToPropertyCacheIfDone() EXCLUSIVE_LOCKS_REQUIRED(mutex_);
RewriteDriver* driver_;
std::unique_ptr<AbstractMutex> mutex_;
// Info we read in from property cache --- used to make decisions about
// the current page.
std::unique_ptr<Dependencies> read_in_info_;
// Things we compute on the current page.
// This uses std::map so we can get a stable sort in document order.
std::map<int, Dependency> computed_info_ GUARDED_BY(mutex_);
int next_id_ GUARDED_BY(mutex_);
int outstanding_candidates_ GUARDED_BY(mutex_);
// Called on ... so we know when we can finally commit results to property
// cache once number of outstanding candidates goes to 0.
bool saw_end_ GUARDED_BY(mutex_);
DISALLOW_COPY_AND_ASSIGN(DependencyTracker);
};
// Compares two Dependency objects based on the order_key field.
class DependencyOrderCompator {
public:
bool operator()(const Dependency& a, const Dependency& b);
};
} // namespace net_instaweb
#endif // NET_INSTAWEB_REWRITER_PUBLIC_DEPENDENCY_TRACKER_H_