Thread: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

[HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahi Gurram
Date:
Hello everyone,

I'm building In-Memory index extension for Postgres, for which i'm trying to use DSA. But ended with some issues, as it is not allowing me to create DSA(Dynamic Shared Area) in _PG_init function.

Please refer my_PG_init code below:
void
_PG_init(void)
{
area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
area_handle = dsa_get_handle(area);
}


Because of this code, Postgres is not starting. Not even giving any error messages in pg logs. Hence, i'm totally clue less :(


Please let me know how to proceed. Your help is highly appreciated.


PS: Applied all the DSM related patches over Postgres 9.6.1 as per below thread and confirmed the same by running some test programs.

https://www.postgresql.org/message-id/flat/CAEepm%3D1z5WLuNoJ80PaCvz6EtG9dN0j-KuHcHtU6QEfcPP5-qA%40mail.gmail.com#CAEepm=1z5WLuNoJ80PaCvz6EtG9dN0j-KuHcHtU6QEfcPP5-qA@mail.gmail.com


Thanks & Best Regards,

- Mahi

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Michael Paquier
Date:
On Tue, May 23, 2017 at 6:42 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
> I'm building In-Memory index extension for Postgres, for which i'm trying to
> use DSA. But ended with some issues, as it is not allowing me to create
> DSA(Dynamic Shared Area) in _PG_init function.
>
> Please refer my_PG_init code below:
>>
>> void
>> _PG_init(void)
>> {
>> area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
>> area_handle = dsa_get_handle(area);
>> }
>
>
> Because of this code, Postgres is not starting. Not even giving any error
> messages in pg logs. Hence, i'm totally clue less :(

It seems to me that you are creating those too early. For example, for
a background worker process, DSA segments would likely be created in
the main process routine. Without understanding what you are trying to
achieve, it is hard to make a good answer. You could always use a
ramdisk, but that would be likely be a waste of memory as Postgres has
its own buffer pool, killing the performance gains of OS caching.
-- 
Michael



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahi Gurram
Date:
Hi Michael,

Thanks for your response.

All i'm building is In-Memory Index as an extension over Postgres.

Postgres Indexes will get Insert calls and Read calls from various processes(typically client/connection process - forked processes to postmaster process). Hence i have to maintain my In-Memory index in shared memory.

If i create DynamicSharedArea (DSA) in postmaster/main process, all these Client/Connection processes(In-Memory Index Processes)  need not attach to that DSA using area handle. Because these are forked processes to postmaster/Main process and hence they automatically gets attached.

Hence i'm trying to create DSA in _PG_init function as it is called by postmaster/main process.

Hope this is clear.

Thanks & Best Regards,
- Mahi
  

On Tue, May 23, 2017 at 5:30 PM, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, May 23, 2017 at 6:42 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
> I'm building In-Memory index extension for Postgres, for which i'm trying to
> use DSA. But ended with some issues, as it is not allowing me to create
> DSA(Dynamic Shared Area) in _PG_init function.
>
> Please refer my_PG_init code below:
>>
>> void
>> _PG_init(void)
>> {
>> area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
>> area_handle = dsa_get_handle(area);
>> }
>
>
> Because of this code, Postgres is not starting. Not even giving any error
> messages in pg logs. Hence, i'm totally clue less :(

It seems to me that you are creating those too early. For example, for
a background worker process, DSA segments would likely be created in
the main process routine. Without understanding what you are trying to
achieve, it is hard to make a good answer. You could always use a
ramdisk, but that would be likely be a waste of memory as Postgres has
its own buffer pool, killing the performance gains of OS caching.
--
Michael

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahi Gurram
Date:
Hi,

As Michael said, i'm creating DSA too early. Shared_Preload libraries are loading prior to memory related stuff. 

But i'm totally clueless how to solve my use case.

Please help me with any work around. 

Thanks & Best Regards,
- Mahi

On Tue, May 23, 2017 at 5:52 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
Hi Michael,

Thanks for your response.

All i'm building is In-Memory Index as an extension over Postgres.

Postgres Indexes will get Insert calls and Read calls from various processes(typically client/connection process - forked processes to postmaster process). Hence i have to maintain my In-Memory index in shared memory.

If i create DynamicSharedArea (DSA) in postmaster/main process, all these Client/Connection processes(In-Memory Index Processes)  need not attach to that DSA using area handle. Because these are forked processes to postmaster/Main process and hence they automatically gets attached.

Hence i'm trying to create DSA in _PG_init function as it is called by postmaster/main process.

Hope this is clear.

Thanks & Best Regards,
- Mahi
  

On Tue, May 23, 2017 at 5:30 PM, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, May 23, 2017 at 6:42 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
> I'm building In-Memory index extension for Postgres, for which i'm trying to
> use DSA. But ended with some issues, as it is not allowing me to create
> DSA(Dynamic Shared Area) in _PG_init function.
>
> Please refer my_PG_init code below:
>>
>> void
>> _PG_init(void)
>> {
>> area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
>> area_handle = dsa_get_handle(area);
>> }
>
>
> Because of this code, Postgres is not starting. Not even giving any error
> messages in pg logs. Hence, i'm totally clue less :(

It seems to me that you are creating those too early. For example, for
a background worker process, DSA segments would likely be created in
the main process routine. Without understanding what you are trying to
achieve, it is hard to make a good answer. You could always use a
ramdisk, but that would be likely be a waste of memory as Postgres has
its own buffer pool, killing the performance gains of OS caching.
--
Michael


Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahi Gurram
Date:
One solution that is striking me is....
1. I'll create one background worker and will initialise DSA in it.
2. If there are any callbacks available for client open/close connections, i'll attach/detach to the DSA in those callbacks.

But i'm not sure there are such callbacks available. If such callbacks exists in postgres and you guys know please help me out with that.

Thanks & Best Regards,
- Mahi

On Wed, May 24, 2017 at 11:32 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
Hi,

As Michael said, i'm creating DSA too early. Shared_Preload libraries are loading prior to memory related stuff. 

But i'm totally clueless how to solve my use case.

Please help me with any work around. 

Thanks & Best Regards,
- Mahi

On Tue, May 23, 2017 at 5:52 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
Hi Michael,

Thanks for your response.

All i'm building is In-Memory Index as an extension over Postgres.

Postgres Indexes will get Insert calls and Read calls from various processes(typically client/connection process - forked processes to postmaster process). Hence i have to maintain my In-Memory index in shared memory.

If i create DynamicSharedArea (DSA) in postmaster/main process, all these Client/Connection processes(In-Memory Index Processes)  need not attach to that DSA using area handle. Because these are forked processes to postmaster/Main process and hence they automatically gets attached.

Hence i'm trying to create DSA in _PG_init function as it is called by postmaster/main process.

Hope this is clear.

Thanks & Best Regards,
- Mahi
  

On Tue, May 23, 2017 at 5:30 PM, Michael Paquier <michael.paquier@gmail.com> wrote:
On Tue, May 23, 2017 at 6:42 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
> I'm building In-Memory index extension for Postgres, for which i'm trying to
> use DSA. But ended with some issues, as it is not allowing me to create
> DSA(Dynamic Shared Area) in _PG_init function.
>
> Please refer my_PG_init code below:
>>
>> void
>> _PG_init(void)
>> {
>> area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
>> area_handle = dsa_get_handle(area);
>> }
>
>
> Because of this code, Postgres is not starting. Not even giving any error
> messages in pg logs. Hence, i'm totally clue less :(

It seems to me that you are creating those too early. For example, for
a background worker process, DSA segments would likely be created in
the main process routine. Without understanding what you are trying to
achieve, it is hard to make a good answer. You could always use a
ramdisk, but that would be likely be a waste of memory as Postgres has
its own buffer pool, killing the performance gains of OS caching.
--
Michael



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Amit Kapila
Date:
On Wed, May 24, 2017 at 11:39 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
> One solution that is striking me is....
> 1. I'll create one background worker and will initialise DSA in it.
> 2. If there are any callbacks available for client open/close connections,
> i'll attach/detach to the DSA in those callbacks.
>
> But i'm not sure there are such callbacks available. If such callbacks
> exists in postgres and you guys know please help me out with that.
>

We do share DSA handle, planned statement, params etc from master
backend with workers.  See ExecInitParallelPlan that might help you in
your work.


-- 
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Thomas Munro
Date:
On Tue, May 23, 2017 at 10:42 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
> Hello everyone,
>
> I'm building In-Memory index extension for Postgres, for which i'm trying to
> use DSA. But ended with some issues, as it is not allowing me to create
> DSA(Dynamic Shared Area) in _PG_init function.
>
> Please refer my_PG_init code below:
>>
>> void
>> _PG_init(void)
>> {
>> area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
>> area_handle = dsa_get_handle(area);
>> }
>
>
> Because of this code, Postgres is not starting. Not even giving any error
> messages in pg logs. Hence, i'm totally clue less :(
>
>
> Please let me know how to proceed. Your help is highly appreciated.

Hi Mahi

If your plan is to write a preloaded library, then I think your
_PG_init() function needs to register a callback with
shmem_startup_hook.  See pgss_shmem_startup for an example.  You may
need to set up a piece of traditional named shared memory that
backends can use to find either (1) the handle for your DSA area or
(2) your DSA area itself (if you use the 'in place' constructor), and
also allocate and share a lock tranche number.

Another approach would be to create the DSA area on demand (ie the
first time you need it for your new index feature), if you don't want
to have to preload the library, but there is a small problem with
that, at least in theory.  You probably still need to use a small bit
of named traditional shmem for discovery purposes, and it's slightly
against the rules to do that when you haven't called
RequestAddinShmemSpace, and it's too late to do that.

-- 
Thomas Munro
http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahi Gurram
Date:
Hi Thomas,
 
If your plan is to write a preloaded library, then I think your
_PG_init() function needs to register a callback with
shmem_startup_hook.  See pgss_shmem_startup for an example.  You may
need to set up a piece of traditional named shared memory that
backends can use to find either (1) the handle for your DSA area or
(2) your DSA area itself (if you use the 'in place' constructor), and
also allocate and share a lock tranche number.

Followed the same as per your suggestion. Refer the code snippet below:

void
_PG_init(void){
RequestAddinShmemSpace(100000000);
        PreviousShmemHook = shmem_startup_hook;
       shmem_startup_hook = BufferShmemHook;
}
void BufferShmemHook(){
dsa_area *area;
dsa_pointer data_ptr;
        char *mem;
  area = dsa_create(my_tranche_id());
       data_ptr = dsa_allocate(area, 42);
       mem = (char *) dsa_get_address(area, data_ptr);
       if (mem != NULL){
           snprintf(mem, 42, "Hello world");
       }
        bool found;
shmemData = ShmemInitStruct("Mahi_Shared_Data",
  sizeof(shared_data),
  &found);
shmemData->shared_area = area;
shmemData->shared_area_handle = dsa_get_handle(area);
shmemData->shared_data_ptr = data_ptr;
        shmemData->head=NULL;
}

Wrote one UDF function, which is called by one of the client connection and that tries to use the same dsa. But unfortunately it is behaving strange.

First call to my UDF function is throwing segmentation fault and postgres is quitting and auto restarting. If i try calling the same UDF function again in new connection(after postgres restart) it is working fine.

Put some prints in postgres source code and found that dsa_allocate() is trying to use area->control(dsa_area_control object) which is pointing to wrong address but after restarting it is pointing to right address and hence it is working fine after restart.

I'm totally confused and stuck at this point. Please help me in solving this.

PS: It is working fine in Mac.. in only linux systems i'm facing this behaviour.
 
I have attached the zip of my extension code along with screenshot of the pgclient and log file with debug prints for better understanding.
*logfile is edited for providing some comments for better understanding.

Please help me in solving this.

Awaiting your response.

Thanks & Best Regards,
- Mahi


On Sat, May 27, 2017 at 7:53 PM, Thomas Munro <thomas.munro@enterprisedb.com> wrote:
On Tue, May 23, 2017 at 10:42 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
> Hello everyone,
>
> I'm building In-Memory index extension for Postgres, for which i'm trying to
> use DSA. But ended with some issues, as it is not allowing me to create
> DSA(Dynamic Shared Area) in _PG_init function.
>
> Please refer my_PG_init code below:
>>
>> void
>> _PG_init(void)
>> {
>> area = dsa_create(LWLockNewTrancheId(), "CustomIndex_DSA");
>> area_handle = dsa_get_handle(area);
>> }
>
>
> Because of this code, Postgres is not starting. Not even giving any error
> messages in pg logs. Hence, i'm totally clue less :(
>
>
> Please let me know how to proceed. Your help is highly appreciated.

Hi Mahi

If your plan is to write a preloaded library, then I think your
_PG_init() function needs to register a callback with
shmem_startup_hook.  See pgss_shmem_startup for an example.  You may
need to set up a piece of traditional named shared memory that
backends can use to find either (1) the handle for your DSA area or
(2) your DSA area itself (if you use the 'in place' constructor), and
also allocate and share a lock tranche number.

Another approach would be to create the DSA area on demand (ie the
first time you need it for your new index feature), if you don't want
to have to preload the library, but there is a small problem with
that, at least in theory.  You probably still need to use a small bit
of named traditional shmem for discovery purposes, and it's slightly
against the rules to do that when you haven't called
RequestAddinShmemSpace, and it's too late to do that.

--
Thomas Munro
http://www.enterprisedb.com

Attachment

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Thomas Munro
Date:
On Thu, Jun 15, 2017 at 6:32 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
> Followed the same as per your suggestion. Refer the code snippet below:
>
>> void
>> _PG_init(void){
>> RequestAddinShmemSpace(100000000);
>>         PreviousShmemHook = shmem_startup_hook;
>>        shmem_startup_hook = BufferShmemHook;
>> }
>> void BufferShmemHook(){
>> dsa_area *area;
>> dsa_pointer data_ptr;
>>         char *mem;
>>   area = dsa_create(my_tranche_id());
>>        data_ptr = dsa_allocate(area, 42);
>>        mem = (char *) dsa_get_address(area, data_ptr);
>>        if (mem != NULL){
>>            snprintf(mem, 42, "Hello world");
>>        }
>>         bool found;
>> shmemData = ShmemInitStruct("Mahi_Shared_Data",
>>   sizeof(shared_data),
>>   &found);
>> shmemData->shared_area = area;
>> shmemData->shared_area_handle = dsa_get_handle(area);
>> shmemData->shared_data_ptr = data_ptr;
>>         shmemData->head=NULL;
>> }
>
>
> Wrote one UDF function, which is called by one of the client connection and
> that tries to use the same dsa. But unfortunately it is behaving strange.
>
> First call to my UDF function is throwing segmentation fault and postgres is
> quitting and auto restarting. If i try calling the same UDF function again
> in new connection(after postgres restart) it is working fine.
>
> Put some prints in postgres source code and found that dsa_allocate() is
> trying to use area->control(dsa_area_control object) which is pointing to
> wrong address but after restarting it is pointing to right address and hence
> it is working fine after restart.
>
> I'm totally confused and stuck at this point. Please help me in solving
> this.
>
> PS: It is working fine in Mac.. in only linux systems i'm facing this
> behaviour.
>
> I have attached the zip of my extension code along with screenshot of the
> pgclient and log file with debug prints for better understanding.
> *logfile is edited for providing some comments for better understanding.
>
> Please help me in solving this.

Hi Mahi

I didn't try your code but I see a few different problems here.  Every
backend is creating a new dsa area, and then storing the pointer to it
in shared memory instead of attaching from other backends using the
handle, and there are synchronisation problems.  That isn't going to
work.  Here's what I think you might want to try:

1.  In BufferShmemHook, acquire and release AddinShmemInitLock while
initialising "Mahi_Shared_Data" (just like pgss_shmem_startup does),
because any number of backends could be starting up at the same time
and would step on each other's toes here.

2.  When ShmemInitStruct returns, check the value of 'found'.  If it's
false, then this backend is the very first one to attach to this bit
of (traditional) shmem.  So it should create the DSA area and store
the handle in the traditional shmem.  Because we hold
AddinShmemInitLock we know that no one else can be doing that at the
same time.   Before even trying to create the DSA area, you should
probably memset the whole thing to zero so that if you fail later, the
state isn't garbage.  If 'found' is true, then we know it's already
all set up (or zeroed out), so instead of creating the DSA area it
should attach to it using the published handle.

3.  Whether you are the backend that created it or a backend that
attached to it, I think you'll need to store the dsa_area in a global
variable for your UDFs to access.  Note that the dsa_area object will
be different in each backend: there is no point in storing that
address itself in shared memory, as you have it, as you certainly
can't use it in any other backend. In other words, each backend that
attached has its own dsa_area object that it can use to access the
common dynamic shared memory area.

4.  After creating, in this case I think you should call
dsa_pin(area), so that it doesn't go away when there are no backends
attached (ie because there are no backends running) (if I understand
correctly that you want this DSA area to last as long as the whole
cluster).

By the way, in _PG_init() where you have
RequestAddinShmemSpace(100000000) I think you want
RequestAddinShmemSpace(sizeof(shared_data)).

The key point is: only one backend should use LWLockNewTrancheId() and
dsa_create(), and then make the handle available to others; all the
other backends should use dsa_attach().  Then they'll all be attached
to the same dynamic shared memory area and can share data.

-- 
Thomas Munro
http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahi Gurram
Date:
Hi Thomas,

Thanks for your response and suggestions to change the code.

Now i have modified my code as per your suggestions. Now dsa_area pointer is not in shared memory, it is a global variable. Also, implemented all your code suggestions but unfortunately, no luck. Still facing the same behaviour. Refer the attachment for the modified code.

I have some doubts in your response. Please clarify.

I didn't try your code but I see a few different problems here.  Every
backend is creating a new dsa area, and then storing the pointer to it
in shared memory instead of attaching from other backends using the
handle, and there are synchronisation problems.  That isn't going to
work.  Here's what I think you might want to try:

Actually i'm not creating dsa_area for every backend. I'm creating it only once(in BufferShmemHook). 
* I put prints in my _PG_init and  BufferShmemHook  function to confirm the same.

As far as i know, _PG_Init of a shared_library/extension is called only once(during startup) by postmaster process, and all the postgres backends are forked/child process to postmaster process.

Since the backends are the postmaster's child processes and are created after the shared memory(dsa_area) has been created and attached, the backend/child process will receive the shared memory segment in its address space and as a result no shared memory operations like dsa_attach are required to access/use dsa data.

Please correct me, if i'm wrong.

3.  Whether you are the backend that created it or a backend that
attached to it, I think you'll need to store the dsa_area in a global
variable for your UDFs to access.  Note that the dsa_area object will
be different in each backend: there is no point in storing that
address itself in shared memory, as you have it, as you certainly
can't use it in any other backend. In other words, each backend that
attached has its own dsa_area object that it can use to access the
common dynamic shared memory area.

In case of forked processes, the OS actually does share the pages initially, because fork implements copy-on-write semantics. which means that provided none of the processes modifies the pages, they both points to same address and the same data.

Based on above theory, assume i have created dsa_area object in postmaster process(_PG_Init) and is a global variable, all the backends/forked processes can able to access/share the same dsa_area object and it's members.

Hence theoretically, the code should work with out any issues. But i'm sure why it is not working as expected :(

I tried debugging by putting prints, and observed the below things:
1. dsa_area_control address is different among postmaster process and backends.
2. After restarting, they seems to be same and hence it is working after that.

2017-06-16 18:08:50.798 IST [9195] LOG:  ++++ Inside Postmaster Process, after dsa_create() +++++
2017-06-16 18:08:50.798 IST [9195] LOG:  the address of dsa_area_control is 0x7f50ddaa6000
2017-06-16 18:08:50.798 IST [9195] LOG:  the dsa_area_handle is 1007561696
2017-06-16 18:11:01.904 IST [9224] LOG:  ++++ Inside UDF function in forked process +++++
2017-06-16 18:11:01.904 IST [9224] LOG:  the address of dsa_area_control is 0x1dac910
2017-06-16 18:11:01.904 IST [9224] LOG:  the dsa_area_handle is 0
2017-06-16 18:11:01.907 IST [9195] LOG:  server process (PID 9224) was terminated by signal 11: Segmentation fault
2017-06-16 18:11:01.907 IST [9195] DETAIL:  Failed process was running: select test_dsa_data_access(1);
2017-06-16 18:11:01.907 IST [9195] LOG:  terminating any other active server processes
2017-06-16 18:11:01.907 IST [9227] FATAL:  the database system is in recovery mode
2017-06-16 18:11:01.907 IST [9220] WARNING:  terminating connection because of crash of another server process
2017-06-16 18:11:01.907 IST [9220] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2017-06-16 18:11:01.907 IST [9220] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
2017-06-16 18:11:01.907 IST [9195] LOG:  all server processes terminated; reinitialising
2017-06-16 18:08:50.798 IST [9195] LOG:  ++++ Inside Postmaster Process, after dsa_create() +++++
2017-06-16 18:11:01.937 IST [9195] LOG:  the address of dsa_area_control is 0x7f50ddaa6000
2017-06-16 18:11:01.937 IST [9195] LOG:  the dsa_area_handle is 1833840303
2017-06-16 18:11:01.904 IST [9224] LOG:  ++++ Inside UDF function in forked process +++++
2017-06-16 18:12:24.247 IST [9239] LOG:  the address of dsa_area_control is 0x7f50ddaa6000
2017-06-16 18:12:24.247 IST [9239] LOG:  the dsa_area_handle is 1833840303

I may be wrong in my understanding, and i might be missing something :(

Please help me in sorting it out. Really appreciate for all your help :)

PS: In mac, It is working fine as expected. I'm facing this issue only in linux systems. I'm working over postgres 10.1 beta FYI.

Thanks & Best Regards,
- Mahi



On Thu, Jun 15, 2017 at 5:00 PM, Thomas Munro <thomas.munro@enterprisedb.com> wrote:
On Thu, Jun 15, 2017 at 6:32 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
> Followed the same as per your suggestion. Refer the code snippet below:
>
>> void
>> _PG_init(void){
>> RequestAddinShmemSpace(100000000);
>>         PreviousShmemHook = shmem_startup_hook;
>>        shmem_startup_hook = BufferShmemHook;
>> }
>> void BufferShmemHook(){
>> dsa_area *area;
>> dsa_pointer data_ptr;
>>         char *mem;
>>   area = dsa_create(my_tranche_id());
>>        data_ptr = dsa_allocate(area, 42);
>>        mem = (char *) dsa_get_address(area, data_ptr);
>>        if (mem != NULL){
>>            snprintf(mem, 42, "Hello world");
>>        }
>>         bool found;
>> shmemData = ShmemInitStruct("Mahi_Shared_Data",
>>   sizeof(shared_data),
>>   &found);
>> shmemData->shared_area = area;
>> shmemData->shared_area_handle = dsa_get_handle(area);
>> shmemData->shared_data_ptr = data_ptr;
>>         shmemData->head=NULL;
>> }
>
>
> Wrote one UDF function, which is called by one of the client connection and
> that tries to use the same dsa. But unfortunately it is behaving strange.
>
> First call to my UDF function is throwing segmentation fault and postgres is
> quitting and auto restarting. If i try calling the same UDF function again
> in new connection(after postgres restart) it is working fine.
>
> Put some prints in postgres source code and found that dsa_allocate() is
> trying to use area->control(dsa_area_control object) which is pointing to
> wrong address but after restarting it is pointing to right address and hence
> it is working fine after restart.
>
> I'm totally confused and stuck at this point. Please help me in solving
> this.
>
> PS: It is working fine in Mac.. in only linux systems i'm facing this
> behaviour.
>
> I have attached the zip of my extension code along with screenshot of the
> pgclient and log file with debug prints for better understanding.
> *logfile is edited for providing some comments for better understanding.
>
> Please help me in solving this.

Hi Mahi

I didn't try your code but I see a few different problems here.  Every
backend is creating a new dsa area, and then storing the pointer to it
in shared memory instead of attaching from other backends using the
handle, and there are synchronisation problems.  That isn't going to
work.  Here's what I think you might want to try:

1.  In BufferShmemHook, acquire and release AddinShmemInitLock while
initialising "Mahi_Shared_Data" (just like pgss_shmem_startup does),
because any number of backends could be starting up at the same time
and would step on each other's toes here.

2.  When ShmemInitStruct returns, check the value of 'found'.  If it's
false, then this backend is the very first one to attach to this bit
of (traditional) shmem.  So it should create the DSA area and store
the handle in the traditional shmem.  Because we hold
AddinShmemInitLock we know that no one else can be doing that at the
same time.   Before even trying to create the DSA area, you should
probably memset the whole thing to zero so that if you fail later, the
state isn't garbage.  If 'found' is true, then we know it's already
all set up (or zeroed out), so instead of creating the DSA area it
should attach to it using the published handle.

3.  Whether you are the backend that created it or a backend that
attached to it, I think you'll need to store the dsa_area in a global
variable for your UDFs to access.  Note that the dsa_area object will
be different in each backend: there is no point in storing that
address itself in shared memory, as you have it, as you certainly
can't use it in any other backend. In other words, each backend that
attached has its own dsa_area object that it can use to access the
common dynamic shared memory area.

4.  After creating, in this case I think you should call
dsa_pin(area), so that it doesn't go away when there are no backends
attached (ie because there are no backends running) (if I understand
correctly that you want this DSA area to last as long as the whole
cluster).

By the way, in _PG_init() where you have
RequestAddinShmemSpace(100000000) I think you want
RequestAddinShmemSpace(sizeof(shared_data)).

The key point is: only one backend should use LWLockNewTrancheId() and
dsa_create(), and then make the handle available to others; all the
other backends should use dsa_attach().  Then they'll all be attached
to the same dynamic shared memory area and can share data.

Attachment

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahendranath Gurram
Date:
Hi Thomas,

Any update on this?

Please let me know how can i proceed further.

Thanks & Best Regards,
-Mahi





---- On Fri, 16 Jun 2017 18:47:37 +0530 Mahi Gurram <teckymahi@gmail.com> wrote ----

Hi Thomas,

Thanks for your response and suggestions to change the code.

Now i have modified my code as per your suggestions. Now dsa_area pointer is not in shared memory, it is a global variable. Also, implemented all your code suggestions but unfortunately, no luck. Still facing the same behaviour. Refer the attachment for the modified code.

I have some doubts in your response. Please clarify.

I didn't try your code but I see a few different problems here.  Every
backend is creating a new dsa area, and then storing the pointer to it
in shared memory instead of attaching from other backends using the
handle, and there are synchronisation problems.  That isn't going to
work.  Here's what I think you might want to try:

Actually i'm not creating dsa_area for every backend. I'm creating it only once(in BufferShmemHook). 
* I put prints in my _PG_init and  BufferShmemHook  function to confirm the same.

As far as i know, _PG_Init of a shared_library/extension is called only once(during startup) by postmaster process, and all the postgres backends are forked/child process to postmaster process.

Since the backends are the postmaster's child processes and are created after the shared memory(dsa_area) has been created and attached, the backend/child process will receive the shared memory segment in its address space and as a result no shared memory operations like dsa_attach are required to access/use dsa data.

Please correct me, if i'm wrong.

3.  Whether you are the backend that created it or a backend that
attached to it, I think you'll need to store the dsa_area in a global
variable for your UDFs to access.  Note that the dsa_area object will
be different in each backend: there is no point in storing that
address itself in shared memory, as you have it, as you certainly
can't use it in any other backend. In other words, each backend that
attached has its own dsa_area object that it can use to access the
common dynamic shared memory area.

In case of forked processes, the OS actually does share the pages initially, because fork implements copy-on-write semantics. which means that provided none of the processes modifies the pages, they both points to same address and the same data.

Based on above theory, assume i have created dsa_area object in postmaster process(_PG_Init) and is a global variable, all the backends/forked processes can able to access/share the same dsa_area object and it's members.

Hence theoretically, the code should work with out any issues. But i'm sure why it is not working as expected :(

I tried debugging by putting prints, and observed the below things:
1. dsa_area_control address is different among postmaster process and backends.
2. After restarting, they seems to be same and hence it is working after that.

2017-06-16 18:08:50.798 IST [9195] LOG:  ++++ Inside Postmaster Process, after dsa_create() +++++
2017-06-16 18:08:50.798 IST [9195] LOG:  the address of dsa_area_control is 0x7f50ddaa6000
2017-06-16 18:08:50.798 IST [9195] LOG:  the dsa_area_handle is 1007561696
2017-06-16 18:11:01.904 IST [9224] LOG:  ++++ Inside UDF function in forked process +++++
2017-06-16 18:11:01.904 IST [9224] LOG:  the address of dsa_area_control is 0x1dac910
2017-06-16 18:11:01.904 IST [9224] LOG:  the dsa_area_handle is 0
2017-06-16 18:11:01.907 IST [9195] LOG:  server process (PID 9224) was terminated by signal 11: Segmentation fault
2017-06-16 18:11:01.907 IST [9195] DETAIL:  Failed process was running: select test_dsa_data_access(1);
2017-06-16 18:11:01.907 IST [9195] LOG:  terminating any other active server processes
2017-06-16 18:11:01.907 IST [9227] FATAL:  the database system is in recovery mode
2017-06-16 18:11:01.907 IST [9220] WARNING:  terminating connection because of crash of another server process
2017-06-16 18:11:01.907 IST [9220] DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2017-06-16 18:11:01.907 IST [9220] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
2017-06-16 18:11:01.907 IST [9195] LOG:  all server processes terminated; reinitialising
2017-06-16 18:08:50.798 IST [9195] LOG:  ++++ Inside Postmaster Process, after dsa_create() +++++
2017-06-16 18:11:01.937 IST [9195] LOG:  the address of dsa_area_control is 0x7f50ddaa6000
2017-06-16 18:11:01.937 IST [9195] LOG:  the dsa_area_handle is 1833840303
2017-06-16 18:11:01.904 IST [9224] LOG:  ++++ Inside UDF function in forked process +++++
2017-06-16 18:12:24.247 IST [9239] LOG:  the address of dsa_area_control is 0x7f50ddaa6000
2017-06-16 18:12:24.247 IST [9239] LOG:  the dsa_area_handle is 1833840303

I may be wrong in my understanding, and i might be missing something :(

Please help me in sorting it out. Really appreciate for all your help :)

PS: In mac, It is working fine as expected. I'm facing this issue only in linux systems. I'm working over postgres 10.1 beta FYI.

Thanks & Best Regards,
- Mahi



On Thu, Jun 15, 2017 at 5:00 PM, Thomas Munro <thomas.munro@enterprisedb.com> wrote:
On Thu, Jun 15, 2017 at 6:32 PM, Mahi Gurram <teckymahi@gmail.com> wrote:
> Followed the same as per your suggestion. Refer the code snippet below:
>
>> void
>> _PG_init(void){
>> RequestAddinShmemSpace(100000000);
>>         PreviousShmemHook = shmem_startup_hook;
>>        shmem_startup_hook = BufferShmemHook;
>> }
>> void BufferShmemHook(){
>> dsa_area *area;
>> dsa_pointer data_ptr;
>>         char *mem;
>>   area = dsa_create(my_tranche_id());
>>        data_ptr = dsa_allocate(area, 42);
>>        mem = (char *) dsa_get_address(area, data_ptr);
>>        if (mem != NULL){
>>            snprintf(mem, 42, "Hello world");
>>        }
>>         bool found;
>> shmemData = ShmemInitStruct("Mahi_Shared_Data",
>>   sizeof(shared_data),
>>   &found);
>> shmemData->shared_area = area;
>> shmemData->shared_area_handle = dsa_get_handle(area);
>> shmemData->shared_data_ptr = data_ptr;
>>         shmemData->head=NULL;
>> }
>
>
> Wrote one UDF function, which is called by one of the client connection and
> that tries to use the same dsa. But unfortunately it is behaving strange.
>
> First call to my UDF function is throwing segmentation fault and postgres is
> quitting and auto restarting. If i try calling the same UDF function again
> in new connection(after postgres restart) it is working fine.
>
> Put some prints in postgres source code and found that dsa_allocate() is
> trying to use area->control(dsa_area_control object) which is pointing to
> wrong address but after restarting it is pointing to right address and hence
> it is working fine after restart.
>
> I'm totally confused and stuck at this point. Please help me in solving
> this.
>
> PS: It is working fine in Mac.. in only linux systems i'm facing this
> behaviour.
>
> I have attached the zip of my extension code along with screenshot of the
> pgclient and log file with debug prints for better understanding.
> *logfile is edited for providing some comments for better understanding.
>
> Please help me in solving this.

Hi Mahi

I didn't try your code but I see a few different problems here.  Every
backend is creating a new dsa area, and then storing the pointer to it
in shared memory instead of attaching from other backends using the
handle, and there are synchronisation problems.  That isn't going to
work.  Here's what I think you might want to try:

1.  In BufferShmemHook, acquire and release AddinShmemInitLock while
initialising "Mahi_Shared_Data" (just like pgss_shmem_startup does),
because any number of backends could be starting up at the same time
and would step on each other's toes here.

2.  When ShmemInitStruct returns, check the value of 'found'.  If it's
false, then this backend is the very first one to attach to this bit
of (traditional) shmem.  So it should create the DSA area and store
the handle in the traditional shmem.  Because we hold
AddinShmemInitLock we know that no one else can be doing that at the
same time.   Before even trying to create the DSA area, you should
probably memset the whole thing to zero so that if you fail later, the
state isn't garbage.  If 'found' is true, then we know it's already
all set up (or zeroed out), so instead of creating the DSA area it
should attach to it using the published handle.

3.  Whether you are the backend that created it or a backend that
attached to it, I think you'll need to store the dsa_area in a global
variable for your UDFs to access.  Note that the dsa_area object will
be different in each backend: there is no point in storing that
address itself in shared memory, as you have it, as you certainly
can't use it in any other backend. In other words, each backend that
attached has its own dsa_area object that it can use to access the
common dynamic shared memory area.

4.  After creating, in this case I think you should call
dsa_pin(area), so that it doesn't go away when there are no backends
attached (ie because there are no backends running) (if I understand
correctly that you want this DSA area to last as long as the whole
cluster).

By the way, in _PG_init() where you have
RequestAddinShmemSpace(100000000) I think you want
RequestAddinShmemSpace(sizeof(shared_data)).

The key point is: only one backend should use LWLockNewTrancheId() and
dsa_create(), and then make the handle available to others; all the
other backends should use dsa_attach().  Then they'll all be attached
to the same dynamic shared memory area and can share data.



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Dilip Kumar
Date:
On Tue, Jun 20, 2017 at 3:16 PM, Mahendranath Gurram
<mahendranath@zohocorp.com> wrote:
> Hi Thomas,
>
> Any update on this?
>
> Please let me know how can i proceed further.
>
> Thanks & Best Regards,
> -Mahi

I did not see the code but just tested with your code.

1) Added test_dsa to shared preload library.
2) CREATE EXTENSION test_dsa;
3) executed test_dsa_data_access(1)

