update a device property at init_device()

Hi,

I would like to copy, at init, the content of a configuration file (many lines) into a property.

Here is the code extracted from the get_device_property() method.


stringstream fileContent;

// read file
ifstream fileNameList(MY_FILE);
if (fileNameList)
{
fileContent << fileNameList.rdbuf();
fileNameList.close();
cout << "size: " << fileContent.str().size() << endl;
string buffer=fileContent.str();
cout << buffer << endl;

// copy property
Tango:: DbDatum new_prop("ManagedAttributeList");
new_prop << buffer;
Tango:: DbData new_db_data;
new_db_data.push_back(new_prop);
this->get_db_device()->put_property(new_db_data);

cout << "ManagedAttributeList size :" << managedAttributeList.size() << endl; // equals 0 !!
}



File content is good and buffer for Db also.
With Jive, I see that the property seems updated, but I encounter 2 problems:
1) the property is not updated but rather concatenated
2) the size of the property is equal to 0 despite as many lines as in the file

Anyone have an explanation?
How do I overwrite the property?
Thank you.
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?

JCM
2) the size of the property is equal to 0 despite as many lines as in the file

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.name);
if (def_prop.is_empty()==false) def_prop >> managedAttributeList;
}
// And try to extract ManagedAttributeList value from database
if (dev_prop.is_empty()==false) dev_prop >> 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 :

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.
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
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?

Yes, i see that with Jive…
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.
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.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.name);
if (def_prop.is_empty()==false)
def_prop >> managedAttributeList;
}
// And try to extract ManagedAttributeList value from database
if (dev_prop.is_empty()==false)
dev_prop >> managedAttributeList;
else
cout << "dev_prop is empty !!!" << endl; // EMPTY !!!

cout << "size dev_prop: " << dev_prop.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? ?

Thanks.
Edited 2 weeks ago
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!
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
Thanks for the information.

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.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.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:

1) now seems to work when the DS starts
BUT
2) at each 'init', the size of dev_prop is increased by 1 after the call to put_property (): goes from 9 to 10
3) 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.

Is there any other way?

Thanks again.
JCM
I found that the size of dev_prop is incremented by 1 (equal to 10) after the call to put_property ()

You are adding an element to dev_prop in your code, so it is normal that the size is incremented by 1:

new_prop << prop_buffer;
dev_prop.push_back(new_prop);


JCM
2) at each 'init', the size of dev_prop is increased by 1 after the call to put_property (): goes from 9 to 10

As I just wrote, this is expected with your code.

JCM
3) 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.

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.


// Read device properties from database.
Tango::DbData dev_prop;
dev_prop.push_back(Tango::DbDatum("ManagedAttributeList"));





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.
Rosenberg's Law: Software is easy to make, except when you want it to do something new.
Corollary: The only software that's worth making is software that does something new.
 
Register or login to create to post a reply.