code: public <T> CompletableFuture<T> execute(final Resource resource, final Serializable[] parameters, final FutureOperation<T> operation) {
          if (!ready) {
              return Futures.failedFuture(new IllegalStateException(getClass().getName() + " not yet ready"));
          }
          final String tag = UUID.randomUUID().toString();
          final TaskData taskData = getTaskData(parameters);
          final CompletableFuture<T> result = new CompletableFuture<>();
          final TaggedResource taggedResource = new TaggedResource(tag, resource);
  
          log.debug("Host={}, Tag={} starting to execute task {}-{} on resource {}", context.hostId, tag,
                  taskData.getMethodName(), taskData.getMethodVersion(), resource);
          if (createIndexOnlyMode) {
              return createIndexes(taggedResource, taskData);
          }
          // PutChild (HostId, resource)
          // Initially store the fact that I am about the update the resource.
          // Since multiple threads within this process could concurrently attempt to modify same resource,
          // we tag the resource name with a random GUID so as not to interfere with other thread's
          // creation or deletion of resource children under HostId node.
          taskMetadataStore.putChild(context.hostId, taggedResource)
                  // After storing that fact, lock the resource, execute task and unlock the resource
                  .thenComposeAsync(x -> executeTask(resource, taskData, tag, operation), executor)
                  // finally delete the resource child created under the controller's HostId
                  .whenCompleteAsync((value, e) ->
                                  taskMetadataStore.removeChild(context.hostId, taggedResource, true)
                                          .whenCompleteAsync((innerValue, innerE) -> {
                                              // ignore the result of removeChile operations, since it is an optimization
                                              if (e != null) {
                                                  result.completeExceptionally(e);
                                              } else {
                                                  result.complete(value);
                                              }
                                          }, executor),
                          executor);
  
          return result;
      }
docs: Wrapper method that initially obtains lock then executes the passed method, and finally releases lock.
  
  @param resource resource to be updated by the task.
  @param parameters method parameters.
  @param operation lambda operation that is the actual task.
  @param <T> type parameter of return value of operation to be executed.
  @return return value of task execution.