<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#include <stdint.h>

#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>

#include <process/collect.hpp>
#include <process/defer.hpp>
#include <process/future.hpp>

#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/hashmap.hpp>
#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/try.hpp>

#include "linux/cgroups.hpp"

#include "slave/flags.hpp"

#include "slave/containerizer/containerizer.hpp"

#include "slave/containerizer/mesos/isolator.hpp"

#include "slave/containerizer/mesos/isolators/gpu/nvidia.hpp"
#include "slave/containerizer/mesos/isolators/gpu/nvml.hpp"

using cgroups::devices::Entry;

using mesos::slave::ContainerConfig;
using mesos::slave::ContainerLaunchInfo;
using mesos::slave::ContainerLimitation;
using mesos::slave::ContainerState;
using mesos::slave::Isolator;

using process::defer;
using process::Failure;
using process::Future;
using process::PID;

using std::list;
using std::map;
using std::set;
using std::string;
using std::vector;

namespace mesos {
namespace internal {
namespace slave {

// TODO(klueska): Expand this when we support other GPU types.
static constexpr unsigned int NVIDIA_MAJOR_DEVICE = 195;

NvidiaGpuIsolatorProcess::NvidiaGpuIsolatorProcess(
    const Flags& _flags,
    const string& _hierarchy,
    const NvidiaGpuAllocator& _allocator,
    const cgroups::devices::Entry& uvmDeviceEntry,
    const cgroups::devices::Entry& ctlDeviceEntry)
  : flags(_flags),
    hierarchy(_hierarchy),
    allocator(_allocator),
    NVIDIA_CTL_DEVICE_ENTRY(ctlDeviceEntry),
    NVIDIA_UVM_DEVICE_ENTRY(uvmDeviceEntry) {}

Try<Isolator*> NvidiaGpuIsolatorProcess::create(const Flags& flags)
{
  // Make sure the 'cgroups/devices' isolator is present and
  // precedes the GPU isolator.
  vector<string> tokens = strings::tokenize(flags.isolation, ",");

  auto gpuIsolator =
    std::find(tokens.begin(), tokens.end(), "gpu/nvidia");
  auto devicesIsolator =
    std::find(tokens.begin(), tokens.end(), "cgroups/devices");

  CHECK(gpuIsolator != tokens.end());

  if (devicesIsolator == tokens.end()) {
    return Error("The 'cgroups/devices' isolator must be enabled in"
                 " order to use the 'gpu/nvidia' isolator");
  }

  if (devicesIsolator > gpuIsolator) {
    return Error("'cgroups/devices' must precede 'gpu/nvidia'"
                 " in the --isolation flag");
  }

  // Create the allocator.
  //
  // TODO(klueska): We need to share the allocator
  // with the docker containerizer.
  Try<Resources> resources =
    NvidiaGpuAllocator::resources(flags);

  if (resources.isError()) {
    return Error("Failed to NvidiaGpuAllocator::resources: " +
                 resources.error());
  }

  Try<NvidiaGpuAllocator> allocator =
    NvidiaGpuAllocator::create(flags, resources.get());

  if (allocator.isError()) {
    return Error("Failed to NvidiaGpuAllocator::create: " +
                 allocator.error());
  }

  // Retrieve the cgroups devices hierarchy.
  Result<string> hierarchy = cgroups::hierarchy("devices");

  if (hierarchy.isError()) {
    return Error(
        "Error retrieving the 'devices' subsystem hierarchy: " +
        hierarchy.error());
  }

  // Create the device entries for
  // `/dev/nvidiactl` and `/dev/nvidia-uvm`.
  Try<dev_t> device = os::stat::rdev("/dev/nvidiactl");
  if (device.isError()) {
    return Error("Failed to obtain device ID for '/dev/nvidiactl': " +
                 device.error());
  }

  cgroups::devices::Entry ctlDeviceEntry;
  ctlDeviceEntry.selector.type = Entry::Selector::Type::CHARACTER;
  ctlDeviceEntry.selector.major = major(device.get());
  ctlDeviceEntry.selector.minor = minor(device.get());
  ctlDeviceEntry.access.read = true;
  ctlDeviceEntry.access.write = true;
  ctlDeviceEntry.access.mknod = true;

  device = os::stat::rdev("/dev/nvidia-uvm");
  if (device.isError()) {
    return Error("Failed to obtain device ID for '/dev/nvidia-uvm': " +
                 device.error());
  }

  cgroups::devices::Entry uvmDeviceEntry;
  uvmDeviceEntry.selector.type = Entry::Selector::Type::CHARACTER;
  uvmDeviceEntry.selector.major = major(device.get());
  uvmDeviceEntry.selector.minor = minor(device.get());
  uvmDeviceEntry.access.read = true;
  uvmDeviceEntry.access.write = true;
  uvmDeviceEntry.access.mknod = true;

  process::Owned<MesosIsolatorProcess> process(
      new NvidiaGpuIsolatorProcess(
          flags,
          hierarchy.get(),
          allocator.get(),
          ctlDeviceEntry,
          uvmDeviceEntry));

  return new MesosIsolator(process);
}

Future<Nothing> NvidiaGpuIsolatorProcess::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  list<Future<Nothing>> futures;

  foreach (const ContainerState& state, states) {
    const ContainerID& containerId = state.container_id();
    const string cgroup = path::join(flags.cgroups_root, containerId.value());

    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
    if (exists.isError()) {
      foreachvalue (Info* info, infos) {
        delete info;
      }
      infos.clear();
      return Failure("Failed to check cgroup for container '" +
                     stringify(containerId) + "'");
    }

    if (!exists.get()) {
      VLOG(1) << "Couldn't find cgroup for container " << containerId;
      // This may occur if the executor has exited and the isolator
      // has destroyed the cgroup but the slave dies before noticing
      // this. This will be detected when the containerizer tries to
      // monitor the executor's pid.
      continue;
    }

    infos[containerId] = new Info(containerId, cgroup);

    // Determine which GPUs are allocated to this container.
    Try<vector<cgroups::devices::Entry>> entries =
      cgroups::devices::list(hierarchy, cgroup);

    if (entries.isError()) {
      return Failure("Failed to obtain devices list for cgroup"
                     " '" + cgroup + "': " + entries.error());
    }

    const set<Gpu>& available = allocator.total();

    set<Gpu> containerGpus;
    foreach (const cgroups::devices::Entry& entry, entries.get()) {
      foreach (const Gpu& gpu, available) {
        if (entry.selector.major == gpu.major &&
            entry.selector.minor == gpu.minor) {
          containerGpus.insert(gpu);
          break;
        }
      }
    }

    futures.push_back(allocator.allocate(containerGpus)
      .then(defer(self(), [=]() -> Future<Nothing> {
        infos[containerId]->allocated = containerGpus;
        return Nothing();
      })));
  }

