diff options
author | Justin Clark-Casey (justincc) | 2011-09-23 02:59:33 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2011-09-23 02:59:33 +0100 |
commit | c8304b7f84b1a8d9fb978cae510f684e36419deb (patch) | |
tree | 9b450813d8023df7daf54fd2ee2b8cd19f58eb94 /OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs | |
parent | Merge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff) | |
download | opensim-SC_OLD-c8304b7f84b1a8d9fb978cae510f684e36419deb.zip opensim-SC_OLD-c8304b7f84b1a8d9fb978cae510f684e36419deb.tar.gz opensim-SC_OLD-c8304b7f84b1a8d9fb978cae510f684e36419deb.tar.bz2 opensim-SC_OLD-c8304b7f84b1a8d9fb978cae510f684e36419deb.tar.xz |
Fix avatar parameter updating for viewer 3 and maybe 2.
When a slider parameter is changed, the viewer uploads a new shape (or other asset) and the item is updated to point to it.
Viewer 1 uploaded the data in the initial request itself, so the asset references was almost always correctly updated.
However, viewer 3/2 always uploads data in a subsequent xfer, which exposed a race condition where the viewer would make the item update before the asset had uploaded.
This commit shuffles the order of operations to avoid this race, the item is updated with the new asset id instead of the old one while the upload was still taking place.
A second race had to be fixed where avatar appearance would also be updated with the old asset id rather than the new one.
This was fixed by updating the avatar appearance ids when the appearance was actually saved, rather than when the wearables update was made.
Diffstat (limited to 'OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs | 127 |
1 files changed, 105 insertions, 22 deletions
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index a7929ba..ec4dfd0 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs | |||
@@ -40,11 +40,21 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
40 | { | 40 | { |
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
42 | 42 | ||
43 | /// <summary> | ||
44 | /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we | ||
45 | /// are performing a delayed update. | ||
46 | /// </summary> | ||
47 | AgentAssetTransactions m_transactions; | ||
48 | |||
43 | private AssetBase m_asset; | 49 | private AssetBase m_asset; |
44 | private UUID InventFolder = UUID.Zero; | 50 | private UUID InventFolder = UUID.Zero; |
45 | private sbyte invType = 0; | 51 | private sbyte invType = 0; |
52 | |||
46 | private bool m_createItem = false; | 53 | private bool m_createItem = false; |
47 | private uint m_createItemCallback = 0; | 54 | private uint m_createItemCallback = 0; |
55 | private bool m_updateItem = false; | ||
56 | private InventoryItemBase m_updateItemData; | ||
57 | |||
48 | private string m_description = String.Empty; | 58 | private string m_description = String.Empty; |
49 | private bool m_dumpAssetToFile; | 59 | private bool m_dumpAssetToFile; |
50 | private bool m_finished = false; | 60 | private bool m_finished = false; |
@@ -58,9 +68,11 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
58 | public ulong XferID; | 68 | public ulong XferID; |
59 | private Scene m_Scene; | 69 | private Scene m_Scene; |
60 | 70 | ||
61 | public AssetXferUploader(Scene scene, bool dumpAssetToFile) | 71 | public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile) |
62 | { | 72 | { |
73 | m_transactions = transactions; | ||
63 | m_Scene = scene; | 74 | m_Scene = scene; |
75 | m_asset = new AssetBase() { FullID = assetID }; | ||
64 | m_dumpAssetToFile = dumpAssetToFile; | 76 | m_dumpAssetToFile = dumpAssetToFile; |
65 | } | 77 | } |
66 | 78 | ||
@@ -73,6 +85,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
73 | /// <returns>True if the transfer is complete, false otherwise or if the xferID was not valid</returns> | 85 | /// <returns>True if the transfer is complete, false otherwise or if the xferID was not valid</returns> |
74 | public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data) | 86 | public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data) |
75 | { | 87 | { |
88 | // m_log.DebugFormat( | ||
89 | // "[ASSET XFER UPLOADER]: Received packet {0} for xfer {1} (data length {2})", | ||
90 | // packetID, xferID, data.Length); | ||
91 | |||
76 | if (XferID == xferID) | 92 | if (XferID == xferID) |
77 | { | 93 | { |
78 | if (m_asset.Data.Length > 1) | 94 | if (m_asset.Data.Length > 1) |
@@ -107,16 +123,20 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
107 | /// <param name="xferID"></param> | 123 | /// <param name="xferID"></param> |
108 | /// <param name="packetID"></param> | 124 | /// <param name="packetID"></param> |
109 | /// <param name="data"></param> | 125 | /// <param name="data"></param> |
110 | /// <returns>True if the transfer is complete, false otherwise</returns> | 126 | public void Initialise(IClientAPI remoteClient, UUID assetID, |
111 | public bool Initialise(IClientAPI remoteClient, UUID assetID, | ||
112 | UUID transaction, sbyte type, byte[] data, bool storeLocal, | 127 | UUID transaction, sbyte type, byte[] data, bool storeLocal, |
113 | bool tempFile) | 128 | bool tempFile) |
114 | { | 129 | { |
130 | // m_log.DebugFormat( | ||
131 | // "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}", | ||
132 | // remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length); | ||
133 | |||
115 | ourClient = remoteClient; | 134 | ourClient = remoteClient; |
116 | m_asset = new AssetBase(assetID, "blank", type, | 135 | m_asset.Name = "blank"; |
117 | remoteClient.AgentId.ToString()); | ||
118 | m_asset.Data = data; | ||
119 | m_asset.Description = "empty"; | 136 | m_asset.Description = "empty"; |
137 | m_asset.Type = type; | ||
138 | m_asset.CreatorID = remoteClient.AgentId.ToString(); | ||
139 | m_asset.Data = data; | ||
120 | m_asset.Local = storeLocal; | 140 | m_asset.Local = storeLocal; |
121 | m_asset.Temporary = tempFile; | 141 | m_asset.Temporary = tempFile; |
122 | 142 | ||
@@ -126,21 +146,22 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
126 | if (m_asset.Data.Length > 2) | 146 | if (m_asset.Data.Length > 2) |
127 | { | 147 | { |
128 | SendCompleteMessage(); | 148 | SendCompleteMessage(); |
129 | return true; | ||
130 | } | 149 | } |
131 | else | 150 | else |
132 | { | 151 | { |
133 | RequestStartXfer(); | 152 | RequestStartXfer(); |
134 | } | 153 | } |
135 | |||
136 | return false; | ||
137 | } | 154 | } |
138 | 155 | ||
139 | protected void RequestStartXfer() | 156 | protected void RequestStartXfer() |
140 | { | 157 | { |
141 | XferID = Util.GetNextXferID(); | 158 | XferID = Util.GetNextXferID(); |
142 | ourClient.SendXferRequest(XferID, m_asset.Type, m_asset.FullID, | 159 | |
143 | 0, new byte[0]); | 160 | // m_log.DebugFormat( |
161 | // "[ASSET XFER UPLOADER]: Requesting Xfer of asset {0}, type {1}, transfer id {2} from {3}", | ||
162 | // m_asset.FullID, m_asset.Type, XferID, ourClient.Name); | ||
163 | |||
164 | ourClient.SendXferRequest(XferID, m_asset.Type, m_asset.FullID, 0, new byte[0]); | ||
144 | } | 165 | } |
145 | 166 | ||
146 | protected void SendCompleteMessage() | 167 | protected void SendCompleteMessage() |
@@ -148,18 +169,32 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
148 | ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, | 169 | ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, |
149 | m_asset.FullID); | 170 | m_asset.FullID); |
150 | 171 | ||
151 | m_finished = true; | 172 | // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create |
152 | if (m_createItem) | 173 | // message from other client UDP. |
153 | { | 174 | lock (this) |
154 | DoCreateItem(m_createItemCallback); | ||
155 | } | ||
156 | else if (m_storeLocal) | ||
157 | { | 175 | { |
158 | m_Scene.AssetService.Store(m_asset); | 176 | m_finished = true; |
177 | if (m_createItem) | ||
178 | { | ||
179 | DoCreateItem(m_createItemCallback); | ||
180 | } | ||
181 | else if (m_updateItem) | ||
182 | { | ||
183 | StoreAssetForItemUpdate(m_updateItemData); | ||
184 | |||
185 | // Remove ourselves from the list of transactions if completion was delayed until the transaction | ||
186 | // was complete. | ||
187 | // TODO: Should probably do the same for create item. | ||
188 | m_transactions.RemoveXferUploader(TransactionID); | ||
189 | } | ||
190 | else if (m_storeLocal) | ||
191 | { | ||
192 | m_Scene.AssetService.Store(m_asset); | ||
193 | } | ||
159 | } | 194 | } |
160 | 195 | ||
161 | m_log.DebugFormat( | 196 | m_log.DebugFormat( |
162 | "[ASSET TRANSACTIONS]: Uploaded asset {0} for transaction {1}", | 197 | "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}", |
163 | m_asset.FullID, TransactionID); | 198 | m_asset.FullID, TransactionID); |
164 | 199 | ||
165 | if (m_dumpAssetToFile) | 200 | if (m_dumpAssetToFile) |
@@ -205,18 +240,66 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction | |||
205 | m_asset.Description = description; | 240 | m_asset.Description = description; |
206 | m_asset.Type = type; | 241 | m_asset.Type = type; |
207 | 242 | ||
243 | // We must lock to avoid a race with a separate thread uploading the asset. | ||
244 | lock (this) | ||
245 | { | ||
246 | if (m_finished) | ||
247 | { | ||
248 | DoCreateItem(callbackID); | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | m_createItem = true; //set flag so the inventory item is created when upload is complete | ||
253 | m_createItemCallback = callbackID; | ||
254 | } | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | |||
259 | public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) | ||
260 | { | ||
261 | // We must lock to avoid a race with a separate thread uploading the asset. | ||
262 | lock (this) | ||
263 | { | ||
264 | m_asset.Name = item.Name; | ||
265 | m_asset.Description = item.Description; | ||
266 | m_asset.Type = (sbyte)item.AssetType; | ||
267 | |||
268 | // We must always store the item at this point even if the asset hasn't finished uploading, in order | ||
269 | // to avoid a race condition when the appearance module retrieves the item to set the asset id in | ||
270 | // the AvatarAppearance structure. | ||
271 | item.AssetID = m_asset.FullID; | ||
272 | m_Scene.InventoryService.UpdateItem(item); | ||
273 | |||
208 | if (m_finished) | 274 | if (m_finished) |
209 | { | 275 | { |
210 | DoCreateItem(callbackID); | 276 | StoreAssetForItemUpdate(item); |
211 | } | 277 | } |
212 | else | 278 | else |
213 | { | 279 | { |
214 | m_createItem = true; //set flag so the inventory item is created when upload is complete | 280 | // m_log.DebugFormat( |
215 | m_createItemCallback = callbackID; | 281 | // "[ASSET XFER UPLOADER]: Holding update inventory item request {0} for {1} pending completion of asset xfer for transaction {2}", |
282 | // item.Name, remoteClient.Name, transactionID); | ||
283 | |||
284 | m_updateItem = true; | ||
285 | m_updateItemData = item; | ||
216 | } | 286 | } |
217 | } | 287 | } |
218 | } | 288 | } |
219 | 289 | ||
290 | /// <summary> | ||
291 | /// Store the asset for the given item. | ||
292 | /// </summary> | ||
293 | /// <param name="item"></param> | ||
294 | private void StoreAssetForItemUpdate(InventoryItemBase item) | ||
295 | { | ||
296 | // m_log.DebugFormat( | ||
297 | // "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", | ||
298 | // m_asset.FullID, item.Name, ourClient.Name); | ||
299 | |||
300 | m_Scene.AssetService.Store(m_asset); | ||
301 | } | ||
302 | |||
220 | private void DoCreateItem(uint callbackID) | 303 | private void DoCreateItem(uint callbackID) |
221 | { | 304 | { |
222 | m_Scene.AssetService.Store(m_asset); | 305 | m_Scene.AssetService.Store(m_asset); |