Skip to content

Commit 38db8ed

Browse files
zhijunfupcmoritz
authored andcommitted
ARROW-2558: [Plasma] avoid walk through all the objects when a client disconnects
Currently plasma stores list-of-clients in ObjectTableEntry, which is used to track which clients are using a given object, this serves for two purposes: - If an object is in use. - If the client trying to abort an object is the one who created it. A problem with list-of-clients approach is that when a client disconnects, we need to walk through all the objects and remove the client pointer from the list for each object. Instead, we could add a reference count in ObjectTableEntry, and store list-of-object-ids in client structure. This could both goals that the original approach is targeting, while when a client disconnects, it just walk through its object-ids and dereference each ObjectTableEntry, there's no need to walk through all objects. Author: Zhijun Fu <[email protected]> Closes #2015 from zhijunfu/client_object_ids and squashes the following commits: d8db8f7 <Zhijun Fu> Address comments from pcmoritz 8a439e8 <Zhijun Fu> Trigger a047572 <Zhijun Fu> use list-of-object-ids in client instead of list-of-clients in object
1 parent 71d487a commit 38db8ed

File tree

4 files changed

+52
-38
lines changed

4 files changed

+52
-38
lines changed

cpp/src/plasma/plasma.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ extern "C" {
3030
void dlfree(void* mem);
3131
}
3232

33-
ObjectTableEntry::ObjectTableEntry() : pointer(nullptr) {}
33+
ObjectTableEntry::ObjectTableEntry() : pointer(nullptr), ref_count(0) {}
3434

