summaryrefslogtreecommitdiffstats
path: root/service/service.php
blob: e53468828d2fba99dc94a2fd6c401ed4a78a44db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php
/**
 * ownCloud - News
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Alessandro Cosentino <cosenal@gmail.com>
 * @author Bernhard Posselt <dev@bernhard-posselt.com>
 * @copyright Alessandro Cosentino 2012
 * @copyright Bernhard Posselt 2012, 2014
 */

namespace OCA\News\Service;

use \OCP\AppFramework\Db\DoesNotExistException;
use \OCP\AppFramework\Db\MultipleObjectsReturnedException;

use \OCA\News\Db\NewsMapper;


abstract class Service {

    protected $mapper;

    public function __construct(NewsMapper $mapper){
        $this->mapper = $mapper;
    }


    /**
     * Delete an entity
     * @param int $id the id of the entity
     * @param string $userId the name of the user for security reasons
     * @throws ServiceNotFoundException if the entity does not exist, or there
     * are more than one of it
     */
    public function delete($id, $userId){
        $entity = $this->find($id, $userId);
        $this->mapper->delete($entity);
    }


    /**
     * Finds an entity by id
     * @param int $id the id of the entity
     * @param string $userId the name of the user for security reasons
     * @throws ServiceNotFoundException if the entity does not exist, or there
     * are more than one of it
     * @return \OCP\AppFramework\Db\Entity the entity
     */
    public function find($id, $userId){
        try {
            return $this->mapper->find($id, $userId);
        } catch(DoesNotExistException $ex){
            throw new ServiceNotFoundException($ex->getMessage());
        } catch(MultipleObjectsReturnedException $ex){
            throw new ServiceNotFoundException($ex->getMessage());
        }
    }

}
'>407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
// SPDX-License-Identifier: GPL-3.0-or-later

#include "ebpf.h"
#include "ebpf_oomkill.h"

struct config oomkill_config = { .first_section = NULL,
    .last_section = NULL,
    .mutex = NETDATA_MUTEX_INITIALIZER,
    .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
        .rwlock = AVL_LOCK_INITIALIZER } };

#define OOMKILL_MAP_KILLCNT 0
static ebpf_local_maps_t oomkill_maps[] = {
    {
        .name = "tbl_oomkill",
        .internal_input = NETDATA_OOMKILL_MAX_ENTRIES,
        .user_input = 0,
        .type = NETDATA_EBPF_MAP_STATIC,
        .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
#ifdef LIBBPF_MAJOR_VERSION
        .map_type = BPF_MAP_TYPE_PERCPU_HASH
#endif
    },
    /* end */
    {
        .name = NULL,
        .internal_input = 0,
        .user_input = 0,
        .type = NETDATA_EBPF_MAP_CONTROLLER,
        .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
#ifdef LIBBPF_MAJOR_VERSION
        .map_type = BPF_MAP_TYPE_PERCPU_HASH
#endif
    }
};

static ebpf_tracepoint_t oomkill_tracepoints[] = {
    {.enabled = false, .class = "oom", .event = "mark_victim"},
    /* end */
    {.enabled = false, .class = NULL, .event = NULL}
};

static netdata_publish_syscall_t oomkill_publish_aggregated = {.name = "oomkill", .dimension = "oomkill",
                                                               .algorithm = "absolute",
                                                               .next = NULL};

static void ebpf_create_specific_oomkill_charts(char *type, int update_every);

/**
 * Obsolete services
 *
 * Obsolete all service charts created
 *
 * @param em a pointer to `struct ebpf_module`
 */
static void ebpf_obsolete_oomkill_services(ebpf_module_t *em)
{
    ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
                              NETDATA_OOMKILL_CHART,
                              "",
                              "OOM kills. This chart is provided by eBPF plugin.",
                              EBPF_COMMON_DIMENSION_KILLS,
                              NETDATA_EBPF_MEMORY_GROUP,
                              NETDATA_EBPF_CHART_TYPE_LINE,
                              NULL,
                              20191,
                              em->update_every);
}

/**
 * Obsolete cgroup chart
 *
 * Send obsolete for all charts created before to close.
 *
 * @param em a pointer to `struct ebpf_module`
 */
static inline void ebpf_obsolete_oomkill_cgroup_charts(ebpf_module_t *em)
{
    pthread_mutex_lock(&mutex_cgroup_shm);

    ebpf_obsolete_oomkill_services(em);

    ebpf_cgroup_target_t *ect;
    for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
        if (ect->systemd)
            continue;

        ebpf_create_specific_oomkill_charts(ect->name, em->update_every);
    }
    pthread_mutex_unlock(&mutex_cgroup_shm);
}

