Finally, a real world use case for shared memory
For a very long time, I was fascinated by the idea of shared memory. It seemed to be the answer for all performance issues (at least database related), and I tried to find any suitable situation where I could apply (and learn about) shared memory. However, most of the times, the situation was easily fixed by turning table buffering on, or simply by creating an internal memory buffer, which would pretty much fix any performance issues and make it quite fast. Ok, the proposition of using shared memory to try and reduce replication of data in application memory was an interesting one, but not strong enough to make me use it where it would not have a noticeable impact on performance.
But alas, finally I came across a requirement where shared memory was the only, suitable solution for a significant performance issue. And the “issue” I found was in class /TMWFLOW/CL_CM_CONFIG in Solution Manager 7.2, method TRANSP_TRACK_CALCULATE_SINGLE. I’m not an expert, but apparently this retrieves information about the entire transportation routing for your landscape. At my company, we have a central development system feeding quite a few systems, each of them with multiple clients, and since we are talking about RFC connections, this was taking a lot of time. Exactly how much time? Well, roughly one minute. Each time a developer wanted to create a transport request, he/she had to wait one minute until it was finally available in the development system. All because the transport route was recreated each time. So finally, after a long time searching for a use case for shared memory, I thought… oh my, this would really be the perfect situation for shared memory. A landscape doesn’t change very often. I can store this information, for example, once a day, save it, and avoid this waiting for all the other requests during this day.
Creation of the shared memory object
The shared memory object was created based on Paul Hardy ‘s book “ABAP to the Future”, but a lot of adjustments had to be done because this is not the typical case of storing information which is coming from a database. So first we start with the root class. Obviously we need an attribute typed with the data that we want to save, and I added an attribute to store the date of last time it was updated.
Attributes of the root class
We basically need 2 methods. One to read the data, and one to store the data. When we read the data, we also check when it was last changed, and if it changed too long ago, we have to invalidate the shared memory object.
Method to read the data
Method to save the data
The broker class was generated like so.
Broker class generation
Notice that we are not selecting the “Transactional Area” option, as this does not represent a database table.
I’ll show you now how I coded the “BUILD” method in the root class, even though this normally is the last step of the show. The interesting part here, and different from the usual application for shared memory, is that we are not reading database information, so the “BUILD” method will, apparently, simply have the necessary steps for creation/instantiation of the shared memory object, but will not really load any data in it, as of yet. We can call the method to load the data independently, in our coding.
Using the shared memory object in the coding
So now our task is clear. When the method to “calculate” the transport track is called, we want to check if we already have the information saved in memory. If not, we want to let it calculate this information and store it at the end. So I basically used the implicit enhancement points at the beginning and end of methods to implement this. Here’s the coding at the top, to check if the information is already stored in memory.
Accessing the data in the memory object
As you can see, I had to use some “gimmick” exporting parameters to get some information on whether the information I wanted had been found or not. Looking at it now, I have the impression that it should be enough to check if there’s information in the variables, but if I didn’t do it that way there must be some obscure reason that I don’t remember at the moment. I remember that this was extremely sensitive with the “attach” and “detach” topics. For example, if you attach it to read but you try to write, or you attach it to write but you don’t try to write, it doesn’t like it much. And finally, how to insert the data, if it was not saved already.
Storing the information you want to save
And there you have it. This should be enough to help you implement a shared memory solution for a similar situation. Do you have something that is expensive to calculate, because it requires many RFC connections, or a lot of calculating power, do you need this result often, but is it ok to store this information daily or so? Well, maybe you can use exactly this solution for it.
Otherwise, do you have any constructive criticism you would like to add? Would you have solved it differently? Let me know!
Oh and how much time is it taking to create a transport request now? One minute the first time in the day, 1 second for the remaining times.
Great piece! I'm trying to send you a message on here but it seems I can only do that for those who follow me. Could you please follow my profile so I can get in touch?
Glad you enjoyed it.
We should be able to connect now, thank you.
I recall on time I had a problem that with a system with more than one application server, you had to have the service set up on each server. Is this still the case, or has this finally been fixed?
It’s actually data storage issue.. the data you store in the Shma is application server specific… for me, I was submitting a report asa background job and was reading the data from shma and suprised to see the data read failing.. because the background jobs were running in a different application server be default.. I did a work around for that.. but don't know how to solve the storage issue... 🙁
As per the latest documentation https://help.sap.com/doc/abapdocu_753_index_htm/7.53/en-US/abenmemory_organization.htm, shared memory is still application server specific.
Luckily, on the system where I am using this, there is only one application server (Solution Manager is not so heavily used), so that's not an issue. But even if it was, I don't think it would make a difference in this case. For each application server, the user would have to wait a long time the first time the function was called each day.
I've worked on many dev, test and productive instances with multiple application servers - ERP and BW. In your case, it's probably ok, but it's important to be aware - especially if the different app servers get out of sync with their buffers.
and what is the solution when we want to share something across all the application servers?
Don't use shared memory 🙂
I've used shared memory objects successfully to pass flat and tabular data structures between different sessions to avoid recreating them.
However, I've not been able to pass instances in the same way (on basis release 740). This may be because they are references and the instance itself is in another memory area. But there are a couple of blogs suggesting it is possible, without giving any detail.
Can anyone shed light on whether it is possible?