Skip to content
This repository was archived by the owner on Aug 11, 2020. It is now read-only.

Commit c3a1c5a

Browse files
addaleaxjasnell
authored andcommitted
http2: use shared memory tracking implementation
The extensive testing done on http2 makes it easier to make sure the implementation is correct (and doesn’t diverge unnecessarily). PR-URL: #126 Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 7d6990b commit c3a1c5a

File tree

2 files changed

+23
-96
lines changed

2 files changed

+23
-96
lines changed

src/node_http2.cc

+14-94
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "node_buffer.h"
66
#include "node_http2.h"
77
#include "node_http2_state.h"
8+
#include "node_mem-inl.h"
89
#include "node_perf.h"
910
#include "node_revert.h"
1011
#include "util-inl.h"
@@ -498,101 +499,20 @@ Http2Session::Callbacks::~Callbacks() {
498499
nghttp2_session_callbacks_del(callbacks);
499500
}
500501

501-
// Track memory allocated by nghttp2 using a custom allocator.
502-
class Http2Session::MemoryAllocatorInfo {
503-
public:
504-
explicit MemoryAllocatorInfo(Http2Session* session)
505-
: info({ session, H2Malloc, H2Free, H2Calloc, H2Realloc }) {}
506-
507-
static void* H2Malloc(size_t size, void* user_data) {
508-
return H2Realloc(nullptr, size, user_data);
509-
}
510-
511-
static void* H2Calloc(size_t nmemb, size_t size, void* user_data) {
512-
size_t real_size = MultiplyWithOverflowCheck(nmemb, size);
513-
void* mem = H2Malloc(real_size, user_data);
514-
if (mem != nullptr)
515-
memset(mem, 0, real_size);
516-
return mem;
517-
}
518-
519-
static void H2Free(void* ptr, void* user_data) {
520-
if (ptr == nullptr) return; // free(null); happens quite often.
521-
void* result = H2Realloc(ptr, 0, user_data);
522-
CHECK_NULL(result);
523-
}
524-
525-
static void* H2Realloc(void* ptr, size_t size, void* user_data) {
526-
Http2Session* session = static_cast<Http2Session*>(user_data);
527-
size_t previous_size = 0;
528-
char* original_ptr = nullptr;
529-
530-
// We prepend each allocated buffer with a size_t containing the full
531-
// size of the allocation.
532-
if (size > 0) size += sizeof(size_t);
533-
534-
if (ptr != nullptr) {
535-
// We are free()ing or re-allocating.
536-
original_ptr = static_cast<char*>(ptr) - sizeof(size_t);
537-
previous_size = *reinterpret_cast<size_t*>(original_ptr);
538-
// This means we called StopTracking() on this pointer before.
539-
if (previous_size == 0) {
540-
// Fall back to the standard Realloc() function.
541-
char* ret = UncheckedRealloc(original_ptr, size);
542-
if (ret != nullptr)
543-
ret += sizeof(size_t);
544-
return ret;
545-
}
546-
}
547-
CHECK_GE(session->current_nghttp2_memory_, previous_size);
548-
549-
// TODO(addaleax): Add the following, and handle NGHTTP2_ERR_NOMEM properly
550-
// everywhere:
551-
//
552-
// if (size > previous_size &&
553-
// !session->IsAvailableSessionMemory(size - previous_size)) {
554-
// return nullptr;
555-
//}
556-
557-
char* mem = UncheckedRealloc(original_ptr, size);
558-
559-
if (mem != nullptr) {
560-
// Adjust the memory info counter.
561-
// TODO(addaleax): Avoid the double bookkeeping we do with
562-
// current_nghttp2_memory_ + AdjustAmountOfExternalAllocatedMemory
563-
// and provide versions of our memory allocation utilities that take an
564-
// Environment*/Isolate* parameter and call the V8 method transparently.
565-
const int64_t new_size = size - previous_size;
566-
session->current_nghttp2_memory_ += new_size;
567-
session->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
568-
new_size);
569-
*reinterpret_cast<size_t*>(mem) = size;
570-
mem += sizeof(size_t);
571-
} else if (size == 0) {
572-
session->current_nghttp2_memory_ -= previous_size;
573-
session->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
574-
-static_cast<int64_t>(previous_size));
575-
}
576-
577-
return mem;
578-
}
579-
580-
static void StopTracking(Http2Session* session, void* ptr) {
581-
size_t* original_ptr = reinterpret_cast<size_t*>(
582-
static_cast<char*>(ptr) - sizeof(size_t));
583-
session->current_nghttp2_memory_ -= *original_ptr;
584-
session->env()->isolate()->AdjustAmountOfExternalAllocatedMemory(
585-
-static_cast<int64_t>(*original_ptr));
586-
*original_ptr = 0;
587-
}
502+
void Http2Session::StopTrackingRcbuf(nghttp2_rcbuf* buf) {
503+
StopTrackingMemory(buf);
504+
}
588505

