ff5f8820dda9b90cb7aae48efc2514f697acb65c
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / actors / dds / DistributedDataStoreClientBehavior.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.databroker.actors.dds;
9
10 import akka.actor.ActorRef;
11 import akka.actor.Status;
12 import java.util.concurrent.CompletableFuture;
13 import java.util.concurrent.CompletionStage;
14 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
15 import org.opendaylight.controller.cluster.datastore.actors.client.ClientActorBehavior;
16 import org.opendaylight.controller.cluster.datastore.actors.client.ClientActorContext;
17 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 /**
22  * {@link ClientActorBehavior} acting as an intermediary between the backend actors and the DistributedDataStore
23  * frontend.
24  *
25  * This class is not visible outside of this package because it breaks the actor containment. Services provided to
26  * Java world outside of actor containment are captured in {@link DistributedDataStoreClient}.
27  *
28  * IMPORTANT: this class breaks actor containment via methods implementing {@link DistributedDataStoreClient} contract.
29  *            When touching internal state, be mindful of the execution context from which execution context, Actor
30  *            or POJO, is the state being accessed or modified.
31  *
32  * THREAD SAFETY: this class must always be kept thread-safe, so that both the Actor System thread and the application
33  *                threads can run concurrently. All state transitions must be made in a thread-safe manner. When in
34  *                doubt, feel free to synchronize on this object.
35  *
36  * PERFORMANCE: this class lies in a performance-critical fast path. All code needs to be concise and efficient, but
37  *              performance must not come at the price of correctness. Any optimizations need to be carefully analyzed
38  *              for correctness and performance impact.
39  *
40  * TRADE-OFFS: part of the functionality runs in application threads without switching contexts, which makes it ideal
41  *             for performing work and charging applications for it. That has two positive effects:
42  *             - CPU usage is distributed across applications, minimizing work done in the actor thread
43  *             - CPU usage provides back-pressure towards the application.
44  *
45  * @author Robert Varga
46  */
47 final class DistributedDataStoreClientBehavior extends ClientActorBehavior implements DistributedDataStoreClient {
48     private static final Logger LOG = LoggerFactory.getLogger(DistributedDataStoreClientBehavior.class);
49
50     private final ModuleShardBackendResolver resolver;
51     private long nextHistoryId;
52
53     DistributedDataStoreClientBehavior(final ClientActorContext context, final ActorContext actorContext) {
54         super(context);
55         resolver = new ModuleShardBackendResolver(actorContext);
56     }
57
58     //
59     //
60     // Methods below are invoked from the client actor thread
61     //
62     //
63
64     @Override
65     protected void haltClient(final Throwable cause) {
66         // FIXME: Add state flushing here once we have state
67     }
68
69     private ClientActorBehavior createLocalHistory(final CompletableFuture<ClientLocalHistory> future) {
70         final LocalHistoryIdentifier historyId = new LocalHistoryIdentifier(getIdentifier(), nextHistoryId++);
71         LOG.debug("{}: creating a new local history {} for {}", persistenceId(), historyId, future);
72
73         // FIXME: initiate backend instantiation
74         future.completeExceptionally(new UnsupportedOperationException("Not implemented yet"));
75         return this;
76     }
77
78     private ClientActorBehavior shutdown() {
79         // FIXME: Add shutdown procedures here
80         return null;
81     }
82
83     @Override
84     protected ClientActorBehavior onCommand(final Object command) {
85         if (command instanceof GetClientRequest) {
86             ((GetClientRequest) command).getReplyTo().tell(new Status.Success(this), ActorRef.noSender());
87         } else {
88             LOG.warn("{}: ignoring unhandled command {}", persistenceId(), command);
89         }
90
91         return this;
92     }
93
94     //
95     //
96     // Methods below are invoked from application threads
97     //
98     //
99
100     @Override
101     public CompletionStage<ClientLocalHistory> createLocalHistory() {
102         final CompletableFuture<ClientLocalHistory> future = new CompletableFuture<>();
103         context().executeInActor(() -> createLocalHistory(future));
104         return future;
105     }
106
107     @Override
108     public void close() {
109         context().executeInActor(this::shutdown);
110     }
111
112     @Override
113     protected ModuleShardBackendResolver resolver() {
114         return resolver;
115     }
116 }