All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.appengine.api.datastore.dev.HighRepJobPolicy Maven / Gradle / Ivy

Go to download

SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.31
Show newest version
/*
 * Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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.api.datastore.dev;

import com.google.appengine.api.datastore.Key;

/**
 * A policy for high replication job application. Implementations can decide whether or not a new
 * job should apply and whether or not a job that initially failed to apply should roll forward on
 * subsequent attempts.
 *
 * 

Some implementation details that are pertinent to implementors of this interface: * *

When a user performs a non-transactional Put(), a non-transactional Delete(), or a Commit() of * a transaction to which at least one transactional Put() or Delete() was added, the {@link * LocalDatastoreService} attempts to apply that mutation using a job associated with the entity * group of the mutation. The decision of whether or not the job should apply is delegated to {@link * HighRepJobPolicy#shouldApplyNewJob(Key)}. * *

Unapplied jobs may be rolled forward in two ways: when the consistency model dictates it, and * when an entity group is groomed. We'll discuss these in turn. * *

When the high replication consistency model guarantees that users will see the most up-to-date * values for an entity group, we roll forward unapplied jobs before returning any data from the * entity group. Specifically, a transactional Get() will roll forward any unapplied jobs in the * entity group, as will a non-transactional Get() with the read policy set to STRONG (the default). * A transactional Query (which is by definition an ancestor Query and therefore a scan over the * entities in a single entity group) will also roll forward any unapplied jobs associated with the * entity group of the query before the query executes. * *

Unapplied jobs can also be rolled forward when the entity group with these jobs is groomed. In * production, the groomer is a background process that is continuously scanning and rolling forward * unapplied jobs. We considered implementing something similar, but it's nearly impossible to write * tests in an environment where you have a background process randomly adjusting your persistent * state, so we opted for a different approach: the local datastore groomer looks at all unapplied * jobs on every Get() and every Query(), and for each unapplied job, consults {@link * HighRepJobPolicy#shouldRollForwardExistingJob(Key)} to see if that job should be rolled forward. * This simulates grooming, but in a deterministic manner that makes testing much more * straightforward. * *

Note, however, that when the groomer rolls these jobs forward, it does so in such a way that * the result of the operation being performed is not affected. This is important, because it * guarantees that when a job fails to apply, a user who reads the entity group without any strong * consistency guarantees will always see the "old" version of the data in the entity group at least * once. Without this guarantee we would have jobs that failed to apply but whose failure was * invisible, which defeats the purpose of what we're trying to simulate. * */ // It's a little wonky to be using a low-level API object in the local // datastore, but it's not unheard of. Here's the reason we do it: This // interface is exposed via the testing apis so that developers can provide // their own implementations, and I'd much rather have people coding against // Key, which is part of the public api, than Onestore.Path, which is not. public interface HighRepJobPolicy { /** * Returns {@code true} if the new job should apply according to the policy, {@code false} * otherwise. * * @param entityGroup A unique identifier for the entity group. */ boolean shouldApplyNewJob(Key entityGroup); /** * Returns {@code true} if the existing job should roll forward according to the policy, {@code * false} otherwise. * * @param entityGroup A unique identifier for the entity group. */ boolean shouldRollForwardExistingJob(Key entityGroup); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy