<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: <NAME> <<EMAIL>>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "child_stock.hxx"
#include "child_socket.hxx"
#include "spawn/ExitListener.hxx"
#include "stock/Stock.hxx"
#include "stock/Item.hxx"
#include "spawn/Interface.hxx"
#include "spawn/Prepared.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "pool/pool.hxx"

#include <string>

#include <assert.h>
#include <unistd.h>

int
ChildStockClass::GetChildSocketType(void *) const noexcept
{
    return SOCK_STREAM;
}

const char *
ChildStockClass::GetChildTag(void *) const noexcept
{
    return nullptr;
}

struct ChildStockItem final : StockItem, ExitListener {
    SpawnService &spawn_service;

    const std::string tag;

    ChildSocket socket;
    int pid = -1;

    bool busy = true;

    ChildStockItem(CreateStockItem c,
                   SpawnService &_spawn_service,
                   const char *_tag) noexcept
        :StockItem(c),
         spawn_service(_spawn_service),
         tag(_tag != nullptr ? _tag : "") {}

    ~ChildStockItem() override;

    void Spawn(ChildStockClass &cls, void *info);

    /* virtual methods from class StockItem */
    bool Borrow() noexcept override {
        assert(!busy);
        busy = true;

        return true;
    }

    bool Release() noexcept override {
        assert(busy);
        busy = false;

        /* reuse this item only if the child process hasn't exited */
        return pid > 0;
    }

    /* virtual methods from class ExitListener */
    void OnChildProcessExit(int status) override;
};

void
ChildStockItem::Spawn(ChildStockClass &cls, void *info)
{
    int socket_type = cls.GetChildSocketType(info);

    PreparedChildProcess p;
    cls.PrepareChild(info, socket.Create(socket_type), p);

    pid = spawn_service.SpawnChildProcess(GetStockName(), std::move(p), this);
}

void
ChildStockItem::OnChildProcessExit(gcc_unused int status)
{
    pid = -1;

    if (!busy)
        InvokeIdleDisconnect();
}

/*
 * stock class
 *
 */

void
ChildStock::Create(CreateStockItem c, void *info,
                   struct pool &, CancellablePointer &)
{
    auto *item = new ChildStockItem(c, spawn_service,
                                    cls.GetChildTag(info));

    try {
        item->Spawn(cls, info);
    } catch (...) {
        delete item;
        throw;
    }

    item->InvokeCreateSuccess();
}

ChildStockItem::~ChildStockItem()
{
    if (pid >= 0)
        spawn_service.KillChildProcess(pid);

    if (socket.IsDefined())
        socket.Unlink();
}

/*
 * interface
 *
 */

ChildStock::ChildStock(EventLoop &event_loop, SpawnService &_spawn_service,
                       ChildStockClass &_cls,
                       unsigned _limit, unsigned _max_idle) noexcept
    :map(event_loop, *this, _limit, _max_idle),
     spawn_service(_spawn_service), cls(_cls)
{
}

void
ChildStock::FadeTag(const char *tag)
{
    map.FadeIf([tag](const StockItem &_item) {
            const auto &item = (const ChildStockItem &)_item;
            return item.tag == tag;
        });
}

UniqueSocketDescriptor
child_stock_item_connect(StockItem &_item)
{
    auto &item = (ChildStockItem &)_item;

    try {
        return item.socket.Connect();
    } catch (...) {
        /* if the connection fails, abandon the child process, don't
           try again - it will never work! */
        item.fade = true;
        throw;
    }
}

const char *
child_stock_item_get_tag(const StockItem &_item)
{
    const auto &item = (const ChildStockItem &)_item;

    return item.tag.empty() ? nullptr : item.tag.c_str();
}<commit_msg>child_stock: convert ChildStockItem to class<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: <NAME> <<EMAIL>>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "child_stock.hxx"
#include "child_socket.hxx"
#include "spawn/ExitListener.hxx"
#include "stock/Stock.hxx"
#include "stock/Item.hxx"
#include "spawn/Interface.hxx"
#include "spawn/Prepared.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "pool/pool.hxx"