postgres=# select test_dsa_data_access(1);
2017-06-20 16:49:39.483 IST [9738] LOG:  Data read is ==> Hello world
2017-06-20 16:49:39.483 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world0
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world1
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world2
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world3
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world4
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world5
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world6
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world7
2017-06-20 16:49:39.484 IST [9907] LOG:  BackgroundWorker Shared
LinkedList Data read is ==> Hello world8
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world0
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world1
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world2
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world3
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world4
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world5
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world6
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world7
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world8
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world9
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world10
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world11
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world12
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world13
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world14
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world15
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world16
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world17
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world18
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG:  LinkedList Node Data read is
==> Hello world19
2017-06-20 16:49:39.485 IST [9738] STATEMENT:  select test_dsa_data_access(1);test_dsa_data_access
----------------------                   0


I don't see any segmentation fault. Is there some other step which I
have missed.

-- 
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahendranath Gurram
Date:
Hi Dilip,

Thanks for your response.

The steps you followed are right. May i know in which OS you tried? Mac/Linux.

Because,  In Mac, it is working fine. just as expected. But the problem(segmentation fault) i'm facing is with linux systems.

Thanks & Best Regards,
-Mahi
Teamwork divides the task and multiplies the success.





---- On Tue, 20 Jun 2017 16:47:24 +0530 Dilip Kumar <dilipbalaut@gmail.com> wrote ----