589-
inline nghttp2_mem* operator*() { return &info; }
506+
void Http2Session::CheckAllocatedSize(size_t previous_size) const {
507+
CHECK_GE(current_nghttp2_memory_, previous_size);
508+
}
590509

591-
nghttp2_mem info;
592-
};
510+
void Http2Session::IncreaseAllocatedSize(size_t size) {
511+
current_nghttp2_memory_ += size;
512+
}
593513

594-
void Http2Session::StopTrackingRcbuf(nghttp2_rcbuf* buf) {
595-
MemoryAllocatorInfo::StopTracking(this, buf);
514+
void Http2Session::DecreaseAllocatedSize(size_t size) {
515+
current_nghttp2_memory_ -= size;
596516
}
597517

598518
Http2Session::Http2Session(Environment* env,
@@ -629,14 +549,14 @@ Http2Session::Http2Session(Environment* env,
629549
nghttp2_session_server_new3 :
630550
nghttp2_session_client_new3;
631551

632-
MemoryAllocatorInfo allocator_info(this);
552+
nghttp2_mem alloc_info = MakeAllocator();
633553

634554
// This should fail only if the system is out of memory, which
635555
// is going to cause lots of other problems anyway, or if any
636556
// of the options are out of acceptable range, which we should
637557
// be catching before it gets this far. Either way, crash if this
638558
// fails.
639-
CHECK_EQ(fn(&session_, callbacks, this, *opts, *allocator_info), 0);
559+
CHECK_EQ(fn(&session_, callbacks, this, *opts, &alloc_info), 0);
640560

641561
outgoing_storage_.reserve(1024);
642562
outgoing_buffers_.reserve(32);

src/node_http2.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "nghttp2/nghttp2.h"
99

1010
#include "node_http2_state.h"
11+
#include "node_mem.h"
1112
#include "node_perf.h"
1213
#include "stream_base-inl.h"
1314
#include "string_bytes.h"
@@ -690,7 +691,9 @@ enum SessionBitfieldFlags {
690691
kSessionHasAltsvcListeners
691692
};
692693

693-
class Http2Session : public AsyncWrap, public StreamListener {
694+
class Http2Session : public AsyncWrap,
695+
public StreamListener,
696+
public mem::NgLibMemoryManager<Http2Session, nghttp2_mem> {
694697
public:
695698
Http2Session(Environment* env,
696699
Local<Object> wrap,
@@ -699,7 +702,6 @@ class Http2Session : public AsyncWrap, public StreamListener {
699702

700703
class Http2Ping;
701704
class Http2Settings;
702-
class MemoryAllocatorInfo;
703705

704706
void EmitStatistics();
705707

@@ -800,6 +802,11 @@ class Http2Session : public AsyncWrap, public StreamListener {
800802
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
801803
void OnStreamAfterWrite(WriteWrap* w, int status) override;
802804

805+
// Implementation for mem::NgLibMemoryManager
806+
void CheckAllocatedSize(size_t previous_size) const;
807+
void IncreaseAllocatedSize(size_t size);
808+
void DecreaseAllocatedSize(size_t size);
809+
803810
// The JavaScript API
804811
static void New(const FunctionCallbackInfo<Value>& args);
805812
static void Consume(const FunctionCallbackInfo<Value>& args);

0 commit comments

Comments
 (0)