<commit_before>//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// WebGLReadOutsideFramebufferTest.cpp : Test functions which read the framebuffer (readPixels,
// copyTexSubImage2D, copyTexImage2D) on areas outside the framebuffer.

#include "test_utils/ANGLETest.h"

#include "test_utils/gl_raii.h"

namespace
{

class PixelRect
{
  public:
    PixelRect(int width, int height) : mWidth(width), mHeight(height), mData(width * height) {}

    // Set each pixel to a different color consisting of the x,y position and a given tag.
    // Making each pixel a different means any misplaced pixel will cause a failure.
    // Encoding the position proved valuable in debugging.
    void fill(unsigned tag)
    {
        for (int x = 0; x < mWidth; ++x)
        {
            for (int y = 0; y < mHeight; ++y)
            {
                mData[x + y * mWidth] = angle::GLColor(x + (y << 8) + (tag << 16));
            }
        }
    }

    void setPixel(GLubyte x, GLubyte y, GLubyte z, GLubyte w)
    {
        mData[x + y * mWidth] = angle::GLColor(x, y, z, w);
    }

    void toTexture2D(GLuint texid) const
    {
        glBindTexture(GL_TEXTURE_2D, texid);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                     mData.data());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }

    void readFB(int x, int y)
    {
        glReadPixels(x, y, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, mData.data());
    }

    // Read pixels from 'other' into 'this' from position (x,y).
    // Pixels outside 'other' are untouched or zeroed according to 'zeroOutside.'
    void readPixelRect(const PixelRect &other, int x, int y, bool zeroOutside)
    {
        for (int i = 0; i < mWidth; ++i)
        {
            for (int j = 0; j < mHeight; ++j)
            {
                angle::GLColor *dest = &mData[i + j * mWidth];
                if (!other.getPixel(x + i, y + j, dest) && zeroOutside)
                {
                    *dest = angle::GLColor(0);
                }
            }
        }
    }

    bool getPixel(int x, int y, angle::GLColor *colorOut) const
    {
        if (0 <= x && x < mWidth && 0 <= y && y < mHeight)
        {
            *colorOut = mData[x + y * mWidth];
            return true;
        }
        return false;
    }

    void compare(const PixelRect &expected) const
    {
        for (int i = 0; i < mWidth * mHeight; ++i)
            ASSERT_EQ(expected.mData[i], mData[i]);
    }

  private:
    int mWidth, mHeight;
    std::vector<angle::GLColor> mData;
};

}  // namespace

namespace angle
{

class WebGLReadOutsideFramebufferTest : public ANGLETest
{
  public:
    // Read framebuffer to 'pixelsOut' via glReadPixels.
    void TestReadPixels(int x, int y, PixelRect *pixelsOut) { pixelsOut->readFB(x, y); }

    // Read framebuffer to 'pixelsOut' via glCopyTexSubImage2D.
    void TestCopyTexSubImage2D(int x, int y, PixelRect *pixelsOut)
    {
        // Init texture with given pixels.
        GLTexture destTexture;
        pixelsOut->toTexture2D(destTexture.get());

        // Read framebuffer -> texture -> 'pixelsOut'
        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x, y, kReadWidth, kReadHeight);
        readTexture(kReadWidth, kReadHeight, pixelsOut);
    }

    // Read framebuffer to 'pixelsOut' via glCopyTexImage2D.
    void TestCopyTexImage2D(int x, int y, PixelRect *pixelsOut)
    {
        // Init texture with given pixels.
        GLTexture destTexture;
        pixelsOut->toTexture2D(destTexture.get());

        // Read framebuffer -> texture -> 'pixelsOut'
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, kReadWidth, kReadHeight, 0);
        readTexture(kReadWidth, kReadHeight, pixelsOut);
    }

  protected:
    static constexpr int kFbWidth    = 128;
    static constexpr int kFbHeight   = 128;
    static constexpr int kReadWidth  = 4;
    static constexpr int kReadHeight = 4;

    // Tag the framebuffer pixels differently than the initial read buffer pixels, so we know for
    // sure which pixels are changed by reading.
    static constexpr GLuint fbTag   = 0x1122;
    static constexpr GLuint readTag = 0xaabb;

    WebGLReadOutsideFramebufferTest() : mFBData(kFbWidth, kFbHeight)
    {
        setWindowWidth(kFbWidth);
        setWindowHeight(kFbHeight);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
        setWebGLCompatibilityEnabled(true);
    }

    void SetUp() override
    {
        ANGLETest::SetUp();

        // TODO(fjhenigman): Factor out this shader and others like it in other tests, into
        // ANGLETest.
        const std::string vertexShader =
            "attribute vec3 a_position;\n"
            "varying vec2 v_texCoord;\n"
            "void main() {\n"
            "    v_texCoord = a_position.xy * 0.5 + 0.5;\n"
            "    gl_Position = vec4(a_position, 1);\n"
            "}\n";
        const std::string fragmentShader =
            "precision mediump float;\n"
            "varying vec2 v_texCoord;\n"
            "uniform sampler2D u_texture;\n"
            "void main() {\n"
            "    gl_FragColor = texture2D(u_texture, v_texCoord);\n"
            "}\n";

        mProgram = CompileProgram(vertexShader, fragmentShader);
        glUseProgram(mProgram);
        GLint uniformLoc = glGetUniformLocation(mProgram, "u_texture");
        ASSERT_NE(-1, uniformLoc);
        glUniform1i(uniformLoc, 0);

        glDisable(GL_BLEND);
        glDisable(GL_DEPTH_TEST);

        // fill framebuffer with unique pixels
        mFBData.fill(fbTag);
        GLTexture fbTexture;
        mFBData.toTexture2D(fbTexture.get());
        drawQuad(mProgram, "a_position", 0.0f, 1.0f, true);
    }

    void TearDown() override
    {
        glDeleteProgram(mProgram);
        ANGLETest::TearDown();
    }

    using TestFunc = void (WebGLReadOutsideFramebufferTest::*)(int x, int y, PixelRect *dest);

    void Main(TestFunc testFunc, bool zeroOutside)
    {
        PixelRect actual(kReadWidth, kReadHeight);
        PixelRect expected(kReadWidth, kReadHeight);

        // Read a kReadWidth*kReadHeight rectangle of pixels from places that include:
        // - completely outside framebuffer, on all sides of it (i,j < 0 or > 2)
        // - completely inside framebuffer (i,j == 1)
        // - straddling framebuffer boundary, at each corner and side
        for (int i = -1; i < 4; ++i)
        {
            for (int j = -1; j < 4; ++j)
            {
                int x = i * kFbWidth / 2 - kReadWidth / 2;
                int y = j * kFbHeight / 2 - kReadHeight / 2;

                // Put unique pixel values into the read destinations.
                actual.fill(readTag);
                expected.readPixelRect(actual, 0, 0, false);

                // Read from framebuffer into 'actual.'
                glBindFramebuffer(GL_FRAMEBUFFER, 0);
                (this->*testFunc)(x, y, &actual);
                glBindFramebuffer(GL_FRAMEBUFFER, 0);

                // Simulate framebuffer read, into 'expected.'
                expected.readPixelRect(mFBData, x, y, zeroOutside);

                // See if they are the same.
                actual.compare(expected);
            }
        }
    }

    // Get contents of current texture by drawing it into a framebuffer then reading with
    // glReadPixels().
    void readTexture(GLsizei width, GLsizei height, PixelRect *out)
    {
        GLRenderbuffer colorBuffer;
        glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);

        GLFramebuffer fbo;
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
                                  colorBuffer.get());

        glViewport(0, 0, width, height);
        drawQuad(mProgram, "a_position", 0.0f, 1.0f, true);
        out->readFB(0, 0);
    }

    PixelRect mFBData;
    GLuint mProgram;
};

// TODO(fjhenigman): Enable each test as part of a CL that lets the test pass.

// Check that readPixels does not set a destination pixel when
// the corresponding source pixel is outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, ReadPixels)
{
    // Main(&WebGLReadOutsideFramebufferTest::TestReadPixels, false);
}

// Check that copyTexSubImage2D does not set a destination pixel when
// the corresponding source pixel is outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, CopyTexSubImage2D)
{
    Main(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage2D, false);
}

// Check that copyTexImage2D sets (0,0,0,0) for pixels outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, CopyTexImage2D)
{
    // Main(&WebGLReadOutsideFramebufferTest::TestCopyTexImage2D, true);
}

ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest,
                       ES2_D3D9(),
                       ES2_D3D11(),
                       ES3_D3D11(),
                       ES2_D3D11_FL9_3(),
                       ES2_OPENGL(),
                       ES3_OPENGL(),
                       ES2_OPENGLES(),
                       ES3_OPENGLES());

}  // namespace
<commit_msg>Skip WebGLReadOutsideFramebufferTest.CopyTexSubImage2D on Win Intel<commit_after>//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

// WebGLReadOutsideFramebufferTest.cpp : Test functions which read the framebuffer (readPixels,
// copyTexSubImage2D, copyTexImage2D) on areas outside the framebuffer.

#include "test_utils/ANGLETest.h"

#include "test_utils/gl_raii.h"

namespace
{

class PixelRect
{
  public:
    PixelRect(int width, int height) : mWidth(width), mHeight(height), mData(width * height) {}

    // Set each pixel to a different color consisting of the x,y position and a given tag.
    // Making each pixel a different means any misplaced pixel will cause a failure.
    // Encoding the position proved valuable in debugging.
    void fill(unsigned tag)
    {
        for (int x = 0; x < mWidth; ++x)
        {
            for (int y = 0; y < mHeight; ++y)
            {
                mData[x + y * mWidth] = angle::GLColor(x + (y << 8) + (tag << 16));
            }
        }
    }

    void setPixel(GLubyte x, GLubyte y, GLubyte z, GLubyte w)
    {
        mData[x + y * mWidth] = angle::GLColor(x, y, z, w);
    }

    void toTexture2D(GLuint texid) const
    {
        glBindTexture(GL_TEXTURE_2D, texid);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                     mData.data());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }

    void readFB(int x, int y)
    {
        glReadPixels(x, y, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, mData.data());
    }

    // Read pixels from 'other' into 'this' from position (x,y).
    // Pixels outside 'other' are untouched or zeroed according to 'zeroOutside.'
    void readPixelRect(const PixelRect &other, int x, int y, bool zeroOutside)
    {
        for (int i = 0; i < mWidth; ++i)
        {
            for (int j = 0; j < mHeight; ++j)
            {
                angle::GLColor *dest = &mData[i + j * mWidth];
                if (!other.getPixel(x + i, y + j, dest) && zeroOutside)
                {
                    *dest = angle::GLColor(0);
                }
            }
        }
    }