On Tue, Jun 20, 2017 at 3:16 PM, Mahendranath Gurram
> Hi Thomas,
>
> Any update on this?
>
> Please let me know how can i proceed further.
>
> Thanks & Best Regards,
> -Mahi

I did not see the code but just tested with your code.

1) Added test_dsa to shared preload library.
2) CREATE EXTENSION test_dsa;
3) executed test_dsa_data_access(1)

postgres=# select test_dsa_data_access(1);
2017-06-20 16:49:39.483 IST [9738] LOG: Data read is ==> Hello world
2017-06-20 16:49:39.483 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world0
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world1
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world2
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world3
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world4
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world5
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world6
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world7
2017-06-20 16:49:39.484 IST [9907] LOG: BackgroundWorker Shared
LinkedList Data read is ==> Hello world8
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world0
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world1
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world2
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world3
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world4
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world5
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world6
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world7
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world8
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world9
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world10
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world11
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world12
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world13
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world14
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world15
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world16
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world17
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world18
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
2017-06-20 16:49:39.485 IST [9738] LOG: LinkedList Node Data read is
==> Hello world19
2017-06-20 16:49:39.485 IST [9738] STATEMENT: select test_dsa_data_access(1);
test_dsa_data_access
----------------------
0


I don't see any segmentation fault. Is there some other step which I
have missed.

