Skip to content

File cgroup.cpp

File List > base > cgroup.cpp

Go to the documentation of this file

/*
 *
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/*
 * cgroup.cpp - get information about cgroup
 */

#include <fstream>
#include <limits>

#include "filesys_parser.hpp"
#include "cgroup.hpp"

// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

namespace os::cgroup
{
  std::optional<std::filesystem::path> mountpoint ()
  {
    std::ifstream file (path::proc_mountinfo);
    std::size_t separator, whitespace;
    std::string line, name, path;

    if (!file)
      {
    /* _er_log_debug (ARG_FILE_LINE, "failed to open %s: %s\n", path::proc_mountinfo, strerror (errno)); */
    return std::nullopt;
      }

    while (std::getline (file, line))
      {
    separator = line.find (" - ");
    if (separator == std::string::npos)
      {
        continue;
      }

    whitespace = line.find (' ', separator + 3);
    if (whitespace == std::string::npos)
      {
        continue;
      }

    name = line.substr (separator + 3, whitespace - (separator + 3));
    if (name.empty ())
      {
        continue;
      }

    if (name.compare ("cgroup2"))
      {
        continue;
      }

    auto vec = parser::string_to_vector (line.substr (0, separator), ' ');
    if (vec.size () > 4)
      {
        return vec[4];
      }
    return std::nullopt;
      }

    return std::nullopt;
  }

  std::optional<std::filesystem::path> relative ()
  {
    std::ifstream file (path::proc_cgroup);
    std::string line;

    if (!file)
      {
    /* _er_log_debug (ARG_FILE_LINE, "failed to open %s: %s\n", path::proc_cgroup, strerror (errno)); */
    return std::nullopt;
      }

    while (std::getline (file, line))
      {
    auto vec = parser::string_to_vector (line, ':');
    if (vec.size () <= 2)
      {
        continue;
      }
    if (vec[0].compare ("0"))
      {
        continue;
      }
    return vec[2];
      }

    return std::nullopt;
  }

  namespace cpu
  {
    std::optional<double> max_v2 (std::filesystem::path path)
    {
      std::ifstream file (path / "cpu.max");
      std::string first;
      double quota, period = 0;

      if (!file)
    {
      return std::nullopt;
    }

      if (! (file >> first >> period) || period <= 0)
    {
      return std::nullopt;
    }

      if (!first.compare ("max"))
    {
      return std::numeric_limits<double>::max ();
    }

      quota = std::atof (first.c_str ());
      if (quota > 0)
    {
      return quota / period;
    }
      return std::nullopt;
    }

    std::optional<std::set<std::size_t>> effective_v2 (std::filesystem::path path)
    {
      std::ifstream file (path / "cpuset.cpus.effective");
      std::string line;

      if (!file)
    {
      return std::nullopt;
    }

      file >> line;
      if (line.empty ())
    {
      /* _er_log_debug (ARG_FILE_LINE, "the file %s is empty.\n", path.c_str ()); */
      return std::nullopt;
    }
      return parser::range_set_to_set<std::size_t> (line);
    }

    context quota_v2 ()
    {
      std::optional<std::filesystem::path> mountpoint, relative;
      std::optional<std::set<std::size_t>> effective;
      std::optional<double> max;
      std::filesystem::path path;
      bool flag = true;
      context ctx;

      mountpoint = cgroup::mountpoint ();
      if (!mountpoint)
    {
      return ctx;
    }
      relative = cgroup::relative ();
      if (mountpoint && relative)
    {
      path = *mountpoint / relative->relative_path ().lexically_normal ();
    }
      else
    {
      path = *mountpoint;
    }

      while (path != mountpoint || flag)
    {
      max = max_v2 (path);
      if (max)
        {
          if (ctx.max_v2)
        {
          if (*ctx.max_v2 > *max)
            {
              ctx.max_v2 = *max;
            }
        }
          else
        {
          ctx.max_v2 = *max;
        }
        }

      effective = effective_v2 (path);
      if (effective)
        {
          if (ctx.effective_v2 && (!effective->empty () && !ctx.effective_v2->empty ()))
        {
          ctx.effective_v2 = parser::intersection (*ctx.effective_v2, *effective);
        }
          else
        {
          ctx.effective_v2 = std::move (effective);
        }
        }

      if (path != mountpoint)
        {
          path = path.parent_path ();
        }
      else
        {
          flag = false;
        }
    }

      return ctx;
    }
  }
}