I don’t observe this behaviour. Where do you see that? In Jive?
It seems like your managedAttributeList variable has not been initialized yet when you invoke managedAttributeList.size().
The code generated by POGO in get_device_property() will initialize it for you:
// Try to initialize ManagedAttributeList from class property
cl_prop = ds_class->get_class_property(dev_prop[++i].name);
if (cl_prop.is_empty()==false) cl_prop >> managedAttributeList;
else {
// Try to initialize ManagedAttributeList from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false) def_prop >> managedAttributeList;
}
// And try to extract ManagedAttributeList value from database
if (dev_prop[i].is_empty()==false) dev_prop[i] >> managedAttributeList;
If you put the code you are sharing at the beginning of the get_device_property() method in the protected section and if you add :
[quote=“Reynald”] JCM
With Jive, I see that the property seems updated, but I encounter 2 problems:
1) the property is not updated but rather concatenated
I don’t observe this behaviour. Where do you see that? In Jive?[/quote]
Yes, i see that with Jive…
[quote=“Reynald”]If you put the code you are sharing at the beginning of the get_device_property() method in the protected section and if you add :
cout << “ManagedAttributeList size :” << managedAttributeList.size() << endl;
at the end of get_device_property() method, you will see it is not empty.
this->get_db_device()->put_property(new_db_data);
does not update managedAttributeList variable. It simply updates the value of the property in the Tango Database. [/quote]
oops!
Yes thanks, you’re right for the size
The problem with writing the code at the start of the method is that the name of my file (user configuration) is also in a property.
so I have to read this other property first, read the file and then put its content in my ‘ManagedAttributeList’ property…
I managed to read my file and copy its content to the “ManagedAttributList” property.
stringstream fileContent;
ifstream fileNameList(MYFILE);
if (fileNameList)
{
// copy content file in the property
string ligne;
Tango:: DbDatum new_prop("ManagedAttributeList");
vector<string> prop_buffer;
while (getline(fileNameList,ligne))
prop_buffer.push_back(ligne);
new_prop << prop_buffer;
dev_prop.push_back(new_prop);
// call database and put values
get_db_device()->put_property(dev_prop);
fileNameList.close();
....
}
I see that with Jive, No concatenation
However Now, when I start my device server, and if the “ManagedAttributeList” property does not exist or is empty, I cannot update my managedAttributeList variable despite a callback from the database (i copied the code from the beginning of the get_device_property() method) :
if (fileNameList)
{
....
int i=0; // index of the property
// Call database and extract values
if (Tango::Util::instance()->_UseDb==true)
get_db_device()->get_property(dev_prop);
// get instance on AcqAttrManagerClass to get class property
Tango::DbDatum def_prop, cl_prop;
AcqAttrManagerClass *ds_class = (static_cast<AcqAttrManagerClass *>(get_device_class()));
// Try to initialize ManagedAttributeList from class property
cl_prop = ds_class->get_class_property(dev_prop[i].name);
if (cl_prop.is_empty()==false)
cl_prop >> managedAttributeList;
else
{
// Try to initialize ManagedAttributeList from default device value
def_prop = ds_class->get_default_device_property(dev_prop[i].name);
if (def_prop.is_empty()==false)
def_prop >> managedAttributeList;
}
// And try to extract ManagedAttributeList value from database
if (dev_prop[i].is_empty()==false)
dev_prop[i] >> managedAttributeList;
else
cout << "dev_prop is empty !!!" << endl; // EMPTY !!!
cout << "size dev_prop: " << dev_prop[i].size()<< endl; // equals to 0 !!!
cout << "size ManagedAttributeList: " << managedAttributeList.size() << endl; // equals to 0 !!!
}
Any idea, please? Is this the right way to modify a property? ?
I reproduced what you are describing in a simple device server and I saw the same behaviour as yours, indeed.
This is due to the fact that during the device server startup phase, an SQL stored procedure is executed on the database server to retrieve all the information related to this device server, including the properties.
All this information is put into a cache and this cache is used every time the device server tries to get one of the data which is present in the cache, like the device properties in your use case.
This cache is used only during the device server startup phase.
So if you try to read again the device property once the device server is fully started (admin device is exported), you will get the correct value for the property you have updated in the database.
For instance, in your use case, if you execute the Init command once the device server is already started, you will see that the behaviour is different and that you will get the correct value in managedAttributeList variable.
Thanks to Emmanuel Taurel for his explanation on the device server startup behaviour!
I went a little further by simplifying the code, and by displaying the contents of dev_prop at the start of the get_device_property () method and after the call to put_property (). What i get is surprising !!
FYI, I have 9 properties including that “ManagedAttributeList” declared 1st with Pogo, so at index i = 0
void AcqAttrManager::get_device_property()
{
/*----- PROTECTED REGION ID(AcqAttrManager::get_device_property_before) ENABLED START -----*/
// Initialize property data members
/*----- PROTECTED REGION END -----*/
// Read device properties from database.
Tango::DbData dev_prop;
dev_prop.push_back(Tango::DbDatum("ManagedAttributeList"));
...
...
...
}
I found that the size of dev_prop is incremented by 1 (equal to 10) after the call to put_property () … so a new index i = 9 !
So i update my managedAttributeList variable not with dev_prop[0] but rather with dev_prop[9].
/*----- PROTECTED REGION ID(AcqAttrManager::get_device_property_after) ENABLED START -----*/
// Check device property data members init
cout << "dev_prop size = " << dev_prop.size() << endl; // equals to 9 !!!
for (int i=0;i<dev_prop.size();i++)
cout << dev_prop[i].size() << endl;
ifstream fileNameList(fileManagedAttributeList);
if (fileNameList)
{
// copy content file in the property
string ligne;
Tango:: DbDatum new_prop("ManagedAttributeList");
vector<string> prop_buffer;
while (getline(fileNameList,ligne))//while not eof
prop_buffer.push_back(ligne);
new_prop << prop_buffer;
dev_prop.push_back(new_prop);
// call database and put values
get_db_device()->put_property(dev_prop);
//close file
fileNameList.close();
cout << "dev_prop size = " << dev_prop.size() << endl;// equals to 10 !!!
for (int i=0;i<dev_prop.size();i++)
cout << dev_prop[i].size() << endl;
// extract ManagedAttributeList value from database
if (dev_prop[dev_prop.size()-1].is_empty()==false)
dev_prop[dev_prop.size()-1] >> managedAttributeList;
else
cout << "dev_prop is empty !!!" << endl;
}
/*----- PROTECTED REGION END -----*/ // AcqAttrManager::get_device_property_after
}
Result:
now seems to work when the DS starts
BUT
at each ‘init’, the size of dev_prop is increased by 1 after the call to put_property (): goes from 9 to 10
if, with Jive, i delete the “ManagedAttributeList” property, or if it is empty, and if i restart the DS, the size of dev_prop is still equal to 9 (cache?) then incremented to 10.
There is a mystery that i don’t understand ;(
Suddenly, i wonder if i do not take a risk by doing this method to modify a property at the init.
dev_prop is initialized by POGO code and each property declared in Pogo is added to it. This is as simple as that.
With POGO it was defined that your Tango class supports 9 different properties, so POGO writes some code to handle them.
So it is initializing dev_prop with the list of property names the Tango class is interested in:
Your Tango class supports 9 properties, dev_prop size will be 9 after the code generated by Pogo.
This does not mean all your properties are defined in the database.
You should probably use another variable with a different name than dev_prop when you update the property.
This would bring less confusion and would avoid to write the other properties too into the database.