    bool getPixel(int x, int y, angle::GLColor *colorOut) const
    {
        if (0 <= x && x < mWidth && 0 <= y && y < mHeight)
        {
            *colorOut = mData[x + y * mWidth];
            return true;
        }
        return false;
    }

    void compare(const PixelRect &expected) const
    {
        for (int i = 0; i < mWidth * mHeight; ++i)
            ASSERT_EQ(expected.mData[i], mData[i]);
    }

  private:
    int mWidth, mHeight;
    std::vector<angle::GLColor> mData;
};

}  // namespace

namespace angle
{

class WebGLReadOutsideFramebufferTest : public ANGLETest
{
  public:
    // Read framebuffer to 'pixelsOut' via glReadPixels.
    void TestReadPixels(int x, int y, PixelRect *pixelsOut) { pixelsOut->readFB(x, y); }

    // Read framebuffer to 'pixelsOut' via glCopyTexSubImage2D.
    void TestCopyTexSubImage2D(int x, int y, PixelRect *pixelsOut)
    {
        // Init texture with given pixels.
        GLTexture destTexture;
        pixelsOut->toTexture2D(destTexture.get());

        // Read framebuffer -> texture -> 'pixelsOut'
        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x, y, kReadWidth, kReadHeight);
        readTexture(kReadWidth, kReadHeight, pixelsOut);
    }

    // Read framebuffer to 'pixelsOut' via glCopyTexImage2D.
    void TestCopyTexImage2D(int x, int y, PixelRect *pixelsOut)
    {
        // Init texture with given pixels.
        GLTexture destTexture;
        pixelsOut->toTexture2D(destTexture.get());

        // Read framebuffer -> texture -> 'pixelsOut'
        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, kReadWidth, kReadHeight, 0);
        readTexture(kReadWidth, kReadHeight, pixelsOut);
    }

  protected:
    static constexpr int kFbWidth    = 128;
    static constexpr int kFbHeight   = 128;
    static constexpr int kReadWidth  = 4;
    static constexpr int kReadHeight = 4;

    // Tag the framebuffer pixels differently than the initial read buffer pixels, so we know for
    // sure which pixels are changed by reading.
    static constexpr GLuint fbTag   = 0x1122;
    static constexpr GLuint readTag = 0xaabb;

    WebGLReadOutsideFramebufferTest() : mFBData(kFbWidth, kFbHeight)
    {
        setWindowWidth(kFbWidth);
        setWindowHeight(kFbHeight);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
        setWebGLCompatibilityEnabled(true);
    }

    void SetUp() override
    {
        ANGLETest::SetUp();

        // TODO(fjhenigman): Factor out this shader and others like it in other tests, into
        // ANGLETest.
        const std::string vertexShader =
            "attribute vec3 a_position;\n"
            "varying vec2 v_texCoord;\n"
            "void main() {\n"
            "    v_texCoord = a_position.xy * 0.5 + 0.5;\n"
            "    gl_Position = vec4(a_position, 1);\n"
            "}\n";
        const std::string fragmentShader =
            "precision mediump float;\n"
            "varying vec2 v_texCoord;\n"
            "uniform sampler2D u_texture;\n"
            "void main() {\n"
            "    gl_FragColor = texture2D(u_texture, v_texCoord);\n"
            "}\n";

        mProgram = CompileProgram(vertexShader, fragmentShader);
        glUseProgram(mProgram);
        GLint uniformLoc = glGetUniformLocation(mProgram, "u_texture");
        ASSERT_NE(-1, uniformLoc);
        glUniform1i(uniformLoc, 0);

        glDisable(GL_BLEND);
        glDisable(GL_DEPTH_TEST);

        // fill framebuffer with unique pixels
        mFBData.fill(fbTag);
        GLTexture fbTexture;
        mFBData.toTexture2D(fbTexture.get());
        drawQuad(mProgram, "a_position", 0.0f, 1.0f, true);
    }

    void TearDown() override
    {
        glDeleteProgram(mProgram);
        ANGLETest::TearDown();
    }

    using TestFunc = void (WebGLReadOutsideFramebufferTest::*)(int x, int y, PixelRect *dest);

    void Main(TestFunc testFunc, bool zeroOutside)
    {
        PixelRect actual(kReadWidth, kReadHeight);
        PixelRect expected(kReadWidth, kReadHeight);

        // Read a kReadWidth*kReadHeight rectangle of pixels from places that include:
        // - completely outside framebuffer, on all sides of it (i,j < 0 or > 2)
        // - completely inside framebuffer (i,j == 1)
        // - straddling framebuffer boundary, at each corner and side
        for (int i = -1; i < 4; ++i)
        {
            for (int j = -1; j < 4; ++j)
            {
                int x = i * kFbWidth / 2 - kReadWidth / 2;
                int y = j * kFbHeight / 2 - kReadHeight / 2;

                // Put unique pixel values into the read destinations.
                actual.fill(readTag);
                expected.readPixelRect(actual, 0, 0, false);

                // Read from framebuffer into 'actual.'
                glBindFramebuffer(GL_FRAMEBUFFER, 0);
                (this->*testFunc)(x, y, &actual);
                glBindFramebuffer(GL_FRAMEBUFFER, 0);

                // Simulate framebuffer read, into 'expected.'
                expected.readPixelRect(mFBData, x, y, zeroOutside);

                // See if they are the same.
                actual.compare(expected);
            }
        }
    }

    // Get contents of current texture by drawing it into a framebuffer then reading with
    // glReadPixels().
    void readTexture(GLsizei width, GLsizei height, PixelRect *out)
    {
        GLRenderbuffer colorBuffer;
        glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);

        GLFramebuffer fbo;
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
                                  colorBuffer.get());

        glViewport(0, 0, width, height);
        drawQuad(mProgram, "a_position", 0.0f, 1.0f, true);
        out->readFB(0, 0);
    }

    PixelRect mFBData;
    GLuint mProgram;
};

// TODO(fjhenigman): Enable each test as part of a CL that lets the test pass.

// Check that readPixels does not set a destination pixel when
// the corresponding source pixel is outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, ReadPixels)
{
    // Main(&WebGLReadOutsideFramebufferTest::TestReadPixels, false);
}

// Check that copyTexSubImage2D does not set a destination pixel when
// the corresponding source pixel is outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, CopyTexSubImage2D)
{
    // TODO(fjhenigman): Figure out why this fails on Win10 Intel OpenGL
    if (IsWindows() && IsIntel() && IsDesktopOpenGL())
    {
        std::cout << "Test skipped on Windows OpenGL on Intel." << std::endl;
        return;
    }

    Main(&WebGLReadOutsideFramebufferTest::TestCopyTexSubImage2D, false);
}

// Check that copyTexImage2D sets (0,0,0,0) for pixels outside the framebuffer.
TEST_P(WebGLReadOutsideFramebufferTest, CopyTexImage2D)
{
    // Main(&WebGLReadOutsideFramebufferTest::TestCopyTexImage2D, true);
}

ANGLE_INSTANTIATE_TEST(WebGLReadOutsideFramebufferTest,
                       ES2_D3D9(),
                       ES2_D3D11(),
                       ES3_D3D11(),
                       ES2_D3D11_FL9_3(),
                       ES2_OPENGL(),
                       ES3_OPENGL(),
                       ES2_OPENGLES(),
                       ES3_OPENGLES());

}  // namespace
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <base/logging.h>
#include <ksync/ksync_index.h>
#include <ksync/ksync_entry.h>
#include <ksync/ksync_object.h>
#include <ksync/ksync_netlink.h>
#include <ksync/ksync_sock.h>
#include <vrouter/ksync/ksync_init.h>
#include "vrouter/ksync/qos_queue_ksync.h"
#include "vrouter/ksync/forwarding_class_ksync.h"

ForwardingClassKSyncEntry::ForwardingClassKSyncEntry(
        ForwardingClassKSyncObject *obj, const ForwardingClassKSyncEntry *fc):
    KSyncNetlinkDBEntry(), ksync_obj_(obj), id_(fc->id()),
    qos_queue_ksync_(NULL) {
}

ForwardingClassKSyncEntry::ForwardingClassKSyncEntry(
        ForwardingClassKSyncObject *obj, const ForwardingClass *fc):
    KSyncNetlinkDBEntry(), ksync_obj_(obj), id_(fc->id()),
    qos_queue_ksync_(NULL) {
}

ForwardingClassKSyncEntry::ForwardingClassKSyncEntry(
        ForwardingClassKSyncObject *obj, uint32_t id):
    KSyncNetlinkDBEntry(), ksync_obj_(obj), id_(id),
    qos_queue_ksync_(NULL) {
}

ForwardingClassKSyncEntry::~ForwardingClassKSyncEntry() {
}

KSyncDBObject *ForwardingClassKSyncEntry::GetObject() {
    return ksync_obj_;
}

bool ForwardingClassKSyncEntry::IsLess(const KSyncEntry &rhs) const {
    const ForwardingClassKSyncEntry &entry = static_cast<const ForwardingClassKSyncEntry &>(rhs);
    return id_ < entry.id_;
}

std::string ForwardingClassKSyncEntry::ToString() const {
    std::stringstream s;
    s << "Forwarding class id " << id_;
    return s.str();
}

bool ForwardingClassKSyncEntry::Sync(DBEntry *e) {
    ForwardingClass *fc = static_cast<ForwardingClass *>(e);

    bool ret = false;
    if (dscp_ != fc->dscp()) {
        dscp_ = fc->dscp();
        ret = true;
    }

    if (vlan_priority_ != fc->vlan_priority()) {
        vlan_priority_ = fc->vlan_priority();
        ret = true;
    }

    if (mpls_exp_ != fc->mpls_exp()) {
        mpls_exp_ = fc->mpls_exp();
        ret = true;
    }

    QosQueueKSyncObject *qos_queue_object =
        (static_cast<QosQueueKSyncObject *>(ksync_obj_))->
        ksync()->qos_queue_ksync_obj();

    KSyncEntry *qos_queue_ksync_ptr = NULL;
    if (fc->qos_queue_ref()) {
        QosQueueKSyncEntry qos_queue_ksync(qos_queue_object,
                                           fc->qos_queue_ref());
        qos_queue_ksync_ptr = qos_queue_object->GetReference(&qos_queue_ksync);
    }

    if (qos_queue_ksync_ptr != qos_queue_ksync_) {
        qos_queue_ksync_ = qos_queue_ksync_ptr;
        ret = true;
    }

    return ret;
}

int ForwardingClassKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
    vr_fc_map_req encoder;
    encoder.set_h_op(op);
    encoder.set_fmr_rid(0);

    std::vector<int16_t> id_list;
    id_list.push_back((int8_t)id_);
    encoder.set_fmr_id(id_list);

    std::vector<int8_t> dscp_list;
    dscp_list.push_back(dscp_);
    encoder.set_fmr_dscp(dscp_list);

    std::vector<int8_t> vlan_priority_list;
    vlan_priority_list.push_back(vlan_priority_);
    encoder.set_fmr_dotonep(vlan_priority_list);

    std::vector<int8_t> mpls_exp_list;
    mpls_exp_list.push_back(mpls_exp_);
    encoder.set_fmr_mpls_qos(mpls_exp_list);

    std::vector<int8_t> qos_queue_list;
    const QosQueueKSyncEntry *qos_queue =
         static_cast<const QosQueueKSyncEntry *>(qos_queue_ksync_.get());
    if (qos_queue) {
        qos_queue_list.push_back(qos_queue->id());
    } else {
        //Default for now
        qos_queue_list.push_back(0);
    }
    encoder.set_fmr_queue_id(qos_queue_list);

    int error = 0;
    int encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
    assert(error == 0);
    assert(encode_len <= buf_len);
    return encode_len;
}

int ForwardingClassKSyncEntry::AddMsg(char *buf, int buf_len) {
    return Encode(sandesh_op::ADD, buf, buf_len);
}

int ForwardingClassKSyncEntry::ChangeMsg(char *buf, int buf_len) {
    return Encode(sandesh_op::ADD, buf, buf_len);
}

int ForwardingClassKSyncEntry::DeleteMsg(char *buf, int buf_len) {
    return Encode(sandesh_op::DELETE, buf, buf_len);
}

KSyncEntry *ForwardingClassKSyncEntry::UnresolvedReference() {
    if (qos_queue_ksync() && qos_queue_ksync()->IsResolved() == false) {
        return qos_queue_ksync();
    }

    return NULL;
}

ForwardingClassKSyncObject::ForwardingClassKSyncObject(KSync *ksync):
    KSyncDBObject("KSync Forwarding class object"), ksync_(ksync) {
}

ForwardingClassKSyncObject::~ForwardingClassKSyncObject() {

}

void ForwardingClassKSyncObject::RegisterDBClients() {
    RegisterDb(ksync_->agent()->forwarding_class_table());
}

KSyncEntry*
ForwardingClassKSyncObject::Alloc(const KSyncEntry *e, uint32_t index) {
    const ForwardingClassKSyncEntry *entry =
        static_cast<const ForwardingClassKSyncEntry *>(e);
    ForwardingClassKSyncEntry *new_entry =
        new ForwardingClassKSyncEntry(this, entry);
    return static_cast<KSyncEntry *>(new_entry);
}

KSyncEntry *ForwardingClassKSyncObject::DBToKSyncEntry(const DBEntry *e) {
    const ForwardingClass *fc = static_cast<const ForwardingClass *>(e);
    ForwardingClassKSyncEntry *entry = new ForwardingClassKSyncEntry(this, fc);
    return static_cast<KSyncEntry *>(entry);
}

void vr_fc_map_req::Process(SandeshContext *context) {
    AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    ioc->ForwardingClassMsgHandler(this);
}

KSyncDBObject::DBFilterResp
ForwardingClassKSyncObject::DBEntryFilter(const DBEntry *entry,
                                          const KSyncDBEntry *ksync) {
    const ForwardingClass *fc = static_cast<const ForwardingClass *>(entry);
    if (ksync) {
        const ForwardingClassKSyncEntry *ksync_entry =
            static_cast<const ForwardingClassKSyncEntry *>(ksync);
        if (fc->id() != ksync_entry->id()) {
            return DBFilterDelAdd;
        }
    }
    return DBFilterAccept;
}
<commit_msg>* Pass forwarding class as int16_t as specified in sandesh file<commit_after>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <base/logging.h>
#include <ksync/ksync_index.h>
#include <ksync/ksync_entry.h>
#include <ksync/ksync_object.h>
#include <ksync/ksync_netlink.h>
#include <ksync/ksync_sock.h>
#include <vrouter/ksync/ksync_init.h>
#include "vrouter/ksync/qos_queue_ksync.h"
#include "vrouter/ksync/forwarding_class_ksync.h"

ForwardingClassKSyncEntry::ForwardingClassKSyncEntry(
        ForwardingClassKSyncObject *obj, const ForwardingClassKSyncEntry *fc):
    KSyncNetlinkDBEntry(), ksync_obj_(obj), id_(fc->id()),
    qos_queue_ksync_(NULL) {
}

ForwardingClassKSyncEntry::ForwardingClassKSyncEntry(
        ForwardingClassKSyncObject *obj, const ForwardingClass *fc):
    KSyncNetlinkDBEntry(), ksync_obj_(obj), id_(fc->id()),
    qos_queue_ksync_(NULL) {
}

ForwardingClassKSyncEntry::ForwardingClassKSyncEntry(
        ForwardingClassKSyncObject *obj, uint32_t id):
    KSyncNetlinkDBEntry(), ksync_obj_(obj), id_(id),
    qos_queue_ksync_(NULL) {
}

ForwardingClassKSyncEntry::~ForwardingClassKSyncEntry() {
}

KSyncDBObject *ForwardingClassKSyncEntry::GetObject() {
    return ksync_obj_;
}

bool ForwardingClassKSyncEntry::IsLess(const KSyncEntry &rhs) const {
    const ForwardingClassKSyncEntry &entry = static_cast<const ForwardingClassKSyncEntry &>(rhs);
    return id_ < entry.id_;
}

std::string ForwardingClassKSyncEntry::ToString() const {
    std::stringstream s;
    s << "Forwarding class id " << id_;
    return s.str();
}

bool ForwardingClassKSyncEntry::Sync(DBEntry *e) {
    ForwardingClass *fc = static_cast<ForwardingClass *>(e);

    bool ret = false;
    if (dscp_ != fc->dscp()) {
        dscp_ = fc->dscp();
        ret = true;
    }

    if (vlan_priority_ != fc->vlan_priority()) {
        vlan_priority_ = fc->vlan_priority();
        ret = true;
    }

    if (mpls_exp_ != fc->mpls_exp()) {
        mpls_exp_ = fc->mpls_exp();
        ret = true;
    }

    QosQueueKSyncObject *qos_queue_object =
        (static_cast<QosQueueKSyncObject *>(ksync_obj_))->
        ksync()->qos_queue_ksync_obj();

    KSyncEntry *qos_queue_ksync_ptr = NULL;
    if (fc->qos_queue_ref()) {
        QosQueueKSyncEntry qos_queue_ksync(qos_queue_object,
                                           fc->qos_queue_ref());
        qos_queue_ksync_ptr = qos_queue_object->GetReference(&qos_queue_ksync);
    }

    if (qos_queue_ksync_ptr != qos_queue_ksync_) {
        qos_queue_ksync_ = qos_queue_ksync_ptr;
        ret = true;
    }

    return ret;
}

int ForwardingClassKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) {
    vr_fc_map_req encoder;
    encoder.set_h_op(op);
    encoder.set_fmr_rid(0);

    std::vector<int16_t> id_list;
    id_list.push_back((int16_t)id_);
    encoder.set_fmr_id(id_list);

    std::vector<int8_t> dscp_list;
    dscp_list.push_back(dscp_);
    encoder.set_fmr_dscp(dscp_list);

    std::vector<int8_t> vlan_priority_list;
    vlan_priority_list.push_back(vlan_priority_);
    encoder.set_fmr_dotonep(vlan_priority_list);

    std::vector<int8_t> mpls_exp_list;
    mpls_exp_list.push_back(mpls_exp_);
    encoder.set_fmr_mpls_qos(mpls_exp_list);

    std::vector<int8_t> qos_queue_list;
    const QosQueueKSyncEntry *qos_queue =
         static_cast<const QosQueueKSyncEntry *>(qos_queue_ksync_.get());
    if (qos_queue) {
        qos_queue_list.push_back(qos_queue->id());
    } else {
        //Default for now
        qos_queue_list.push_back(0);
    }
    encoder.set_fmr_queue_id(qos_queue_list);

    int error = 0;
    int encode_len = encoder.WriteBinary((uint8_t *)buf, buf_len, &error);
    assert(error == 0);
    assert(encode_len <= buf_len);
    return encode_len;
}

int ForwardingClassKSyncEntry::AddMsg(char *buf, int buf_len) {
    return Encode(sandesh_op::ADD, buf, buf_len);
}

int ForwardingClassKSyncEntry::ChangeMsg(char *buf, int buf_len) {
    return Encode(sandesh_op::ADD, buf, buf_len);
}

int ForwardingClassKSyncEntry::DeleteMsg(char *buf, int buf_len) {
    return Encode(sandesh_op::DELETE, buf, buf_len);
}

KSyncEntry *ForwardingClassKSyncEntry::UnresolvedReference() {
    if (qos_queue_ksync() && qos_queue_ksync()->IsResolved() == false) {
        return qos_queue_ksync();
    }

    return NULL;
}

ForwardingClassKSyncObject::ForwardingClassKSyncObject(KSync *ksync):
    KSyncDBObject("KSync Forwarding class object"), ksync_(ksync) {
}

ForwardingClassKSyncObject::~ForwardingClassKSyncObject() {

}

void ForwardingClassKSyncObject::RegisterDBClients() {
    RegisterDb(ksync_->agent()->forwarding_class_table());
}

KSyncEntry*
ForwardingClassKSyncObject::Alloc(const KSyncEntry *e, uint32_t index) {
    const ForwardingClassKSyncEntry *entry =
        static_cast<const ForwardingClassKSyncEntry *>(e);
    ForwardingClassKSyncEntry *new_entry =
        new ForwardingClassKSyncEntry(this, entry);
    return static_cast<KSyncEntry *>(new_entry);
}

KSyncEntry *ForwardingClassKSyncObject::DBToKSyncEntry(const DBEntry *e) {
    const ForwardingClass *fc = static_cast<const ForwardingClass *>(e);
    ForwardingClassKSyncEntry *entry = new ForwardingClassKSyncEntry(this, fc);
    return static_cast<KSyncEntry *>(entry);
}

void vr_fc_map_req::Process(SandeshContext *context) {
    AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
    ioc->ForwardingClassMsgHandler(this);
}

