zeromq / libzmq

ZeroMQ core engine in C++, implements ZMTP/3.1
https://www.zeromq.org
Mozilla Public License 2.0
9.64k stars 2.35k forks source link

Setting context option ZMQ_MAX_SOCKETS after socket creation is ignored #4280

Open baptistepetit opened 2 years ago

baptistepetit commented 2 years ago

Issue description

I noticed that if we create a socket using a context, changing the option ZMQ_MAX_SOCKETS on that context after has no effect. I could not find if this is the intended behavior of the API. If this is the intended behavior of the API, then maybe zmq_ctx_set should return -1, and in my experience it is not the case. Note: In this use case zmq_ctx_get returns the value I manually set, but the option does not get applied.

Environment

Minimal test code / Steps to reproduce the issue

Here is a minimal test code inspired from libzmq test_many_sockets.cpp unit test:

#include <iostream>
#include <vector>
#include <zmq.h>

int main()
{
  void *context = zmq_ctx_new ();
  std::vector<void *> sockets;
  const int no_of_sockets = 2 * 65536;

  // Create a first socket
  void *first_socket = zmq_socket(context, ZMQ_PAIR);
  sockets.push_back (first_socket);

  // Then change the context options
  const int ret = zmq_ctx_set(context, ZMQ_MAX_SOCKETS, no_of_sockets);
  std::cout << "zmq_ctx_set returned: " << ret << "\n";

  // Check if the value is set in the context
  const int no_of_socket_from_ctx = zmq_ctx_get(context, ZMQ_MAX_SOCKETS);
  std::cout << "zmq_ctx_get returned: " << no_of_socket_from_ctx << "\n";

  while (true) {
      void *socket = zmq_socket(context, ZMQ_PAIR);
      if (!socket)
          break;
      sockets.push_back (socket);
  }

  std::cout << "Number of socket created: " <<  sockets.size() << std::endl;

  return 0;
}

What's the actual result? (include assertion message & call stack if applicable)

The test code output is:

zmq_ctx_set returned: 0
zmq_ctx_get returned: 131072
Number of socket created: 1023

What's the expected result?

If we are not allowed to change this option after creating a first socket, the result should be:

zmq_ctx_set returned: -1
zmq_ctx_get returned: 1023
Number of socket created: 1023

If we are allowed to change this option after creating a first socket, the result should be:

zmq_ctx_set returned: 0
zmq_ctx_get returned: 131072
Number of socket created: 131072

Additional information:

This should not be linked to the number of files open on my system because if you comment out the creation of the first socket in my test code the result is then as expected:

zmq_ctx_set returned: 0
zmq_ctx_get returned: 131072
Number of socket created: 131072

To avoid errors due to Too many open files in my testing, I expanded the number of files that can be open in the process with: ulimit -n 1048576.

ljluestc commented 2 weeks ago

#include <iostream>
#include <vector>
#include <zmq.h>

int main()
{
    // Create a new context
    void *context = zmq_ctx_new();
    const int no_of_sockets = 2 * 65536;

    // Change the context options before creating any sockets
    const int ret = zmq_ctx_set(context, ZMQ_MAX_SOCKETS, no_of_sockets);
    if (ret != 0) {
        std::cerr << "Error setting context option: " << zmq_strerror(zmq_errno()) << std::endl;
        return 1;
    }

    // Verify the context option is set
    const int no_of_socket_from_ctx = zmq_ctx_get(context, ZMQ_MAX_SOCKETS);
    std::cout << "zmq_ctx_get returned: " << no_of_socket_from_ctx << "\n";

    std::vector<void *> sockets;

    // Create sockets
    for (int i = 0; i < no_of_sockets; ++i) {
        void *socket = zmq_socket(context, ZMQ_PAIR);
        if (!socket) {
            std::cerr << "Failed to create socket: " << zmq_strerror(zmq_errno()) << std::endl;
            break;
        }
        sockets.push_back(socket);
    }

    std::cout << "Number of sockets created: " << sockets.size() << std::endl;

    // Clean up
    for (void *socket : sockets) {
        zmq_close(socket);
    }
    zmq_ctx_destroy(context);

    return 0;
}
ljluestc commented 2 weeks ago

#include <iostream>
#include <vector>
#include <zmq.h>

int main()
{
    // Create a new context
    void *context = zmq_ctx_new();
    const int no_of_sockets = 2 * 65536;

    // Change the context options before creating any sockets
    const int ret = zmq_ctx_set(context, ZMQ_MAX_SOCKETS, no_of_sockets);
    if (ret != 0) {
        std::cerr << "Error setting context option: " << zmq_strerror(zmq_errno()) << std::endl;
        return 1;
    }

    // Verify the context option is set
    const int no_of_socket_from_ctx = zmq_ctx_get(context, ZMQ_MAX_SOCKETS);
    std::cout << "zmq_ctx_get returned: " << no_of_socket_from_ctx << "\n";

    std::vector<void *> sockets;

    // Create sockets
    for (int i = 0; i < no_of_sockets; ++i) {
        void *socket = zmq_socket(context, ZMQ_PAIR);
        if (!socket) {
            std::cerr << "Failed to create socket: " << zmq_strerror(zmq_errno()) << std::endl;
            break;
        }
        sockets.push_back(socket);
    }

    std::cout << "Number of sockets created: " << sockets.size() << std::endl;

    // Clean up
    for (void *socket : sockets) {
        zmq_close(socket);
    }
    zmq_ctx_destroy(context);

    return 0;
}