  return collect(futures).then([]() { return Nothing(); });
}

Future<Option<ContainerLaunchInfo>> NvidiaGpuIsolatorProcess::prepare(
    const ContainerID& containerId,
    const mesos::slave::ContainerConfig& containerConfig)
{
  if (infos.contains(containerId)) {
    return Failure("Container has already been prepared");
  }

  infos[containerId] = new Info(
      containerId, path::join(flags.cgroups_root, containerId.value()));

  // Grant access to /dev/nvidiactl and /dev/nvida-uvm.
  //
  // This allows standard NVIDIA tools like `nvidia-smi` to be
  // used within the container even if no GPUs are allocated.
  // Without these devices, these tools fail abnormally.
  map<string, const cgroups::devices::Entry> entries = {
    { "/dev/nvidiactl", NVIDIA_CTL_DEVICE_ENTRY },
    { "/dev/nvidia-uvm", NVIDIA_UVM_DEVICE_ENTRY },
  };

  foreachkey (const string& device, entries) {
    Try<Nothing> allow = cgroups::devices::allow(
        hierarchy, infos[containerId]->cgroup, entries[device]);

    if (allow.isError()) {
      return Failure("Failed to grant cgroups access to"
                     " '" + device + "': " + allow.error());
    }
  }

  return update(containerId, containerConfig.executor_info().resources())
    .then([]() -> Future<Option<ContainerLaunchInfo>> {
      return None();
    });
}

Future<Nothing> NvidiaGpuIsolatorProcess::update(
    const ContainerID& containerId,
    const Resources& resources)
{
  if (!infos.contains(containerId)) {
    return Failure("Unknown container");
  }

  Info* info = CHECK_NOTNULL(infos[containerId]);

  Option<double> gpus = resources.gpus();

  // Make sure that the `gpus` resource is not fractional.
  // We rely on scalar resources only having 3 digits of precision.
  if (static_cast<long long>(gpus.getOrElse(0.0) * 1000.0) % 1000 != 0) {
    return Failure("The 'gpus' resource must be an unsigned integer");
  }

  size_t requested = static_cast<size_t>(resources.gpus().getOrElse(0.0));

  // Update the GPU allocation to reflect the new total.
  if (requested > info->allocated.size()) {
    size_t additional = requested - info->allocated.size();

    return allocator.allocate(additional)
      .then(defer(PID<NvidiaGpuIsolatorProcess>(this),
                  &NvidiaGpuIsolatorProcess::_update,
                  containerId,
                  lambda::_1));
  } else if (requested < info->allocated.size()) {
    size_t fewer = info->allocated.size() - requested;

    set<Gpu> deallocated;

    for (size_t i = 0; i < fewer; i++) {
      const auto gpu = info->allocated.begin();

      cgroups::devices::Entry entry;
      entry.selector.type = Entry::Selector::Type::CHARACTER;
      entry.selector.major = gpu->major;
      entry.selector.minor = gpu->minor;
      entry.access.read = true;
      entry.access.write = true;
      entry.access.mknod = true;

      Try<Nothing> deny = cgroups::devices::deny(
          hierarchy, info->cgroup, entry);

      if (deny.isError()) {
        return Failure("Failed to deny cgroups access to GPU device"
                       " '" + stringify(entry) + "': " + deny.error());
      }

      deallocated.insert(*gpu);
      info->allocated.erase(gpu);
    }

    return allocator.deallocate(deallocated);
  }

  return Nothing();
}

Future<Nothing> NvidiaGpuIsolatorProcess::_update(
    const ContainerID& containerId,
    const set<Gpu>& allocation)
{
  if (!infos.contains(containerId)) {
    return Failure("Failed to complete GPU allocation: unknown container");
  }

  Info* info = CHECK_NOTNULL(infos.at(containerId));

  foreach (const Gpu& gpu, allocation) {
    cgroups::devices::Entry entry;
    entry.selector.type = Entry::Selector::Type::CHARACTER;
    entry.selector.major = gpu.major;
    entry.selector.minor = gpu.minor;
    entry.access.read = true;
    entry.access.write = true;
    entry.access.mknod = true;

    Try<Nothing> allow = cgroups::devices::allow(
        hierarchy, info->cgroup, entry);

    if (allow.isError()) {
      return Failure("Failed to grant cgroups access to GPU device"
                     " '" + stringify(entry) + "': " + allow.error());
    }
  }

  info->allocated = allocation;

  return Nothing();
}

Future<ResourceStatistics> NvidiaGpuIsolatorProcess::usage(
    const ContainerID& containerId)
{
  if (!infos.contains(containerId)) {
    return Failure("Unknown container");
  }

  // TODO(rtodd): Obtain usage information from NVML.

  ResourceStatistics result;
  return result;
}

Future<Nothing> NvidiaGpuIsolatorProcess::cleanup(
    const ContainerID& containerId)
{
  // Multiple calls may occur during test clean up.
  if (!infos.contains(containerId)) {
    VLOG(1) << "Ignoring cleanup request for unknown container " << containerId;

    return Nothing();
  }

  Info* info = CHECK_NOTNULL(infos.at(containerId));

  // Make any remaining GPUs available.
  return allocator.deallocate(info->allocated)
    .then(defer(self(), [=]() -> Future<Nothing> {
      CHECK(infos.contains(containerId));
      delete infos.at(containerId);
      infos.erase(containerId);

      return Nothing();
    }));
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<commit_msg>Removed an unused constant in the GPU isolator.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#include <stdint.h>

#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>

#include <process/collect.hpp>
#include <process/defer.hpp>
#include <process/future.hpp>

#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/hashmap.hpp>
#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/try.hpp>

#include "linux/cgroups.hpp"

#include "slave/flags.hpp"

#include "slave/containerizer/containerizer.hpp"

#include "slave/containerizer/mesos/isolator.hpp"

#include "slave/containerizer/mesos/isolators/gpu/nvidia.hpp"
#include "slave/containerizer/mesos/isolators/gpu/nvml.hpp"

using cgroups::devices::Entry;

using mesos::slave::ContainerConfig;
using mesos::slave::ContainerLaunchInfo;
using mesos::slave::ContainerLimitation;
using mesos::slave::ContainerState;
using mesos::slave::Isolator;

using process::defer;
using process::Failure;
using process::Future;
using process::PID;

using std::list;
using std::map;
using std::set;
using std::string;
using std::vector;

namespace mesos {
namespace internal {
namespace slave {

NvidiaGpuIsolatorProcess::NvidiaGpuIsolatorProcess(
    const Flags& _flags,
    const string& _hierarchy,
    const NvidiaGpuAllocator& _allocator,
    const cgroups::devices::Entry& uvmDeviceEntry,
    const cgroups::devices::Entry& ctlDeviceEntry)
  : flags(_flags),
    hierarchy(_hierarchy),
    allocator(_allocator),
    NVIDIA_CTL_DEVICE_ENTRY(ctlDeviceEntry),
    NVIDIA_UVM_DEVICE_ENTRY(uvmDeviceEntry) {}

Try<Isolator*> NvidiaGpuIsolatorProcess::create(const Flags& flags)
{
  // Make sure the 'cgroups/devices' isolator is present and
  // precedes the GPU isolator.
  vector<string> tokens = strings::tokenize(flags.isolation, ",");

  auto gpuIsolator =
    std::find(tokens.begin(), tokens.end(), "gpu/nvidia");
  auto devicesIsolator =
    std::find(tokens.begin(), tokens.end(), "cgroups/devices");

  CHECK(gpuIsolator != tokens.end());

  if (devicesIsolator == tokens.end()) {
    return Error("The 'cgroups/devices' isolator must be enabled in"
                 " order to use the 'gpu/nvidia' isolator");
  }

  if (devicesIsolator > gpuIsolator) {
    return Error("'cgroups/devices' must precede 'gpu/nvidia'"
                 " in the --isolation flag");
  }

  // Create the allocator.
  //
  // TODO(klueska): We need to share the allocator
  // with the docker containerizer.
  Try<Resources> resources =
    NvidiaGpuAllocator::resources(flags);

  if (resources.isError()) {
    return Error("Failed to NvidiaGpuAllocator::resources: " +
                 resources.error());
  }

  Try<NvidiaGpuAllocator> allocator =
    NvidiaGpuAllocator::create(flags, resources.get());

  if (allocator.isError()) {
    return Error("Failed to NvidiaGpuAllocator::create: " +
                 allocator.error());
  }

  // Retrieve the cgroups devices hierarchy.
  Result<string> hierarchy = cgroups::hierarchy("devices");

  if (hierarchy.isError()) {
    return Error(
        "Error retrieving the 'devices' subsystem hierarchy: " +
        hierarchy.error());
  }

  // Create the device entries for
  // `/dev/nvidiactl` and `/dev/nvidia-uvm`.
  Try<dev_t> device = os::stat::rdev("/dev/nvidiactl");
  if (device.isError()) {
    return Error("Failed to obtain device ID for '/dev/nvidiactl': " +
                 device.error());
  }

  cgroups::devices::Entry ctlDeviceEntry;
  ctlDeviceEntry.selector.type = Entry::Selector::Type::CHARACTER;
  ctlDeviceEntry.selector.major = major(device.get());
  ctlDeviceEntry.selector.minor = minor(device.get());
  ctlDeviceEntry.access.read = true;
  ctlDeviceEntry.access.write = true;
  ctlDeviceEntry.access.mknod = true;

  device = os::stat::rdev("/dev/nvidia-uvm");
  if (device.isError()) {
    return Error("Failed to obtain device ID for '/dev/nvidia-uvm': " +
                 device.error());
  }

  cgroups::devices::Entry uvmDeviceEntry;
  uvmDeviceEntry.selector.type = Entry::Selector::Type::CHARACTER;
  uvmDeviceEntry.selector.major = major(device.get());
  uvmDeviceEntry.selector.minor = minor(device.get());
  uvmDeviceEntry.access.read = true;
  uvmDeviceEntry.access.write = true;
  uvmDeviceEntry.access.mknod = true;

  process::Owned<MesosIsolatorProcess> process(
      new NvidiaGpuIsolatorProcess(
          flags,
          hierarchy.get(),
          allocator.get(),
          ctlDeviceEntry,
          uvmDeviceEntry));

  return new MesosIsolator(process);
}

Future<Nothing> NvidiaGpuIsolatorProcess::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  list<Future<Nothing>> futures;

  foreach (const ContainerState& state, states) {
    const ContainerID& containerId = state.container_id();
    const string cgroup = path::join(flags.cgroups_root, containerId.value());

    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
    if (exists.isError()) {
      foreachvalue (Info* info, infos) {
        delete info;
      }
      infos.clear();
      return Failure("Failed to check cgroup for container '" +
                     stringify(containerId) + "'");
    }

    if (!exists.get()) {
      VLOG(1) << "Couldn't find cgroup for container " << containerId;
      // This may occur if the executor has exited and the isolator
      // has destroyed the cgroup but the slave dies before noticing
      // this. This will be detected when the containerizer tries to
      // monitor the executor's pid.
      continue;
    }

    infos[containerId] = new Info(containerId, cgroup);

    // Determine which GPUs are allocated to this container.
    Try<vector<cgroups::devices::Entry>> entries =
      cgroups::devices::list(hierarchy, cgroup);

    if (entries.isError()) {
      return Failure("Failed to obtain devices list for cgroup"
                     " '" + cgroup + "': " + entries.error());
    }

    const set<Gpu>& available = allocator.total();

    set<Gpu> containerGpus;
    foreach (const cgroups::devices::Entry& entry, entries.get()) {
      foreach (const Gpu& gpu, available) {
        if (entry.selector.major == gpu.major &&
            entry.selector.minor == gpu.minor) {
          containerGpus.insert(gpu);
          break;
        }
      }
    }

    futures.push_back(allocator.allocate(containerGpus)
      .then(defer(self(), [=]() -> Future<Nothing> {
        infos[containerId]->allocated = containerGpus;
        return Nothing();
      })));
  }

  return collect(futures).then([]() { return Nothing(); });
}

Future<Option<ContainerLaunchInfo>> NvidiaGpuIsolatorProcess::prepare(
    const ContainerID& containerId,
    const mesos::slave::ContainerConfig& containerConfig)
{
  if (infos.contains(containerId)) {
    return Failure("Container has already been prepared");
  }

  infos[containerId] = new Info(
      containerId, path::join(flags.cgroups_root, containerId.value()));

  // Grant access to /dev/nvidiactl and /dev/nvida-uvm.
  //
  // This allows standard NVIDIA tools like `nvidia-smi` to be
  // used within the container even if no GPUs are allocated.
  // Without these devices, these tools fail abnormally.
  map<string, const cgroups::devices::Entry> entries = {
    { "/dev/nvidiactl", NVIDIA_CTL_DEVICE_ENTRY },
    { "/dev/nvidia-uvm", NVIDIA_UVM_DEVICE_ENTRY },
  };

  foreachkey (const string& device, entries) {
    Try<Nothing> allow = cgroups::devices::allow(
        hierarchy, infos[containerId]->cgroup, entries[device]);

    if (allow.isError()) {
      return Failure("Failed to grant cgroups access to"
                     " '" + device + "': " + allow.error());
    }
  }

  return update(containerId, containerConfig.executor_info().resources())
    .then([]() -> Future<Option<ContainerLaunchInfo>> {
      return None();
    });
}

Future<Nothing> NvidiaGpuIsolatorProcess::update(
    const ContainerID& containerId,
    const Resources& resources)
{
  if (!infos.contains(containerId)) {
    return Failure("Unknown container");
  }

  Info* info = CHECK_NOTNULL(infos[containerId]);

  Option<double> gpus = resources.gpus();

  // Make sure that the `gpus` resource is not fractional.
  // We rely on scalar resources only having 3 digits of precision.
  if (static_cast<long long>(gpus.getOrElse(0.0) * 1000.0) % 1000 != 0) {
    return Failure("The 'gpus' resource must be an unsigned integer");
  }

  size_t requested = static_cast<size_t>(resources.gpus().getOrElse(0.0));

  // Update the GPU allocation to reflect the new total.
  if (requested > info->allocated.size()) {
    size_t additional = requested - info->allocated.size();

    return allocator.allocate(additional)
      .then(defer(PID<NvidiaGpuIsolatorProcess>(this),
                  &NvidiaGpuIsolatorProcess::_update,
                  containerId,
                  lambda::_1));
  } else if (requested < info->allocated.size()) {
    size_t fewer = info->allocated.size() - requested;

    set<Gpu> deallocated;

    for (size_t i = 0; i < fewer; i++) {
      const auto gpu = info->allocated.begin();

      cgroups::devices::Entry entry;
      entry.selector.type = Entry::Selector::Type::CHARACTER;
      entry.selector.major = gpu->major;
      entry.selector.minor = gpu->minor;
      entry.access.read = true;
      entry.access.write = true;
      entry.access.mknod = true;

      Try<Nothing> deny = cgroups::devices::deny(
          hierarchy, info->cgroup, entry);

      if (deny.isError()) {
        return Failure("Failed to deny cgroups access to GPU device"
                       " '" + stringify(entry) + "': " + deny.error());
      }

      deallocated.insert(*gpu);
      info->allocated.erase(gpu);
    }

    return allocator.deallocate(deallocated);
  }

  return Nothing();
}

Future<Nothing> NvidiaGpuIsolatorProcess::_update(
    const ContainerID& containerId,
    const set<Gpu>& allocation)
{
  if (!infos.contains(containerId)) {
    return Failure("Failed to complete GPU allocation: unknown container");
  }

  Info* info = CHECK_NOTNULL(infos.at(containerId));

  foreach (const Gpu& gpu, allocation) {
    cgroups::devices::Entry entry;
    entry.selector.type = Entry::Selector::Type::CHARACTER;
    entry.selector.major = gpu.major;
    entry.selector.minor = gpu.minor;
    entry.access.read = true;
    entry.access.write = true;
    entry.access.mknod = true;

    Try<Nothing> allow = cgroups::devices::allow(
        hierarchy, info->cgroup, entry);

    if (allow.isError()) {
      return Failure("Failed to grant cgroups access to GPU device"
                     " '" + stringify(entry) + "': " + allow.error());
    }
  }

  info->allocated = allocation;

  return Nothing();
}

Future<ResourceStatistics> NvidiaGpuIsolatorProcess::usage(
    const ContainerID& containerId)
{
  if (!infos.contains(containerId)) {
    return Failure("Unknown container");
  }

  // TODO(rtodd): Obtain usage information from NVML.

  ResourceStatistics result;
  return result;
}

Future<Nothing> NvidiaGpuIsolatorProcess::cleanup(
    const ContainerID& containerId)
{
  // Multiple calls may occur during test clean up.
  if (!infos.contains(containerId)) {
    VLOG(1) << "Ignoring cleanup request for unknown container " << containerId;

    return Nothing();
  }

  Info* info = CHECK_NOTNULL(infos.at(containerId));

  // Make any remaining GPUs available.
  return allocator.deallocate(info->allocated)
    .then(defer(self(), [=]() -> Future<Nothing> {
      CHECK(infos.contains(containerId));
      delete infos.at(containerId);
      infos.erase(containerId);

      return Nothing();
    }));
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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
///
///     vpp://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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include "VppCommTask.h"

#include "Basics/StringBuffer.h"
#include "Basics/HybridLogicalClock.h"
#include "Basics/VelocyPackHelper.h"
#include "GeneralServer/GeneralServer.h"
#include "GeneralServer/GeneralServerFeature.h"
#include "GeneralServer/RestHandler.h"
#include "GeneralServer/RestHandlerFactory.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/SchedulerFeature.h"
#include "Logger/LoggerFeature.h"
#include "VocBase/ticks.h"

#include <velocypack/Validator.h>
#include <velocypack/velocypack-aliases.h>

#include <iostream>
#include <stdexcept>

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

namespace {
std::size_t findAndValidateVPacks(char const* vpHeaderStart,
                                  char const* chunkEnd) {
  VPackValidator validator;
  // check for slice start to the end of Chunk
  // isSubPart allows the slice to be shorter than the checked buffer.
  validator.validate(vpHeaderStart, std::distance(vpHeaderStart, chunkEnd),
                     /*isSubPart =*/true);

  // check if there is payload and locate the start
  VPackSlice vpHeader(vpHeaderStart);
  auto vpHeaderLen = vpHeader.byteSize();
  auto vpPayloadStart = vpHeaderStart + vpHeaderLen;
  if (vpPayloadStart == chunkEnd) {
    return 0;  // no payload available
  }

  // validate Payload VelocyPack
  validator.validate(vpPayloadStart, std::distance(vpPayloadStart, chunkEnd),
                     /*isSubPart =*/false);
  return std::distance(vpHeaderStart, vpPayloadStart);
}

std::unique_ptr<basics::StringBuffer> createChunkForNetworkDetail(
    std::vector<VPackSlice> const& slices, bool isFirstChunk, uint32_t chunk,
    uint64_t id, uint32_t totalMessageLength = 0) {
  using basics::StringBuffer;
  bool firstOfMany = false;

  // if we have more than one chunk and the chunk is the first
  // then we are sending the first in a series. if this condition
  // is true we also send extra 8 bytes for the messageLength
  // (length of all VPackData)
  if (isFirstChunk && chunk > 1) {
    firstOfMany = true;
  }

  // build chunkX -- see VelocyStream Documentaion
  chunk <<= 1;
  chunk |= isFirstChunk ? 0x1 : 0x0;

  // get the lenght of VPack data
  uint32_t dataLength = 0;
  for (auto& slice : slices) {
    dataLength += slice.byteSize();
  }

  // calculate length of current chunk
  uint32_t chunkLength = dataLength;
  chunkLength += (sizeof(chunkLength) + sizeof(chunk) + sizeof(id));
  if (firstOfMany) {
    chunkLength += sizeof(totalMessageLength);
  }

  auto buffer =
      std::make_unique<StringBuffer>(TRI_UNKNOWN_MEM_ZONE, chunkLength, false);

  char cChunkLength[sizeof(chunkLength)];
  char const* cChunkLengthPtr = cChunkLength;
  std::memcpy(&cChunkLength, &chunkLength, sizeof(chunkLength));
  buffer->appendText(cChunkLengthPtr, sizeof(chunkLength));

  char cChunk[sizeof(chunk)];
  char const* cChunkPtr = cChunk;
  std::memcpy(&cChunk, &chunk, sizeof(chunk));
  buffer->appendText(cChunkPtr, sizeof(chunk));

  char cId[sizeof(id)];
  char const* cIdPtr = cId;
  std::memcpy(&cId, &id, sizeof(id));
  buffer->appendText(cIdPtr, sizeof(id));

  if (firstOfMany) {
    char cTotalMessageLength[sizeof(totalMessageLength)];
    char const* cTotalMessageLengthPtr = cTotalMessageLength;
    std::memcpy(&cTotalMessageLength, &totalMessageLength,
                sizeof(totalMessageLength));
    buffer->appendText(cTotalMessageLengthPtr, sizeof(totalMessageLength));
  }

  // append data in slices
  for (auto const& slice : slices) {
    buffer->appendText(std::string(slice.startAs<char>(), slice.byteSize()));
  }

  return buffer;
}

std::unique_ptr<basics::StringBuffer> createChunkForNetworkSingle(
    std::vector<VPackSlice> const& slices, uint64_t id) {
  return createChunkForNetworkDetail(slices, true, 1, id, 0 /*unused*/);
}

// TODO FIXME make use of these functions
// std::unique_ptr<basics::StringBuffer> createChunkForNetworkMultiFirst(
//     std::vector<VPackSlice> const& slices, uint64_t id, uint32_t
//     numberOfChunks,
//     uint32_t totalMessageLength) {
//   return createChunkForNetworkDetail(slices, true, numberOfChunks, id,
//                                      totalMessageLength);
// }
//
// std::unique_ptr<basics::StringBuffer> createChunkForNetworkMultiFollow(
//     std::vector<VPackSlice> const& slices, uint64_t id, uint32_t chunkNumber,
//     uint32_t totalMessageLength) {
//   return createChunkForNetworkDetail(slices, false, chunkNumber, id, 0);
// }
}

VppCommTask::VppCommTask(GeneralServer* server, TRI_socket_t sock,
                         ConnectionInfo&& info, double timeout)
    : Task("VppCommTask"),
      GeneralCommTask(server, sock, std::move(info), timeout) {
  _protocol = "vpp";
  // connectionStatisticsAgentSetVpp();
}

void VppCommTask::addResponse(VppResponse* response, bool isError) {
  if (isError) {
    // FIXME (obi)
    // what do we need to do?
    // clean read buffer? reset process read cursor
  }

  VPackMessageNoOwnBuffer response_message = response->prepareForNetwork();
  uint64_t& id = response_message._id;

  std::vector<VPackSlice> slices;
  slices.push_back(response_message._header);

  VPackBuilder builder;
  if (response_message._generateBody) {
    builder = basics::VelocyPackHelper::stanitizeExternalsChecked(
        response_message._payload);
    slices.push_back(builder.slice());
  }

  // FIXME (obi)
  // If the message is big we will create many small chunks in a loop.
  // For the first tests we just send single Messages

  LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "got response:";
  for (auto const& slice : slices) {
    try {
      LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << slice.toJson();
    } catch (Exception const& e) {
      std::cout << e.message();
    }
  }

  // adds chunk header infromation and creates SingBuffer* that can be
  // used with _writeBuffers
  auto buffer = createChunkForNetworkSingle(slices, id);
  _writeBuffers.push_back(buffer.get());
  buffer.release();

  fillWriteBuffer();  // move data from _writebuffers to _writebuffer
                      // implemented in base
}

VppCommTask::ChunkHeader VppCommTask::readChunkHeader() {
  VppCommTask::ChunkHeader header;

  auto cursor = _processReadVariables._readBufferCursor;

  std::memcpy(&header._chunkLength, cursor, sizeof(header._chunkLength));
  cursor += sizeof(header._chunkLength);

  uint32_t chunkX;
  std::memcpy(&chunkX, cursor, sizeof(chunkX));
  cursor += sizeof(chunkX);

  header._isFirst = chunkX & 0x1;
  header._chunk = chunkX >> 1;

  std::memcpy(&header._messageID, cursor, sizeof(header._messageID));
  cursor += sizeof(header._messageID);

  // extract total len of message
  if (header._isFirst && header._chunk > 1) {
    std::memcpy(&header._messageLength, cursor, sizeof(header._messageLength));
    cursor += sizeof(header._messageLength);
  } else {
    header._messageLength = 0;  // not needed
  }

  header._headerLength =
      std::distance(_processReadVariables._readBufferCursor, cursor);

  return header;
}

bool VppCommTask::isChunkComplete(char* start) {
  std::size_t length = std::distance(start, _readBuffer->end());
  auto& prv = _processReadVariables;

  if (!prv._currentChunkLength && length < sizeof(uint32_t)) {
    return false;
  }
  if (!prv._currentChunkLength) {
    // read chunk length
    std::memcpy(&prv._currentChunkLength, start, sizeof(uint32_t));
  }
  if (length < prv._currentChunkLength) {
    // chunk not complete
    return false;
  }

  return true;
}

// reads data from the socket
bool VppCommTask::processRead() {
  // TODO FIXME
  // - in case of error send an operation failed to all incomplete messages /
  //   operation and close connection (implement resetState/resetCommtask)

  auto& prv = _processReadVariables;
  if (!prv._readBufferCursor) {
    prv._readBufferCursor = _readBuffer->begin();
  }

  auto chunkBegin = prv._readBufferCursor;
  if (chunkBegin == nullptr || !isChunkComplete(chunkBegin)) {
    return false;  // no data or incomplete
  }

  ChunkHeader chunkHeader = readChunkHeader();
  auto chunkEnd = chunkBegin + chunkHeader._chunkLength;
  auto vpackBegin = chunkBegin + chunkHeader._headerLength;
  bool doExecute = false;
  bool read_maybe_only_part_of_buffer = false;
  VPackMessage message;  // filled in CASE 1 or CASE 2b

  // CASE 1: message is in one chunk
  if (chunkHeader._isFirst && chunkHeader._chunk == 1) {
    std::size_t payloadOffset = findAndValidateVPacks(vpackBegin, chunkEnd);
    message._id = chunkHeader._messageID;
    message._buffer.append(vpackBegin, std::distance(vpackBegin, chunkEnd));
    message._header = VPackSlice(message._buffer.data());
    if (payloadOffset) {
      message._payload = VPackSlice(message._buffer.data() + payloadOffset);
    }
    VPackValidator val;
    val.validate(message._header.begin(), message._header.byteSize());

    doExecute = true;
    LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 1";
  }
  // CASE 2:  message is in multiple chunks
  auto incompleteMessageItr = _incompleteMessages.find(chunkHeader._messageID);

  // CASE 2a: chunk starts new message
  if (chunkHeader._isFirst) {  // first chunk of multi chunk message
    if (incompleteMessageItr != _incompleteMessages.end()) {
      throw std::logic_error(
          "Message should be first but is already in the Map of incomplete "
          "messages");
    }

    IncompleteVPackMessage message(chunkHeader._messageLength,
                                   chunkHeader._chunk /*number of chunks*/);
    message._buffer.append(vpackBegin, std::distance(vpackBegin, chunkEnd));
    auto insertPair = _incompleteMessages.emplace(
        std::make_pair(chunkHeader._messageID, std::move(message)));
    if (!insertPair.second) {
      throw std::logic_error("insert failed");
    }

    LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 2a";

    // CASE 2b: chunk continues a message
  } else {  // followup chunk of some mesage
    if (incompleteMessageItr == _incompleteMessages.end()) {
      throw std::logic_error("found message without previous part");
    }
    auto& im = incompleteMessageItr->second;  // incomplete Message
    im._currentChunk++;
    assert(im._currentChunk == chunkHeader._chunk);
    im._buffer.append(vpackBegin, std::distance(vpackBegin, chunkEnd));
    // check buffer longer than length

    // MESSAGE COMPLETE
    if (im._currentChunk == im._numberOfChunks - 1 /* zero based counting */) {
      std::size_t payloadOffset = findAndValidateVPacks(
          reinterpret_cast<char const*>(im._buffer.data()),
          reinterpret_cast<char const*>(im._buffer.data() +
                                        im._buffer.byteSize()));
      message._id = chunkHeader._messageID;
      message._buffer = std::move(im._buffer);
      message._header = VPackSlice(message._buffer.data());
      if (payloadOffset) {
        message._payload = VPackSlice(message._buffer.data() + payloadOffset);
      }
      _incompleteMessages.erase(incompleteMessageItr);
      // check length

      doExecute = true;
      LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 2b - complete";
    }
    LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 2b - still incomplete";
  }

  // clean buffer up to length of chunk
  read_maybe_only_part_of_buffer = true;
  prv._currentChunkLength = 0;
  prv._readBufferCursor = chunkEnd;
  std::size_t processedDataLen =
      std::distance(_readBuffer->begin(), prv._readBufferCursor);
  if (processedDataLen > prv._cleanupLength) {
    _readBuffer->move_front(prv._cleanupLength);
    prv._readBufferCursor = nullptr;  // the positon will be set at the
                                      // begin of this function
  }

  if (doExecute) {
    //    return false;  // we have no complete request, so we return early
    // for now we can handle only one request at a time
    // lock _request???? REVIEW (fc)
    LOG_TOPIC(DEBUG, Logger::COMMUNICATION)
        << "got request:" << message._header.toJson();
    _request = new VppRequest(_connectionInfo, std::move(message));
    GeneralServerFeature::HANDLER_FACTORY->setRequestContext(_request);
    if (_request->requestContext() == nullptr) {
      handleSimpleError(GeneralResponse::ResponseCode::NOT_FOUND,
                        TRI_ERROR_ARANGO_DATABASE_NOT_FOUND,
                        TRI_errno_string(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND));
    } else {
      _request->setClientTaskId(_taskId);
      _protocolVersion = _request->protocolVersion();
      executeRequest(
          _request, new VppResponse(GeneralResponse::ResponseCode::SERVER_ERROR,
                                    chunkHeader._messageID));
    }
  }

  if (read_maybe_only_part_of_buffer) {
    if (prv._readBufferCursor == _readBuffer->end()) {
      return false;
    }
    return true;
  }
  return doExecute;
}

void VppCommTask::completedWriteBuffer() {
  // REVIEW (fc)
}

void VppCommTask::resetState(bool close) {
  // REVIEW (fc)
  // is there a case where we do not want to close the connection
  replyToIncompleteMessages();
}

// GeneralResponse::ResponseCode VppCommTask::authenticateRequest() {
//   auto context = (_request == nullptr) ? nullptr :
//   _request->requestContext();
//
//   if (context == nullptr && _request != nullptr) {
//     bool res =
//         GeneralServerFeature::HANDLER_FACTORY->setRequestContext(_request);
//
//     if (!res) {
//       return GeneralResponse::ResponseCode::NOT_FOUND;
//     }
//
//     context = _request->requestContext();
//   }
//
//   if (context == nullptr) {
//     return GeneralResponse::ResponseCode::SERVER_ERROR;
//   }
//
//   return context->authenticate();
// }

// convert internal GeneralRequest to VppRequest
VppRequest* VppCommTask::requestAsVpp() {
  VppRequest* request = dynamic_cast<VppRequest*>(_request);
  if (request == nullptr) {
    THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
  }
  return request;
};
<commit_msg>i fix type of execepton so it gets caught<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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
///
///     vpp://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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////

#include "VppCommTask.h"

#include "Basics/StringBuffer.h"
#include "Basics/HybridLogicalClock.h"
#include "Basics/VelocyPackHelper.h"
#include "GeneralServer/GeneralServer.h"
#include "GeneralServer/GeneralServerFeature.h"
#include "GeneralServer/RestHandler.h"
#include "GeneralServer/RestHandlerFactory.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/SchedulerFeature.h"
#include "Logger/LoggerFeature.h"
#include "VocBase/ticks.h"

#include <velocypack/Validator.h>
#include <velocypack/velocypack-aliases.h>

#include <iostream>
#include <stdexcept>

using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::rest;

namespace {
std::size_t findAndValidateVPacks(char const* vpHeaderStart,
                                  char const* chunkEnd) {
  VPackValidator validator;
  // check for slice start to the end of Chunk
  // isSubPart allows the slice to be shorter than the checked buffer.
  validator.validate(vpHeaderStart, std::distance(vpHeaderStart, chunkEnd),
                     /*isSubPart =*/true);

  // check if there is payload and locate the start
  VPackSlice vpHeader(vpHeaderStart);
  auto vpHeaderLen = vpHeader.byteSize();
  auto vpPayloadStart = vpHeaderStart + vpHeaderLen;
  if (vpPayloadStart == chunkEnd) {
    return 0;  // no payload available
  }

  // validate Payload VelocyPack
  validator.validate(vpPayloadStart, std::distance(vpPayloadStart, chunkEnd),
                     /*isSubPart =*/false);
  return std::distance(vpHeaderStart, vpPayloadStart);
}

std::unique_ptr<basics::StringBuffer> createChunkForNetworkDetail(
    std::vector<VPackSlice> const& slices, bool isFirstChunk, uint32_t chunk,
    uint64_t id, uint32_t totalMessageLength = 0) {
  using basics::StringBuffer;
  bool firstOfMany = false;

  // if we have more than one chunk and the chunk is the first
  // then we are sending the first in a series. if this condition
  // is true we also send extra 8 bytes for the messageLength
  // (length of all VPackData)
  if (isFirstChunk && chunk > 1) {
    firstOfMany = true;
  }

  // build chunkX -- see VelocyStream Documentaion
  chunk <<= 1;
  chunk |= isFirstChunk ? 0x1 : 0x0;

  // get the lenght of VPack data
  uint32_t dataLength = 0;
  for (auto& slice : slices) {
    dataLength += slice.byteSize();
  }

  // calculate length of current chunk
  uint32_t chunkLength = dataLength;
  chunkLength += (sizeof(chunkLength) + sizeof(chunk) + sizeof(id));
  if (firstOfMany) {
    chunkLength += sizeof(totalMessageLength);
  }

  auto buffer =
      std::make_unique<StringBuffer>(TRI_UNKNOWN_MEM_ZONE, chunkLength, false);

  char cChunkLength[sizeof(chunkLength)];
  char const* cChunkLengthPtr = cChunkLength;
  std::memcpy(&cChunkLength, &chunkLength, sizeof(chunkLength));
  buffer->appendText(cChunkLengthPtr, sizeof(chunkLength));

  char cChunk[sizeof(chunk)];
  char const* cChunkPtr = cChunk;
  std::memcpy(&cChunk, &chunk, sizeof(chunk));
  buffer->appendText(cChunkPtr, sizeof(chunk));

  char cId[sizeof(id)];
  char const* cIdPtr = cId;
  std::memcpy(&cId, &id, sizeof(id));
  buffer->appendText(cIdPtr, sizeof(id));

  if (firstOfMany) {
    char cTotalMessageLength[sizeof(totalMessageLength)];
    char const* cTotalMessageLengthPtr = cTotalMessageLength;
    std::memcpy(&cTotalMessageLength, &totalMessageLength,
                sizeof(totalMessageLength));
    buffer->appendText(cTotalMessageLengthPtr, sizeof(totalMessageLength));
  }

  // append data in slices
  for (auto const& slice : slices) {
    buffer->appendText(std::string(slice.startAs<char>(), slice.byteSize()));
  }

  return buffer;
}

std::unique_ptr<basics::StringBuffer> createChunkForNetworkSingle(
    std::vector<VPackSlice> const& slices, uint64_t id) {
  return createChunkForNetworkDetail(slices, true, 1, id, 0 /*unused*/);
}

// TODO FIXME make use of these functions
// std::unique_ptr<basics::StringBuffer> createChunkForNetworkMultiFirst(
//     std::vector<VPackSlice> const& slices, uint64_t id, uint32_t
//     numberOfChunks,
//     uint32_t totalMessageLength) {
//   return createChunkForNetworkDetail(slices, true, numberOfChunks, id,
//                                      totalMessageLength);
// }
//
// std::unique_ptr<basics::StringBuffer> createChunkForNetworkMultiFollow(
//     std::vector<VPackSlice> const& slices, uint64_t id, uint32_t chunkNumber,
//     uint32_t totalMessageLength) {
//   return createChunkForNetworkDetail(slices, false, chunkNumber, id, 0);
// }
}

VppCommTask::VppCommTask(GeneralServer* server, TRI_socket_t sock,
                         ConnectionInfo&& info, double timeout)
    : Task("VppCommTask"),
      GeneralCommTask(server, sock, std::move(info), timeout) {
  _protocol = "vpp";
  // connectionStatisticsAgentSetVpp();
}

void VppCommTask::addResponse(VppResponse* response, bool isError) {
  if (isError) {
    // FIXME (obi)
    // what do we need to do?
    // clean read buffer? reset process read cursor
  }

  VPackMessageNoOwnBuffer response_message = response->prepareForNetwork();
  uint64_t& id = response_message._id;

  std::vector<VPackSlice> slices;
  slices.push_back(response_message._header);

  VPackBuilder builder;
  if (response_message._generateBody) {
    builder = basics::VelocyPackHelper::stanitizeExternalsChecked(
        response_message._payload);
    slices.push_back(builder.slice());
  }

  // FIXME (obi)
  // If the message is big we will create many small chunks in a loop.
  // For the first tests we just send single Messages

  LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "got response:";
  for (auto const& slice : slices) {
    try {
      LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << slice.toJson();
    } catch (arangodb::velocypack::Exception const& e) {
      std::cout << "obi exception" << e.what();
    }
  }

  // adds chunk header infromation and creates SingBuffer* that can be
  // used with _writeBuffers
  auto buffer = createChunkForNetworkSingle(slices, id);
  _writeBuffers.push_back(buffer.get());
  buffer.release();

  fillWriteBuffer();  // move data from _writebuffers to _writebuffer
                      // implemented in base
}

VppCommTask::ChunkHeader VppCommTask::readChunkHeader() {
  VppCommTask::ChunkHeader header;

  auto cursor = _processReadVariables._readBufferCursor;

  std::memcpy(&header._chunkLength, cursor, sizeof(header._chunkLength));
  cursor += sizeof(header._chunkLength);

  uint32_t chunkX;
  std::memcpy(&chunkX, cursor, sizeof(chunkX));
  cursor += sizeof(chunkX);

  header._isFirst = chunkX & 0x1;
  header._chunk = chunkX >> 1;

  std::memcpy(&header._messageID, cursor, sizeof(header._messageID));
  cursor += sizeof(header._messageID);

  // extract total len of message
  if (header._isFirst && header._chunk > 1) {
    std::memcpy(&header._messageLength, cursor, sizeof(header._messageLength));
    cursor += sizeof(header._messageLength);
  } else {
    header._messageLength = 0;  // not needed
  }

  header._headerLength =
      std::distance(_processReadVariables._readBufferCursor, cursor);

  return header;
}

bool VppCommTask::isChunkComplete(char* start) {
  std::size_t length = std::distance(start, _readBuffer->end());
  auto& prv = _processReadVariables;

  if (!prv._currentChunkLength && length < sizeof(uint32_t)) {
    return false;
  }
  if (!prv._currentChunkLength) {
    // read chunk length
    std::memcpy(&prv._currentChunkLength, start, sizeof(uint32_t));
  }
  if (length < prv._currentChunkLength) {
    // chunk not complete
    return false;
  }

  return true;
}

// reads data from the socket
bool VppCommTask::processRead() {
  // TODO FIXME
  // - in case of error send an operation failed to all incomplete messages /
  //   operation and close connection (implement resetState/resetCommtask)

  auto& prv = _processReadVariables;
  if (!prv._readBufferCursor) {
    prv._readBufferCursor = _readBuffer->begin();
  }

  auto chunkBegin = prv._readBufferCursor;
  if (chunkBegin == nullptr || !isChunkComplete(chunkBegin)) {
    return false;  // no data or incomplete
  }

  ChunkHeader chunkHeader = readChunkHeader();
  auto chunkEnd = chunkBegin + chunkHeader._chunkLength;
  auto vpackBegin = chunkBegin + chunkHeader._headerLength;
  bool doExecute = false;
  bool read_maybe_only_part_of_buffer = false;
  VPackMessage message;  // filled in CASE 1 or CASE 2b

  // CASE 1: message is in one chunk
  if (chunkHeader._isFirst && chunkHeader._chunk == 1) {
    std::size_t payloadOffset = findAndValidateVPacks(vpackBegin, chunkEnd);
    message._id = chunkHeader._messageID;
    message._buffer.append(vpackBegin, std::distance(vpackBegin, chunkEnd));
    message._header = VPackSlice(message._buffer.data());
    if (payloadOffset) {
      message._payload = VPackSlice(message._buffer.data() + payloadOffset);
    }
    VPackValidator val;
    val.validate(message._header.begin(), message._header.byteSize());

    doExecute = true;
    LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 1";
  }
  // CASE 2:  message is in multiple chunks
  auto incompleteMessageItr = _incompleteMessages.find(chunkHeader._messageID);

  // CASE 2a: chunk starts new message
  if (chunkHeader._isFirst) {  // first chunk of multi chunk message
    if (incompleteMessageItr != _incompleteMessages.end()) {
      throw std::logic_error(
          "Message should be first but is already in the Map of incomplete "
          "messages");
    }

    IncompleteVPackMessage message(chunkHeader._messageLength,
                                   chunkHeader._chunk /*number of chunks*/);
    message._buffer.append(vpackBegin, std::distance(vpackBegin, chunkEnd));
    auto insertPair = _incompleteMessages.emplace(
        std::make_pair(chunkHeader._messageID, std::move(message)));
    if (!insertPair.second) {
      throw std::logic_error("insert failed");
    }

    LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 2a";

    // CASE 2b: chunk continues a message
  } else {  // followup chunk of some mesage
    if (incompleteMessageItr == _incompleteMessages.end()) {
      throw std::logic_error("found message without previous part");
    }
    auto& im = incompleteMessageItr->second;  // incomplete Message
    im._currentChunk++;
    assert(im._currentChunk == chunkHeader._chunk);
    im._buffer.append(vpackBegin, std::distance(vpackBegin, chunkEnd));
    // check buffer longer than length

    // MESSAGE COMPLETE
    if (im._currentChunk == im._numberOfChunks - 1 /* zero based counting */) {
      std::size_t payloadOffset = findAndValidateVPacks(
          reinterpret_cast<char const*>(im._buffer.data()),
          reinterpret_cast<char const*>(im._buffer.data() +
                                        im._buffer.byteSize()));
      message._id = chunkHeader._messageID;
      message._buffer = std::move(im._buffer);
      message._header = VPackSlice(message._buffer.data());
      if (payloadOffset) {
        message._payload = VPackSlice(message._buffer.data() + payloadOffset);
      }
      _incompleteMessages.erase(incompleteMessageItr);
      // check length

      doExecute = true;
      LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 2b - complete";
    }
    LOG_TOPIC(DEBUG, Logger::COMMUNICATION) << "CASE 2b - still incomplete";
  }

  // clean buffer up to length of chunk
  read_maybe_only_part_of_buffer = true;
  prv._currentChunkLength = 0;
  prv._readBufferCursor = chunkEnd;
  std::size_t processedDataLen =
      std::distance(_readBuffer->begin(), prv._readBufferCursor);
  if (processedDataLen > prv._cleanupLength) {
    _readBuffer->move_front(prv._cleanupLength);
    prv._readBufferCursor = nullptr;  // the positon will be set at the
                                      // begin of this function
  }

  if (doExecute) {
    //    return false;  // we have no complete request, so we return early
    // for now we can handle only one request at a time
    // lock _request???? REVIEW (fc)
    LOG_TOPIC(DEBUG, Logger::COMMUNICATION)
        << "got request:" << message._header.toJson();
    _request = new VppRequest(_connectionInfo, std::move(message));
    GeneralServerFeature::HANDLER_FACTORY->setRequestContext(_request);
    if (_request->requestContext() == nullptr) {
      handleSimpleError(GeneralResponse::ResponseCode::NOT_FOUND,
                        TRI_ERROR_ARANGO_DATABASE_NOT_FOUND,
                        TRI_errno_string(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND));
    } else {
      _request->setClientTaskId(_taskId);
      _protocolVersion = _request->protocolVersion();
      executeRequest(
          _request, new VppResponse(GeneralResponse::ResponseCode::SERVER_ERROR,
                                    chunkHeader._messageID));
    }
  }

  if (read_maybe_only_part_of_buffer) {
    if (prv._readBufferCursor == _readBuffer->end()) {
      return false;
    }
    return true;
  }
  return doExecute;
}

void VppCommTask::completedWriteBuffer() {
  // REVIEW (fc)
}

void VppCommTask::resetState(bool close) {
  // REVIEW (fc)
  // is there a case where we do not want to close the connection
  replyToIncompleteMessages();
}

// GeneralResponse::ResponseCode VppCommTask::authenticateRequest() {
//   auto context = (_request == nullptr) ? nullptr :
//   _request->requestContext();
//
//   if (context == nullptr && _request != nullptr) {
//     bool res =
//         GeneralServerFeature::HANDLER_FACTORY->setRequestContext(_request);
//
//     if (!res) {
//       return GeneralResponse::ResponseCode::NOT_FOUND;
//     }
//
//     context = _request->requestContext();
//   }
//
//   if (context == nullptr) {
//     return GeneralResponse::ResponseCode::SERVER_ERROR;
//   }
//
//   return context->authenticate();
// }

// convert internal GeneralRequest to VppRequest
VppRequest* VppCommTask::requestAsVpp() {
  VppRequest* request = dynamic_cast<VppRequest*>(_request);
  if (request == nullptr) {
    THROW_ARANGO_EXCEPTION(TRI_ERROR_INTERNAL);
  }
  return request;
};
<|endoftext|>


<commit_before>/*****************************************************************************

  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
  more contributor license agreements.  See the NOTICE file distributed
  with this work for additional information regarding copyright ownership.
  Accellera licenses this file to you 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.

 *****************************************************************************/

#ifndef __SYSTEMC_EXT_TLM_CORE_2_SOCKETS_INITIATOR_SOCKET_HH__
#define __SYSTEMC_EXT_TLM_CORE_2_SOCKETS_INITIATOR_SOCKET_HH__

#include <typeindex>

#include "../interfaces/fw_bw_ifs.hh"
#include "base_socket_if.hh"

namespace tlm
{

template <unsigned int BUSWIDTH=32,
          typename FW_IF=tlm_fw_transport_if<>,
          typename BW_IF=tlm_bw_transport_if<>>
class tlm_base_initiator_socket_b
{
  public:
    virtual ~tlm_base_initiator_socket_b() {}

    virtual sc_core::sc_port_b<FW_IF> &get_base_port() = 0;
    virtual sc_core::sc_port_b<FW_IF> const &get_base_port() const = 0;
    virtual BW_IF &get_base_interface() = 0;
    virtual BW_IF const &get_base_interface() const = 0;
    virtual sc_core::sc_export<BW_IF> &get_base_export() = 0;
    virtual sc_core::sc_export<BW_IF> const &get_base_export() const = 0;
};

template <unsigned int BUSWIDTH, typename FW_IF, typename BW_IF>
class tlm_base_target_socket_b;

template <unsigned int BUSWIDTH, typename FW_IF, typename BW_IF, int N,
          sc_core::sc_port_policy POL>
class tlm_base_target_socket;

template <unsigned int BUSWIDTH=32, typename FW_IF=tlm_fw_transport_if<>,
          typename BW_IF=tlm_bw_transport_if<>, int N=1,
          sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND>
class tlm_base_initiator_socket :
    public tlm_base_socket_if,
    public tlm_base_initiator_socket_b<BUSWIDTH, FW_IF, BW_IF>,
    public sc_core::sc_port<FW_IF, N, POL>
{
  public:
    typedef FW_IF fw_interface_type;
    typedef BW_IF bw_interface_type;
    typedef sc_core::sc_port<fw_interface_type, N, POL> port_type;

    typedef sc_core::sc_export<bw_interface_type> export_type;

    typedef tlm_base_target_socket_b<
        BUSWIDTH, fw_interface_type, bw_interface_type>
        base_target_socket_type;
    typedef tlm_base_initiator_socket_b<
        BUSWIDTH, fw_interface_type, bw_interface_type> base_type;

    template <unsigned int, typename, typename, int, sc_core::sc_port_policy>
    friend class tlm_base_target_socket;

  public:
    tlm_base_initiator_socket() :
        port_type(sc_core::sc_gen_unique_name("tlm_base_initiator_socket")),
        m_export(sc_core::sc_gen_unique_name(
                    "tlm_base_initiator_socket_export"))
    {}

    explicit tlm_base_initiator_socket(const char *name) : port_type(name),
        m_export(sc_core::sc_gen_unique_name(
                    (std::string(name) + "_export").c_str()))
    {}

    virtual const char* kind() const { return "tlm_base_initiator_socket"; }

    //
    // Bind initiator socket to target socket
    // - Binds the port of the initiator socket to the export of the target
    //   socket
    // - Binds the port of the target socket to the export of the initiator
    //   socket
    //
    virtual void
    bind(base_target_socket_type &s)
    {
        // initiator.port -> target.export
        (get_base_port())(s.get_base_interface());
        // target.port -> initiator.export
        (s.get_base_port())(get_base_interface());
    }

    void operator () (base_target_socket_type &s) { bind(s); }

    //
    // Bind initiator socket to initiator socket (hierarchical bind)
    // - Binds both the export and the port
    //
    virtual void
    bind(base_type &s)
    {
        // port
        (get_base_port())(s.get_base_port());
        // export
        (s.get_base_export())(get_base_export());
    }

    void operator() (base_type &s) { bind(s); }

    //
    // Bind interface to socket
    // - Binds the interface to the export of this socket
    //
    virtual void bind(bw_interface_type &ifs) { (get_base_export())(ifs); }
    void operator() (bw_interface_type &s) { bind(s); }

    // Implementation of tlm_base_socket_if functions
    virtual sc_core::sc_port_base &get_port_base() { return *this; }
    virtual sc_core::sc_port_base const &
    get_port_base() const
    {
        return *this;
    }
    virtual sc_core::sc_export_base &get_export_base() { return m_export; }
    virtual sc_core::sc_export_base const &
    get_export_base() const
    {
        return m_export;
    }
    virtual unsigned int get_bus_width() const { return BUSWIDTH; }
    virtual tlm_socket_category
    get_socket_category() const
    {
        return TLM_INITIATOR_SOCKET;
    }

    // Implementation of tlm_base_target_socket_b functions
    virtual sc_core::sc_port_b<FW_IF> &get_base_port() { return *this; }
    virtual sc_core::sc_port_b<FW_IF> const &
    get_base_port() const
    {
        return *this;
    }

    virtual BW_IF &get_base_interface() { return m_export; }
    virtual BW_IF const &get_base_interface() const { return m_export; }

    virtual sc_core::sc_export<BW_IF> &get_base_export() { return m_export; }
    virtual sc_core::sc_export<BW_IF> const &
    get_base_export() const
    {
        return m_export;
    }

  protected:
    export_type m_export;

  private:
    using port_type::bind;
};

//
// Convenience socket classes
//

template <unsigned int BUSWIDTH=32, typename TYPES=tlm_base_protocol_types,
          int N=1, sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND>
class tlm_initiator_socket : public tlm_base_initiator_socket<
                             BUSWIDTH, tlm_fw_transport_if<TYPES>,
                             tlm_bw_transport_if<TYPES>, N, POL>
{
  public:
    tlm_initiator_socket() : tlm_base_initiator_socket<
                             BUSWIDTH, tlm_fw_transport_if<TYPES>,
                             tlm_bw_transport_if<TYPES>, N, POL>()
    {}

    explicit tlm_initiator_socket(const char *name) :
        tlm_base_initiator_socket<BUSWIDTH, tlm_fw_transport_if<TYPES>,
                                  tlm_bw_transport_if<TYPES>, N, POL>(name)
    {}

    virtual const char *kind() const { return "tlm_initiator_socket"; }

    virtual std::type_index
    get_protocol_types() const
    {
        return typeid(TYPES);
    }
};

} // namespace tlm

#endif /* __SYSTEMC_EXT_TLM_CORE_2_SOCKETS_INITIATOR_SOCKET_HH__ */
<commit_msg>systemc: Purposefully *expose* bind in the initiator socket.<commit_after>/*****************************************************************************

  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
  more contributor license agreements.  See the NOTICE file distributed
  with this work for additional information regarding copyright ownership.
  Accellera licenses this file to you 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.

 *****************************************************************************/

#ifndef __SYSTEMC_EXT_TLM_CORE_2_SOCKETS_INITIATOR_SOCKET_HH__
#define __SYSTEMC_EXT_TLM_CORE_2_SOCKETS_INITIATOR_SOCKET_HH__

#include <typeindex>

#include "../interfaces/fw_bw_ifs.hh"
#include "base_socket_if.hh"

namespace tlm
{

template <unsigned int BUSWIDTH=32,
          typename FW_IF=tlm_fw_transport_if<>,
          typename BW_IF=tlm_bw_transport_if<>>
class tlm_base_initiator_socket_b
{
  public:
    virtual ~tlm_base_initiator_socket_b() {}

    virtual sc_core::sc_port_b<FW_IF> &get_base_port() = 0;
    virtual sc_core::sc_port_b<FW_IF> const &get_base_port() const = 0;
    virtual BW_IF &get_base_interface() = 0;
    virtual BW_IF const &get_base_interface() const = 0;
    virtual sc_core::sc_export<BW_IF> &get_base_export() = 0;
    virtual sc_core::sc_export<BW_IF> const &get_base_export() const = 0;
};

template <unsigned int BUSWIDTH, typename FW_IF, typename BW_IF>
class tlm_base_target_socket_b;

template <unsigned int BUSWIDTH, typename FW_IF, typename BW_IF, int N,
          sc_core::sc_port_policy POL>
class tlm_base_target_socket;

template <unsigned int BUSWIDTH=32, typename FW_IF=tlm_fw_transport_if<>,
          typename BW_IF=tlm_bw_transport_if<>, int N=1,
          sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND>
class tlm_base_initiator_socket :
    public tlm_base_socket_if,
    public tlm_base_initiator_socket_b<BUSWIDTH, FW_IF, BW_IF>,
    public sc_core::sc_port<FW_IF, N, POL>
{
  public:
    typedef FW_IF fw_interface_type;
    typedef BW_IF bw_interface_type;
    typedef sc_core::sc_port<fw_interface_type, N, POL> port_type;

    typedef sc_core::sc_export<bw_interface_type> export_type;

    typedef tlm_base_target_socket_b<
        BUSWIDTH, fw_interface_type, bw_interface_type>
        base_target_socket_type;
    typedef tlm_base_initiator_socket_b<
        BUSWIDTH, fw_interface_type, bw_interface_type> base_type;

    template <unsigned int, typename, typename, int, sc_core::sc_port_policy>
    friend class tlm_base_target_socket;

  public:
    tlm_base_initiator_socket() :
        port_type(sc_core::sc_gen_unique_name("tlm_base_initiator_socket")),
        m_export(sc_core::sc_gen_unique_name(
                    "tlm_base_initiator_socket_export"))
    {}

    explicit tlm_base_initiator_socket(const char *name) : port_type(name),
        m_export(sc_core::sc_gen_unique_name(
                    (std::string(name) + "_export").c_str()))
    {}

    virtual const char* kind() const { return "tlm_base_initiator_socket"; }

    //
    // Bind initiator socket to target socket
    // - Binds the port of the initiator socket to the export of the target
    //   socket
    // - Binds the port of the target socket to the export of the initiator
    //   socket
    //
    virtual void
    bind(base_target_socket_type &s)
    {
        // initiator.port -> target.export
        (get_base_port())(s.get_base_interface());
        // target.port -> initiator.export
        (s.get_base_port())(get_base_interface());
    }

    void operator () (base_target_socket_type &s) { bind(s); }

    //
    // Bind initiator socket to initiator socket (hierarchical bind)
    // - Binds both the export and the port
    //
    virtual void
    bind(base_type &s)
    {
        // port
        (get_base_port())(s.get_base_port());
        // export
        (s.get_base_export())(get_base_export());
    }

    using port_type::bind;

    void operator() (base_type &s) { bind(s); }

    //
    // Bind interface to socket
    // - Binds the interface to the export of this socket
    //
    virtual void bind(bw_interface_type &ifs) { (get_base_export())(ifs); }
    void operator() (bw_interface_type &s) { bind(s); }

    // Implementation of tlm_base_socket_if functions
    virtual sc_core::sc_port_base &get_port_base() { return *this; }
    virtual sc_core::sc_port_base const &
    get_port_base() const
    {
        return *this;
    }
    virtual sc_core::sc_export_base &get_export_base() { return m_export; }
    virtual sc_core::sc_export_base const &
    get_export_base() const
    {
        return m_export;
    }
    virtual unsigned int get_bus_width() const { return BUSWIDTH; }
    virtual tlm_socket_category
    get_socket_category() const
    {
        return TLM_INITIATOR_SOCKET;
    }

    // Implementation of tlm_base_target_socket_b functions
    virtual sc_core::sc_port_b<FW_IF> &get_base_port() { return *this; }
    virtual sc_core::sc_port_b<FW_IF> const &
    get_base_port() const
    {
        return *this;
    }

    virtual BW_IF &get_base_interface() { return m_export; }
    virtual BW_IF const &get_base_interface() const { return m_export; }

    virtual sc_core::sc_export<BW_IF> &get_base_export() { return m_export; }
    virtual sc_core::sc_export<BW_IF> const &
    get_base_export() const
    {
        return m_export;
    }

  protected:
    export_type m_export;
};

//
// Convenience socket classes
//

template <unsigned int BUSWIDTH=32, typename TYPES=tlm_base_protocol_types,
          int N=1, sc_core::sc_port_policy POL=sc_core::SC_ONE_OR_MORE_BOUND>
class tlm_initiator_socket : public tlm_base_initiator_socket<
                             BUSWIDTH, tlm_fw_transport_if<TYPES>,
                             tlm_bw_transport_if<TYPES>, N, POL>
{
  public:
    tlm_initiator_socket() : tlm_base_initiator_socket<
                             BUSWIDTH, tlm_fw_transport_if<TYPES>,
                             tlm_bw_transport_if<TYPES>, N, POL>()
    {}

    explicit tlm_initiator_socket(const char *name) :
        tlm_base_initiator_socket<BUSWIDTH, tlm_fw_transport_if<TYPES>,
                                  tlm_bw_transport_if<TYPES>, N, POL>(name)
    {}

    virtual const char *kind() const { return "tlm_initiator_socket"; }

    virtual std::type_index
    get_protocol_types() const
    {
        return typeid(TYPES);
    }
};

} // namespace tlm

#endif /* __SYSTEMC_EXT_TLM_CORE_2_SOCKETS_INITIATOR_SOCKET_HH__ */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ip_ce.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 16:19:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ARY_IDL_IP_CE_HXX
#define ARY_IDL_IP_CE_HXX

// USED SERVICES
    // BASE CLASSES
    // COMPONENTS
    // PARAMETERS
#include <ary/idl/i_language.hxx>
#include <ary/idl/i_property.hxx>

namespace ary
{

class QualifiedName;

namespace idl
{
    class Module;

    class ConstantsGroup;
    class Enum;
    class Exception;
    class Interface;
    class Service;
    class SglIfcService;
    class Singleton;
    class SglIfcSingleton;
    class Struct;
    class Typedef;

    class Attribute;
    class Constant;
    class EnumValue;
    class Function;
    class Property;
    class StructElement;
    class Variable;

    class NameLookup;

/** @resp
    Provides the access logic for all code entities.

    @interface
*/
class CePilot
{
  public:
    // LIFECYCLE
    virtual             ~CePilot() {}

    // OPERATIONS
    Module &            CheckIn_Module(
                            Ce_id               i_nParentId,
                            const String &      i_sName );
    Service &           Store_Service(
                            Ce_id               i_nOwner,
                            const String &      i_sName );
    virtual SglIfcService &
                        Store_SglIfcService(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBaseInterface ) = 0;
    Interface &         Store_Interface(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase );
    Struct &            Store_Struct(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase,
                            const String &      i_sTemplateParam = String::Null_() );
    Exception &         Store_Exception(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase );
    Enum &              Store_Enum(
                            Ce_id               i_nOwner,
                            const String &      i_sName );
    Typedef &           Store_Typedef(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nDefiningType );
    ConstantsGroup &    Store_ConstantsGroup(
                            Ce_id               i_nOwner,
                            const String &      i_sName );
    Singleton &         Store_Singleton(
                            Ce_id               i_nOwner,
                            const String &      i_sName );
    virtual SglIfcSingleton &
                        Store_SglIfcSingleton(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBaseInterface ) = 0;

    Constant &          Store_Constant(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            const String &      i_sValue );
    Property &          Store_Property(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            Property::Stereotypes
                                                i_stereotypes );
    Function &          Store_Function(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nReturnType,
                            bool                i_bOneWay );
    virtual Function &  Store_ServiceConstructor(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    StructElement &     Store_StructMember(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType );
    StructElement &     Store_ExceptionMember(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType );
    EnumValue &         Store_EnumValue(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            const String &      i_sValue );
    Attribute &         Store_Attribute(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            bool                i_bReadOnly,
                            bool                i_bBound );
    // INQUIRY
    const Module &      GlobalNamespace() const;
    const CodeEntity &  Find_Ce(
                            Ce_id               i_nId ) const;

    const Module &      Find_Module(
                            Ce_id               i_nId ) const;
    const Module *      Search_Module(
                            Ce_id               i_nId ) const;
    const Function &    Find_Function(
                            Ce_id               i_nId ) const;
    const Property &    Find_Property(
                            Ce_id               i_nId ) const;
    const EnumValue &   Find_EnumValue(
                            Ce_id               i_nId ) const;
    const Constant &    Find_Constant(
                            Ce_id               i_nId ) const;
    const StructElement &
                        Find_StructElement(
                            Ce_id               i_nId ) const;
    void                Get_Text(
                            StringVector &      o_module,
                            String &            o_ce,
                            String &            o_member,
                            const CodeEntity &  i_ce ) const;
    const NameLookup &  NameDictionary() const;

    // ACCESS
    Module &            GlobalNamespace();
    CodeEntity &        Find_Ce(
                            Ce_id               i_nId );

  private:
    // Locals
    virtual Module &    do_CheckIn_Module(
                            Ce_id               i_nParentId,
                            const String &      i_sName ) = 0;
    virtual Service &   do_Store_Service(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual Interface & do_Store_Interface(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase ) = 0;
    virtual Struct &    do_Store_Struct(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase,
                            const String &      i_sTemplateParam ) = 0;
    virtual Exception & do_Store_Exception(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase ) = 0;
    virtual Enum &      do_Store_Enum(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual Typedef &   do_Store_Typedef(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nDefiningType ) = 0;
    virtual ConstantsGroup &
                        do_Store_ConstantsGroup(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual Singleton & do_Store_Singleton(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;

    virtual Constant &  do_Store_Constant(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            const String &      i_sValue ) = 0;
    virtual Property &  do_Store_Property(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            Property::Stereotypes
                                                i_stereotypes ) = 0;
    virtual Function &  do_Store_Function(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nReturnType,
                            bool                i_bOneWay ) = 0;
    virtual StructElement &
                        do_Store_StructMember(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType ) = 0;
    virtual StructElement &
                        do_Store_ExceptionMember(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType ) = 0;
    virtual EnumValue & do_Store_EnumValue(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            const String &      i_sValue ) = 0;
    virtual Attribute & do_Store_Attribute(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            bool                i_bReadOnly,
                            bool                i_bBound ) = 0;

    virtual const Module &
                        inq_GlobalNamespace() const = 0;
    virtual const CodeEntity &
                        inq_Find_Ce(
                            Ce_id               i_nId ) const = 0;
    virtual const Module &
                        inq_Find_Module(
                            Ce_id               i_nId ) const = 0;
    virtual const Module *
                        inq_Search_Module(
                            Ce_id               i_nId ) const = 0;
    virtual const Function &
                        inq_Find_Function(
                            Ce_id               i_nId ) const = 0;
    virtual const Property &
                        inq_Find_Property(
                            Ce_id               i_nId ) const = 0;
    virtual const EnumValue &
                        inq_Find_EnumValue(
                            Ce_id               i_nId ) const = 0;
    virtual const Constant &
                        inq_Find_Constant(
                            Ce_id               i_nId ) const = 0;
    virtual const StructElement &
                        inq_Find_StructElement(
                            Ce_id               i_nId ) const = 0;
    virtual void        inq_Get_Text(
                            StringVector &      o_module,
                            String &            o_ce,
                            String &            o_member,
                            const CodeEntity &  i_ce ) const = 0;
    virtual const NameLookup &
                        inq_NameDictionary() const = 0;

    // ACCESS
    virtual Module &    access_GlobalNamespace() = 0;
    virtual CodeEntity &
                        access_Find_Ce(
                            Ce_id               i_nId ) = 0;
};

// IMPLEMENTATION

inline Module &
CePilot::CheckIn_Module(    Ce_id               i_nParentId,
                            const String &      i_sName )
    { return do_CheckIn_Module(i_nParentId, i_sName); }

inline Service &
CePilot::Store_Service(     Ce_id               i_nOwner,
                            const String &      i_sName )
    { return do_Store_Service(i_nOwner,i_sName); }

inline Interface &
CePilot::Store_Interface(   Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase )
    { return do_Store_Interface(i_nOwner,i_sName,i_nBase); }

inline Struct &
CePilot::Store_Struct(      Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase,
                            const String &      i_sTemplateParam )
    { return do_Store_Struct(i_nOwner,i_sName,i_nBase,i_sTemplateParam); }

inline Exception &
CePilot::Store_Exception(   Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase )
    { return do_Store_Exception(i_nOwner,i_sName,i_nBase); }

inline Enum &
CePilot::Store_Enum(        Ce_id               i_nOwner,
                            const String &      i_sName )
    { return do_Store_Enum(i_nOwner,i_sName); }

inline Typedef &
CePilot::Store_Typedef(     Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nDefiningType )
    { return do_Store_Typedef(i_nOwner,i_sName,i_nDefiningType); }

inline ConstantsGroup &
CePilot::Store_ConstantsGroup(  Ce_id               i_nOwner,
                                const String &      i_sName )
    { return do_Store_ConstantsGroup(i_nOwner,i_sName); }

inline Singleton &
CePilot::Store_Singleton( Ce_id               i_nOwner,
                          const String &      i_sName )
    { return do_Store_Singleton(i_nOwner,i_sName); }

inline Constant &
CePilot::Store_Constant(    Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            const String &      i_sValue )
    { return do_Store_Constant(i_nOwner,i_sName,i_nType,i_sValue); }

inline Property &
CePilot::Store_Property(    Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            ary::idl::Property::Stereotypes
                                                i_stereotypes )
    { return do_Store_Property(i_nOwner,i_sName,i_nType,i_stereotypes); }

inline Function &
CePilot::Store_Function(    Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nReturnType,
                            bool                i_bOneWay )
    { return do_Store_Function(i_nOwner,i_sName,i_nReturnType,i_bOneWay); }

inline StructElement &
CePilot::Store_StructMember(   Ce_id               i_nOwner,
                               const String &      i_sName,
                               Type_id             i_nType )
    { return do_Store_StructMember(i_nOwner,i_sName,i_nType); }

inline StructElement &
CePilot::Store_ExceptionMember( Ce_id               i_nOwner,
                                const String &      i_sName,
                                Type_id             i_nType )
    { return do_Store_ExceptionMember(i_nOwner,i_sName,i_nType); }

inline EnumValue &
CePilot::Store_EnumValue(   Ce_id               i_nOwner,
                            const String &      i_sName,
                            const String &      i_sValue )
    { return do_Store_EnumValue(i_nOwner,i_sName,i_sValue); }

inline Attribute &
CePilot::Store_Attribute( Ce_id               i_nOwner,
                          const String &      i_sName,
                          Type_id             i_nType,
                          bool                i_bReadOnly,
                          bool                i_bBound )
    { return do_Store_Attribute(i_nOwner, i_sName, i_nType, i_bReadOnly, i_bBound); }

inline const Module &
CePilot::GlobalNamespace() const
    { return inq_GlobalNamespace(); }
inline const CodeEntity &
CePilot::Find_Ce( Ce_id i_nId ) const
    { return inq_Find_Ce(i_nId); }
inline const Module &
CePilot::Find_Module( Ce_id i_nId ) const
    { return inq_Find_Module(i_nId); }
inline const Module *
CePilot::Search_Module( Ce_id i_nId ) const
    { return inq_Search_Module(i_nId); }
inline const Function &
CePilot::Find_Function( Ce_id i_nId ) const
    { return inq_Find_Function(i_nId); }
inline const Property &
CePilot::Find_Property( Ce_id i_nId ) const
    { return inq_Find_Property(i_nId); }
inline const EnumValue &
CePilot::Find_EnumValue( Ce_id i_nId ) const
    { return inq_Find_EnumValue(i_nId); }
inline const Constant &
CePilot::Find_Constant( Ce_id i_nId ) const
    { return inq_Find_Constant(i_nId); }

inline const StructElement &
CePilot::Find_StructElement( Ce_id i_nId ) const
    { return inq_Find_StructElement(i_nId); }
inline void
CePilot::Get_Text( StringVector &      o_module,
                   String &            o_ce,
                   String &            o_member,
                   const CodeEntity &  i_ce ) const
    { inq_Get_Text(o_module, o_ce, o_member, i_ce);  }

inline const NameLookup &
CePilot::NameDictionary() const
    { return inq_NameDictionary(); }

inline Module &
CePilot::GlobalNamespace()
    { return access_GlobalNamespace(); }
inline CodeEntity &
CePilot::Find_Ce( Ce_id i_nId )
    { return access_Find_Ce(i_nId); }

}   // namespace idl
}   // namespace ary

#endif

<commit_msg>INTEGRATION: CWS adc18 (1.5.56); FILE MERGED 2007/10/18 13:06:37 np 1.5.56.1: #i81775#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ip_ce.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2007-11-02 15:14:08 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ARY_IDL_IP_CE_HXX
#define ARY_IDL_IP_CE_HXX

// USED SERVICES
#include <ary/idl/i_types4idl.hxx>
#include <ary/idl/i_property.hxx>

namespace ary
{
namespace idl
{
    class Module;

    class ConstantsGroup;
    class Enum;
    class Exception;
    class Interface;
    class Service;
    class SglIfcService;
    class Singleton;
    class SglIfcSingleton;
    class Struct;
    class Typedef;

    class Attribute;
    class Constant;
    class EnumValue;
    class Function;
    class Property;
    class StructElement;
    class Variable;

    class NameLookup;

/** Provides the access logic for all code entities.
*/
class CePilot
{
  public:
    // LIFECYCLE
    virtual             ~CePilot() {}

    // OPERATIONS
    virtual Module &    CheckIn_Module(
                            Ce_id               i_nParentId,
                            const String &      i_sName ) = 0;
    virtual Service &   Store_Service(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual SglIfcService &
                        Store_SglIfcService(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBaseInterface ) = 0;
    virtual Interface & Store_Interface(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase ) = 0;
    virtual Struct &    Store_Struct(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase,
                            const String &      i_sTemplateParam = String::Null_() ) = 0;
    virtual Exception & Store_Exception(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBase ) = 0;
    virtual Enum &      Store_Enum(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual Typedef &   Store_Typedef(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nDefiningType ) = 0;
    virtual ConstantsGroup &
                        Store_ConstantsGroup(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual Singleton & Store_Singleton(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual SglIfcSingleton &
                        Store_SglIfcSingleton(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nBaseInterface ) = 0;

    virtual Constant &  Store_Constant(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            const String &      i_sValue ) = 0;
    virtual Property &  Store_Property(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            Property::Stereotypes
                                                i_stereotypes ) = 0;
    virtual Function &  Store_Function(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nReturnType,
                            bool                i_bOneWay ) = 0;
    virtual Function &  Store_ServiceConstructor(
                            Ce_id               i_nOwner,
                            const String &      i_sName ) = 0;
    virtual StructElement &
                        Store_StructMember(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType ) = 0;
    virtual StructElement &
                        Store_ExceptionMember(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType ) = 0;
    virtual EnumValue & Store_EnumValue(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            const String &      i_sValue ) = 0;
    virtual Attribute & Store_Attribute(
                            Ce_id               i_nOwner,
                            const String &      i_sName,
                            Type_id             i_nType,
                            bool                i_bReadOnly,
                            bool                i_bBound ) = 0;
    // INQUIRY
    virtual const Module &
                        GlobalNamespace() const = 0;
    virtual const CodeEntity &
                        Find_Ce(
                            Ce_id               i_nId ) const = 0;

    virtual const Module &
                        Find_Module(
                            Ce_id               i_nId ) const = 0;
    virtual const Module *
                        Search_Module(
                            Ce_id               i_nId ) const = 0;
    virtual const Function &
                        Find_Function(
                            Ce_id               i_nId ) const = 0;
    virtual const Property &
                        Find_Property(
                            Ce_id               i_nId ) const = 0;
    virtual const EnumValue &
                        Find_EnumValue(
                            Ce_id               i_nId ) const = 0;
    virtual const Constant &
                        Find_Constant(
                            Ce_id               i_nId ) const = 0;
    virtual const StructElement &
                        Find_StructElement(
                            Ce_id               i_nId ) const = 0;
    virtual void        Get_Text(
                            StringVector &      o_module,
                            String &            o_ce,
                            String &            o_member,
                            const CodeEntity &  i_ce ) const = 0;
    virtual const NameLookup &
                        NameDictionary() const = 0;
    virtual void        Get_AlphabeticalIndex(
                            std::vector<Ce_id> &
                                                o_rResult,
                            alphabetical_index::E_Letter
                                                i_cLetter) const = 0;
    // ACCESS
    virtual Module &    GlobalNamespace() = 0;
    virtual CodeEntity &
                        Find_Ce(
                            Ce_id               i_nId ) = 0;
};

}   // namespace idl
}   // namespace ary
#endif
<|endoftext|>