KSyncDBObject::DBFilterResp
ForwardingClassKSyncObject::DBEntryFilter(const DBEntry *entry,
                                          const KSyncDBEntry *ksync) {
    const ForwardingClass *fc = static_cast<const ForwardingClass *>(entry);
    if (ksync) {
        const ForwardingClassKSyncEntry *ksync_entry =
            static_cast<const ForwardingClassKSyncEntry *>(ksync);
        if (fc->id() != ksync_entry->id()) {
            return DBFilterDelAdd;
        }
    }
    return DBFilterAccept;
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#include "tensorflow/compiler/xla/service/gpu/amdgpu_compiler.h"

#include "tensorflow/compiler/xla/service/algebraic_simplifier.h"
#include "tensorflow/compiler/xla/service/call_inliner.h"
#include "tensorflow/compiler/xla/service/gpu/cusolver_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/gemm_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_conv_algorithm_picker.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_conv_padding_legalization.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_conv_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_layout_assignment.h"
#include "tensorflow/compiler/xla/service/gpu/llvm_gpu_backend/gpu_backend_lib.h"
#include "tensorflow/compiler/xla/service/gpu/reduction_degenerate_dim_remover.h"
#include "tensorflow/compiler/xla/service/gpu/reduction_dimension_grouper.h"
#include "tensorflow/compiler/xla/service/gpu/reduction_layout_normalizer.h"
#include "tensorflow/compiler/xla/service/gpu/target_constants.h"
#include "tensorflow/compiler/xla/service/gpu/tree_reduction_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/triangular_solve_rewriter.h"
#include "tensorflow/compiler/xla/service/hlo_constant_folding.h"
#include "tensorflow/compiler/xla/service/hlo_cse.h"
#include "tensorflow/compiler/xla/service/hlo_pass_fix.h"
#include "tensorflow/compiler/xla/service/hlo_pass_pipeline.h"
#include "tensorflow/compiler/xla/service/hlo_verifier.h"
#include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"
#include "tensorflow/compiler/xla/service/tuple_simplifier.h"
#include "tensorflow/core/platform/rocm_rocdl_path.h"

namespace xla {
namespace gpu {

namespace {

// Returns the directory containing ROCm-Device-Libs files. This function is
// called in AMDGPUCompiler's constructor, so can't return an error. But
// AMDGPUCompiler::Compile will return an error when the wanted rocdl file
// doesn't exist in the folder this function returns.
std::string GetROCDLDir(const HloModuleConfig& config) {
  std::vector<std::string> potential_rocdl_dirs;
  const std::string datadir = config.debug_options().xla_gpu_cuda_data_dir();
  if (!datadir.empty()) {
    potential_rocdl_dirs.push_back(datadir);
  }
  potential_rocdl_dirs.push_back(tensorflow::RocdlRoot());

  // Tries all potential ROCDL directories in the order they are inserted.
  // Returns the first directory that exists in the file system.
  for (const std::string& potential_rocdl_dir : potential_rocdl_dirs) {
    if (tensorflow::Env::Default()->IsDirectory(potential_rocdl_dir).ok()) {
      VLOG(2) << "Found ROCm-Device-Libs dir " << potential_rocdl_dir;
      return potential_rocdl_dir;
    }
    VLOG(2) << "Unable to find potential ROCm-Device-Libs dir "
            << potential_rocdl_dir;
  }

  // Last resort: maybe in the current folder.
  return ".";
}

}  // namespace

Status AMDGPUCompiler::OptimizeHloConvolutionCanonicalization(
    HloModule* hlo_module, se::StreamExecutor* stream_exec,
    se::DeviceMemoryAllocator* device_allocator) {
  // Convert convolutions into CustomCalls to MIOpen, then canonicalize them
  // (PadInsertion).
  HloPassPipeline pipeline("conv_canonicalization");
  pipeline.AddInvariantCheckerDebug<HloVerifier>(
      /*layout_sensitive=*/false,
      /*allow_mixed_precision=*/false);
  pipeline.AddPass<GpusolverRewriter>();
  pipeline.AddPass<GpuConvRewriter>();
  pipeline.AddPass<GpuConvPaddingLegalization>();

  // The conv padding/vectorization passes which we need to get rid of.  They
  // also leave behind unnecessary tuple/get-tuple-element pairs that
  // TupleSimplifier fixes.
  pipeline.AddPass<CallInliner>();
  pipeline.AddPass<TupleSimplifier>();

  // tf2xla bridge, DepthwiseConvolutionConverter and GpuConvRewriter
  // introduces reshapes and transposes that can be eliminated using
  // AlgebraicSimplifier  We run algsimp to a fixed point.
  //
  // When transposes appear in a fusion node, we can easily adjust the
  // multi-dimensional index to create the one needed for the operand. This
  // is not as easy with bitcasts, because we don't have the information
  // readily available which dimensions are permuted. In addition to that,
  // if we have a transpose and a reshape next to each other, they will both
  // be replaced by a bitcast, and we replace bitcast(bitcast) with one
  // bitcast. This leads to having to linearize and then delinearize the
  // index.
  AlgebraicSimplifierOptions options;
  options.set_enable_conv_operand_swap(false);
  pipeline.AddPass<HloPassFix<AlgebraicSimplifier>>(options);

  pipeline.AddPass<HloConstantFolding>();
  TF_RETURN_IF_ERROR(pipeline.Run(hlo_module).status());

  return Status::OK();
}

Status AMDGPUCompiler::OptimizeHloPostLayoutAssignment(
    HloModule* hlo_module, se::StreamExecutor* stream_exec,
    se::DeviceMemoryAllocator* device_allocator) {
  TF_RETURN_IF_ERROR(GpuCompiler::OptimizeHloPostLayoutAssignment(
      hlo_module, stream_exec, device_allocator));

  HloPassPipeline post_pipeline("AMDGPU post-layout_assignment");

  if (!IsBefEnabled(hlo_module->config())) {
    // Transform TriangularSolve ops into custom-calls, so we can add temp
    // memory. XLIR allocates temp memory, and so the custom-call implementation
    // for TriangularSolve is not needed.
    post_pipeline.AddPass<TriangularSolveRewriter>();
  }

  TF_RETURN_IF_ERROR(post_pipeline.Run(hlo_module).status());

  return Status::OK();
}

AMDGPUCompiler::AMDGPUCompiler()
    : GpuCompiler(stream_executor::rocm::kROCmPlatformId,
                  amdgpu::TargetTriple(), amdgpu::DataLayout()) {}

GpuVersion AMDGPUCompiler::GetGpuVersion(se::StreamExecutor* stream_exec) {
  return stream_exec->GetDeviceDescription().rocm_compute_capability();
}

StatusOr<std::pair<std::string, std::vector<uint8_t>>>
AMDGPUCompiler::CompileTargetBinary(const HloModuleConfig& module_config,
                                    llvm::Module* llvm_module,
                                    GpuVersion gpu_version,
                                    se::StreamExecutor* stream_exec,
                                    bool relocatable,
                                    const HloModule* debug_module) {
  if (rocdl_dir_.empty()) {
    // Compute rocdl_dir_ just once and cache it in this member.
    rocdl_dir_ = GetROCDLDir(module_config);
  }

  if (relocatable) {
    return Unimplemented("relocatable target binary is not implemented");
  }

  std::vector<uint8_t> hsaco;
  {
    XLA_SCOPED_LOGGING_TIMER(
        "AMDGPUCompiler::CompileTargetBinary - CompileToHsaco");
    TF_ASSIGN_OR_RETURN(
        hsaco, amdgpu::CompileToHsaco(llvm_module, gpu_version, module_config,
                                      rocdl_dir_));
  }

  return std::pair<std::string, std::vector<uint8_t>>("", std::move(hsaco));
}

}  // namespace gpu
}  // namespace xla
<commit_msg>Remove stale comment.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

#include "tensorflow/compiler/xla/service/gpu/amdgpu_compiler.h"

#include "tensorflow/compiler/xla/service/algebraic_simplifier.h"
#include "tensorflow/compiler/xla/service/call_inliner.h"
#include "tensorflow/compiler/xla/service/gpu/cusolver_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/gemm_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_conv_algorithm_picker.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_conv_padding_legalization.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_conv_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/gpu_layout_assignment.h"
#include "tensorflow/compiler/xla/service/gpu/llvm_gpu_backend/gpu_backend_lib.h"
#include "tensorflow/compiler/xla/service/gpu/reduction_degenerate_dim_remover.h"
#include "tensorflow/compiler/xla/service/gpu/reduction_dimension_grouper.h"
#include "tensorflow/compiler/xla/service/gpu/reduction_layout_normalizer.h"
#include "tensorflow/compiler/xla/service/gpu/target_constants.h"
#include "tensorflow/compiler/xla/service/gpu/tree_reduction_rewriter.h"
#include "tensorflow/compiler/xla/service/gpu/triangular_solve_rewriter.h"
#include "tensorflow/compiler/xla/service/hlo_constant_folding.h"
#include "tensorflow/compiler/xla/service/hlo_cse.h"
#include "tensorflow/compiler/xla/service/hlo_pass_fix.h"
#include "tensorflow/compiler/xla/service/hlo_pass_pipeline.h"
#include "tensorflow/compiler/xla/service/hlo_verifier.h"
#include "tensorflow/compiler/xla/service/llvm_ir/llvm_util.h"
#include "tensorflow/compiler/xla/service/tuple_simplifier.h"
#include "tensorflow/core/platform/rocm_rocdl_path.h"

namespace xla {
namespace gpu {

namespace {

// Returns the directory containing ROCm-Device-Libs files. This function is
// called in AMDGPUCompiler's constructor, so can't return an error. But
// AMDGPUCompiler::Compile will return an error when the wanted rocdl file
// doesn't exist in the folder this function returns.
std::string GetROCDLDir(const HloModuleConfig& config) {
  std::vector<std::string> potential_rocdl_dirs;
  const std::string datadir = config.debug_options().xla_gpu_cuda_data_dir();
  if (!datadir.empty()) {
    potential_rocdl_dirs.push_back(datadir);
  }
  potential_rocdl_dirs.push_back(tensorflow::RocdlRoot());

  // Tries all potential ROCDL directories in the order they are inserted.
  // Returns the first directory that exists in the file system.
  for (const std::string& potential_rocdl_dir : potential_rocdl_dirs) {
    if (tensorflow::Env::Default()->IsDirectory(potential_rocdl_dir).ok()) {
      VLOG(2) << "Found ROCm-Device-Libs dir " << potential_rocdl_dir;
      return potential_rocdl_dir;
    }
    VLOG(2) << "Unable to find potential ROCm-Device-Libs dir "
            << potential_rocdl_dir;
  }

  // Last resort: maybe in the current folder.
  return ".";
}

}  // namespace

Status AMDGPUCompiler::OptimizeHloConvolutionCanonicalization(
    HloModule* hlo_module, se::StreamExecutor* stream_exec,
    se::DeviceMemoryAllocator* device_allocator) {
  // Convert convolutions into CustomCalls to MIOpen, then canonicalize them
  // (PadInsertion).
  HloPassPipeline pipeline("conv_canonicalization");
  pipeline.AddInvariantCheckerDebug<HloVerifier>(
      /*layout_sensitive=*/false,
      /*allow_mixed_precision=*/false);
  pipeline.AddPass<GpusolverRewriter>();
  pipeline.AddPass<GpuConvRewriter>();
  pipeline.AddPass<GpuConvPaddingLegalization>();

  // The conv padding/vectorization passes which we need to get rid of.  They
  // also leave behind unnecessary tuple/get-tuple-element pairs that
  // TupleSimplifier fixes.
  pipeline.AddPass<CallInliner>();
  pipeline.AddPass<TupleSimplifier>();

  // tf2xla bridge, DepthwiseConvolutionConverter and GpuConvRewriter
  // introduces reshapes and transposes that can be eliminated using
  // AlgebraicSimplifier  We run algsimp to a fixed point.
  AlgebraicSimplifierOptions options;
  options.set_enable_conv_operand_swap(false);
  pipeline.AddPass<HloPassFix<AlgebraicSimplifier>>(options);

  pipeline.AddPass<HloConstantFolding>();
  TF_RETURN_IF_ERROR(pipeline.Run(hlo_module).status());

  return Status::OK();
}

Status AMDGPUCompiler::OptimizeHloPostLayoutAssignment(
    HloModule* hlo_module, se::StreamExecutor* stream_exec,
    se::DeviceMemoryAllocator* device_allocator) {
  TF_RETURN_IF_ERROR(GpuCompiler::OptimizeHloPostLayoutAssignment(
      hlo_module, stream_exec, device_allocator));

  HloPassPipeline post_pipeline("AMDGPU post-layout_assignment");

  if (!IsBefEnabled(hlo_module->config())) {
    // Transform TriangularSolve ops into custom-calls, so we can add temp
    // memory. XLIR allocates temp memory, and so the custom-call implementation
    // for TriangularSolve is not needed.
    post_pipeline.AddPass<TriangularSolveRewriter>();
  }

  TF_RETURN_IF_ERROR(post_pipeline.Run(hlo_module).status());

  return Status::OK();
}

AMDGPUCompiler::AMDGPUCompiler()
    : GpuCompiler(stream_executor::rocm::kROCmPlatformId,
                  amdgpu::TargetTriple(), amdgpu::DataLayout()) {}

GpuVersion AMDGPUCompiler::GetGpuVersion(se::StreamExecutor* stream_exec) {
  return stream_exec->GetDeviceDescription().rocm_compute_capability();
}

StatusOr<std::pair<std::string, std::vector<uint8_t>>>
AMDGPUCompiler::CompileTargetBinary(const HloModuleConfig& module_config,
                                    llvm::Module* llvm_module,
                                    GpuVersion gpu_version,
                                    se::StreamExecutor* stream_exec,
                                    bool relocatable,
                                    const HloModule* debug_module) {
  if (rocdl_dir_.empty()) {
    // Compute rocdl_dir_ just once and cache it in this member.
    rocdl_dir_ = GetROCDLDir(module_config);
  }

  if (relocatable) {
    return Unimplemented("relocatable target binary is not implemented");
  }

  std::vector<uint8_t> hsaco;
  {
    XLA_SCOPED_LOGGING_TIMER(
        "AMDGPUCompiler::CompileTargetBinary - CompileToHsaco");
    TF_ASSIGN_OR_RETURN(
        hsaco, amdgpu::CompileToHsaco(llvm_module, gpu_version, module_config,
                                      rocdl_dir_));
  }

  return std::pair<std::string, std::vector<uint8_t>>("", std::move(hsaco));
}

}  // namespace gpu
}  // namespace xla
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB 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
///
///     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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////

#include "RestServerFeature.h"

#include "ApplicationFeatures/SslFeature.h"
#include "Aql/RestAqlHandler.h"
#include "Agency/AgencyFeature.h"
#include "Agency/RestAgencyHandler.h"
#include "Agency/RestAgencyPrivHandler.h"
#include "Cluster/AgencyCallbackRegistry.h"
#include "Cluster/ClusterComm.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/RestAgencyCallbacksHandler.h"
#include "Cluster/RestShardHandler.h"
#include "Dispatcher/DispatcherFeature.h"
#include "HttpServer/HttpHandlerFactory.h"
#include "HttpServer/HttpServer.h"
#include "HttpServer/HttpsServer.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "Rest/Version.h"
#include "RestHandler/RestAdminLogHandler.h"
#include "RestHandler/RestBatchHandler.h"
#include "RestHandler/RestCursorHandler.h"
#include "RestHandler/RestDebugHandler.h"
#include "RestHandler/RestDocumentHandler.h"
#include "RestHandler/RestEchoHandler.h"
#include "RestHandler/RestEdgesHandler.h"
#include "RestHandler/RestExportHandler.h"
#include "RestHandler/RestHandlerCreator.h"
#include "RestHandler/RestImportHandler.h"
#include "RestHandler/RestJobHandler.h"
#include "RestHandler/RestPleaseUpgradeHandler.h"
#include "RestHandler/RestQueryCacheHandler.h"
#include "RestHandler/RestQueryHandler.h"
#include "RestHandler/RestReplicationHandler.h"
#include "RestHandler/RestShutdownHandler.h"
#include "RestHandler/RestSimpleHandler.h"
#include "RestHandler/RestSimpleQueryHandler.h"
#include "RestHandler/RestUploadHandler.h"
#include "RestHandler/RestVersionHandler.h"
#include "RestHandler/WorkMonitorHandler.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/DatabaseServerFeature.h"
#include "RestServer/EndpointFeature.h"
#include "RestServer/QueryRegistryFeature.h"
#include "RestServer/ServerFeature.h"
#include "Scheduler/SchedulerFeature.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/server.h"

using namespace arangodb;
using namespace arangodb::application_features;
using namespace arangodb::rest;
using namespace arangodb::options;

RestServerFeature::RestServerFeature(
    application_features::ApplicationServer* server,
    std::string const& authenticationRealm)
    : ApplicationFeature(server, "RestServer"),
      _keepAliveTimeout(300.0),
      _authenticationRealm(authenticationRealm),
      _defaultApiCompatibility(Version::getNumericServerVersion()),
      _allowMethodOverride(false),
      _authentication(true),
      _authenticationUnixSockets(true),
      _authenticationSystemOnly(false),
      _handlerFactory(nullptr),
      _jobManager(nullptr) {
  setOptional(true);
  requiresElevatedPrivileges(false);
  startsAfter("Dispatcher");
  startsAfter("Endpoint");
  startsAfter("Scheduler");
  startsAfter("Server");
  startsAfter("Agency");
  startsAfter("LogfileManager");
  startsAfter("Database");
  startsAfter("Upgrade");
  startsAfter("CheckVersion");
}

void RestServerFeature::collectOptions(
    std::shared_ptr<ProgramOptions> options) {
  options->addSection("server", "Server features");

  options->addHiddenOption("--server.default-api-compatibility",
                           "default API compatibility version",
                           new Int32Parameter(&_defaultApiCompatibility));

  options->addOption("--server.authentication",
                     "enable or disable authentication for ALL client requests",
                     new BooleanParameter(&_authentication));

  options->addOption(
      "--server.authentication-system-only",
      "use HTTP authentication only for requests to /_api and /_admin",
      new BooleanParameter(&_authenticationSystemOnly));

#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
  options->addOption("--server.authentication-unix-sockets",
                     "authentication for requests via UNIX domain sockets",
                     new BooleanParameter(&_authenticationUnixSockets));
#endif

  options->addSection("http", "HttpServer features");

  options->addHiddenOption("--http.allow-method-override",
                           "allow HTTP method override using special headers",
                           new BooleanParameter(&_allowMethodOverride));

  options->addOption("--http.keep-alive-timeout",
                     "keep-alive timeout in seconds",
                     new DoubleParameter(&_keepAliveTimeout));

  options->addOption(
      "--http.hide-product-header",
      "do not expose \"Server: ArangoDB\" header in HTTP responses",
      new BooleanParameter(&HttpResponse::HIDE_PRODUCT_HEADER));
}

void RestServerFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
  if (_defaultApiCompatibility < HttpRequest::MIN_COMPATIBILITY) {
    LOG(FATAL) << "invalid value for --server.default-api-compatibility. "
                  "minimum allowed value is "
               << HttpRequest::MIN_COMPATIBILITY;
    FATAL_ERROR_EXIT();
  }
}