#include <string>

#include <assert.h>
#include <unistd.h>

int
ChildStockClass::GetChildSocketType(void *) const noexcept
{
    return SOCK_STREAM;
}

const char *
ChildStockClass::GetChildTag(void *) const noexcept
{
    return nullptr;
}

class ChildStockItem final : public StockItem, ExitListener {
    SpawnService &spawn_service;

    const std::string tag;

    ChildSocket socket;
    int pid = -1;

    bool busy = true;

public:
    ChildStockItem(CreateStockItem c,
                   SpawnService &_spawn_service,
                   const char *_tag) noexcept
        :StockItem(c),
         spawn_service(_spawn_service),
         tag(_tag != nullptr ? _tag : "") {}

    ~ChildStockItem() override;

    void Spawn(ChildStockClass &cls, void *info);

    gcc_pure
    const char *GetTag() const {
        return tag.empty() ? nullptr : tag.c_str();
    }

    gcc_pure
    bool IsTag(const char *_tag) const {
        return tag == _tag;
    }

    UniqueSocketDescriptor Connect() {
        try {
            return socket.Connect();
        } catch (...) {
            /* if the connection fails, abandon the child process, don't
               try again - it will never work! */
            fade = true;
            throw;
        }
    }

    /* virtual methods from class StockItem */
    bool Borrow() noexcept override {
        assert(!busy);
        busy = true;

        return true;
    }

    bool Release() noexcept override {
        assert(busy);
        busy = false;

        /* reuse this item only if the child process hasn't exited */
        return pid > 0;
    }

private:
    /* virtual methods from class ExitListener */
    void OnChildProcessExit(int status) override;
};

void
ChildStockItem::Spawn(ChildStockClass &cls, void *info)
{
    int socket_type = cls.GetChildSocketType(info);

    PreparedChildProcess p;
    cls.PrepareChild(info, socket.Create(socket_type), p);

    pid = spawn_service.SpawnChildProcess(GetStockName(), std::move(p), this);
}

void
ChildStockItem::OnChildProcessExit(gcc_unused int status)
{
    pid = -1;

    if (!busy)
        InvokeIdleDisconnect();
}

/*
 * stock class
 *
 */

void
ChildStock::Create(CreateStockItem c, void *info,
                   struct pool &, CancellablePointer &)
{
    auto *item = new ChildStockItem(c, spawn_service,
                                    cls.GetChildTag(info));

    try {
        item->Spawn(cls, info);
    } catch (...) {
        delete item;
        throw;
    }

    item->InvokeCreateSuccess();
}

ChildStockItem::~ChildStockItem()
{
    if (pid >= 0)
        spawn_service.KillChildProcess(pid);

    if (socket.IsDefined())
        socket.Unlink();
}

/*
 * interface
 *
 */

ChildStock::ChildStock(EventLoop &event_loop, SpawnService &_spawn_service,
                       ChildStockClass &_cls,
                       unsigned _limit, unsigned _max_idle) noexcept
    :map(event_loop, *this, _limit, _max_idle),
     spawn_service(_spawn_service), cls(_cls)
{
}

void
ChildStock::FadeTag(const char *tag)
{
    map.FadeIf([tag](const StockItem &_item) {
            const auto &item = (const ChildStockItem &)_item;
            return item.IsTag(tag);
        });
}

UniqueSocketDescriptor
child_stock_item_connect(StockItem &_item)
{
    auto &item = (ChildStockItem &)_item;

    return item.Connect();
}

const char *
child_stock_item_get_tag(const StockItem &_item)
{
    const auto &item = (const ChildStockItem &)_item;

    return item.GetTag();
}
{'fraction_non_alphanumeric': 0.09860960457548565, 'fraction_numerical': 0.0023666305098116558, 'mean_word_length': 3.011867088607595, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '191586', 'n_tokens_mistral': 3132, 'n_tokens_neox': 2917, 'n_words': 922}