/**
 * Obsolete global
 *
 * Obsolete global charts created by thread.
 *
 * @param em a pointer to `struct ebpf_module`
 */
static void ebpf_obsolete_oomkill_apps(ebpf_module_t *em)
{
    struct ebpf_target *w;
    int update_every = em->update_every;
    for (w = apps_groups_root_target; w; w = w->next) {
        if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_OOMKILL_IDX))))
            continue;

        ebpf_write_chart_obsolete(NETDATA_APP_FAMILY,
                                  w->clean_name,
                                  "_app_oomkill",
                                  "OOM kills.",
                                  EBPF_COMMON_DIMENSION_KILLS,
                                  NETDATA_EBPF_MEMORY_GROUP,
                                  NETDATA_EBPF_CHART_TYPE_STACKED,
                                  "ebpf.app_oomkill",
                                  20020,
                                  update_every);

        w->charts_created &= ~(1<<EBPF_MODULE_OOMKILL_IDX);
    }
}

/**
 * Clean up the main thread.
 *
 * @param ptr thread data.
 */
static void oomkill_cleanup(void *ptr)
{
    ebpf_module_t *em = (ebpf_module_t *)ptr;

    if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
        pthread_mutex_lock(&lock);

        if (em->cgroup_charts) {
            ebpf_obsolete_oomkill_cgroup_charts(em);
        }

        ebpf_obsolete_oomkill_apps(em);

        fflush(stdout);
        pthread_mutex_unlock(&lock);
    }

    ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);

    if (em->objects) {
        ebpf_unload_legacy_code(em->objects, em->probe_links);
        em->objects = NULL;
        em->probe_links = NULL;
    }

    pthread_mutex_lock(&ebpf_exit_cleanup);
    em->enabled = NETDATA_THREAD_EBPF_STOPPED;
    ebpf_update_stats(&plugin_statistics, em);
    pthread_mutex_unlock(&ebpf_exit_cleanup);
}

static void oomkill_write_data(int32_t *keys, uint32_t total)
{
    // for each app, see if it was OOM killed. record as 1 if so otherwise 0.
    struct ebpf_target *w;
    for (w = apps_groups_root_target; w != NULL; w = w->next) {
        if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_OOMKILL_IDX))))
            continue;

        bool was_oomkilled = false;
        if (total) {
            struct ebpf_pid_on_target *pids = w->root_pid;
            while (pids) {
                uint32_t j;
                for (j = 0; j < total; j++) {
                    if (pids->pid == keys[j]) {
                        was_oomkilled = true;
                        // set to 0 so we consider it "done".
                        keys[j] = 0;
                        goto write_dim;
                    }
                }
                pids = pids->next;
            }
        }
write_dim:
        ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_oomkill");
        write_chart_dimension(EBPF_COMMON_DIMENSION_KILLS, was_oomkilled);
        ebpf_write_end_chart();
    }

    // for any remaining keys for which we couldn't find a group, this could be
    // for various reasons, but the primary one is that the PID has not yet
    // been picked up by the process thread when parsing the proc filesystem.
    // since it's been OOM killed, it will never be parsed in the future, so
    // we have no choice but to dump it into `other`.
    uint32_t j;
    uint32_t rem_count = 0;
    for (j = 0; j < total; j++) {
        int32_t key = keys[j];
        if (key != 0) {
            rem_count += 1;
        }
    }
    if (rem_count > 0) {
        write_chart_dimension("other", rem_count);
    }
}

/**
 * Create specific OOMkill charts
 *
 * Create charts for cgroup/application.
 *
 * @param type the chart type.
 * @param update_every value to overwrite the update frequency set by the server.
 */
static void ebpf_create_specific_oomkill_charts(char *type, int update_every)
{
    ebpf_create_chart(type, NETDATA_OOMKILL_CHART, "OOM kills. This chart is provided by eBPF plugin.",
                      EBPF_COMMON_DIMENSION_KILLS, NETDATA_EBPF_MEMORY_GROUP,
                      NETDATA_CGROUP_OOMKILLS_CONTEXT, NETDATA_EBPF_CHART_TYPE_LINE,
                      NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5600,
                      ebpf_create_global_dimension,
                      &oomkill_publish_aggregated, 1, update_every, NETDATA_EBPF_MODULE_NAME_OOMKILL);
}

/**