static TRI_vocbase_t* LookupDatabaseFromRequest(HttpRequest* request,
                                                TRI_server_t* server) {
  // get database name from request
  std::string dbName = request->databaseName();

  if (dbName.empty()) {
    // if no databases was specified in the request, use system database name
    // as a fallback
    dbName = TRI_VOC_SYSTEM_DATABASE;
    request->setDatabaseName(dbName);
  }

  if (ServerState::instance()->isCoordinator()) {
    return TRI_UseCoordinatorDatabaseServer(server, dbName.c_str());
  }

  return TRI_UseDatabaseServer(server, dbName.c_str());
}

static bool SetRequestContext(HttpRequest* request, void* data) {
  TRI_server_t* server = static_cast<TRI_server_t*>(data);
  TRI_vocbase_t* vocbase = LookupDatabaseFromRequest(request, server);

  // invalid database name specified, database not found etc.
  if (vocbase == nullptr) {
    return false;
  }

  // database needs upgrade
  if (vocbase->_state == (sig_atomic_t)TRI_VOCBASE_STATE_FAILED_VERSION) {
    request->setRequestPath("/_msg/please-upgrade");
    return false;
  }

  VocbaseContext* ctx = new arangodb::VocbaseContext(request, server, vocbase);
  request->setRequestContext(ctx, true);

  // the "true" means the request is the owner of the context
  return true;
}

void RestServerFeature::prepare() {
  HttpHandlerFactory::setMaintenance(true);
}

