Skip to content

Commit 464c613

Browse files
authored
cripts: shrink Context from 3408 to 1920 bytes, expand data[] to 16 (#13195)
* cripts: shrink Context from 3408 to 1920 bytes, expand data[] to 16 Pimpl Url::Path and Url::Query state behind unique_ptr so the heavy vector/unordered_map/cripts::string members only allocate when a script actually decomposes the path or query. Lazy-allocate Pristine, Parent, and Remap From/To URLs in _UrlBlock — they're rarely all touched, and the embedded 384-byte Url objects dominated the per-txn cost. Pimpl Error::Reason for the same reason. Drop the unused INET6_ADDRSTRLEN buffer in detail::ConnBase. Make cripts::Url's destructor virtual now that we delete via unique_ptr. Bump CONTEXT_DATA_SLOTS from 4 to 16 so scripts have room to stash more per-txn state — the 384-byte cost sits inside the budget freed by the URL/Connection cuts. * Address Copilot's review comments Bounds-check Path::Erase to avoid dereferencing a null _owner when ix is out of range — operator[] returns a default-constructed String in that case, and the subsequent p.operator=("") would then crash inside String::operator=.
1 parent e78ed66 commit 464c613

7 files changed

Lines changed: 215 additions & 152 deletions

File tree

include/cripts/Connections.hpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,9 @@ class ConnBase
459459

460460
void virtual _initialize() { _initialized = true; }
461461

462-
cripts::Transaction *_state = nullptr;
463-
struct sockaddr const *_socket = nullptr;
464-
TSVConn _vc = nullptr;
465-
char _str[INET6_ADDRSTRLEN + 1];
462+
cripts::Transaction *_state = nullptr;
463+
struct sockaddr const *_socket = nullptr;
464+
TSVConn _vc = nullptr;
466465
bool _initialized = false;
467466

468467
}; // End class ConnBase

include/cripts/Context.hpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#pragma once
1919

2020
#include <array>
21+
#include <memory>
2122
#include <variant>
2223
#include "ts/ts.h"
2324
#include "ts/remap.h"
@@ -28,7 +29,7 @@
2829
#include "cripts/Connections.hpp"
2930

3031
// These are pretty arbitrary for now
31-
constexpr int CONTEXT_DATA_SLOTS = 4;
32+
constexpr int CONTEXT_DATA_SLOTS = 16;
3233

3334
namespace cripts
3435
{
@@ -132,23 +133,16 @@ class Context
132133
} _cache;
133134

134135
struct _UrlBlock {
135-
cripts::Client::URL &request;
136-
cripts::Pristine::URL pristine;
137-
cripts::Parent::URL parent;
136+
cripts::Client::URL &request;
137+
std::unique_ptr<cripts::Pristine::URL> pristine;
138+
std::unique_ptr<cripts::Parent::URL> parent;
138139

139140
struct {
140-
cripts::Remap::From::URL from;
141-
cripts::Remap::To::URL to;
141+
std::unique_ptr<cripts::Remap::From::URL> from;
142+
std::unique_ptr<cripts::Remap::To::URL> to;
142143
} remap;
143144

144-
_UrlBlock(Context *ctx, cripts::Client::URL &alias) : request(alias)
145-
{
146-
request.set_context(ctx);
147-
pristine.set_context(ctx);
148-
parent.set_context(ctx);
149-
remap.from.set_context(ctx);
150-
remap.to.set_context(ctx);
151-
}
145+
_UrlBlock(Context *ctx, cripts::Client::URL &alias) : request(alias) { request.set_context(ctx); }
152146

153147
} _urls;
154148
}; // End class Context

include/cripts/Error.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
#pragma once
1919

20+
#include <memory>
2021
#include <utility>
2122

2223
#include "ts/ts.h"
@@ -132,10 +133,10 @@ class Error
132133
void Execute(cripts::Context *context);
133134

134135
private:
135-
Reason _reason;
136-
Status _status;
137-
bool _failed = false;
138-
bool _redirect = false;
136+
std::unique_ptr<Reason> _reason;
137+
Status _status;
138+
bool _failed = false;
139+
bool _redirect = false;
139140
};
140141

141142
} // namespace cripts

include/cripts/Urls.hpp

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#pragma once
1919

2020
#include <algorithm>
21+
#include <memory>
2122
#include <string>
2223
#include <string_view>
2324
#include <unordered_map>
@@ -338,16 +339,18 @@ class Url
338339

339340
cripts::string_view GetSV() override;
340341
cripts::string operator+=(cripts::string_view add);
341-
self_type operator=(cripts::string_view path);
342+
self_type &operator=(cripts::string_view path);
342343
String operator[](Segments::size_type ix);
343344

344345
void
345346
Erase(Segments::size_type ix)
346347
{
347348
auto p = operator[](ix);
348349

349-
_size -= p.size();
350-
p.operator=("");
350+
if (_state && ix < _state->segments.size()) {
351+
_state->size -= p.size();
352+
p.operator=("");
353+
}
351354
}
352355

