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.

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 :


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=“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 :slight_smile:

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 :slight_smile:
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? ?

Thanks.

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!

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

  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.

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);

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

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.