--
Regards,
Dilip Kumar


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Dilip Kumar
Date:
On Tue, Jun 20, 2017 at 6:48 PM, Mahendranath Gurram
<mahendranath@zohocorp.com> wrote:
> The steps you followed are right. May i know in which OS you tried?
> Mac/Linux.
>
> Because,  In Mac, it is working fine. just as expected. But the
> problem(segmentation fault) I'm facing is with linux systems.

Mine is Linux.

CentOS Linux release 7.2.1511


-- 
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Thomas Munro
Date:
On Sat, Jun 17, 2017 at 1:17 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
>> 3.  Whether you are the backend that created it or a backend that
>> attached to it, I think you'll need to store the dsa_area in a global
>> variable for your UDFs to access.  Note that the dsa_area object will
>> be different in each backend: there is no point in storing that
>> address itself in shared memory, as you have it, as you certainly
>> can't use it in any other backend. In other words, each backend that
>> attached has its own dsa_area object that it can use to access the
>> common dynamic shared memory area.
>
>
> In case of forked processes, the OS actually does share the pages initially,
> because fork implements copy-on-write semantics. which means that provided
> none of the processes modifies the pages, they both points to same address
> and the same data.
>
> Based on above theory, assume i have created dsa_area object in postmaster
> process(_PG_Init) and is a global variable, all the backends/forked
> processes can able to access/share the same dsa_area object and it's
> members.
>
> Hence theoretically, the code should work with out any issues. But i'm sure
> why it is not working as expected :(
>
> I tried debugging by putting prints, and observed the below things:
> 1. dsa_area_control address is different among postmaster process and
> backends.
> 2. After restarting, they seems to be same and hence it is working after
> that.

Postgres extensions can't rely on backends inheriting the postmaster's
memory map like this (other than the main shared memory areas which
the core code looks after).  For one thing, new backends aren't
created with fork() on all platforms (mainly Windows AFAIK, but also
any build with EXEC_BACKEND defined).  The next problem is that dsa.c
and dsm.c work with reference counts that will be wrong if you try to
use memory map inheritance like this.  Another problem is that the
postmaster isn't allowed to create DSM segment: if it's working for
you then I think you must be building with asserts disabled?

I'm not sure exactly why you're seeing the symptoms you're seeing
(working on one flavour of Unix and not another, and then working
after a crash-restart -- I guess it has something to do with
coincidences of mapped address).  That's simply not how DSA is
designed to be used: you need to create DSA areas in a non-postmaster
backend, and then attach explicitly from every other backend that
wants to access the area.  Each backend needs to get its own dsa_area
object (either by creating or attaching).

-- 
Thomas Munro
http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahendranath Gurram
Date:
Hi Thomas,

Thanks for taking time and explaining the things.
Postgres extensions can't rely on backends inheriting the postmaster's
memory map like this (other than the main shared memory areas which
the core code looks after). For one thing, new backends aren't
created with fork() on all platforms (mainly Windows AFAIK, but also
any build with EXEC_BACKEND defined). The next problem is that dsa.c
and dsm.c work with reference counts that will be wrong if you try to
use memory map inheritance like this. Another problem is that the
postmaster isn't allowed to create DSM segment: if it's working for
you then I think you must be building with asserts disabled?
Now I understood, i took wrong approach.
That's simply not how DSA is
designed to be used: you need to create DSA areas in a non-postmaster
backend, and then attach explicitly from every other backend that
wants to access the area. Each backend needs to get its own dsa_area
object (either by creating or attaching).
Initially i tried to design the same way.
I mean, i have created a background worker and created dsa in it.
I tried to attach/detach to the same dsa/dsm by all the backends(postgres clients/connections) during backend(client/connection) init/destroy.
I didn't find any triggers or callbacks during backend init/close to attach/detach the dsa/dsm.  Hence, i took this approach.
If postgres have any such triggers/callbacks available, please let me know, that is of great great help for me.

Anyways now i understood, i have taken a wrong approach to use dsa. I'll try to figure out any other way to build my in-memory index over postgres.

Once again thanks a lot for taking time to help me.

@Dilip thank you for your response :)