353356
void
@@ -368,18 +371,31 @@ class Url
368371
void
369372
Flush()
370373
{
371-
if (_modified) {
374+
if (_state && _state->modified) {
372375
operator=(GetSV());
373376
}
374377
}
375378

376379
private:
377380
void _parser();
378381

379-
bool _modified = false;
380-
Segments _segments; // Lazy loading on this
381-
cripts::string _storage; // Used when recombining the segments into a full path
382-
cripts::string::size_type _size = 0; // Mostly a guestimate for managing _storage
382+
struct State {
383+
bool modified = false;
384+
Segments segments; // Ordered list of path segments
385+
cripts::string storage; // Used when recombining the segments into a full path
386+
cripts::string::size_type size = 0; // Mostly a guestimate for managing storage
387+
};
388+
389+
State &
390+
_ensure_state()
391+
{
392+
if (!_state) {
393+
_state = std::make_unique<State>();
394+
}
395+
return *_state;
396+
}
397+
398+
std::unique_ptr<State> _state; // Lazily allocated when path is parsed or modified
383399

384400
}; // End class Url::Path
385401

@@ -461,18 +477,18 @@ class Url
461477

462478
using Component::Component;
463479

464-
Query(cripts::string_view load)
480+
Query(cripts::string_view load) : _state(std::make_unique<State>())
465481
{
466-
_data = load;
467-
_size = load.size();
468-
_loaded = true;
469-
_standalone = true;
482+
_data = load;
483+
_state->size = load.size();
484+
_loaded = true;
485+
_state->standalone = true;
470486
}
471487

472488
void Reset() override;
473489

474490
cripts::string_view GetSV() override;
475-
self_type operator=(cripts::string_view query);
491+
self_type &operator=(cripts::string_view query);
476492
cripts::string operator+=(cripts::string_view add);
477493
Parameter operator[](cripts::string_view param);
478494
void Erase(cripts::string_view param);
@@ -482,7 +498,9 @@ class Url
482498
Erase()
483499
{
484500
operator=("");
485-
_size = 0;
501+
if (_state) {
502+
_state->size = 0;
503+
}
486504
}
487505

488506
void
@@ -503,34 +521,48 @@ class Url
503521
// Make sure the hash and vector are populated
504522
_parser();
505523

506-
std::ranges::sort(_ordered);
507-
_modified = true;
524+
std::ranges::sort(_state->ordered);
525+
_state->modified = true;
508526
}
509527

510528
void
511529
Flush()
512530
{
513-
if (_modified) {
531+
if (_state && _state->modified) {
514532
operator=(GetSV());
515533
}
516534
}
517535

518536
private:
519537
void _parser();
520538

521-
bool _modified = false;
522-
bool _standalone = false; // This component is used outside of a URL owner, not common
523-
OrderedParams _ordered; // Ordered vector of all parameters, can be sorted etc.
524-
HashParams _hashed; // Unordered map to go from "name" to the query parameter
525-
cripts::string _storage; // Used when recombining the query params into a
526-
// full query string
527-
cripts::string::size_type _size = 0; // Mostly a guesttimate
539+
struct State {
540+
bool modified = false;
541+
bool standalone = false; // This component is used outside of a URL owner, not common
542+
OrderedParams ordered; // Ordered vector of all parameters, can be sorted etc.
543+
HashParams hashed; // Unordered map to go from "name" to the query parameter
544+
cripts::string storage; // Used when recombining the query params into a full query string
545+
cripts::string::size_type size = 0; // Mostly a guesttimate
546+
};
547+
548+
State &
549+
_ensure_state()
550+
{
551+
if (!_state) {
552+
_state = std::make_unique<State>();
553+
}
554+
return *_state;
555+
}
556+
557+
std::unique_ptr<State> _state; // Lazily allocated when query is parsed or modified
528558

529559
}; // End class Url::Query
530560

531561
public:
532562
Url() : scheme(this), host(this), port(this), path(this), query(this) {}
533563

564+
virtual ~Url() = default;
565+
534566
// Clear anything "cached" in the Url, this is rather draconian, but it's safe...
535567
virtual void
536568
Reset()

src/cripts/Context.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,12 @@ Context::reset()
4848
_server.request.Reset();
4949
}
5050

51-
// Clear the initialized URLs before calling next hook
52-
if (_urls.pristine.Initialized()) {
53-
_urls.pristine.Reset();
54-
}
55-
if (_urls.parent.Initialized()) {
56-
_urls.parent.Reset();
57-
}
51+
// Release lazy URLs entirely — they get recreated on demand for the next txn.
52+
_urls.pristine.reset();
53+
_urls.parent.reset();
54+
_urls.remap.from.reset();
55+
_urls.remap.to.reset();
56+
5857
if (_cache.url.Initialized()) {
5958
_cache.url.Reset();
6059
}

src/cripts/Error.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ void
4141
Error::Reason::_set(cripts::Context *context, const cripts::string_view msg)
4242
{
4343
context->state.error.Fail();
44-
context->state.error._reason._setter(msg);
44+
if (!context->state.error._reason) {
45+
context->state.error._reason = std::make_unique<Reason>();
46+
}
47+
context->state.error._reason->_setter(msg);
4548
}
4649

4750
// For convenience, an optional Reason message can also be specified with the status
@@ -52,7 +55,10 @@ Error::Status::_set(cripts::Context *context, TSHttpStatus status, const cripts:
5255
context->state.error._status._setter(status);
5356

5457
if (msg.size() > 0) {
55-
context->state.error._reason._setter(msg);
58+
if (!context->state.error._reason) {
59+
context->state.error._reason = std::make_unique<Reason>();
60+
}
61+
context->state.error._reason->_setter(msg);
5662
}
5763

5864
if (context->state.error.Redirected() || status == TS_HTTP_STATUS_MOVED_PERMANENTLY ||

0 commit comments

Comments
 (0)