Skip to content

Commit

Permalink
Add infrastructure for sharing memory in a TBuffer.
Browse files Browse the repository at this point in the history
Allow two TBuffer objects to share an underlying memory buffer.
Have the user buffer linked to the TBranch's buffer.
  • Loading branch information
bbockelm authored and pcanal committed Apr 4, 2019
1 parent fc393c4 commit 0987896
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 53 deletions.
39 changes: 34 additions & 5 deletions core/base/inc/TBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ namespace TStreamerInfoActions {
class TActionSequence;
}

// Will be used to reallocate the contents of a shared buffer.
char *R__ReAllocShared(void *obj_void, char *current, size_t new_size, size_t old_size);

class TBuffer : public TObject {

protected:
Expand All @@ -49,7 +52,8 @@ class TBuffer : public TObject {
char *fBufCur; //Current position in buffer
char *fBufMax; //End of buffer
TObject *fParent; //Pointer to parent object owning this buffer
ReAllocCharFun_t fReAllocFunc; //! Realloc function to be used when extending the buffer.
ReAllocStateFun_t fReAllocFunc{nullptr}; //! Realloc function to be used when extending the buffer.
void *fReAllocData; //! Realloc data pointer. Used if the realloc function needs some state.
CacheList_t fCacheStack; //Stack of pointers to the cache where to temporarily store the value of 'missing' data members

// Default ctor
Expand All @@ -76,17 +80,18 @@ class TBuffer : public TObject {

TBuffer(EMode mode);
TBuffer(EMode mode, Int_t bufsiz);
TBuffer(EMode mode, Int_t bufsiz, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = 0);
TBuffer(EMode mode, Int_t bufsiz, void *buf, Bool_t adopt = kTRUE, ReAllocStateFun_t reallocfunc = 0, void *reallocData = nullptr);
virtual ~TBuffer();

Int_t GetBufferVersion() const { return fVersion; }
Bool_t IsReading() const { return (fMode & kWrite) == 0; }
Bool_t IsWriting() const { return (fMode & kWrite) != 0; }
void SetReadMode();
void SetWriteMode();
void SetBuffer(void *buf, UInt_t bufsiz = 0, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = 0);
ReAllocCharFun_t GetReAllocFunc() const;
void SetReAllocFunc(ReAllocCharFun_t reallocfunc = 0);
void SetBuffer(void *buf, UInt_t bufsiz = 0, Bool_t adopt = kTRUE, ReAllocStateFun_t reallocfunc = 0, void *reallocData = nullptr);
ReAllocStateFun_t GetReAllocFunc() const;
void *GetReAllocData() const;
void SetReAllocFunc(ReAllocStateFun_t reallocfunc = 0, void *reallocData = nullptr);
void SetBufferOffset(Int_t offset = 0) { fBufCur = fBuffer+offset; }
void SetParent(TObject *parent);
TObject *GetParent() const;
Expand All @@ -98,6 +103,30 @@ class TBuffer : public TObject {
void Expand(Int_t newsize, Bool_t copy = kTRUE); // expand buffer to newsize
void AutoExpand(Int_t size_needed); // expand buffer to newsize

////////////////////////////////////////////////////////////////////////////////
/// Share the underlying memory allocation with another buffer.
//
// This causes the passed TBuffer object to share our memory buffer. This is
// useful if two objects want to have their own view of the TBuffer state but
// see identical data.
//
// Internally, not only do both buffers get the same memory location but a
// resize done by the "slave" buffer updates the "owner" buffer (the opposite
// is not true!).
//
// This is most useful if the "slave" does all the writings and the "owner"
// only does reads.
//
virtual void SetSlaveBuffer(TBuffer &other) { // Share the underlying memory allocation with another TBuffer object.
if (other.Buffer() == Buffer()) {return;}
Int_t other_buf_size = BufferSize();
other.Expand(0, false); // Free up other buffer.
other.fBuffer = fBuffer;
ResetBit(other.kIsOwner);
other.SetReAllocFunc(R__ReAllocShared, this);
if (other_buf_size > BufferSize()) {other.Expand(other_buf_size);}
}

virtual Bool_t CheckObject(const TObject *obj) = 0;
virtual Bool_t CheckObject(const void *obj, const TClass *ptrClass) = 0;

Expand Down
6 changes: 5 additions & 1 deletion core/base/inc/TStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
typedef void (*FreeHookFun_t)(void*, void *addr, size_t);
typedef void *(*ReAllocFun_t)(void*, size_t);
typedef void *(*ReAllocCFun_t)(void*, size_t, size_t);
typedef char *(*ReAllocCharFun_t)(char*, size_t, size_t);
typedef char *(*ReAllocCharFun_t)(void *, char*, size_t, size_t);
// Re-allocate data; first argument is a user-provided opaque
// pointer. Second is the current address of the data buffer.
typedef char *(*ReAllocStateFun_t)(void *, char*, size_t, size_t);


class TStorage {
Expand Down Expand Up @@ -56,6 +59,7 @@ class TStorage {
static void *ReAlloc(void *vp, size_t size);
static void *ReAlloc(void *vp, size_t size, size_t oldsize);
static char *ReAllocChar(char *vp, size_t size, size_t oldsize);
static char *ReAllocState(void *, char *vp, size_t size, size_t oldsize);
static Int_t *ReAllocInt(Int_t *vp, size_t size, size_t oldsize);
static void *ObjectAlloc(size_t size);
static void *ObjectAllocArray(size_t size);
Expand Down
73 changes: 58 additions & 15 deletions core/base/src/TBuffer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ void ROOT::Internal::DefaultStreamer(TBuffer &R__b, const TClass *cl, void *objp
/// The user has provided memory than we don't own, thus we can not extent it
/// either.

static char *R__NoReAllocChar(char *, size_t, size_t)
static char *R__NoReAllocState(void *, char *, size_t, size_t)
{
return 0;
}
Expand Down Expand Up @@ -83,7 +83,7 @@ TBuffer::TBuffer(EMode mode, Int_t bufsiz)
fBufCur = fBuffer;
fBufMax = fBuffer + fBufSize;

SetReAllocFunc( 0 );
SetReAllocFunc( nullptr, nullptr );
}

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -97,7 +97,8 @@ TBuffer::TBuffer(EMode mode, Int_t bufsiz)
/// is provided, a Fatal error will be issued if the Buffer attempts to
/// expand.

TBuffer::TBuffer(EMode mode, Int_t bufsiz, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc)
TBuffer::TBuffer(EMode mode, Int_t bufsiz, void *buf, Bool_t adopt, ReAllocStateFun_t reallocfunc, void *reallocData)
: fReAllocData(reallocData)
{
fBufSize = bufsiz;
fMode = mode;
Expand Down Expand Up @@ -172,7 +173,7 @@ void TBuffer::AutoExpand(Int_t size_needed)
/// is provided, a Fatal error will be issued if the Buffer attempts to
/// expand.

void TBuffer::SetBuffer(void *buf, UInt_t newsiz, Bool_t adopt, ReAllocCharFun_t reallocfunc)
void TBuffer::SetBuffer(void *buf, UInt_t newsiz, Bool_t adopt, ReAllocStateFun_t reallocfunc, void *reallocData)
{
if (fBuffer && TestBit(kIsOwner))
delete [] fBuffer;
Expand All @@ -193,7 +194,7 @@ void TBuffer::SetBuffer(void *buf, UInt_t newsiz, Bool_t adopt, ReAllocCharFun_t
}
fBufMax = fBuffer + fBufSize;

SetReAllocFunc( reallocfunc );
SetReAllocFunc( reallocfunc, reallocData );

if (buf && ( (fMode&kWrite)!=0 ) && fBufSize < 0) {
Expand( kMinimalSize );
Expand All @@ -215,16 +216,16 @@ void TBuffer::Expand(Int_t newsize, Bool_t copy)
newsize = l;
}
if ( (fMode&kWrite)!=0 ) {
fBuffer = fReAllocFunc(fBuffer, newsize+kExtraSpace,
fBuffer = fReAllocFunc(fReAllocData, fBuffer, newsize+kExtraSpace,
copy ? fBufSize+kExtraSpace : 0);
} else {
fBuffer = fReAllocFunc(fBuffer, newsize,
fBuffer = fReAllocFunc(fReAllocData, fBuffer, newsize,
copy ? fBufSize : 0);
}
if (fBuffer == 0) {
if (fReAllocFunc == TStorage::ReAllocChar) {
Fatal("Expand","Failed to expand the data buffer using TStorage::ReAllocChar.");
} else if (fReAllocFunc == R__NoReAllocChar) {
if (fReAllocFunc == TStorage::ReAllocState) {
Fatal("Expand","Failed to expand the data buffer using TStorage::ReAllocState.");
} else if (fReAllocFunc == R__NoReAllocState) {
Fatal("Expand","Failed to expand the data buffer because TBuffer does not own it and no custom memory reallocator was provided.");
} else {
Fatal("Expand","Failed to expand the data buffer using custom memory reallocator 0x%lx.", (Long_t)fReAllocFunc);
Expand Down Expand Up @@ -253,28 +254,70 @@ void TBuffer::SetParent(TObject *parent)
////////////////////////////////////////////////////////////////////////////////
/// Return the reallocation method currently used.

ReAllocCharFun_t TBuffer::GetReAllocFunc() const
ReAllocStateFun_t TBuffer::GetReAllocFunc() const
{
return fReAllocFunc;
}

////////////////////////////////////////////////////////////////////////////////
/// Return the reallocation state currently used.
void *TBuffer::GetReAllocData() const
{
return fReAllocData;
}

////////////////////////////////////////////////////////////////////////////////
/// Set which memory reallocation method to use. If reallocafunc is null,
/// reset it to the default value (TStorage::ReAlloc)
/// reset it to the default value (TStorage::ReAlloc).
//
// Also allows the user to provide a void* as state for the reallocation.

void TBuffer::SetReAllocFunc(ReAllocCharFun_t reallocfunc )
void TBuffer::SetReAllocFunc(ReAllocStateFun_t reallocfunc, void *reallocData)
{
if (reallocfunc) {
fReAllocFunc = reallocfunc;
} else {
if (TestBit(kIsOwner)) {
fReAllocFunc = TStorage::ReAllocChar;
fReAllocFunc = TStorage::ReAllocState;
} else {
fReAllocFunc = R__NoReAllocChar;
fReAllocFunc = R__NoReAllocState;
}
}
fReAllocData = reallocData;
}

char *R__ReAllocShared(void *obj_void, char *current, size_t new_size, size_t old_size)
{
TBuffer *owner_buffer = static_cast<TBuffer*>(obj_void);
if (current != owner_buffer->Buffer()) {
owner_buffer->Fatal("ReAllocShared", "Re-allocating a non-shared buffer as shared.");
}
owner_buffer->Expand(new_size, old_size); // If old_size is non-zero, then we are copying over the old memory.
return owner_buffer->Buffer();
}

////////////////////////////////////////////////////////////////////////////////
/// Share the underlying memory allocation with another buffer.
//
// This causes the passed TBuffer object to share our memory buffer. This is
// useful if two objects want to have their own view of the TBuffer state but
// see identical data.
//
// Internally, not only do both buffers get the same memory location but a
// resize done by the "slave" buffer updates the "owner" buffer (the opposite
// is not true!).
//
// This is most useful if the "slave" does all the writings and the "owner"
// only does reads.
//
/*
Bool_t TBuffer::SetSlaveBuffer(TBuffer &other)
{
this->fBuffer = other.SetReAllocFunc(R__ReAllocShared, this);
return true;
}
*/

////////////////////////////////////////////////////////////////////////////////
/// Set buffer in read mode.

Expand Down
5 changes: 5 additions & 0 deletions core/base/src/TStorage.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ char *TStorage::ReAllocChar(char *ovp, size_t size, size_t oldsize)
return vp;
}

char *TStorage::ReAllocState(void *, char*ovp, size_t size, size_t oldsize)
{
return TStorage::ReAllocChar(ovp, size, oldsize);
}

////////////////////////////////////////////////////////////////////////////////
/// Reallocate (i.e. resize) array of integers. Size and oldsize are
/// number of integers (not number of bytes).
Expand Down
2 changes: 1 addition & 1 deletion io/io/inc/TBufferFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class TBufferFile : public TBufferIO {

TBufferFile(TBuffer::EMode mode);
TBufferFile(TBuffer::EMode mode, Int_t bufsiz);
TBufferFile(TBuffer::EMode mode, Int_t bufsiz, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = 0);
TBufferFile(TBuffer::EMode mode, Int_t bufsiz, void *buf, Bool_t adopt = kTRUE, ReAllocStateFun_t reallocfunc = 0, void *reallocdata = nullptr);
virtual ~TBufferFile();

virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss);
Expand Down
2 changes: 1 addition & 1 deletion io/io/src/TBufferFile.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ TBufferFile::TBufferFile(TBuffer::EMode mode, Int_t bufsiz)
/// expand.

TBufferFile::TBufferFile(TBuffer::EMode mode, Int_t bufsiz, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc) :
TBufferIO(mode,bufsiz,buf,adopt,reallocfunc),
TBufferIO(mode,bufsiz,buf,adopt,reallocfunc,reallocdata),
fInfo(nullptr), fInfoStack()
{
}
Expand Down
5 changes: 3 additions & 2 deletions tree/tree/inc/TBranch.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,14 @@ class TBranch : public TNamed , public TAttFill {
void SetSkipZip(Bool_t skip = kTRUE) { fSkipZip = skip; }
void Init(const char *name, const char *leaflist, Int_t compress);

TBasket *GetFreshBasket();
TBasket *GetFreshBasket(TBuffer *user_buffer);
TBasket *GetFreshCluster();
Int_t WriteBasket(TBasket* basket, Int_t where) { return WriteBasketImpl(basket, where, nullptr); }

TString GetRealFileName() const;

private:
Int_t GetBasketAndFirst(TBasket*& basket, Long64_t& first, TBuffer* user_buffer);
Int_t FillEntryBuffer(TBasket* basket,TBuffer* buf, Int_t& lnew);
Int_t WriteBasketImpl(TBasket* basket, Int_t where, ROOT::Internal::TBranchIMTHelper *);
TBranch(const TBranch&) = delete; // not implemented
Expand All @@ -169,7 +170,7 @@ class TBranch : public TNamed , public TAttFill {
Int_t FlushOneBasket(UInt_t which);

virtual char *GetAddress() const {return fAddress;}
TBasket *GetBasket(Int_t basket);
TBasket *GetBasket(Int_t basket, TBuffer* user_buffer=nullptr);
Int_t *GetBasketBytes() const {return fBasketBytes;}
Long64_t *GetBasketEntry() const {return fBasketEntry;}
virtual Long64_t GetBasketSeek(Int_t basket) const;
Expand Down
Loading

0 comments on commit 0987896

Please sign in to comment.