Thanks & Best Regards,
-Mahi
Teamwork divides the task and multiplies the success.





---- On Wed, 21 Jun 2017 04:26:45 +0530 Thomas Munro <thomas.munro@enterprisedb.com> wrote ----

On Sat, Jun 17, 2017 at 1:17 AM, Mahi Gurram <teckymahi@gmail.com> wrote:
>> 3. Whether you are the backend that created it or a backend that
>> attached to it, I think you'll need to store the dsa_area in a global
>> variable for your UDFs to access. Note that the dsa_area object will
>> be different in each backend: there is no point in storing that
>> address itself in shared memory, as you have it, as you certainly
>> can't use it in any other backend. In other words, each backend that
>> attached has its own dsa_area object that it can use to access the
>> common dynamic shared memory area.
>
>
> In case of forked processes, the OS actually does share the pages initially,
> because fork implements copy-on-write semantics. which means that provided
> none of the processes modifies the pages, they both points to same address
> and the same data.
>
> Based on above theory, assume i have created dsa_area object in postmaster
> process(_PG_Init) and is a global variable, all the backends/forked
> processes can able to access/share the same dsa_area object and it's
> members.
>
> Hence theoretically, the code should work with out any issues. But i'm sure
> why it is not working as expected :(
>
> I tried debugging by putting prints, and observed the below things:
> 1. dsa_area_control address is different among postmaster process and
> backends.
> 2. After restarting, they seems to be same and hence it is working after
> that.

Postgres extensions can't rely on backends inheriting the postmaster's
memory map like this (other than the main shared memory areas which
the core code looks after). For one thing, new backends aren't
created with fork() on all platforms (mainly Windows AFAIK, but also
any build with EXEC_BACKEND defined). The next problem is that dsa.c
and dsm.c work with reference counts that will be wrong if you try to
use memory map inheritance like this. Another problem is that the
postmaster isn't allowed to create DSM segment: if it's working for
you then I think you must be building with asserts disabled?

I'm not sure exactly why you're seeing the symptoms you're seeing
(working on one flavour of Unix and not another, and then working
after a crash-restart -- I guess it has something to do with
coincidences of mapped address). That's simply not how DSA is
designed to be used: you need to create DSA areas in a non-postmaster
backend, and then attach explicitly from every other backend that
wants to access the area. Each backend needs to get its own dsa_area
object (either by creating or attaching).

--
Thomas Munro


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Thomas Munro
Date:
On Wed, Jun 21, 2017 at 5:27 PM, Mahendranath Gurram
<mahendranath@zohocorp.com> wrote:
> Initially i tried to design the same way.
> I mean, i have created a background worker and created dsa in it.
> I tried to attach/detach to the same dsa/dsm by all the backends(postgres
> clients/connections) during backend(client/connection) init/destroy.
> I didn't find any triggers or callbacks during backend init/close to
> attach/detach the dsa/dsm.  Hence, i took this approach.
> If postgres have any such triggers/callbacks available, please let me know,
> that is of great great help for me.
>
> Anyways now i understood, i have taken a wrong approach to use dsa. I'll try
> to figure out any other way to build my in-memory index over postgres.

You definitely can use DSA or DSM for this.  As a matter of fact
shared in-memory indexing was one of our target use cases.  You just
have to jump through a few hoops...  Here's one approach:

1.  Use _PG_init and the shmem hook to reserve a little bit of
traditional shared memory and initialise it to zero.  This will be
used just to share the DSA handle, but you can't actually create the
DSA area in postmaster.  In other words, this little bit of shared
memory is for "discovery", since it can be looked up by name from any
backend.

2.  In each backend that wants to use your new in-memory index system,
you need to be able to attach or create the DSA area on-demand.
Perhaps you could have a get_my_shared_state() function (insert better
name) that uses a static local variable to hold a pointer to some
state.  If it's NULL, you know you need to create the state.  That
should happen only once in each backend, the first time through the
function.  In that case you need to create or attach to the DSA area
as appropriate, which you should wrap in
LWLockAcquire(AddinShmemInitLock,
LW_EXCLUSIVE)/LWLockRelease(AddinShmemInitLock) to serialise the code
block.  First, look up the bit of traditional shared memory to see if
there is a DSA handle published in it already.  If there is you can
attach.  If there isn't, you are the first so you need to create, and
publish the handle for others to attach to.  Remember whatever state
you need to remember, such as the dsa_area, in static local variables
so that all future calls to get_my_shared_state() in that backend will
be fast.

If you do it that way, then it doesn't matter whether it's background
workers or foreground processes: whoever is first to call
get_my_shared_state() will create the DSA area (and whatever else you
want to do to set things up).  All later callers will attach to the
existing one.  But each backend only ever has to enter the locked code
path once, and from then on it's fast and there's no lock.

Note that you could skip step 1 and not require a preload shared
library.  Then you'd be creating the 'discovery' shmem region on
demand too!  Just make sure it's in the locked region and pay
attention to the 'found' output variable to decide whether you're
first and need to initialise it.  Skipping step 1 is very slightly
against the rules though, because you'd be using a little piece of
memory that you didn't tell the postmaster to reserve space for with
RequestAddinShmemSpace.  It's very small though, so you might decide
that's OK...

If you don't like the idea of creating that shmem stuff on demand, you
could look into using session_preload_libraries as a way to get a
'backend init' hook.

-- 
Thomas Munro
http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahendranath Gurram
Date:
Hi Thomas,

I like the whole idea.
In fact, i understood this in your very first response itself.
Only thing is every time i have to check for dsa_attached or not. I mean get_my_shared_state() is NULL or not.
To avoid that check, i tried creating it in _PG_Init(postmaster process itself) all that stuff :(

Anyways the solution you suggested will work for me. I'll live with that if check.

Thanks a lot for all your help.

I'll implement this and update the status.

Cheers :)

Thanks & Best Regards,
-Mahi
Teamwork divides the task and multiplies the success.





---- On Wed, 21 Jun 2017 12:02:30 +0530 Thomas Munro <thomas.munro@enterprisedb.com> wrote ----

On Wed, Jun 21, 2017 at 5:27 PM, Mahendranath Gurram
> Initially i tried to design the same way.
> I mean, i have created a background worker and created dsa in it.
> I tried to attach/detach to the same dsa/dsm by all the backends(postgres
> clients/connections) during backend(client/connection) init/destroy.
> I didn't find any triggers or callbacks during backend init/close to
> attach/detach the dsa/dsm. Hence, i took this approach.
> If postgres have any such triggers/callbacks available, please let me know,
> that is of great great help for me.
>
> Anyways now i understood, i have taken a wrong approach to use dsa. I'll try
> to figure out any other way to build my in-memory index over postgres.

You definitely can use DSA or DSM for this. As a matter of fact
shared in-memory indexing was one of our target use cases. You just
have to jump through a few hoops... Here's one approach:

1. Use _PG_init and the shmem hook to reserve a little bit of
traditional shared memory and initialise it to zero. This will be
used just to share the DSA handle, but you can't actually create the
DSA area in postmaster. In other words, this little bit of shared
memory is for "discovery", since it can be looked up by name from any
backend.

2. In each backend that wants to use your new in-memory index system,
you need to be able to attach or create the DSA area on-demand.
Perhaps you could have a get_my_shared_state() function (insert better
name) that uses a static local variable to hold a pointer to some
state. If it's NULL, you know you need to create the state. That
should happen only once in each backend, the first time through the
function. In that case you need to create or attach to the DSA area
as appropriate, which you should wrap in
LWLockAcquire(AddinShmemInitLock,
LW_EXCLUSIVE)/LWLockRelease(AddinShmemInitLock) to serialise the code
block. First, look up the bit of traditional shared memory to see if
there is a DSA handle published in it already. If there is you can
attach. If there isn't, you are the first so you need to create, and
publish the handle for others to attach to. Remember whatever state
you need to remember, such as the dsa_area, in static local variables
so that all future calls to get_my_shared_state() in that backend will
be fast.

If you do it that way, then it doesn't matter whether it's background
workers or foreground processes: whoever is first to call
get_my_shared_state() will create the DSA area (and whatever else you
want to do to set things up). All later callers will attach to the
existing one. But each backend only ever has to enter the locked code
path once, and from then on it's fast and there's no lock.

Note that you could skip step 1 and not require a preload shared
library. Then you'd be creating the 'discovery' shmem region on
demand too! Just make sure it's in the locked region and pay
attention to the 'found' output variable to decide whether you're
first and need to initialise it. Skipping step 1 is very slightly
against the rules though, because you'd be using a little piece of
memory that you didn't tell the postmaster to reserve space for with
RequestAddinShmemSpace. It's very small though, so you might decide
that's OK...

If you don't like the idea of creating that shmem stuff on demand, you
could look into using session_preload_libraries as a way to get a
'backend init' hook.

--
Thomas Munro


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahendranath Gurram
Date:
Hi Thomas,

I'm implementing the In-Memory index as per your suggestion. So far it's good.

As of now, only one thing is unclear for me. How could i detach the dsa(dsa_detach() call) in backend (typically during backend quit).

Of-course when process quits, all it's associated memory will be cleared/destroyed. But we have to decrement dsm reference counts as part of the potgres dsa framework implementation. which can not be done now.

I have gone through the postgres source code. But unfortunately, i couldn't see anything in handling this case.

Thanks a lot.

Best Regards,
-Mahi
Teamwork divides the task and multiplies the success.




---- On Wed, 21 Jun 2017 13:13:28 +0530 Mahendranath Gurram <mahendranath@zohocorp.com> wrote ----

Hi Thomas,

I like the whole idea.
In fact, i understood this in your very first response itself.
Only thing is every time i have to check for dsa_attached or not. I mean get_my_shared_state() is NULL or not.
To avoid that check, i tried creating it in _PG_Init(postmaster process itself) all that stuff :(

Anyways the solution you suggested will work for me. I'll live with that if check.

Thanks a lot for all your help.

I'll implement this and update the status.

Cheers :)

Thanks & Best Regards,
-Mahi
Teamwork divides the task and multiplies the success.




---- On Wed, 21 Jun 2017 12:02:30 +0530 Thomas Munro <thomas.munro@enterprisedb.com> wrote ----



On Wed, Jun 21, 2017 at 5:27 PM, Mahendranath Gurram
> Initially i tried to design the same way.
> I mean, i have created a background worker and created dsa in it.
> I tried to attach/detach to the same dsa/dsm by all the backends(postgres
> clients/connections) during backend(client/connection) init/destroy.
> I didn't find any triggers or callbacks during backend init/close to
> attach/detach the dsa/dsm. Hence, i took this approach.
> If postgres have any such triggers/callbacks available, please let me know,
> that is of great great help for me.
>
> Anyways now i understood, i have taken a wrong approach to use dsa. I'll try
> to figure out any other way to build my in-memory index over postgres.

You definitely can use DSA or DSM for this. As a matter of fact
shared in-memory indexing was one of our target use cases. You just
have to jump through a few hoops... Here's one approach:

1. Use _PG_init and the shmem hook to reserve a little bit of
traditional shared memory and initialise it to zero. This will be
used just to share the DSA handle, but you can't actually create the
DSA area in postmaster. In other words, this little bit of shared
memory is for "discovery", since it can be looked up by name from any
backend.

2. In each backend that wants to use your new in-memory index system,
you need to be able to attach or create the DSA area on-demand.
Perhaps you could have a get_my_shared_state() function (insert better
name) that uses a static local variable to hold a pointer to some
state. If it's NULL, you know you need to create the state. That
should happen only once in each backend, the first time through the
function. In that case you need to create or attach to the DSA area
as appropriate, which you should wrap in
LWLockAcquire(AddinShmemInitLock,
LW_EXCLUSIVE)/LWLockRelease(AddinShmemInitLock) to serialise the code
block. First, look up the bit of traditional shared memory to see if
there is a DSA handle published in it already. If there is you can
attach. If there isn't, you are the first so you need to create, and
publish the handle for others to attach to. Remember whatever state
you need to remember, such as the dsa_area, in static local variables
so that all future calls to get_my_shared_state() in that backend will
be fast.

If you do it that way, then it doesn't matter whether it's background
workers or foreground processes: whoever is first to call
get_my_shared_state() will create the DSA area (and whatever else you
want to do to set things up). All later callers will attach to the
existing one. But each backend only ever has to enter the locked code
path once, and from then on it's fast and there's no lock.

Note that you could skip step 1 and not require a preload shared
library. Then you'd be creating the 'discovery' shmem region on
demand too! Just make sure it's in the locked region and pay
attention to the 'found' output variable to decide whether you're
first and need to initialise it. Skipping step 1 is very slightly
against the rules though, because you'd be using a little piece of
memory that you didn't tell the postmaster to reserve space for with
RequestAddinShmemSpace. It's very small though, so you might decide
that's OK...

If you don't like the idea of creating that shmem stuff on demand, you
could look into using session_preload_libraries as a way to get a
'backend init' hook.

--
Thomas Munro


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Thomas Munro
Date:
On Thu, Jun 22, 2017 at 10:59 PM, Mahendranath Gurram
<mahendranath@zohocorp.com> wrote:
> I'm implementing the In-Memory index as per your suggestion. So far it's
> good.

Great news.

> As of now, only one thing is unclear for me. How could i detach the
> dsa(dsa_detach() call) in backend (typically during backend quit).
>
> Of-course when process quits, all it's associated memory will be
> cleared/destroyed. But we have to decrement dsm reference counts as part of
> the potgres dsa framework implementation. which can not be done now.
>
> I have gone through the postgres source code. But unfortunately, i couldn't
> see anything in handling this case.

When you create or attach to a DSA area, a detach callback is
automatically registered on the control segment (or containing
segment, for an in-place DSA area).  See the code like this in dsa.c:
       /* Clean up when the control segment detaches. */       on_dsm_detach(segment,
&dsa_on_dsm_detach_release_in_place,

PointerGetDatum(dsm_segment_address(segment)));

So the reference counting is automatically looked after and you don't
need to do anything.  There are four possibilities: (1) you explicitly
detach from the area, (2) the ResourceManager active when you created
or attached goes out of scope, detaching you automatically (you
probably want to disable that with dsa_pin_mapping(area)), (3) your
backend exits normally and it's automatically detached (4) you crash
and the postmaster restarts the whole cluster on the basis that shared
memory could be arbitrarily corrupted.

Note that if you call dsa_pin(area) after creating the DSA area the
reference count cannot reach zero until you either call
dsa_unpin(area) or the cluster exits.  That's the right thing to do
for a case where backends might come and go and it's possible for no
one to be attached for periods of time, but you want the DSA area to
continue to exist.  I think that's probably what you need for a
DSA-backed in-memory index.

-- 
Thomas Munro
http://www.enterprisedb.com



Re: [HACKERS] Regarding Postgres Dynamic Shared Memory (DSA)

From
Mahendranath Gurram
Date:
Hi Thomas,

When you create or attach to a DSA area, a detach callback is
automatically registered on the control segment (or containing
segment, for an in-place DSA area). See the code like this in dsa.c:

/* Clean up when the control segment detaches. */
on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,

PointerGetDatum(dsm_segment_address(segment)));

