Rename photon -> local scheduler. (#322)

This commit is contained in:
Robert Nishihara
2017-02-27 12:24:07 -08:00
committed by Philipp Moritz
parent a30eed452e
commit 1ae7e7d29e
36 changed files with 758 additions and 688 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ function(define_test test_name library)
add_executable(${test_name} test/${test_name}.c ${ARGN})
add_dependencies(${test_name} hiredis flatcc)
target_link_libraries(${test_name} common ${FLATBUFFERS_STATIC_LIB} ${library})
target_compile_options(${test_name} PUBLIC "-DPLASMA_TEST -DPHOTON_TEST -DCOMMON_TEST -DRAY_COMMON_LOG_LEVEL=4 -DRAY_TIMEOUT=50")
target_compile_options(${test_name} PUBLIC "-DPLASMA_TEST -DLOCAL_SCHEDULER_TEST -DCOMMON_TEST -DRAY_COMMON_LOG_LEVEL=4 -DRAY_TIMEOUT=50")
endfunction()
define_test(common_tests "")
+2 -2
View File
@@ -83,7 +83,7 @@ PyObject *PyObjectID_make(ObjectID object_id) {
*
* This is called from Python like
*
* task = photon.task_from_string("...")
* task = local_scheduler.task_from_string("...")
*
* @param task_string String representation of the task specification.
* @return Python task specification object.
@@ -112,7 +112,7 @@ PyObject *PyTask_from_string(PyObject *self, PyObject *args) {
*
* This is called from Python like
*
* s = photon.task_to_string(task)
* s = local_scheduler.task_to_string(task)
*
* @param task Ray task specification Python object.
* @return String representing the task specification.
+39 -31
View File
@@ -83,17 +83,21 @@ void GlobalSchedulerState_free(GlobalSchedulerState *state) {
db_disconnect(state->db);
utarray_free(state->local_schedulers);
GlobalSchedulerPolicyState_free(state->policy_state);
/* Delete the plasma to photon association map. */
HASH_ITER(plasma_photon_hh, state->plasma_photon_map, entry, tmp) {
HASH_DELETE(plasma_photon_hh, state->plasma_photon_map, entry);
/* The hash entry is shared with the photon_plasma hashmap and will be freed
* there. */
/* Delete the plasma to local scheduler association map. */
HASH_ITER(plasma_local_scheduler_hh, state->plasma_local_scheduler_map, entry,
tmp) {
HASH_DELETE(plasma_local_scheduler_hh, state->plasma_local_scheduler_map,
entry);
/* The hash entry is shared with the local_scheduler_plasma hashmap and will
* be freed there. */
free(entry->aux_address);
}
/* Delete the photon to plasma association map. */
HASH_ITER(photon_plasma_hh, state->photon_plasma_map, entry, tmp) {
HASH_DELETE(photon_plasma_hh, state->photon_plasma_map, entry);
/* Delete the local scheduler to plasma association map. */
HASH_ITER(local_scheduler_plasma_hh, state->local_scheduler_plasma_map, entry,
tmp) {
HASH_DELETE(local_scheduler_plasma_hh, state->local_scheduler_plasma_map,
entry);
/* Now free the shared hash entry -- no longer needed. */
free(entry);
}
@@ -135,13 +139,13 @@ void signal_handler(int signal) {
/* End of the cleanup code. */
LocalScheduler *get_local_scheduler(GlobalSchedulerState *state,
DBClientID photon_id) {
DBClientID local_scheduler_id) {
LocalScheduler *local_scheduler_ptr;
for (int i = 0; i < utarray_len(state->local_schedulers); ++i) {
local_scheduler_ptr =
(LocalScheduler *) utarray_eltptr(state->local_schedulers, i);
if (DBClientID_equal(local_scheduler_ptr->id, photon_id)) {
LOG_DEBUG("photon_id matched cached local scheduler entry.");
if (DBClientID_equal(local_scheduler_ptr->id, local_scheduler_id)) {
LOG_DEBUG("local_scheduler_id matched cached local scheduler entry.");
return local_scheduler_ptr;
}
}
@@ -176,32 +180,36 @@ void process_new_db_client(DBClientID db_client_id,
LOG_DEBUG("db client table callback for db client = %s",
ObjectID_to_string(db_client_id, id_string, ID_STRING_SIZE));
UNUSED(id_string);
if (strncmp(client_type, "photon", strlen("photon")) == 0) {
/* Add plasma_manager ip:port -> photon_db_client_id association to state.
*/
AuxAddressEntry *plasma_photon_entry = calloc(1, sizeof(AuxAddressEntry));
plasma_photon_entry->aux_address = strdup(aux_address);
plasma_photon_entry->photon_db_client_id = db_client_id;
HASH_ADD_KEYPTR(plasma_photon_hh, state->plasma_photon_map,
plasma_photon_entry->aux_address,
strlen(plasma_photon_entry->aux_address),
plasma_photon_entry);
if (strncmp(client_type, "local_scheduler", strlen("local_scheduler")) == 0) {
/* Add plasma_manager ip:port -> local_scheduler_db_client_id association to
* state. */
AuxAddressEntry *plasma_local_scheduler_entry =
calloc(1, sizeof(AuxAddressEntry));
plasma_local_scheduler_entry->aux_address = strdup(aux_address);
plasma_local_scheduler_entry->local_scheduler_db_client_id = db_client_id;
HASH_ADD_KEYPTR(plasma_local_scheduler_hh,
state->plasma_local_scheduler_map,
plasma_local_scheduler_entry->aux_address,
strlen(plasma_local_scheduler_entry->aux_address),
plasma_local_scheduler_entry);
/* Add photon_db_client_id -> plasma_manager ip:port association to state.
*/
HASH_ADD(photon_plasma_hh, state->photon_plasma_map, photon_db_client_id,
sizeof(plasma_photon_entry->photon_db_client_id),
plasma_photon_entry);
/* Add local_scheduler_db_client_id -> plasma_manager ip:port association to
* state. */
HASH_ADD(local_scheduler_plasma_hh, state->local_scheduler_plasma_map,
local_scheduler_db_client_id,
sizeof(plasma_local_scheduler_entry->local_scheduler_db_client_id),
plasma_local_scheduler_entry);
#if (RAY_COMMON_LOG_LEVEL <= RAY_COMMON_DEBUG)
{
/* Print the photon to plasma association map so far. */
/* Print the local scheduler to plasma association map so far. */
AuxAddressEntry *entry, *tmp;
LOG_DEBUG("Photon to Plasma hash map so far:");
HASH_ITER(plasma_photon_hh, state->plasma_photon_map, entry, tmp) {
LOG_DEBUG("Local scheduler to plasma hash map so far:");
HASH_ITER(plasma_local_scheduler_hh, state->plasma_local_scheduler_map,
entry, tmp) {
LOG_DEBUG("%s -> %s", entry->aux_address,
ObjectID_to_string(entry->photon_db_client_id, id_string,
ID_STRING_SIZE));
ObjectID_to_string(entry->local_scheduler_db_client_id,
id_string, ID_STRING_SIZE));
}
}
#endif
+14 -14
View File
@@ -44,17 +44,17 @@ typedef struct {
} SchedulerObjectInfo;
/**
* A struct used for caching Photon to Plasma association.
* A struct used for caching local scheduler to Plasma association.
*/
typedef struct {
/** IP:port string for the plasma_manager. */
char *aux_address;
/** Photon db client id. */
DBClientID photon_db_client_id;
/** Plasma_manager ip:port -> photon_db_client_id. */
UT_hash_handle plasma_photon_hh;
/** Photon_db_client_id -> plasma_manager ip:port. */
UT_hash_handle photon_plasma_hh;
/** Local scheduler db client id. */
DBClientID local_scheduler_db_client_id;
/** Plasma_manager ip:port -> local_scheduler_db_client_id. */
UT_hash_handle plasma_local_scheduler_hh;
/** local_scheduler_db_client_id -> plasma_manager ip:port. */
UT_hash_handle local_scheduler_plasma_hh;
} AuxAddressEntry;
/**
@@ -71,10 +71,10 @@ typedef struct {
UT_array *local_schedulers;
/** The state managed by the scheduling policy. */
GlobalSchedulerPolicyState *policy_state;
/** The plasma_manager ip:port -> photon_db_client_id association. */
AuxAddressEntry *plasma_photon_map;
/** The photon_db_client_id -> plasma_manager ip:port association. */
AuxAddressEntry *photon_plasma_map;
/** The plasma_manager ip:port -> local_scheduler_db_client_id association. */
AuxAddressEntry *plasma_local_scheduler_map;
/** The local_scheduler_db_client_id -> plasma_manager ip:port association. */
AuxAddressEntry *local_scheduler_plasma_map;
/** Objects cached by this global scheduler instance. */
SchedulerObjectInfo *scheduler_object_info_table;
/** An array of tasks that haven't been scheduled yet. */
@@ -83,15 +83,15 @@ typedef struct {
/**
* This is a helper method to look up the local scheduler struct that
* corresponds to a particular photon_id.
* corresponds to a particular local_scheduler_id.
*
* @param state The state of the global scheduler.
* @param The photon_id of the local scheduler.
* @param The local_scheduler_id of the local scheduler.
* @return The corresponding local scheduler struct. If the global scheduler is
* not aware of the local scheduler, then this will be NULL.
*/
LocalScheduler *get_local_scheduler(GlobalSchedulerState *state,
DBClientID photon_id);
DBClientID local_scheduler_id);
/**
* Assign the given task to the local scheduler, update Redis and scheduler data
@@ -154,42 +154,48 @@ void free_object_size_hashmap(ObjectSizeEntry *object_size_table) {
}
}
DBClientID get_photon_id(GlobalSchedulerState *state,
const char *plasma_location) {
DBClientID get_local_scheduler_id(GlobalSchedulerState *state,
const char *plasma_location) {
AuxAddressEntry *aux_entry = NULL;
DBClientID photon_id = NIL_ID;
DBClientID local_scheduler_id = NIL_ID;
if (plasma_location != NULL) {
LOG_DEBUG("max object size location found : %s", plasma_location);
/* Lookup association of plasma location to photon. */
HASH_FIND(plasma_photon_hh, state->plasma_photon_map, plasma_location,
uthash_strlen(plasma_location), aux_entry);
/* Lookup association of plasma location to local scheduler. */
HASH_FIND(plasma_local_scheduler_hh, state->plasma_local_scheduler_map,
plasma_location, uthash_strlen(plasma_location), aux_entry);
if (aux_entry) {
LOG_DEBUG("found photon db client association for plasma ip:port = %s",
aux_entry->aux_address);
/* Plasma to photon db client ID association found, get photon ID. */
photon_id = aux_entry->photon_db_client_id;
LOG_DEBUG(
"found local scheduler db client association for plasma ip:port = %s",
aux_entry->aux_address);
/* Plasma to local scheduler db client ID association found, get local
* scheduler ID. */
local_scheduler_id = aux_entry->local_scheduler_db_client_id;
} else {
LOG_ERROR("photon db client association not found for plasma ip:port=%s",
plasma_location);
LOG_ERROR(
"local scheduler db client association not found for plasma "
"ip:port=%s",
plasma_location);
}
}
char id_string[ID_STRING_SIZE];
LOG_DEBUG("photon ID found = %s",
ObjectID_to_string(photon_id, id_string, ID_STRING_SIZE));
LOG_DEBUG("local scheduler ID found = %s",
ObjectID_to_string(local_scheduler_id, id_string, ID_STRING_SIZE));
UNUSED(id_string);
if (IS_NIL_ID(photon_id)) {
return photon_id;
if (IS_NIL_ID(local_scheduler_id)) {
return local_scheduler_id;
}
/* Check to make sure this photon_db_client_id matches one of the
/* Check to make sure this local_scheduler_db_client_id matches one of the
* schedulers. */
LocalScheduler *local_scheduler_ptr = get_local_scheduler(state, photon_id);
LocalScheduler *local_scheduler_ptr =
get_local_scheduler(state, local_scheduler_id);
if (local_scheduler_ptr == NULL) {
LOG_WARN("photon_id didn't match any cached local scheduler entries");
LOG_WARN(
"local_scheduler_id didn't match any cached local scheduler entries");
}
return photon_id;
return local_scheduler_id;
}
double inner_product(double a[], double b[], int size) {
@@ -210,22 +216,25 @@ double calculate_object_size_fraction(GlobalSchedulerState *state,
double object_size_fraction = 0;
if (total_task_object_size > 0) {
/* Does this node contribute anything to this task object size? */
/* Lookup scheduler->id in photon_plasma_map to get plasma aux address,
* which is used as the key for object_size_table.
* This uses the plasma aux address to locate the object_size this node
* contributes. */
AuxAddressEntry *photon_plasma_pair = NULL;
HASH_FIND(photon_plasma_hh, state->photon_plasma_map, &(scheduler->id),
sizeof(scheduler->id), photon_plasma_pair);
if (photon_plasma_pair != NULL) {
/* Lookup scheduler->id in local_scheduler_plasma_map to get plasma aux
* address, which is used as the key for object_size_table. This uses the
* plasma aux address to locate the object_size this node contributes. */
AuxAddressEntry *local_scheduler_plasma_pair = NULL;
HASH_FIND(local_scheduler_plasma_hh, state->local_scheduler_plasma_map,
&(scheduler->id), sizeof(scheduler->id),
local_scheduler_plasma_pair);
if (local_scheduler_plasma_pair != NULL) {
ObjectSizeEntry *s = NULL;
/* Found this node's photon to plasma mapping. Use the corresponding
* plasma key to see if this node has any cached objects for this task. */
HASH_FIND_STR(object_size_table, photon_plasma_pair->aux_address, s);
/* Found this node's local scheduler to plasma mapping. Use the
* corresponding plasma key to see if this node has any cached objects for
* this task. */
HASH_FIND_STR(object_size_table, local_scheduler_plasma_pair->aux_address,
s);
if (s != NULL) {
/* This node has some of this task's objects. Calculate what fraction.
*/
CHECK(strcmp(s->object_location, photon_plasma_pair->aux_address) == 0);
CHECK(strcmp(s->object_location,
local_scheduler_plasma_pair->aux_address) == 0);
object_size_fraction =
MIN(1, (double) (s->total_object_size) / total_task_object_size);
}
@@ -286,9 +295,10 @@ bool handle_task_waiting(GlobalSchedulerState *state,
/* Go through all the nodes, calculate the score for each, pick max score. */
LocalScheduler *scheduler = NULL;
double best_photon_score = INT32_MIN;
CHECKM(best_photon_score < 0, "We might have a floating point underflow");
DBClientID best_photon_id = NIL_ID; /* best node to send this task */
double best_local_scheduler_score = INT32_MIN;
CHECKM(best_local_scheduler_score < 0,
"We might have a floating point underflow");
DBClientID best_local_scheduler_id = NIL_ID; /* best node to send this task */
for (scheduler = (LocalScheduler *) utarray_front(state->local_schedulers);
scheduler != NULL; scheduler = (LocalScheduler *) utarray_next(
state->local_schedulers, scheduler)) {
@@ -300,9 +310,9 @@ bool handle_task_waiting(GlobalSchedulerState *state,
task_feasible = true;
/* This node satisfies the hard capacity constraint. Calculate its score. */
double score = -1 * calculate_cost_pending(state, scheduler);
if (score > best_photon_score) {
best_photon_score = score;
best_photon_id = scheduler->id;
if (score > best_local_scheduler_score) {
best_local_scheduler_score = score;
best_local_scheduler_id = scheduler->id;
}
} /* For each local scheduler. */
@@ -317,10 +327,10 @@ bool handle_task_waiting(GlobalSchedulerState *state,
* cache the task in case new local schedulers satisfy it in the future. */
return false;
}
CHECKM(!IS_NIL_ID(best_photon_id),
CHECKM(!IS_NIL_ID(best_local_scheduler_id),
"Task is feasible, but doesn't have a local scheduler assigned.");
/* A local scheduler ID was found, so assign the task. */
assign_task_to_local_scheduler(state, task, best_photon_id);
assign_task_to_local_scheduler(state, task, best_local_scheduler_id);
return true;
}
+45
View File
@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 2.8)
project(local_scheduler)
# Recursively include common
include(${CMAKE_CURRENT_LIST_DIR}/../common/cmake/Common.cmake)
if(APPLE)
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
endif(APPLE)
include_directories("${PYTHON_INCLUDE_DIRS}")
# set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} --std=c99 -Werror")
if(UNIX AND NOT APPLE)
link_libraries(rt)
endif()
include_directories("${CMAKE_CURRENT_LIST_DIR}/")
include_directories("${CMAKE_CURRENT_LIST_DIR}/../")
include_directories("${CMAKE_CURRENT_LIST_DIR}/../plasma/")
add_library(local_scheduler_library SHARED
local_scheduler_extension.c
../common/lib/python/common_extension.c)
get_filename_component(PYTHON_SHARED_LIBRARY ${PYTHON_LIBRARIES} NAME)
if(APPLE)
add_custom_command(TARGET local_scheduler_library
POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change ${PYTHON_SHARED_LIBRARY} ${PYTHON_LIBRARIES} liblocal_scheduler_library.so)
endif(APPLE)
add_library(local_scheduler_client STATIC local_scheduler_client.c)
target_link_libraries(local_scheduler_library local_scheduler_client ${COMMON_LIB} ${PYTHON_LIBRARIES})
add_executable(local_scheduler local_scheduler.c local_scheduler_algorithm.c)
target_link_libraries(local_scheduler local_scheduler_client common ${HIREDIS_LIB} plasma_lib)
add_executable(local_scheduler_tests test/local_scheduler_tests.c local_scheduler.c local_scheduler_algorithm.c )
target_link_libraries(local_scheduler_tests local_scheduler_client common ${HIREDIS_LIB} plasma_lib)
target_compile_options(local_scheduler_tests PUBLIC "-DLOCAL_SCHEDULER_TEST")
install(TARGETS local_scheduler_library DESTINATION ${CMAKE_SOURCE_DIR}/local_scheduler)
@@ -12,9 +12,9 @@
#include "io.h"
#include "logging.h"
#include "object_info.h"
#include "photon.h"
#include "photon_scheduler.h"
#include "photon_algorithm.h"
#include "local_scheduler_shared.h"
#include "local_scheduler.h"
#include "local_scheduler_algorithm.h"
#include "state/actor_notification_table.h"
#include "state/db.h"
#include "state/task_table.h"
@@ -361,8 +361,8 @@ LocalSchedulerState *LocalSchedulerState_init(
db_connect_args[4] = "num_gpus";
db_connect_args[5] = utstring_body(num_gpus);
}
state->db = db_connect(redis_addr, redis_port, "photon", node_ip_address,
num_args, db_connect_args);
state->db = db_connect(redis_addr, redis_port, "local_scheduler",
node_ip_address, num_args, db_connect_args);
utstring_free(num_cpus);
utstring_free(num_gpus);
free(db_connect_args);
@@ -417,7 +417,7 @@ void update_dynamic_resources(LocalSchedulerState *state,
if (!return_resources && state->dynamic_resources[i] < 0) {
/* We are using more resources than we have been allocated. */
LOG_WARN("photon dynamic resources dropped to %8.4f\t%8.4f\n",
LOG_WARN("local_scheduler dynamic resources dropped to %8.4f\t%8.4f\n",
state->dynamic_resources[0], state->dynamic_resources[1]);
}
CHECK(state->dynamic_resources[i] <= state->static_resources[i]);
@@ -911,7 +911,7 @@ void start_server(const char *node_ip_address,
/* Only declare the main function if we are not in testing mode, since the test
* suite has its own declaration of main. */
#ifndef PHOTON_TEST
#ifndef LOCAL_SCHEDULER_TEST
int main(int argc, char *argv[]) {
signal(SIGTERM, signal_handler);
/* Path of the listening socket of the local scheduler. */
@@ -922,7 +922,8 @@ int main(int argc, char *argv[]) {
char *plasma_store_socket_name = NULL;
/* Socket name for the local Plasma manager. */
char *plasma_manager_socket_name = NULL;
/* Address for the plasma manager associated with this Photon instance. */
/* Address for the plasma manager associated with this local scheduler
* instance. */
char *plasma_manager_address = NULL;
/* The IP address of the node that this local scheduler is running on. */
char *node_ip_address = NULL;
@@ -1,5 +1,5 @@
#ifndef PHOTON_SCHEDULER_H
#define PHOTON_SCHEDULER_H
#ifndef LOCAL_SCHEDULER_H
#define LOCAL_SCHEDULER_H
#include "task.h"
#include "event_loop.h"
@@ -110,7 +110,7 @@ void update_dynamic_resources(LocalSchedulerState *state,
bool return_resources);
/** The following methods are for testing purposes only. */
#ifdef PHOTON_TEST
#ifdef LOCAL_SCHEDULER_TEST
LocalSchedulerState *LocalSchedulerState_init(
const char *node_ip_address,
event_loop *loop,
@@ -136,4 +136,4 @@ void process_message(event_loop *loop,
#endif
#endif /* PHOTON_SCHEDULER_H */
#endif /* LOCAL_SCHEDULER_H */
@@ -1,4 +1,4 @@
#include "photon_algorithm.h"
#include "local_scheduler_algorithm.h"
#include <stdbool.h>
#include "utarray.h"
@@ -7,8 +7,8 @@
#include "state/task_table.h"
#include "state/local_scheduler_table.h"
#include "state/object_table.h"
#include "photon.h"
#include "photon_scheduler.h"
#include "local_scheduler_shared.h"
#include "local_scheduler.h"
#include "common/task.h"
/* Declared for convenience. */
@@ -65,7 +65,8 @@ typedef struct {
UT_hash_handle hh;
} LocalActorInfo;
/** Part of the photon state that is maintained by the scheduling algorithm. */
/** Part of the local scheduler state that is maintained by the scheduling
* algorithm. */
struct SchedulingAlgorithmState {
/** An array of pointers to tasks that are waiting for dependencies. */
task_queue_entry *waiting_task_queue;
@@ -1,7 +1,7 @@
#ifndef PHOTON_ALGORITHM_H
#define PHOTON_ALGORITHM_H
#ifndef LOCAL_SCHEDULER_ALGORITHM_H
#define LOCAL_SCHEDULER_ALGORITHM_H
#include "photon.h"
#include "local_scheduler_shared.h"
#include "common/task.h"
#include "state/local_scheduler_table.h"
@@ -250,7 +250,7 @@ void print_worker_info(const char *message,
SchedulingAlgorithmState *algorithm_state);
/** The following methods are for testing purposes only. */
#ifdef PHOTON_TEST
#ifdef LOCAL_SCHEDULER_TEST
/**
* Get the number of tasks currently waiting for object dependencies to become
* available locally.
@@ -269,4 +269,4 @@ int num_waiting_tasks(SchedulingAlgorithmState *algorithm_state);
int num_dispatch_tasks(SchedulingAlgorithmState *algorithm_state);
#endif
#endif /* PHOTON_ALGORITHM_H */
#endif /* LOCAL_SCHEDULER_ALGORITHM_H */
@@ -1,14 +1,15 @@
#include "photon_client.h"
#include "local_scheduler_client.h"
#include "common/io.h"
#include "common/task.h"
#include <stdlib.h>
PhotonConnection *PhotonConnection_init(const char *photon_socket,
ActorID actor_id) {
PhotonConnection *result =
(PhotonConnection *) malloc(sizeof(PhotonConnection));
result->conn = connect_ipc_sock_retry(photon_socket, -1, -1);
LocalSchedulerConnection *LocalSchedulerConnection_init(
const char *local_scheduler_socket,
ActorID actor_id) {
LocalSchedulerConnection *result =
(LocalSchedulerConnection *) malloc(sizeof(LocalSchedulerConnection));
result->conn = connect_ipc_sock_retry(local_scheduler_socket, -1, -1);
register_worker_info info;
memset(&info, 0, sizeof(info));
/* Register the process ID with the local scheduler. */
@@ -20,16 +21,16 @@ PhotonConnection *PhotonConnection_init(const char *photon_socket,
return result;
}
void PhotonConnection_free(PhotonConnection *conn) {
void LocalSchedulerConnection_free(LocalSchedulerConnection *conn) {
close(conn->conn);
free(conn);
}
void photon_log_event(PhotonConnection *conn,
uint8_t *key,
int64_t key_length,
uint8_t *value,
int64_t value_length) {
void local_scheduler_log_event(LocalSchedulerConnection *conn,
uint8_t *key,
int64_t key_length,
uint8_t *value,
int64_t value_length) {
int64_t message_length =
sizeof(key_length) + sizeof(value_length) + key_length + value_length;
uint8_t *message = (uint8_t *) malloc(message_length);
@@ -47,12 +48,12 @@ void photon_log_event(PhotonConnection *conn,
free(message);
}
void photon_submit(PhotonConnection *conn, task_spec *task) {
void local_scheduler_submit(LocalSchedulerConnection *conn, task_spec *task) {
write_message(conn->conn, SUBMIT_TASK, task_spec_size(task),
(uint8_t *) task);
}
task_spec *photon_get_task(PhotonConnection *conn) {
task_spec *local_scheduler_get_task(LocalSchedulerConnection *conn) {
write_message(conn->conn, GET_TASK, 0, NULL);
int64_t type;
int64_t length;
@@ -66,19 +67,20 @@ task_spec *photon_get_task(PhotonConnection *conn) {
return task;
}
void photon_task_done(PhotonConnection *conn) {
void local_scheduler_task_done(LocalSchedulerConnection *conn) {
write_message(conn->conn, TASK_DONE, 0, NULL);
}
void photon_reconstruct_object(PhotonConnection *conn, ObjectID object_id) {
void local_scheduler_reconstruct_object(LocalSchedulerConnection *conn,
ObjectID object_id) {
write_message(conn->conn, RECONSTRUCT_OBJECT, sizeof(object_id),
(uint8_t *) &object_id);
}
void photon_log_message(PhotonConnection *conn) {
void local_scheduler_log_message(LocalSchedulerConnection *conn) {
write_message(conn->conn, LOG_MESSAGE, 0, NULL);
}
void photon_notify_unblocked(PhotonConnection *conn) {
void local_scheduler_notify_unblocked(LocalSchedulerConnection *conn) {
write_message(conn->conn, NOTIFY_UNBLOCKED, 0, NULL);
}
@@ -1,33 +1,36 @@
#ifndef PHOTON_CLIENT_H
#define PHOTON_CLIENT_H
#ifndef LOCAL_SCHEDULER_CLIENT_H
#define LOCAL_SCHEDULER_CLIENT_H
#include "common/task.h"
#include "photon.h"
#include "local_scheduler_shared.h"
typedef struct {
/* File descriptor of the Unix domain socket that connects to photon. */
/** File descriptor of the Unix domain socket that connects to local
* scheduler. */
int conn;
} PhotonConnection;
} LocalSchedulerConnection;
/**
* Connect to the local scheduler.
*
* @param photon_socket The name of the socket to use to connect to the local
* scheduler.
* @param local_scheduler_socket The name of the socket to use to connect to the
* local scheduler.
* @param actor_id The ID of the actor running on this worker. If no actor is
* running on this actor, this should be NIL_ACTOR_ID.
* @return The connection information.
*/
PhotonConnection *PhotonConnection_init(const char *photon_socket,
ActorID actor_id);
LocalSchedulerConnection *LocalSchedulerConnection_init(
const char *local_scheduler_socket,
ActorID actor_id);
/**
* Disconnect from the local scheduler.
*
* @param conn Photon connection information returned by PhotonConnection_init.
* @param conn Local scheduler connection information returned by
* LocalSchedulerConnection_init.
* @return Void.
*/
void PhotonConnection_free(PhotonConnection *conn);
void LocalSchedulerConnection_free(LocalSchedulerConnection *conn);
/**
* Submit a task to the local scheduler.
@@ -36,7 +39,7 @@ void PhotonConnection_free(PhotonConnection *conn);
* @param task The address of the task to submit.
* @return Void.
*/
void photon_submit(PhotonConnection *conn, task_spec *task);
void local_scheduler_submit(LocalSchedulerConnection *conn, task_spec *task);
/**
* Log an event to the event log. This will call RPUSH key value. We use RPUSH
@@ -51,11 +54,11 @@ void photon_submit(PhotonConnection *conn, task_spec *task);
* @param value_length The length of the value.
* @return Void.
*/
void photon_log_event(PhotonConnection *conn,
uint8_t *key,
int64_t key_length,
uint8_t *value,
int64_t value_length);
void local_scheduler_log_event(LocalSchedulerConnection *conn,
uint8_t *key,
int64_t key_length,
uint8_t *value,
int64_t value_length);
/**
* Get next task for this client. This will block until the scheduler assigns
@@ -67,7 +70,7 @@ void photon_log_event(PhotonConnection *conn,
* @param conn The connection information.
* @return The address of the assigned task.
*/
task_spec *photon_get_task(PhotonConnection *conn);
task_spec *local_scheduler_get_task(LocalSchedulerConnection *conn);
/**
* Tell the local scheduler that the client has finished executing a task.
@@ -75,7 +78,7 @@ task_spec *photon_get_task(PhotonConnection *conn);
* @param conn The connection information.
* @return Void.
*/
void photon_task_done(PhotonConnection *conn);
void local_scheduler_task_done(LocalSchedulerConnection *conn);
/**
* Tell the local scheduler to reconstruct an object.
@@ -84,7 +87,8 @@ void photon_task_done(PhotonConnection *conn);
* @param object_id The ID of the object to reconstruct.
* @return Void.
*/
void photon_reconstruct_object(PhotonConnection *conn, ObjectID object_id);
void local_scheduler_reconstruct_object(LocalSchedulerConnection *conn,
ObjectID object_id);
/**
* Send a log message to the local scheduler.
@@ -92,7 +96,7 @@ void photon_reconstruct_object(PhotonConnection *conn, ObjectID object_id);
* @param conn The connection information.
* @return Void.
*/
void photon_log_message(PhotonConnection *conn);
void local_scheduler_log_message(LocalSchedulerConnection *conn);
/**
* Notify the local scheduler that this client (worker) is no longer blocked.
@@ -100,6 +104,6 @@ void photon_log_message(PhotonConnection *conn);
* @param conn The connection information.
* @return Void.
*/
void photon_notify_unblocked(PhotonConnection *conn);
void local_scheduler_notify_unblocked(LocalSchedulerConnection *conn);
#endif
@@ -0,0 +1,234 @@
#include <Python.h>
#include "common_extension.h"
#include "local_scheduler_client.h"
#include "task.h"
PyObject *LocalSchedulerError;
// clang-format off
typedef struct {
PyObject_HEAD
LocalSchedulerConnection *local_scheduler_connection;
} PyLocalSchedulerClient;
// clang-format on
static int PyLocalSchedulerClient_init(PyLocalSchedulerClient *self,
PyObject *args,
PyObject *kwds) {
char *socket_name;
ActorID actor_id;
if (!PyArg_ParseTuple(args, "sO&", &socket_name, PyStringToUniqueID,
&actor_id)) {
return -1;
}
/* Connect to the local scheduler. */
self->local_scheduler_connection =
LocalSchedulerConnection_init(socket_name, actor_id);
return 0;
}
static void PyLocalSchedulerClient_dealloc(PyLocalSchedulerClient *self) {
LocalSchedulerConnection_free(
((PyLocalSchedulerClient *) self)->local_scheduler_connection);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject *PyLocalSchedulerClient_submit(PyObject *self, PyObject *args) {
PyObject *py_task;
if (!PyArg_ParseTuple(args, "O", &py_task)) {
return NULL;
}
local_scheduler_submit(
((PyLocalSchedulerClient *) self)->local_scheduler_connection,
((PyTask *) py_task)->spec);
Py_RETURN_NONE;
}
// clang-format off
static PyObject *PyLocalSchedulerClient_get_task(PyObject *self) {
task_spec *task_spec;
/* Drop the global interpreter lock while we get a task because
* local_scheduler_get_task may block for a long time. */
Py_BEGIN_ALLOW_THREADS
task_spec = local_scheduler_get_task(
((PyLocalSchedulerClient *) self)->local_scheduler_connection);
Py_END_ALLOW_THREADS
return PyTask_make(task_spec);
}
// clang-format on
static PyObject *PyLocalSchedulerClient_reconstruct_object(PyObject *self,
PyObject *args) {
ObjectID object_id;
if (!PyArg_ParseTuple(args, "O&", PyStringToUniqueID, &object_id)) {
return NULL;
}
local_scheduler_reconstruct_object(
((PyLocalSchedulerClient *) self)->local_scheduler_connection, object_id);
Py_RETURN_NONE;
}
static PyObject *PyLocalSchedulerClient_log_event(PyObject *self,
PyObject *args) {
const char *key;
int key_length;
const char *value;
int value_length;
if (!PyArg_ParseTuple(args, "s#s#", &key, &key_length, &value,
&value_length)) {
return NULL;
}
local_scheduler_log_event(
((PyLocalSchedulerClient *) self)->local_scheduler_connection,
(uint8_t *) key, key_length, (uint8_t *) value, value_length);
Py_RETURN_NONE;
}
static PyObject *PyLocalSchedulerClient_notify_unblocked(PyObject *self) {
local_scheduler_notify_unblocked(
((PyLocalSchedulerClient *) self)->local_scheduler_connection);
Py_RETURN_NONE;
}
static PyMethodDef PyLocalSchedulerClient_methods[] = {
{"submit", (PyCFunction) PyLocalSchedulerClient_submit, METH_VARARGS,
"Submit a task to the local scheduler."},
{"get_task", (PyCFunction) PyLocalSchedulerClient_get_task, METH_NOARGS,
"Get a task from the local scheduler."},
{"reconstruct_object",
(PyCFunction) PyLocalSchedulerClient_reconstruct_object, METH_VARARGS,
"Ask the local scheduler to reconstruct an object."},
{"log_event", (PyCFunction) PyLocalSchedulerClient_log_event, METH_VARARGS,
"Log an event to the event log through the local scheduler."},
{"notify_unblocked", (PyCFunction) PyLocalSchedulerClient_notify_unblocked,
METH_NOARGS, "Notify the local scheduler that we are unblocked."},
{NULL} /* Sentinel */
};
static PyTypeObject PyLocalSchedulerClientType = {
PyVarObject_HEAD_INIT(NULL, 0) /* ob_size */
"local_scheduler.LocalSchedulerClient", /* tp_name */
sizeof(PyLocalSchedulerClient), /* tp_basicsize */
0, /* tp_itemsize */
(destructor) PyLocalSchedulerClient_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"LocalSchedulerClient object", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyLocalSchedulerClient_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc) PyLocalSchedulerClient_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
static PyMethodDef local_scheduler_methods[] = {
{"check_simple_value", check_simple_value, METH_VARARGS,
"Should the object be passed by value?"},
{"compute_put_id", compute_put_id, METH_VARARGS,
"Return the object ID for a put call within a task."},
{"task_from_string", PyTask_from_string, METH_VARARGS,
"Creates a Python PyTask object from a string representation of "
"task_spec."},
{"task_to_string", PyTask_to_string, METH_VARARGS,
"Translates a PyTask python object to a byte string."},
{NULL} /* Sentinel */
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"liblocal_scheduler", /* m_name */
"A module for the local scheduler.", /* m_doc */
0, /* m_size */
local_scheduler_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#endif
#if PY_MAJOR_VERSION >= 3
#define INITERROR return NULL
#else
#define INITERROR return
#endif
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
#if PY_MAJOR_VERSION >= 3
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
#else
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
#endif
MOD_INIT(liblocal_scheduler_library) {
if (PyType_Ready(&PyTaskType) < 0) {
INITERROR;
}
if (PyType_Ready(&PyObjectIDType) < 0) {
INITERROR;
}
if (PyType_Ready(&PyLocalSchedulerClientType) < 0) {
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
PyObject *m = PyModule_Create(&moduledef);
#else
PyObject *m =
Py_InitModule3("liblocal_scheduler_library", local_scheduler_methods,
"A module for the local scheduler.");
#endif
init_pickle_module();
Py_INCREF(&PyTaskType);
PyModule_AddObject(m, "Task", (PyObject *) &PyTaskType);
Py_INCREF(&PyObjectIDType);
PyModule_AddObject(m, "ObjectID", (PyObject *) &PyObjectIDType);
Py_INCREF(&PyLocalSchedulerClientType);
PyModule_AddObject(m, "LocalSchedulerClient",
(PyObject *) &PyLocalSchedulerClientType);
char local_scheduler_error[] = "local_scheduler.error";
LocalSchedulerError = PyErr_NewException(local_scheduler_error, NULL, NULL);
Py_INCREF(LocalSchedulerError);
PyModule_AddObject(m, "local_scheduler_error", LocalSchedulerError);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}
@@ -1,5 +1,5 @@
#ifndef PHOTON_H
#define PHOTON_H
#ifndef LOCAL_SCHEDULER_SHARED_H
#define LOCAL_SCHEDULER_SHARED_H
#include "common/task.h"
#include "common/state/table.h"
@@ -8,7 +8,7 @@
#include "utarray.h"
#include "uthash.h"
enum photon_message_type {
enum local_scheduler_message_type {
/** Notify the local scheduler that a task has finished. */
TASK_DONE = 64,
/** Get a new task from the local scheduler. */
@@ -34,7 +34,7 @@ UT_icd workers_icd;
UT_icd pid_t_icd;
/** This struct is used to register a new worker with the local scheduler.
* It is shipped as part of photon_connect */
* It is shipped as part of local_scheduler_connect */
typedef struct {
/** The ID of the actor. This is NIL_ACTOR_ID if the worker is not an actor.
*/
@@ -123,4 +123,4 @@ typedef struct {
LocalSchedulerState *local_scheduler_state;
} LocalSchedulerClient;
#endif /* PHOTON_H */
#endif /* LOCAL_SCHEDULER_SHARED_H */
@@ -16,16 +16,17 @@
#include "state/object_table.h"
#include "state/task_table.h"
#include "photon.h"
#include "photon_scheduler.h"
#include "photon_algorithm.h"
#include "photon_client.h"
#include "local_scheduler_shared.h"
#include "local_scheduler.h"
#include "local_scheduler_algorithm.h"
#include "local_scheduler_client.h"
SUITE(photon_tests);
SUITE(local_scheduler_tests);
const char *plasma_store_socket_name = "/tmp/plasma_store_socket_1";
const char *plasma_manager_socket_name_format = "/tmp/plasma_manager_socket_%d";
const char *photon_socket_name_format = "/tmp/photon_socket_%d";
const char *local_scheduler_socket_name_format =
"/tmp/local_scheduler_socket_%d";
int64_t timeout_handler(event_loop *loop, int64_t id, void *context) {
event_loop_stop(loop);
@@ -38,35 +39,36 @@ typedef struct {
int plasma_manager_fd;
/** A socket to communicate with the Plasma store. */
int plasma_store_fd;
/** Photon's socket for IPC requests. */
int photon_fd;
/** Photon's local scheduler state. */
LocalSchedulerState *photon_state;
/** Photon's event loop. */
/** Local scheduler's socket for IPC requests. */
int local_scheduler_fd;
/** Local scheduler's local scheduler state. */
LocalSchedulerState *local_scheduler_state;
/** Local scheduler's event loop. */
event_loop *loop;
/** Number of Photon client connections, or mock workers. */
int num_photon_conns;
/** Photon client connections. */
PhotonConnection **conns;
} PhotonMock;
/** Number of local scheduler client connections, or mock workers. */
int num_local_scheduler_conns;
/** Local scheduler client connections. */
LocalSchedulerConnection **conns;
} LocalSchedulerMock;
PhotonMock *PhotonMock_init(int num_workers, int num_mock_workers) {
LocalSchedulerMock *LocalSchedulerMock_init(int num_workers,
int num_mock_workers) {
const char *node_ip_address = "127.0.0.1";
const char *redis_addr = node_ip_address;
int redis_port = 6379;
const double static_resource_conf[MAX_RESOURCE_INDEX] = {DEFAULT_NUM_CPUS,
DEFAULT_NUM_GPUS};
PhotonMock *mock = malloc(sizeof(PhotonMock));
memset(mock, 0, sizeof(PhotonMock));
LocalSchedulerMock *mock = malloc(sizeof(LocalSchedulerMock));
memset(mock, 0, sizeof(LocalSchedulerMock));
mock->loop = event_loop_create();
/* Bind to the Photon port and initialize the Photon scheduler. */
/* Bind to the local scheduler port and initialize the local scheduler. */
UT_string *plasma_manager_socket_name = bind_ipc_sock_retry(
plasma_manager_socket_name_format, &mock->plasma_manager_fd);
mock->plasma_store_fd =
connect_ipc_sock_retry(plasma_store_socket_name, 5, 100);
UT_string *photon_socket_name =
bind_ipc_sock_retry(photon_socket_name_format, &mock->photon_fd);
CHECK(mock->plasma_store_fd >= 0 && mock->photon_fd >= 0);
UT_string *local_scheduler_socket_name = bind_ipc_sock_retry(
local_scheduler_socket_name_format, &mock->local_scheduler_fd);
CHECK(mock->plasma_store_fd >= 0 && mock->local_scheduler_fd >= 0);
UT_string *worker_command;
utstring_new(worker_command);
@@ -77,11 +79,12 @@ PhotonMock *PhotonMock_init(int num_workers, int num_mock_workers) {
"--redis-address=%s:%d",
node_ip_address, plasma_store_socket_name,
utstring_body(plasma_manager_socket_name),
utstring_body(photon_socket_name), redis_addr, redis_port);
utstring_body(local_scheduler_socket_name), redis_addr,
redis_port);
mock->photon_state = LocalSchedulerState_init(
mock->local_scheduler_state = LocalSchedulerState_init(
"127.0.0.1", mock->loop, redis_addr, redis_port,
utstring_body(photon_socket_name), plasma_store_socket_name,
utstring_body(local_scheduler_socket_name), plasma_store_socket_name,
utstring_body(plasma_manager_socket_name), NULL, false,
static_resource_conf, utstring_body(worker_command), num_workers);
@@ -90,50 +93,50 @@ PhotonMock *PhotonMock_init(int num_workers, int num_mock_workers) {
accept_client(mock->plasma_manager_fd);
}
/* Connect a Photon client. */
mock->num_photon_conns = num_mock_workers;
mock->conns = malloc(sizeof(PhotonConnection *) * num_mock_workers);
/* Connect a local scheduler client. */
mock->num_local_scheduler_conns = num_mock_workers;
mock->conns = malloc(sizeof(LocalSchedulerConnection *) * num_mock_workers);
for (int i = 0; i < num_mock_workers; ++i) {
mock->conns[i] =
PhotonConnection_init(utstring_body(photon_socket_name), NIL_ACTOR_ID);
new_client_connection(mock->loop, mock->photon_fd,
(void *) mock->photon_state, 0);
mock->conns[i] = LocalSchedulerConnection_init(
utstring_body(local_scheduler_socket_name), NIL_ACTOR_ID);
new_client_connection(mock->loop, mock->local_scheduler_fd,
(void *) mock->local_scheduler_state, 0);
}
utstring_free(worker_command);
utstring_free(plasma_manager_socket_name);
utstring_free(photon_socket_name);
utstring_free(local_scheduler_socket_name);
return mock;
}
void PhotonMock_free(PhotonMock *mock) {
void LocalSchedulerMock_free(LocalSchedulerMock *mock) {
/* Disconnect clients. */
for (int i = 0; i < mock->num_photon_conns; ++i) {
PhotonConnection_free(mock->conns[i]);
for (int i = 0; i < mock->num_local_scheduler_conns; ++i) {
LocalSchedulerConnection_free(mock->conns[i]);
}
free(mock->conns);
/* Kill all the workers and run the event loop again so that the task table
* updates propagate and the tasks in progress are freed. */
LocalSchedulerClient **worker =
(LocalSchedulerClient **) utarray_eltptr(mock->photon_state->workers, 0);
LocalSchedulerClient **worker = (LocalSchedulerClient **) utarray_eltptr(
mock->local_scheduler_state->workers, 0);
while (worker != NULL) {
kill_worker(*worker, true);
worker = (LocalSchedulerClient **) utarray_eltptr(
mock->photon_state->workers, 0);
mock->local_scheduler_state->workers, 0);
}
event_loop_add_timer(mock->loop, 500,
(event_loop_timer_handler) timeout_handler, NULL);
event_loop_run(mock->loop);
/* This also frees mock->loop. */
LocalSchedulerState_free(mock->photon_state);
LocalSchedulerState_free(mock->local_scheduler_state);
close(mock->plasma_store_fd);
close(mock->plasma_manager_fd);
free(mock);
}
void reset_worker(PhotonMock *mock, LocalSchedulerClient *worker) {
void reset_worker(LocalSchedulerMock *mock, LocalSchedulerClient *worker) {
if (worker->task_in_progress) {
Task_free(worker->task_in_progress);
worker->task_in_progress = NULL;
@@ -146,8 +149,8 @@ void reset_worker(PhotonMock *mock, LocalSchedulerClient *worker) {
* value, the task should get assigned to a worker again.
*/
TEST object_reconstruction_test(void) {
PhotonMock *photon = PhotonMock_init(0, 1);
PhotonConnection *worker = photon->conns[0];
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
LocalSchedulerConnection *worker = local_scheduler->conns[0];
/* Create a task with zero dependencies and one return value. */
task_spec *spec = example_task_spec(0, 1);
@@ -170,41 +173,47 @@ TEST object_reconstruction_test(void) {
if (pid == 0) {
/* Make sure we receive the task twice. First from the initial submission,
* and second from the reconstruct request. */
photon_submit(worker, spec);
task_spec *task_assigned = photon_get_task(worker);
local_scheduler_submit(worker, spec);
task_spec *task_assigned = local_scheduler_get_task(worker);
ASSERT_EQ(memcmp(task_assigned, spec, task_spec_size(spec)), 0);
task_spec *reconstruct_task = photon_get_task(worker);
task_spec *reconstruct_task = local_scheduler_get_task(worker);
ASSERT_EQ(memcmp(reconstruct_task, spec, task_spec_size(spec)), 0);
/* Clean up. */
free_task_spec(reconstruct_task);
free_task_spec(task_assigned);
free_task_spec(spec);
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
exit(0);
} else {
/* Run the event loop. NOTE: OSX appears to require the parent process to
* listen for events on the open file descriptors. */
event_loop_add_timer(photon->loop, 500,
event_loop_add_timer(local_scheduler->loop, 500,
(event_loop_timer_handler) timeout_handler, NULL);
event_loop_run(photon->loop);
event_loop_run(local_scheduler->loop);
/* Set the task's status to TASK_STATUS_DONE to prevent the race condition
* that would suppress object reconstruction. */
Task *task = Task_alloc(spec, TASK_STATUS_DONE,
get_db_client_id(photon->photon_state->db));
task_table_add_task(photon->photon_state->db, task, NULL, NULL, NULL);
Task *task = Task_alloc(
spec, TASK_STATUS_DONE,
get_db_client_id(local_scheduler->local_scheduler_state->db));
task_table_add_task(local_scheduler->local_scheduler_state->db, task, NULL,
NULL, NULL);
/* Trigger reconstruction, and run the event loop again. */
ObjectID return_id = task_return(spec, 0);
photon_reconstruct_object(worker, return_id);
event_loop_add_timer(photon->loop, 500,
local_scheduler_reconstruct_object(worker, return_id);
event_loop_add_timer(local_scheduler->loop, 500,
(event_loop_timer_handler) timeout_handler, NULL);
event_loop_run(photon->loop);
event_loop_run(local_scheduler->loop);
/* Wait for the child process to exit and check that there are no tasks
* left in the local scheduler's task queue. Then, clean up. */
wait(NULL);
free_task_spec(spec);
ASSERT_EQ(num_waiting_tasks(photon->photon_state->algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(photon->photon_state->algorithm_state), 0);
PhotonMock_free(photon);
ASSERT_EQ(num_waiting_tasks(
local_scheduler->local_scheduler_state->algorithm_state),
0);
ASSERT_EQ(num_dispatch_tasks(
local_scheduler->local_scheduler_state->algorithm_state),
0);
LocalSchedulerMock_free(local_scheduler);
PASS();
}
}
@@ -215,8 +224,8 @@ TEST object_reconstruction_test(void) {
* should trigger reconstruction of all previous tasks in the lineage.
*/
TEST object_reconstruction_recursive_test(void) {
PhotonMock *photon = PhotonMock_init(0, 1);
PhotonConnection *worker = photon->conns[0];
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
LocalSchedulerConnection *worker = local_scheduler->conns[0];
/* Create a chain of tasks, each one dependent on the one before it. Mark
* each object as available so that tasks will run immediately. */
const int NUM_TASKS = 10;
@@ -224,8 +233,9 @@ TEST object_reconstruction_recursive_test(void) {
specs[0] = example_task_spec(0, 1);
for (int i = 1; i < NUM_TASKS; ++i) {
ObjectID arg_id = task_return(specs[i - 1], 0);
handle_object_available(photon->photon_state,
photon->photon_state->algorithm_state, arg_id);
handle_object_available(
local_scheduler->local_scheduler_state,
local_scheduler->local_scheduler_state->algorithm_state, arg_id);
specs[i] = example_task_spec_with_args(1, 1, &arg_id);
}
@@ -249,11 +259,11 @@ TEST object_reconstruction_recursive_test(void) {
if (pid == 0) {
/* Submit the tasks, and make sure each one gets assigned to a worker. */
for (int i = 0; i < NUM_TASKS; ++i) {
photon_submit(worker, specs[i]);
local_scheduler_submit(worker, specs[i]);
}
/* Make sure we receive each task from the initial submission. */
for (int i = 0; i < NUM_TASKS; ++i) {
task_spec *task_assigned = photon_get_task(worker);
task_spec *task_assigned = local_scheduler_get_task(worker);
ASSERT_EQ(memcmp(task_assigned, specs[i], task_spec_size(task_assigned)),
0);
free_task_spec(task_assigned);
@@ -261,7 +271,7 @@ TEST object_reconstruction_recursive_test(void) {
/* Check that the workers receive all tasks in the final return object's
* lineage during reconstruction. */
for (int i = 0; i < NUM_TASKS; ++i) {
task_spec *task_assigned = photon_get_task(worker);
task_spec *task_assigned = local_scheduler_get_task(worker);
bool found = false;
for (int j = 0; j < NUM_TASKS; ++j) {
if (specs[j] == NULL) {
@@ -277,35 +287,41 @@ TEST object_reconstruction_recursive_test(void) {
free_task_spec(task_assigned);
ASSERT(found);
}
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
exit(0);
} else {
/* Run the event loop. NOTE: OSX appears to require the parent process to
* listen for events on the open file descriptors. */
event_loop_add_timer(photon->loop, 500,
event_loop_add_timer(local_scheduler->loop, 500,
(event_loop_timer_handler) timeout_handler, NULL);
event_loop_run(photon->loop);
event_loop_run(local_scheduler->loop);
/* Set the final task's status to TASK_STATUS_DONE to prevent the race
* condition that would suppress object reconstruction. */
Task *last_task = Task_alloc(specs[NUM_TASKS - 1], TASK_STATUS_DONE,
get_db_client_id(photon->photon_state->db));
task_table_add_task(photon->photon_state->db, last_task, NULL, NULL, NULL);
Task *last_task = Task_alloc(
specs[NUM_TASKS - 1], TASK_STATUS_DONE,
get_db_client_id(local_scheduler->local_scheduler_state->db));
task_table_add_task(local_scheduler->local_scheduler_state->db, last_task,
NULL, NULL, NULL);
/* Trigger reconstruction for the last object, and run the event loop
* again. */
ObjectID return_id = task_return(specs[NUM_TASKS - 1], 0);
photon_reconstruct_object(worker, return_id);
event_loop_add_timer(photon->loop, 500,
local_scheduler_reconstruct_object(worker, return_id);
event_loop_add_timer(local_scheduler->loop, 500,
(event_loop_timer_handler) timeout_handler, NULL);
event_loop_run(photon->loop);
event_loop_run(local_scheduler->loop);
/* Wait for the child process to exit and check that there are no tasks
* left in the local scheduler's task queue. Then, clean up. */
wait(NULL);
ASSERT_EQ(num_waiting_tasks(photon->photon_state->algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(photon->photon_state->algorithm_state), 0);
ASSERT_EQ(num_waiting_tasks(
local_scheduler->local_scheduler_state->algorithm_state),
0);
ASSERT_EQ(num_dispatch_tasks(
local_scheduler->local_scheduler_state->algorithm_state),
0);
for (int i = 0; i < NUM_TASKS; ++i) {
free_task_spec(specs[i]);
}
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
PASS();
}
}
@@ -319,13 +335,13 @@ task_spec *object_reconstruction_suppression_spec;
void object_reconstruction_suppression_callback(ObjectID object_id,
void *user_context) {
/* Submit the task after adding the object to the object table. */
PhotonConnection *worker = user_context;
photon_submit(worker, object_reconstruction_suppression_spec);
LocalSchedulerConnection *worker = user_context;
local_scheduler_submit(worker, object_reconstruction_suppression_spec);
}
TEST object_reconstruction_suppression_test(void) {
PhotonMock *photon = PhotonMock_init(0, 1);
PhotonConnection *worker = photon->conns[0];
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
LocalSchedulerConnection *worker = local_scheduler->conns[0];
object_reconstruction_suppression_spec = example_task_spec(0, 1);
ObjectID return_id = task_return(object_reconstruction_suppression_spec, 0);
@@ -333,48 +349,52 @@ TEST object_reconstruction_suppression_test(void) {
if (pid == 0) {
/* Make sure we receive the task once. This will block until the
* object_table_add callback completes. */
task_spec *task_assigned = photon_get_task(worker);
task_spec *task_assigned = local_scheduler_get_task(worker);
ASSERT_EQ(memcmp(task_assigned, object_reconstruction_suppression_spec,
task_spec_size(object_reconstruction_suppression_spec)),
0);
/* Trigger a reconstruction. We will check that no tasks get queued as a
* result of this line in the event loop process. */
photon_reconstruct_object(worker, return_id);
local_scheduler_reconstruct_object(worker, return_id);
/* Clean up. */
free_task_spec(task_assigned);
free_task_spec(object_reconstruction_suppression_spec);
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
exit(0);
} else {
/* Connect a plasma manager client so we can call object_table_add. */
const char *db_connect_args[] = {"address", "127.0.0.1:12346"};
DBHandle *db = db_connect("127.0.0.1", 6379, "plasma_manager", "127.0.0.1",
2, db_connect_args);
db_attach(db, photon->loop, false);
db_attach(db, local_scheduler->loop, false);
/* Add the object to the object table. */
object_table_add(db, return_id, 1, (unsigned char *) NIL_DIGEST, NULL,
object_reconstruction_suppression_callback,
(void *) worker);
/* Run the event loop. NOTE: OSX appears to require the parent process to
* listen for events on the open file descriptors. */
event_loop_add_timer(photon->loop, 1000,
event_loop_add_timer(local_scheduler->loop, 1000,
(event_loop_timer_handler) timeout_handler, NULL);
event_loop_run(photon->loop);
event_loop_run(local_scheduler->loop);
/* Wait for the child process to exit and check that there are no tasks
* left in the local scheduler's task queue. Then, clean up. */
wait(NULL);
ASSERT_EQ(num_waiting_tasks(photon->photon_state->algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(photon->photon_state->algorithm_state), 0);
ASSERT_EQ(num_waiting_tasks(
local_scheduler->local_scheduler_state->algorithm_state),
0);
ASSERT_EQ(num_dispatch_tasks(
local_scheduler->local_scheduler_state->algorithm_state),
0);
free_task_spec(object_reconstruction_suppression_spec);
db_disconnect(db);
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
PASS();
}
}
TEST task_dependency_test(void) {
PhotonMock *photon = PhotonMock_init(0, 1);
LocalSchedulerState *state = photon->photon_state;
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
LocalSchedulerState *state = local_scheduler->local_scheduler_state;
SchedulingAlgorithmState *algorithm_state = state->algorithm_state;
/* Get the first worker. */
LocalSchedulerClient *worker =
@@ -395,7 +415,7 @@ TEST task_dependency_test(void) {
handle_worker_available(state, algorithm_state, worker);
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
reset_worker(photon, worker);
reset_worker(local_scheduler, worker);
/* Check that the task gets queued in the waiting queue if the task is
* submitted and a worker is available, but the input is not. */
@@ -408,7 +428,7 @@ TEST task_dependency_test(void) {
handle_object_available(state, algorithm_state, oid);
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
reset_worker(photon, worker);
reset_worker(local_scheduler, worker);
/* Check that the task gets queued in the dispatch queue if the task is
* submitted and the input is available, but no worker is available yet. */
@@ -419,7 +439,7 @@ TEST task_dependency_test(void) {
handle_worker_available(state, algorithm_state, worker);
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
reset_worker(photon, worker);
reset_worker(local_scheduler, worker);
/* If an object gets removed, check the first scenario again, where the task
* gets queued in the waiting task if the task is submitted and a worker is
@@ -443,13 +463,13 @@ TEST task_dependency_test(void) {
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
free_task_spec(spec);
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
PASS();
}
TEST task_multi_dependency_test(void) {
PhotonMock *photon = PhotonMock_init(0, 1);
LocalSchedulerState *state = photon->photon_state;
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(0, 1);
LocalSchedulerState *state = local_scheduler->local_scheduler_state;
SchedulingAlgorithmState *algorithm_state = state->algorithm_state;
/* Get the first worker. */
LocalSchedulerClient *worker =
@@ -476,7 +496,7 @@ TEST task_multi_dependency_test(void) {
handle_worker_available(state, algorithm_state, worker);
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
reset_worker(photon, worker);
reset_worker(local_scheduler, worker);
/* Check that the task gets queued in the dispatch queue if the task is
* submitted and the inputs are available, but no worker is available yet. */
@@ -514,77 +534,90 @@ TEST task_multi_dependency_test(void) {
handle_worker_available(state, algorithm_state, worker);
ASSERT_EQ(num_waiting_tasks(algorithm_state), 0);
ASSERT_EQ(num_dispatch_tasks(algorithm_state), 0);
reset_worker(photon, worker);
reset_worker(local_scheduler, worker);
free_task_spec(spec);
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
PASS();
}
TEST start_kill_workers_test(void) {
/* Start some workers. */
int num_workers = 4;
PhotonMock *photon = PhotonMock_init(num_workers, 0);
LocalSchedulerMock *local_scheduler = LocalSchedulerMock_init(num_workers, 0);
/* We start off with num_workers children processes, but no workers
* registered yet. */
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), num_workers);
ASSERT_EQ(utarray_len(photon->photon_state->workers), 0);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids),
num_workers);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers), 0);
/* Make sure that each worker connects to the photon scheduler. This for loop
* will hang if one of the workers does not connect. */
/* Make sure that each worker connects to the local_scheduler scheduler. This
* for loop will hang if one of the workers does not connect. */
for (int i = 0; i < num_workers; ++i) {
new_client_connection(photon->loop, photon->photon_fd,
(void *) photon->photon_state, 0);
new_client_connection(local_scheduler->loop,
local_scheduler->local_scheduler_fd,
(void *) local_scheduler->local_scheduler_state, 0);
}
/* After handling each worker's initial connection, we should now have all
* workers accounted for, but we haven't yet matched up process IDs with our
* children processes. */
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), num_workers);
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids),
num_workers);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
num_workers);
/* Each worker should register its process ID. */
for (int i = 0; i < utarray_len(photon->photon_state->workers); ++i) {
for (int i = 0;
i < utarray_len(local_scheduler->local_scheduler_state->workers); ++i) {
LocalSchedulerClient *worker = *(LocalSchedulerClient **) utarray_eltptr(
photon->photon_state->workers, i);
process_message(photon->photon_state->loop, worker->sock, worker, 0);
local_scheduler->local_scheduler_state->workers, i);
process_message(local_scheduler->local_scheduler_state->loop, worker->sock,
worker, 0);
}
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 0);
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 0);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
num_workers);
/* After killing a worker, its state is cleaned up. */
LocalSchedulerClient *worker = *(LocalSchedulerClient **) utarray_eltptr(
photon->photon_state->workers, 0);
local_scheduler->local_scheduler_state->workers, 0);
kill_worker(worker, false);
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 0);
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers - 1);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 0);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
num_workers - 1);
/* Start a worker after the local scheduler has been initialized. */
start_worker(photon->photon_state, NIL_ACTOR_ID);
start_worker(local_scheduler->local_scheduler_state, NIL_ACTOR_ID);
/* Accept the workers as clients to the plasma manager. */
int new_worker_fd = accept_client(photon->plasma_manager_fd);
int new_worker_fd = accept_client(local_scheduler->plasma_manager_fd);
/* The new worker should register its process ID. */
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 1);
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers - 1);
/* Make sure the new worker connects to the photon scheduler. */
new_client_connection(photon->loop, photon->photon_fd,
(void *) photon->photon_state, 0);
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 1);
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 1);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
num_workers - 1);
/* Make sure the new worker connects to the local_scheduler scheduler. */
new_client_connection(local_scheduler->loop,
local_scheduler->local_scheduler_fd,
(void *) local_scheduler->local_scheduler_state, 0);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 1);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
num_workers);
/* Make sure that the new worker registers its process ID. */
worker = *(LocalSchedulerClient **) utarray_eltptr(
photon->photon_state->workers, num_workers - 1);
process_message(photon->photon_state->loop, worker->sock, worker, 0);
ASSERT_EQ(utarray_len(photon->photon_state->child_pids), 0);
ASSERT_EQ(utarray_len(photon->photon_state->workers), num_workers);
local_scheduler->local_scheduler_state->workers, num_workers - 1);
process_message(local_scheduler->local_scheduler_state->loop, worker->sock,
worker, 0);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->child_pids), 0);
ASSERT_EQ(utarray_len(local_scheduler->local_scheduler_state->workers),
num_workers);
/* Clean up. */
close(new_worker_fd);
PhotonMock_free(photon);
LocalSchedulerMock_free(local_scheduler);
PASS();
}
SUITE(photon_tests) {
SUITE(local_scheduler_tests) {
RUN_REDIS_TEST(object_reconstruction_test);
RUN_REDIS_TEST(object_reconstruction_recursive_test);
RUN_REDIS_TEST(object_reconstruction_suppression_test);
@@ -597,6 +630,6 @@ GREATEST_MAIN_DEFS();
int main(int argc, char **argv) {
GREATEST_MAIN_BEGIN();
RUN_SUITE(photon_tests);
RUN_SUITE(local_scheduler_tests);
GREATEST_MAIN_END();
}
@@ -9,6 +9,6 @@ set -e
sleep 1s
./src/plasma/plasma_store -s /tmp/plasma_store_socket_1 -m 100000000 &
sleep 0.5s
./src/photon/photon_tests
./src/local_scheduler/local_scheduler_tests
./src/common/thirdparty/redis/src/redis-cli shutdown
killall plasma_store
@@ -9,6 +9,6 @@ set -e
sleep 1s
./src/plasma/plasma_store -s /tmp/plasma_store_socket_1 -m 100000000 &
sleep 0.5s
valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./src/photon/photon_tests
valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./src/local_scheduler/local_scheduler_tests
./src/common/thirdparty/redis/src/redis-cli shutdown
killall plasma_store
-45
View File
@@ -1,45 +0,0 @@
cmake_minimum_required(VERSION 2.8)
project(photon)
# Recursively include common
include(${CMAKE_CURRENT_LIST_DIR}/../common/cmake/Common.cmake)
if(APPLE)
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
endif(APPLE)
include_directories("${PYTHON_INCLUDE_DIRS}")
# set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} --std=c99 -Werror")
if(UNIX AND NOT APPLE)
link_libraries(rt)
endif()
include_directories("${CMAKE_CURRENT_LIST_DIR}/")
include_directories("${CMAKE_CURRENT_LIST_DIR}/../")
include_directories("${CMAKE_CURRENT_LIST_DIR}/../plasma/")
add_library(photon SHARED
photon_extension.c
../common/lib/python/common_extension.c)
get_filename_component(PYTHON_SHARED_LIBRARY ${PYTHON_LIBRARIES} NAME)
if(APPLE)
add_custom_command(TARGET photon
POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change ${PYTHON_SHARED_LIBRARY} ${PYTHON_LIBRARIES} libphoton.so)
endif(APPLE)
add_library(photon_client STATIC photon_client.c)
target_link_libraries(photon photon_client ${COMMON_LIB} ${PYTHON_LIBRARIES})
add_executable(photon_scheduler photon_scheduler.c photon_algorithm.c)
target_link_libraries(photon_scheduler photon_client common ${HIREDIS_LIB} plasma_lib)
add_executable(photon_tests test/photon_tests.c photon_scheduler.c photon_algorithm.c )
target_link_libraries(photon_tests photon_client common ${HIREDIS_LIB} plasma_lib)
target_compile_options(photon_tests PUBLIC "-DPHOTON_TEST")
install(TARGETS photon DESTINATION ${CMAKE_SOURCE_DIR}/photon)
-225
View File
@@ -1,225 +0,0 @@
#include <Python.h>
#include "common_extension.h"
#include "photon_client.h"
#include "task.h"
PyObject *PhotonError;
// clang-format off
typedef struct {
PyObject_HEAD
PhotonConnection *photon_connection;
} PyPhotonClient;
// clang-format on
static int PyPhotonClient_init(PyPhotonClient *self,
PyObject *args,
PyObject *kwds) {
char *socket_name;
ActorID actor_id;
if (!PyArg_ParseTuple(args, "sO&", &socket_name, PyStringToUniqueID,
&actor_id)) {
return -1;
}
/* Connect to the Photon scheduler. */
self->photon_connection = PhotonConnection_init(socket_name, actor_id);
return 0;
}
static void PyPhotonClient_dealloc(PyPhotonClient *self) {
PhotonConnection_free(((PyPhotonClient *) self)->photon_connection);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject *PyPhotonClient_submit(PyObject *self, PyObject *args) {
PyObject *py_task;
if (!PyArg_ParseTuple(args, "O", &py_task)) {
return NULL;
}
photon_submit(((PyPhotonClient *) self)->photon_connection,
((PyTask *) py_task)->spec);
Py_RETURN_NONE;
}
// clang-format off
static PyObject *PyPhotonClient_get_task(PyObject *self) {
task_spec *task_spec;
/* Drop the global interpreter lock while we get a task because
* photon_get_task may block for a long time. */
Py_BEGIN_ALLOW_THREADS
task_spec = photon_get_task(((PyPhotonClient *) self)->photon_connection);
Py_END_ALLOW_THREADS
return PyTask_make(task_spec);
}
// clang-format on
static PyObject *PyPhotonClient_reconstruct_object(PyObject *self,
PyObject *args) {
ObjectID object_id;
if (!PyArg_ParseTuple(args, "O&", PyStringToUniqueID, &object_id)) {
return NULL;
}
photon_reconstruct_object(((PyPhotonClient *) self)->photon_connection,
object_id);
Py_RETURN_NONE;
}
static PyObject *PyPhotonClient_log_event(PyObject *self, PyObject *args) {
const char *key;
int key_length;
const char *value;
int value_length;
if (!PyArg_ParseTuple(args, "s#s#", &key, &key_length, &value,
&value_length)) {
return NULL;
}
photon_log_event(((PyPhotonClient *) self)->photon_connection,
(uint8_t *) key, key_length, (uint8_t *) value,
value_length);
Py_RETURN_NONE;
}
static PyObject *PyPhotonClient_notify_unblocked(PyObject *self) {
photon_notify_unblocked(((PyPhotonClient *) self)->photon_connection);
Py_RETURN_NONE;
}
static PyMethodDef PyPhotonClient_methods[] = {
{"submit", (PyCFunction) PyPhotonClient_submit, METH_VARARGS,
"Submit a task to the local scheduler."},
{"get_task", (PyCFunction) PyPhotonClient_get_task, METH_NOARGS,
"Get a task from the local scheduler."},
{"reconstruct_object", (PyCFunction) PyPhotonClient_reconstruct_object,
METH_VARARGS, "Ask the local scheduler to reconstruct an object."},
{"log_event", (PyCFunction) PyPhotonClient_log_event, METH_VARARGS,
"Log an event to the event log through the local scheduler."},
{"notify_unblocked", (PyCFunction) PyPhotonClient_notify_unblocked,
METH_NOARGS, "Notify the local scheduler that we are unblocked."},
{NULL} /* Sentinel */
};
static PyTypeObject PyPhotonClientType = {
PyVarObject_HEAD_INIT(NULL, 0) /* ob_size */
"photon.PhotonClient", /* tp_name */
sizeof(PyPhotonClient), /* tp_basicsize */
0, /* tp_itemsize */
(destructor) PyPhotonClient_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"PhotonClient object", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyPhotonClient_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc) PyPhotonClient_init, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
static PyMethodDef photon_methods[] = {
{"check_simple_value", check_simple_value, METH_VARARGS,
"Should the object be passed by value?"},
{"compute_put_id", compute_put_id, METH_VARARGS,
"Return the object ID for a put call within a task."},
{"task_from_string", PyTask_from_string, METH_VARARGS,
"Creates a Python PyTask object from a string representation of "
"task_spec."},
{"task_to_string", PyTask_to_string, METH_VARARGS,
"Translates a PyTask python object to a byte string."},
{NULL} /* Sentinel */
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"libphoton", /* m_name */
"A module for the local scheduler.", /* m_doc */
0, /* m_size */
photon_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#endif
#if PY_MAJOR_VERSION >= 3
#define INITERROR return NULL
#else
#define INITERROR return
#endif
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
#if PY_MAJOR_VERSION >= 3
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
#else
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
#endif
MOD_INIT(libphoton) {
if (PyType_Ready(&PyTaskType) < 0) {
INITERROR;
}
if (PyType_Ready(&PyObjectIDType) < 0) {
INITERROR;
}
if (PyType_Ready(&PyPhotonClientType) < 0) {
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
PyObject *m = PyModule_Create(&moduledef);
#else
PyObject *m = Py_InitModule3("libphoton", photon_methods,
"A module for the local scheduler.");
#endif
init_pickle_module();
Py_INCREF(&PyTaskType);
PyModule_AddObject(m, "Task", (PyObject *) &PyTaskType);
Py_INCREF(&PyObjectIDType);
PyModule_AddObject(m, "ObjectID", (PyObject *) &PyObjectIDType);
Py_INCREF(&PyPhotonClientType);
PyModule_AddObject(m, "PhotonClient", (PyObject *) &PyPhotonClientType);
char photon_error[] = "photon.error";
PhotonError = PyErr_NewException(photon_error, NULL, NULL);
Py_INCREF(PhotonError);
PyModule_AddObject(m, "photon_error", PhotonError);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}