3535
ObjectTableEntry::~ObjectTableEntry() {
3636
dlfree(pointer);

cpp/src/plasma/plasma.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ struct ObjectTableEntry {
134134
/// IPC GPU handle to share with clients.
135135
std::shared_ptr<CudaIpcMemHandle> ipc_handle;
136136
#endif
137-
/// Set of clients currently using this object.
138-
std::unordered_set<Client*> clients;
137+
/// Number of clients currently using this object.
138+
int ref_count;
139+
139140
/// The state of the object, e.g., whether it is open or sealed.
140141
object_state state;
141142
/// The digest of the object. Used to see if two objects are the same.

cpp/src/plasma/store.cc

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,24 @@ const PlasmaStoreInfo* PlasmaStore::get_plasma_store_info() { return &store_info
124124

125125
// If this client is not already using the object, add the client to the
126126
// object's list of clients, otherwise do nothing.
127-
void PlasmaStore::add_client_to_object_clients(ObjectTableEntry* entry, Client* client) {
127+
void PlasmaStore::add_to_client_object_ids(ObjectTableEntry* entry, Client* client) {
128128
// Check if this client is already using the object.
129-
if (entry->clients.find(client) != entry->clients.end()) {
129+
if (client->object_ids.find(entry->object_id) != client->object_ids.end()) {
130130
return;
131131
}
132132
// If there are no other clients using this object, notify the eviction policy
133133
// that the object is being used.
134-
if (entry->clients.size() == 0) {
134+
if (entry->ref_count == 0) {
135135
// Tell the eviction policy that this object is being used.
136136
std::vector<ObjectID> objects_to_evict;
137137
eviction_policy_.begin_object_access(entry->object_id, &objects_to_evict);
138138
delete_objects(objects_to_evict);
139139
}
140-
// Add the client pointer to the list of clients using this object.
141-
entry->clients.insert(client);
140+
// Increase reference count.
141+
entry->ref_count++;
142+
143+
// Add object id to the list of object ids that this client is using.
144+
client->object_ids.insert(entry->object_id);
142145
}
143146

144147
// Create a new object buffer in the hash table.
@@ -225,11 +228,11 @@ int PlasmaStore::create_object(const ObjectID& object_id, int64_t data_size,
225228
result->metadata_size = metadata_size;
226229
result->device_num = device_num;
227230
// Notify the eviction policy that this object was created. This must be done
228-
// immediately before the call to add_client_to_object_clients so that the
231+
// immediately before the call to add_to_client_object_ids so that the
229232
// eviction policy does not have an opportunity to evict the object.
230233
eviction_policy_.object_created(object_id);
231234
// Record that this client is using this object.
232-
add_client_to_object_clients(store_info_.objects[object_id].get(), client);
235+
add_to_client_object_ids(store_info_.objects[object_id].get(), client);
233236
return PlasmaError_OK;
234237
}
235238

@@ -324,7 +327,7 @@ void PlasmaStore::update_object_get_requests(const ObjectID& object_id) {
324327
get_req->num_satisfied += 1;
325328
// Record the fact that this client will be using this object and will
326329
// be responsible for releasing this object.
327-
add_client_to_object_clients(entry, get_req->client);
330+
add_to_client_object_ids(entry, get_req->client);
328331

329332
// If this get request is done, reply to the client.
330333
if (get_req->num_satisfied == get_req->num_objects_to_wait_for) {
@@ -358,7 +361,7 @@ void PlasmaStore::process_get_request(Client* client,
358361
get_req->num_satisfied += 1;
359362
// If necessary, record that this client is using this object. In the case
360363
// where entry == NULL, this will be called from seal_object.
361-
add_client_to_object_clients(entry, client);
364+
add_to_client_object_ids(entry, client);
362365
} else {
363366
// Add a placeholder plasma object to the get request to indicate that the
364367
// object is not present. This will be parsed by the client. We set the
@@ -383,14 +386,16 @@ void PlasmaStore::process_get_request(Client* client,
383386
}
384387
}
385388

386-
int PlasmaStore::remove_client_from_object_clients(ObjectTableEntry* entry,
387-
Client* client) {
388-
auto it = entry->clients.find(client);
389-
if (it != entry->clients.end()) {
390-
entry->clients.erase(it);
389+
int PlasmaStore::remove_from_client_object_ids(ObjectTableEntry* entry, Client* client) {
390+
auto it = client->object_ids.find(entry->object_id);
391+
if (it != client->object_ids.end()) {
392+
client->object_ids.erase(it);
393+
// Decrease reference count.
394+
entry->ref_count--;
395+
391396
// If no more clients are using this object, notify the eviction policy
392397
// that the object is no longer being used.
393-
if (entry->clients.size() == 0) {
398+
if (entry->ref_count == 0) {
394399
// Tell the eviction policy that this object is no longer being used.
395400
std::vector<ObjectID> objects_to_evict;
396401
eviction_policy_.end_object_access(entry->object_id, &objects_to_evict);
@@ -408,7 +413,7 @@ void PlasmaStore::release_object(const ObjectID& object_id, Client* client) {
408413
auto entry = get_object_table_entry(&store_info_, object_id);
409414
ARROW_CHECK(entry != NULL);
410415
// Remove the client from the object's array of clients.
411-
ARROW_CHECK(remove_client_from_object_clients(entry, client) == 1);
416+
ARROW_CHECK(remove_from_client_object_ids(entry, client) == 1);
412417
}
413418

414419
// Check if an object is present.
@@ -439,8 +444,8 @@ int PlasmaStore::abort_object(const ObjectID& object_id, Client* client) {
439444
ARROW_CHECK(entry != NULL) << "To abort an object it must be in the object table.";
440445
ARROW_CHECK(entry->state != PLASMA_SEALED)
441446
<< "To abort an object it must not have been sealed.";
442-
auto it = entry->clients.find(client);
443-
if (it == entry->clients.end()) {
447+
auto it = client->object_ids.find(object_id);
448+
if (it == client->object_ids.end()) {
444449
// If the client requesting the abort is not the creator, do not
445450
// perform the abort.
446451
return 0;
@@ -466,7 +471,7 @@ int PlasmaStore::delete_object(ObjectID& object_id) {
466471
return PlasmaError_ObjectNotSealed;
467472
}
468473

469-
if (entry->clients.size() != 0) {
474+
if (entry->ref_count != 0) {
470475
// To delete an object, there must be no clients currently using it.
471476
return PlasmaError_ObjectInUse;
472477
}
@@ -493,7 +498,7 @@ void PlasmaStore::delete_objects(const std::vector<ObjectID>& object_ids) {
493498
ARROW_CHECK(entry != NULL) << "To delete an object it must be in the object table.";
494499
ARROW_CHECK(entry->state == PLASMA_SEALED)
495500
<< "To delete an object it must have been sealed.";
496-
ARROW_CHECK(entry->clients.size() == 0)
501+
ARROW_CHECK(entry->ref_count == 0)
497502
<< "To delete an object, there must be no clients currently using it.";
498503
store_info_.objects.erase(object_id);
499504
// Inform all subscribers that the object has been deleted.
@@ -529,23 +534,27 @@ void PlasmaStore::disconnect_client(int client_fd) {
529534
// Close the socket.
530535
close(client_fd);
531536
ARROW_LOG(INFO) << "Disconnecting client on fd " << client_fd;
532-
// If this client was using any objects, remove it from the appropriate
533-
// lists.
534-
// TODO(swang): Avoid iteration through the object table.
537+
// Release all the objects that the client was using.
535538
auto client = it->second.get();
536-
std::vector<ObjectID> unsealed_objects;
537-
for (const auto& entry : store_info_.objects) {
538-
if (entry.second->state == PLASMA_SEALED) {
539-
remove_client_from_object_clients(entry.second.get(), client);
539+
std::vector<ObjectTableEntry*> sealed_objects;
540+
for (const auto& object_id : client->object_ids) {
541+
auto it = store_info_.objects.find(object_id);
542+
if (it == store_info_.objects.end()) {
543+
continue;
544+
}
545+
546+
if (it->second->state == PLASMA_SEALED) {
547+
// Add sealed objects to a temporary list of object IDs. Do not perform
548+
// the remove here, since it potentially modifies the object_ids table.
549+
sealed_objects.push_back(it->second.get());
540550
} else {
541-
// Add unsealed objects to a temporary list of object IDs. Do not perform
542-
// the abort here, since it potentially modifies the object table.
543-
unsealed_objects.push_back(entry.first);
551+
// Abort unsealed object.
552+
abort_object(it->first, client);
544553
}
545554
}
546-
// If the client was creating any objects, abort them.
547-
for (const auto& entry : unsealed_objects) {
548-
abort_object(entry, client);
555+
556+
for (const auto& entry : sealed_objects) {
557+
remove_from_client_object_ids(entry, client);
549558
}
550559

551560
// Note, the store may still attempt to send a message to the disconnected

cpp/src/plasma/store.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <memory>
2323
#include <string>
2424
#include <unordered_map>
25+
#include <unordered_set>
2526
#include <vector>
2627

2728
#include "plasma/common.h"
@@ -46,6 +47,9 @@ struct Client {
4647

4748
/// The file descriptor used to communicate with the client.
4849
int fd;
50+
51+
/// Object ids that are used by this client.
52+
std::unordered_set<ObjectID, UniqueIDHasher> object_ids;
4953
};
5054

5155
class PlasmaStore {
@@ -164,13 +168,13 @@ class PlasmaStore {
164168
private:
165169
void push_notification(ObjectInfoT* object_notification);
166170

167-
void add_client_to_object_clients(ObjectTableEntry* entry, Client* client);
171+
void add_to_client_object_ids(ObjectTableEntry* entry, Client* client);
168172

169173
void return_from_get(GetRequest* get_req);
170174

171175
void update_object_get_requests(const ObjectID& object_id);
172176

173-
int remove_client_from_object_clients(ObjectTableEntry* entry, Client* client);
177+
int remove_from_client_object_ids(ObjectTableEntry* entry, Client* client);
174178

175179
/// Event loop of the plasma store.
176180
EventLoop* loop_;

0 commit comments

Comments
 (0)