So the reference counting is automatically looked after and you don't
need to do anything. There are four possibilities: (1) you explicitly
detach from the area, (2) the ResourceManager active when you created
or attached goes out of scope, detaching you automatically (you
probably want to disable that with dsa_pin_mapping(area)), (3) your
backend exits normally and it's automatically detached (4) you crash
and the postmaster restarts the whole cluster on the basis that shared
memory could be arbitrarily corrupted.
The third possibility is our use case. We want the dsa_area to be alive through out the lifetime of the cluster and we want each backend to hold the attached dsa through out the lifetime of the backend irrespective of ResourceManager scope.

Hence we are calling dsa_pin(area) after dsa_create() and dsa_pin_mapping(area) after dsa_create() and dsa_attach().
DSA implementation in autovacuum.c helped me in understanding these concepts :)

So in my case, i could safely assume that postgres will automatically takes care of dsa detaching and reference count decrements during backend exit.

It's so nice of you, taking time and explaining and helping to solve the use cases.

Best Regards,
-Mahi
Teamwork divides the task and multiplies the success.




---- On Thu, 22 Jun 2017 17:08:01 +0530 Thomas Munro <thomas.munro@enterprisedb.com> wrote ----

On Thu, Jun 22, 2017 at 10:59 PM, Mahendranath Gurram
> I'm implementing the In-Memory index as per your suggestion. So far it's
> good.