void RestServerFeature::start() {
  LOG(DEBUG) << "using default API compatibility: "
             << (long int)_defaultApiCompatibility;

  _jobManager.reset(new AsyncJobManager(ClusterCommRestCallback));

  auto vocbase = DatabaseFeature::DATABASE->vocbase();
  V8DealerFeature::DEALER->loadJavascript(vocbase, "server/server.js");
  _httpOptions._vocbase = vocbase;

  _handlerFactory.reset(new HttpHandlerFactory(
      _authenticationRealm, _defaultApiCompatibility, _allowMethodOverride,
      &SetRequestContext, DatabaseServerFeature::SERVER));

  defineHandlers();
  buildServers();

  for (auto& server : _servers) {
    server->startListening();
  }

  // disabled maintenance mode
  HttpHandlerFactory::setMaintenance(false);

  LOG(INFO) << "Authentication is turned " << (_authentication ? "on" : "off");

  if (_authentication) {
    if (_authenticationSystemOnly) {
      LOG(INFO) << "Authentication system only";
    }

#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
    LOG(INFO) << "Authentication for unix sockets is turned "
              << (_authenticationUnixSockets ? "on" : "off");
#endif
  }

  LOG(INFO) << "ArangoDB (version " << ARANGODB_VERSION_FULL
            << ") is ready for business. Have fun!";
}

void RestServerFeature::stop() {
  for (auto& server : _servers) {
    server->stopListening();
  }

  for (auto& server : _servers) {
    server->stop();
  }

  for (auto& server : _servers) {
    delete server;
  }

  _httpOptions._vocbase = nullptr;
}

void RestServerFeature::buildServers() {
  EndpointFeature* endpoint =
      application_features::ApplicationServer::getFeature<EndpointFeature>(
          "Endpoint");

  // unencrypted HTTP endpoints
  HttpServer* httpServer = new HttpServer(
      SchedulerFeature::SCHEDULER, DispatcherFeature::DISPATCHER,
      _handlerFactory.get(), _jobManager.get(), _keepAliveTimeout);

  // YYY #warning FRANK filter list
  auto const& endpointList = endpoint->endpointList();
  httpServer->setEndpointList(&endpointList);
  _servers.push_back(httpServer);

  // ssl endpoints
  if (endpointList.hasSsl()) {
    SslFeature* ssl =
        application_features::ApplicationServer::getFeature<SslFeature>("Ssl");

    // check the ssl context
    if (ssl->sslContext() == nullptr) {
      LOG(FATAL) << "no ssl context is known, cannot create https server, "
                    "please use the '--ssl.keyfile' option";
      FATAL_ERROR_EXIT();
    }

    SSL_CTX* sslContext = ssl->sslContext();

    // https
    httpServer =
        new HttpsServer(SchedulerFeature::SCHEDULER,
                        DispatcherFeature::DISPATCHER, _handlerFactory.get(),
                        _jobManager.get(), _keepAliveTimeout, sslContext);

    httpServer->setEndpointList(&endpointList);
    _servers.push_back(httpServer);
  }
}

void RestServerFeature::defineHandlers() {
  AgencyFeature* agency =
      application_features::ApplicationServer::getFeature<AgencyFeature>(
          "Agency");
  TRI_ASSERT(agency != nullptr);

  ClusterFeature* cluster =
      application_features::ApplicationServer::getFeature<ClusterFeature>(
          "Cluster");
  TRI_ASSERT(cluster != nullptr);

  auto queryRegistry = QueryRegistryFeature::QUERY_REGISTRY;

  // ...........................................................................
  // /_msg
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      "/_msg/please-upgrade",
      RestHandlerCreator<RestPleaseUpgradeHandler>::createNoData);

  // ...........................................................................
  // /_api
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::BATCH_PATH,
      RestHandlerCreator<RestBatchHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::CURSOR_PATH,
      RestHandlerCreator<RestCursorHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::DOCUMENT_PATH,
      RestHandlerCreator<RestDocumentHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::EDGES_PATH,
      RestHandlerCreator<RestEdgesHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::EXPORT_PATH,
      RestHandlerCreator<RestExportHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::IMPORT_PATH,
      RestHandlerCreator<RestImportHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::REPLICATION_PATH,
      RestHandlerCreator<RestReplicationHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_PATH,
      RestHandlerCreator<RestSimpleQueryHandler>::createData<
          aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_KEYS_PATH,
      RestHandlerCreator<RestSimpleQueryHandler>::createData<
          aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_LOOKUP_PATH,
      RestHandlerCreator<RestSimpleHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_REMOVE_PATH,
      RestHandlerCreator<RestSimpleHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::UPLOAD_PATH,
      RestHandlerCreator<RestUploadHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_api/shard-comm", RestHandlerCreator<RestShardHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_api/aql",
      RestHandlerCreator<aql::RestAqlHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      "/_api/query", RestHandlerCreator<RestQueryHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_api/query-cache",
      RestHandlerCreator<RestQueryCacheHandler>::createNoData);

  if (agency->isEnabled()) {
    _handlerFactory->addPrefixHandler(
        RestVocbaseBaseHandler::AGENCY_PATH,
        RestHandlerCreator<RestAgencyHandler>::createData<consensus::Agent*>,
        agency->agent());

    _handlerFactory->addPrefixHandler(
        RestVocbaseBaseHandler::AGENCY_PRIV_PATH,
        RestHandlerCreator<RestAgencyPrivHandler>::createData<
            consensus::Agent*>,
        agency->agent());
  }

  if (cluster->isEnabled()) {
    // add "/agency-callbacks" handler
    _handlerFactory->addPrefixHandler(
        cluster->agencyCallbacksPath(),
        RestHandlerCreator<RestAgencyCallbacksHandler>::createData<
            AgencyCallbackRegistry*>,
        cluster->agencyCallbackRegistry());
  }

  // And now some handlers which are registered in both /_api and /_admin
  _handlerFactory->addPrefixHandler(
      "/_api/job", RestHandlerCreator<arangodb::RestJobHandler>::createData<
                       AsyncJobManager*>,
      _jobManager.get());

  _handlerFactory->addHandler(
      "/_api/version", RestHandlerCreator<RestVersionHandler>::createNoData);

  // ...........................................................................
  // /_admin
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      "/_admin/job", RestHandlerCreator<arangodb::RestJobHandler>::createData<
                         AsyncJobManager*>,
      _jobManager.get());

  _handlerFactory->addHandler(
      "/_admin/version", RestHandlerCreator<RestVersionHandler>::createNoData);

  // further admin handlers
  _handlerFactory->addHandler(
      "/_admin/log",
      RestHandlerCreator<arangodb::RestAdminLogHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_admin/work-monitor",
      RestHandlerCreator<WorkMonitorHandler>::createNoData);

  _handlerFactory->addHandler(
      "/_admin/json-echo",
      RestHandlerCreator<RestEchoHandler>::createNoData);

#ifdef ARANGODB_ENABLE_FAILURE_TESTS
  // This handler is to activate SYS_DEBUG_FAILAT on DB servers
  _handlerFactory->addPrefixHandler(
      "/_admin/debug", RestHandlerCreator<RestDebugHandler>::createNoData);
#endif

  _handlerFactory->addPrefixHandler(
      "/_admin/shutdown",
      RestHandlerCreator<arangodb::RestShutdownHandler>::createNoData);

  // ...........................................................................
  // /_admin
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      "/", RestHandlerCreator<RestActionHandler>::createData<
               RestActionHandler::action_options_t*>,
      (void*)&_httpOptions);
}
<commit_msg>fixed namespace<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB 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
///
///     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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////

#include "RestServerFeature.h"

#include "ApplicationFeatures/SslFeature.h"
#include "Aql/RestAqlHandler.h"
#include "Agency/AgencyFeature.h"
#include "Agency/RestAgencyHandler.h"
#include "Agency/RestAgencyPrivHandler.h"
#include "Cluster/AgencyCallbackRegistry.h"
#include "Cluster/ClusterComm.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/RestAgencyCallbacksHandler.h"
#include "Cluster/RestShardHandler.h"
#include "Dispatcher/DispatcherFeature.h"
#include "HttpServer/HttpHandlerFactory.h"
#include "HttpServer/HttpServer.h"
#include "HttpServer/HttpsServer.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "Rest/Version.h"
#include "RestHandler/RestAdminLogHandler.h"
#include "RestHandler/RestBatchHandler.h"
#include "RestHandler/RestCursorHandler.h"
#include "RestHandler/RestDebugHandler.h"
#include "RestHandler/RestDocumentHandler.h"
#include "RestHandler/RestEchoHandler.h"
#include "RestHandler/RestEdgesHandler.h"
#include "RestHandler/RestExportHandler.h"
#include "RestHandler/RestHandlerCreator.h"
#include "RestHandler/RestImportHandler.h"
#include "RestHandler/RestJobHandler.h"
#include "RestHandler/RestPleaseUpgradeHandler.h"
#include "RestHandler/RestQueryCacheHandler.h"
#include "RestHandler/RestQueryHandler.h"
#include "RestHandler/RestReplicationHandler.h"
#include "RestHandler/RestShutdownHandler.h"
#include "RestHandler/RestSimpleHandler.h"
#include "RestHandler/RestSimpleQueryHandler.h"
#include "RestHandler/RestUploadHandler.h"
#include "RestHandler/RestVersionHandler.h"
#include "RestHandler/WorkMonitorHandler.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/DatabaseServerFeature.h"
#include "RestServer/EndpointFeature.h"
#include "RestServer/QueryRegistryFeature.h"
#include "RestServer/ServerFeature.h"
#include "Scheduler/SchedulerFeature.h"
#include "V8Server/V8DealerFeature.h"
#include "VocBase/server.h"

using namespace arangodb;
using namespace arangodb::rest;
using namespace arangodb::options;

RestServerFeature::RestServerFeature(
    application_features::ApplicationServer* server,
    std::string const& authenticationRealm)
    : ApplicationFeature(server, "RestServer"),
      _keepAliveTimeout(300.0),
      _authenticationRealm(authenticationRealm),
      _defaultApiCompatibility(Version::getNumericServerVersion()),
      _allowMethodOverride(false),
      _authentication(true),
      _authenticationUnixSockets(true),
      _authenticationSystemOnly(false),
      _handlerFactory(nullptr),
      _jobManager(nullptr) {
  setOptional(true);
  requiresElevatedPrivileges(false);
  startsAfter("Dispatcher");
  startsAfter("Endpoint");
  startsAfter("Scheduler");
  startsAfter("Server");
  startsAfter("Agency");
  startsAfter("LogfileManager");
  startsAfter("Database");
  startsAfter("Upgrade");
  startsAfter("CheckVersion");
}

void RestServerFeature::collectOptions(
    std::shared_ptr<ProgramOptions> options) {
  options->addSection("server", "Server features");

  options->addHiddenOption("--server.default-api-compatibility",
                           "default API compatibility version",
                           new Int32Parameter(&_defaultApiCompatibility));

  options->addOption("--server.authentication",
                     "enable or disable authentication for ALL client requests",
                     new BooleanParameter(&_authentication));

  options->addOption(
      "--server.authentication-system-only",
      "use HTTP authentication only for requests to /_api and /_admin",
      new BooleanParameter(&_authenticationSystemOnly));

#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
  options->addOption("--server.authentication-unix-sockets",
                     "authentication for requests via UNIX domain sockets",
                     new BooleanParameter(&_authenticationUnixSockets));
#endif

  options->addSection("http", "HttpServer features");

  options->addHiddenOption("--http.allow-method-override",
                           "allow HTTP method override using special headers",
                           new BooleanParameter(&_allowMethodOverride));

  options->addOption("--http.keep-alive-timeout",
                     "keep-alive timeout in seconds",
                     new DoubleParameter(&_keepAliveTimeout));

  options->addOption(
      "--http.hide-product-header",
      "do not expose \"Server: ArangoDB\" header in HTTP responses",
      new BooleanParameter(&HttpResponse::HIDE_PRODUCT_HEADER));
}

void RestServerFeature::validateOptions(std::shared_ptr<ProgramOptions>) {
  if (_defaultApiCompatibility < HttpRequest::MIN_COMPATIBILITY) {
    LOG(FATAL) << "invalid value for --server.default-api-compatibility. "
                  "minimum allowed value is "
               << HttpRequest::MIN_COMPATIBILITY;
    FATAL_ERROR_EXIT();
  }
}

static TRI_vocbase_t* LookupDatabaseFromRequest(HttpRequest* request,
                                                TRI_server_t* server) {
  // get database name from request
  std::string dbName = request->databaseName();

  if (dbName.empty()) {
    // if no databases was specified in the request, use system database name
    // as a fallback
    dbName = TRI_VOC_SYSTEM_DATABASE;
    request->setDatabaseName(dbName);
  }

  if (ServerState::instance()->isCoordinator()) {
    return TRI_UseCoordinatorDatabaseServer(server, dbName.c_str());
  }

  return TRI_UseDatabaseServer(server, dbName.c_str());
}

static bool SetRequestContext(HttpRequest* request, void* data) {
  TRI_server_t* server = static_cast<TRI_server_t*>(data);
  TRI_vocbase_t* vocbase = LookupDatabaseFromRequest(request, server);

  // invalid database name specified, database not found etc.
  if (vocbase == nullptr) {
    return false;
  }

  // database needs upgrade
  if (vocbase->_state == (sig_atomic_t)TRI_VOCBASE_STATE_FAILED_VERSION) {
    request->setRequestPath("/_msg/please-upgrade");
    return false;
  }

  VocbaseContext* ctx = new arangodb::VocbaseContext(request, server, vocbase);
  request->setRequestContext(ctx, true);

  // the "true" means the request is the owner of the context
  return true;
}

void RestServerFeature::prepare() {
  HttpHandlerFactory::setMaintenance(true);
}

void RestServerFeature::start() {
  LOG(DEBUG) << "using default API compatibility: "
             << (long int)_defaultApiCompatibility;

  _jobManager.reset(new AsyncJobManager(ClusterCommRestCallback));

  auto vocbase = DatabaseFeature::DATABASE->vocbase();
  V8DealerFeature::DEALER->loadJavascript(vocbase, "server/server.js");
  _httpOptions._vocbase = vocbase;

  _handlerFactory.reset(new HttpHandlerFactory(
      _authenticationRealm, _defaultApiCompatibility, _allowMethodOverride,
      &SetRequestContext, DatabaseServerFeature::SERVER));

  defineHandlers();
  buildServers();

  for (auto& server : _servers) {
    server->startListening();
  }

  // disabled maintenance mode
  HttpHandlerFactory::setMaintenance(false);

  LOG(INFO) << "Authentication is turned " << (_authentication ? "on" : "off");

  if (_authentication) {
    if (_authenticationSystemOnly) {
      LOG(INFO) << "Authentication system only";
    }

#ifdef ARANGODB_HAVE_DOMAIN_SOCKETS
    LOG(INFO) << "Authentication for unix sockets is turned "
              << (_authenticationUnixSockets ? "on" : "off");
#endif
  }

  LOG(INFO) << "ArangoDB (version " << ARANGODB_VERSION_FULL
            << ") is ready for business. Have fun!";
}

void RestServerFeature::stop() {
  for (auto& server : _servers) {
    server->stopListening();
  }

  for (auto& server : _servers) {
    server->stop();
  }

  for (auto& server : _servers) {
    delete server;
  }

  _httpOptions._vocbase = nullptr;
}

void RestServerFeature::buildServers() {
  EndpointFeature* endpoint =
      application_features::ApplicationServer::getFeature<EndpointFeature>(
          "Endpoint");

  // unencrypted HTTP endpoints
  HttpServer* httpServer = new HttpServer(
      SchedulerFeature::SCHEDULER, DispatcherFeature::DISPATCHER,
      _handlerFactory.get(), _jobManager.get(), _keepAliveTimeout);

  // YYY #warning FRANK filter list
  auto const& endpointList = endpoint->endpointList();
  httpServer->setEndpointList(&endpointList);
  _servers.push_back(httpServer);

  // ssl endpoints
  if (endpointList.hasSsl()) {
    SslFeature* ssl =
        application_features::ApplicationServer::getFeature<SslFeature>("Ssl");

    // check the ssl context
    if (ssl->sslContext() == nullptr) {
      LOG(FATAL) << "no ssl context is known, cannot create https server, "
                    "please use the '--ssl.keyfile' option";
      FATAL_ERROR_EXIT();
    }

    SSL_CTX* sslContext = ssl->sslContext();

    // https
    httpServer =
        new HttpsServer(SchedulerFeature::SCHEDULER,
                        DispatcherFeature::DISPATCHER, _handlerFactory.get(),
                        _jobManager.get(), _keepAliveTimeout, sslContext);

    httpServer->setEndpointList(&endpointList);
    _servers.push_back(httpServer);
  }
}

void RestServerFeature::defineHandlers() {
  AgencyFeature* agency =
      application_features::ApplicationServer::getFeature<AgencyFeature>(
          "Agency");
  TRI_ASSERT(agency != nullptr);

  ClusterFeature* cluster =
      application_features::ApplicationServer::getFeature<ClusterFeature>(
          "Cluster");
  TRI_ASSERT(cluster != nullptr);

  auto queryRegistry = QueryRegistryFeature::QUERY_REGISTRY;

  // ...........................................................................
  // /_msg
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      "/_msg/please-upgrade",
      RestHandlerCreator<RestPleaseUpgradeHandler>::createNoData);

  // ...........................................................................
  // /_api
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::BATCH_PATH,
      RestHandlerCreator<RestBatchHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::CURSOR_PATH,
      RestHandlerCreator<RestCursorHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::DOCUMENT_PATH,
      RestHandlerCreator<RestDocumentHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::EDGES_PATH,
      RestHandlerCreator<RestEdgesHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::EXPORT_PATH,
      RestHandlerCreator<RestExportHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::IMPORT_PATH,
      RestHandlerCreator<RestImportHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::REPLICATION_PATH,
      RestHandlerCreator<RestReplicationHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_PATH,
      RestHandlerCreator<RestSimpleQueryHandler>::createData<
          aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_KEYS_PATH,
      RestHandlerCreator<RestSimpleQueryHandler>::createData<
          aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_LOOKUP_PATH,
      RestHandlerCreator<RestSimpleHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::SIMPLE_REMOVE_PATH,
      RestHandlerCreator<RestSimpleHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      RestVocbaseBaseHandler::UPLOAD_PATH,
      RestHandlerCreator<RestUploadHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_api/shard-comm", RestHandlerCreator<RestShardHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_api/aql",
      RestHandlerCreator<aql::RestAqlHandler>::createData<aql::QueryRegistry*>,
      queryRegistry);

  _handlerFactory->addPrefixHandler(
      "/_api/query", RestHandlerCreator<RestQueryHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_api/query-cache",
      RestHandlerCreator<RestQueryCacheHandler>::createNoData);

  if (agency->isEnabled()) {
    _handlerFactory->addPrefixHandler(
        RestVocbaseBaseHandler::AGENCY_PATH,
        RestHandlerCreator<RestAgencyHandler>::createData<consensus::Agent*>,
        agency->agent());

    _handlerFactory->addPrefixHandler(
        RestVocbaseBaseHandler::AGENCY_PRIV_PATH,
        RestHandlerCreator<RestAgencyPrivHandler>::createData<
            consensus::Agent*>,
        agency->agent());
  }

  if (cluster->isEnabled()) {
    // add "/agency-callbacks" handler
    _handlerFactory->addPrefixHandler(
        cluster->agencyCallbacksPath(),
        RestHandlerCreator<RestAgencyCallbacksHandler>::createData<
            AgencyCallbackRegistry*>,
        cluster->agencyCallbackRegistry());
  }

  // And now some handlers which are registered in both /_api and /_admin
  _handlerFactory->addPrefixHandler(
      "/_api/job", RestHandlerCreator<arangodb::RestJobHandler>::createData<
                       AsyncJobManager*>,
      _jobManager.get());

  _handlerFactory->addHandler(
      "/_api/version", RestHandlerCreator<RestVersionHandler>::createNoData);

  // ...........................................................................
  // /_admin
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      "/_admin/job", RestHandlerCreator<arangodb::RestJobHandler>::createData<
                         AsyncJobManager*>,
      _jobManager.get());

  _handlerFactory->addHandler(
      "/_admin/version", RestHandlerCreator<RestVersionHandler>::createNoData);

  // further admin handlers
  _handlerFactory->addHandler(
      "/_admin/log",
      RestHandlerCreator<arangodb::RestAdminLogHandler>::createNoData);

  _handlerFactory->addPrefixHandler(
      "/_admin/work-monitor",
      RestHandlerCreator<WorkMonitorHandler>::createNoData);

  _handlerFactory->addHandler(
      "/_admin/json-echo",
      RestHandlerCreator<RestEchoHandler>::createNoData);

#ifdef ARANGODB_ENABLE_FAILURE_TESTS
  // This handler is to activate SYS_DEBUG_FAILAT on DB servers
  _handlerFactory->addPrefixHandler(
      "/_admin/debug", RestHandlerCreator<RestDebugHandler>::createNoData);
#endif

  _handlerFactory->addPrefixHandler(
      "/_admin/shutdown",
      RestHandlerCreator<arangodb::RestShutdownHandler>::createNoData);

  // ...........................................................................
  // /_admin
  // ...........................................................................

  _handlerFactory->addPrefixHandler(
      "/", RestHandlerCreator<RestActionHandler>::createData<
               RestActionHandler::action_options_t*>,
      (void*)&_httpOptions);
}
<|endoftext|>


<commit_before>// ==========================================================================
//                 SeqAn - The Library for Sequence Analysis
// ==========================================================================
// Copyright (c) 2006-2014, Knut Reinert, FU Berlin
// All rights reserved.
//
// 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.
//     * Neither the name of Knut Reinert or the FU Berlin nor the names of
//       its contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// 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 KNUT REINERT OR THE FU BERLIN 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.
//
// ==========================================================================
// Author: Manuel Holtgrewe <manuel.holtgrewe@fu-berlin.de>
// ==========================================================================

#include <sstream>

#include <seqan/basic.h>
#include <seqan/stream.h>

#include <seqan/simple_intervals_io.h>

SEQAN_DEFINE_TEST(test_simple_intervals_io_read_records)
{
    // Input file contents and input iterator.
    std::string input = "chr1:2489281-2489282\n"
                        "chr4:2489841\n";
    typename seqan::DirectionIterator<std::string, seqan::Input>::Type it =
        directionIterator(input, seqan::Input());

    // Buffers and record.
    seqan::SimpleIntervalsIOContext context;
    seqan::GenomicRegion region;

    // Read and check first record.
    readRecord(region, context, it, seqan::SimpleIntervals());
    SEQAN_ASSERT_EQ(region.seqName, "chr1");
    SEQAN_ASSERT_EQ(region.beginPos, 2489280u);
    SEQAN_ASSERT_EQ(region.endPos, 2489282u);

    // Read and check second record.
    readRecord(region, context, it, seqan::SimpleIntervals());
    SEQAN_ASSERT_EQ(region.seqName, "chr4");
    SEQAN_ASSERT_EQ(region.beginPos, 2489840u);
    SEQAN_ASSERT_EQ(region.endPos, 2489841u);

    // We should be at the end of the file.
    SEQAN_ASSERT(atEnd(it));
}

SEQAN_DEFINE_TEST(test_simple_intervals_io_write_records)
{
    // Output buffer and output iterator.
    seqan::CharString out;
    typename seqan::DirectionIterator<seqan::CharString, seqan::Output>::Type it =
        directionIterator(out, seqan::Output());

    // Buffer and record.
    seqan::GenomicRegion region;
    seqan::SimpleIntervalsIOContext context;

    // Write out first record.
    region.seqName = "chr1";
    region.beginPos = 2489280;
    region.endPos = 2489282;
    writeRecord(it, context, region, seqan::SimpleIntervals());

    // Write out second record.
    region.seqName = "chr4";
    region.beginPos = 2489840;
    region.endPos = 2489841;
    writeRecord(it, context, region, seqan::SimpleIntervals());

    seqan::CharString expected = "chr1:2489281-2489282\n"
                                 "chr4:2489841\n";
    SEQAN_ASSERT_EQ(expected, out);
}

SEQAN_DEFINE_TEST(test_simple_intervals_io_smart_file_read)
{
    // Input file contents and input iterator.
    std::istringstream input("chr1:2489281-2489282\n"
                             "chr4:2489841\n");
    seqan::SimpleIntervalsFileIn simple_intervalsIn(input);

    // Buffers and record.
    seqan::SimpleIntervalsIOContext context;
    seqan::GenomicRegion region;

    // Read and check first record.
    readRecord(region, simple_intervalsIn);
    SEQAN_ASSERT_EQ(region.seqName, "chr1");
    SEQAN_ASSERT_EQ(region.beginPos, 2489280u);
    SEQAN_ASSERT_EQ(region.endPos, 2489282u);

    // Read and check second record.
    readRecord(region, simple_intervalsIn);
    SEQAN_ASSERT_EQ(region.seqName, "chr4");
    SEQAN_ASSERT_EQ(region.beginPos, 2489840u);
    SEQAN_ASSERT_EQ(region.endPos, 2489841u);

    // We should be at the end of the file.
    SEQAN_ASSERT(atEnd(simple_intervalsIn));
}

SEQAN_DEFINE_TEST(test_simple_intervals_io_smart_file_write)
{
    // Output buffer and output iterator.
    std::ostringstream output;
    seqan::SimpleIntervalsFileOut simple_intervalsOut(output, seqan::SimpleIntervals());

    // Buffer and record.
    seqan::GenomicRegion region;
    seqan::SimpleIntervalsIOContext context;

    // Write out first record.
    region.seqName = "chr1";
    region.beginPos = 2489280;
    region.endPos = 2489282;
    writeRecord(simple_intervalsOut, region);

    // Write out second record.
    region.seqName = "chr4";
    region.beginPos = 2489840;
    region.endPos = 2489841;
    writeRecord(simple_intervalsOut, region);

    seqan::CharString expected = "chr1:2489281-2489282\n"
                                 "chr4:2489841\n";
    SEQAN_ASSERT_EQ(expected, output.str());
}

SEQAN_BEGIN_TESTSUITE(test_simple_intervals_io)
{
	SEQAN_CALL_TEST(test_simple_intervals_io_read_records);
	SEQAN_CALL_TEST(test_simple_intervals_io_write_records);

	SEQAN_CALL_TEST(test_simple_intervals_io_smart_file_read);
	SEQAN_CALL_TEST(test_simple_intervals_io_smart_file_write);
}
SEQAN_END_TESTSUITE
<commit_msg>[FIX] Fixes compiler warnings for comparison of different types.<commit_after>// ==========================================================================
//                 SeqAn - The Library for Sequence Analysis
// ==========================================================================
// Copyright (c) 2006-2014, Knut Reinert, FU Berlin
// All rights reserved.
//
// 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.
//     * Neither the name of Knut Reinert or the FU Berlin nor the names of
//       its contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// 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 KNUT REINERT OR THE FU BERLIN 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.
//
// ==========================================================================
// Author: Manuel Holtgrewe <manuel.holtgrewe@fu-berlin.de>
// ==========================================================================

#include <sstream>

#include <seqan/basic.h>
#include <seqan/stream.h>

#include <seqan/simple_intervals_io.h>

SEQAN_DEFINE_TEST(test_simple_intervals_io_read_records)
{
    // Input file contents and input iterator.
    std::string input = "chr1:2489281-2489282\n"
                        "chr4:2489841\n";
    typename seqan::DirectionIterator<std::string, seqan::Input>::Type it =
        directionIterator(input, seqan::Input());

    // Buffers and record.
    seqan::SimpleIntervalsIOContext context;
    seqan::GenomicRegion region;

    // Read and check first record.
    readRecord(region, context, it, seqan::SimpleIntervals());
    SEQAN_ASSERT_EQ(region.seqName, "chr1");
    SEQAN_ASSERT_EQ(region.beginPos, 2489280);
    SEQAN_ASSERT_EQ(region.endPos, 2489282);

    // Read and check second record.
    readRecord(region, context, it, seqan::SimpleIntervals());
    SEQAN_ASSERT_EQ(region.seqName, "chr4");
    SEQAN_ASSERT_EQ(region.beginPos, 2489840);
    SEQAN_ASSERT_EQ(region.endPos, 2489841);

    // We should be at the end of the file.
    SEQAN_ASSERT(atEnd(it));
}

SEQAN_DEFINE_TEST(test_simple_intervals_io_write_records)
{
    // Output buffer and output iterator.
    seqan::CharString out;
    typename seqan::DirectionIterator<seqan::CharString, seqan::Output>::Type it =
        directionIterator(out, seqan::Output());

    // Buffer and record.
    seqan::GenomicRegion region;
    seqan::SimpleIntervalsIOContext context;

    // Write out first record.
    region.seqName = "chr1";
    region.beginPos = 2489280;
    region.endPos = 2489282;
    writeRecord(it, context, region, seqan::SimpleIntervals());

    // Write out second record.
    region.seqName = "chr4";
    region.beginPos = 2489840;
    region.endPos = 2489841;
    writeRecord(it, context, region, seqan::SimpleIntervals());

    seqan::CharString expected = "chr1:2489281-2489282\n"
                                 "chr4:2489841\n";
    SEQAN_ASSERT_EQ(expected, out);
}

SEQAN_DEFINE_TEST(test_simple_intervals_io_smart_file_read)
{
    // Input file contents and input iterator.
    std::istringstream input("chr1:2489281-2489282\n"
                             "chr4:2489841\n");
    seqan::SimpleIntervalsFileIn simple_intervalsIn(input);

    // Buffers and record.
    seqan::SimpleIntervalsIOContext context;
    seqan::GenomicRegion region;

    // Read and check first record.
    readRecord(region, simple_intervalsIn);
    SEQAN_ASSERT_EQ(region.seqName, "chr1");
    SEQAN_ASSERT_EQ(region.beginPos, 2489280);
    SEQAN_ASSERT_EQ(region.endPos, 2489282);

    // Read and check second record.
    readRecord(region, simple_intervalsIn);
    SEQAN_ASSERT_EQ(region.seqName, "chr4");
    SEQAN_ASSERT_EQ(region.beginPos, 2489840);
    SEQAN_ASSERT_EQ(region.endPos, 2489841);

    // We should be at the end of the file.
    SEQAN_ASSERT(atEnd(simple_intervalsIn));
}

SEQAN_DEFINE_TEST(test_simple_intervals_io_smart_file_write)
{
    // Output buffer and output iterator.
    std::ostringstream output;
    seqan::SimpleIntervalsFileOut simple_intervalsOut(output, seqan::SimpleIntervals());

    // Buffer and record.
    seqan::GenomicRegion region;
    seqan::SimpleIntervalsIOContext context;

    // Write out first record.
    region.seqName = "chr1";
    region.beginPos = 2489280;
    region.endPos = 2489282;
    writeRecord(simple_intervalsOut, region);

    // Write out second record.
    region.seqName = "chr4";
    region.beginPos = 2489840;
    region.endPos = 2489841;
    writeRecord(simple_intervalsOut, region);

    seqan::CharString expected = "chr1:2489281-2489282\n"
                                 "chr4:2489841\n";
    SEQAN_ASSERT_EQ(expected, output.str());
}

SEQAN_BEGIN_TESTSUITE(test_simple_intervals_io)
{
	SEQAN_CALL_TEST(test_simple_intervals_io_read_records);
	SEQAN_CALL_TEST(test_simple_intervals_io_write_records);

	SEQAN_CALL_TEST(test_simple_intervals_io_smart_file_read);
	SEQAN_CALL_TEST(test_simple_intervals_io_smart_file_write);
}
SEQAN_END_TESTSUITE
<|endoftext|>