Great news.

> As of now, only one thing is unclear for me. How could i detach the
> dsa(dsa_detach() call) in backend (typically during backend quit).
>
> Of-course when process quits, all it's associated memory will be
> cleared/destroyed. But we have to decrement dsm reference counts as part of
> the potgres dsa framework implementation. which can not be done now.
>
> I have gone through the postgres source code. But unfortunately, i couldn't
> see anything in handling this case.

When you create or attach to a DSA area, a detach callback is
automatically registered on the control segment (or containing
segment, for an in-place DSA area). See the code like this in dsa.c:

/* Clean up when the control segment detaches. */
on_dsm_detach(segment, &dsa_on_dsm_detach_release_in_place,

PointerGetDatum(dsm_segment_address(segment)));

So the reference counting is automatically looked after and you don't
need to do anything. There are four possibilities: (1) you explicitly
detach from the area, (2) the ResourceManager active when you created
or attached goes out of scope, detaching you automatically (you
probably want to disable that with dsa_pin_mapping(area)), (3) your
backend exits normally and it's automatically detached (4) you crash
and the postmaster restarts the whole cluster on the basis that shared
memory could be arbitrarily corrupted.

Note that if you call dsa_pin(area) after creating the DSA area the
reference count cannot reach zero until you either call
dsa_unpin(area) or the cluster exits. That's the right thing to do
for a case where backends might come and go and it's possible for no
one to be attached for periods of time, but you want the DSA area to
continue to exist. I think that's probably what you need for a
DSA-backed in-memory index.

--
Thomas Munro


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription: