Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
Alchemy Viewer
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Releases
Package registry
Operate
Terraform modules
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Silent mode is enabled
All outbound communications are blocked.
Learn more
.
Show more breadcrumbs
Alchemy Viewer
Alchemy Viewer
Commits
f952e72f
Commit
f952e72f
authored
12 years ago
by
Logan Dethrow
Browse files
Options
Downloads
Plain Diff
Merge.
parents
1004eff4
be9c0574
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
indra/newview/app_settings/settings.xml
+11
-0
11 additions, 0 deletions
indra/newview/app_settings/settings.xml
indra/newview/llappearancemgr.cpp
+201
-79
201 additions, 79 deletions
indra/newview/llappearancemgr.cpp
with
212 additions
and
79 deletions
indra/newview/app_settings/settings.xml
+
11
−
0
View file @
f952e72f
...
@@ -4315,6 +4315,17 @@
...
@@ -4315,6 +4315,17 @@
<key>
Value
</key>
<key>
Value
</key>
<real>
1.0
</real>
<real>
1.0
</real>
</map>
</map>
<key>
InventoryDebugSimulateOpFailureRate
</key>
<map>
<key>
Comment
</key>
<string>
Rate at which we simulate failures of copy/link requests in some operations
</string>
<key>
Persist
</key>
<integer>
1
</integer>
<key>
Type
</key>
<string>
F32
</string>
<key>
Value
</key>
<real>
0.0
</real>
</map>
<key>
InventoryDisplayInbox
</key>
<key>
InventoryDisplayInbox
</key>
<map>
<map>
<key>
Comment
</key>
<key>
Comment
</key>
...
...
This diff is collapsed.
Click to expand it.
indra/newview/llappearancemgr.cpp
+
201
−
79
View file @
f952e72f
...
@@ -186,140 +186,255 @@ void report_fire(const LLUUID& item_id)
...
@@ -186,140 +186,255 @@ void report_fire(const LLUUID& item_id)
llinfos
<<
item_id
<<
llendl
;
llinfos
<<
item_id
<<
llendl
;
}
}
class
LLInventory
Copy
Mgr
:
public
LLEventTimer
class
LL
CallAfter
Inventory
Batch
Mgr
:
public
LLEventTimer
{
{
public:
public:
LLInventoryCopyMgr
(
LLInventoryModel
::
item_array_t
&
src_items
,
const
LLUUID
&
dst_cat_id
,
LLCallAfterInventoryBatchMgr
(
const
LLUUID
&
dst_cat_id
,
bool
append
,
const
std
::
string
&
phase
)
:
const
std
::
string
&
phase_name
,
nullary_func_t
on_completion_func
,
nullary_func_t
on_failure_func
,
F32
check_period
=
5.0
,
F32
retry_after
=
10.0
,
S32
max_retries
=
2
)
:
mDstCatID
(
dst_cat_id
),
mDstCatID
(
dst_cat_id
),
mAppend
(
append
),
mTrackingPhase
(
phase_name
),
mTrackingPhase
(
phase
),
mOnCompletionFunc
(
on_completion_func
),
LLEventTimer
(
5.0
)
mOnFailureFunc
(
on_failure_func
),
mRetryAfter
(
retry_after
),
mMaxRetries
(
max_retries
),
mPendingRequests
(
0
),
mFailCount
(
0
),
mRetryCount
(
0
),
LLEventTimer
(
check_period
)
{
if
(
!
mTrackingPhase
.
empty
())
{
selfStartPhase
(
mTrackingPhase
);
}
}
void
addItems
(
LLInventoryModel
::
item_array_t
&
src_items
)
{
{
for
(
LLInventoryModel
::
item_array_t
::
const_iterator
it
=
src_items
.
begin
();
for
(
LLInventoryModel
::
item_array_t
::
const_iterator
it
=
src_items
.
begin
();
it
!=
src_items
.
end
();
it
!=
src_items
.
end
();
++
it
)
++
it
)
{
{
LLViewerInventoryItem
*
item
=
*
it
;
LLViewerInventoryItem
*
item
=
*
it
;
mSrcTimes
[
item
->
getUUID
()]
=
LLTimer
();
llassert
(
item
);
requestCopy
(
item
->
getUUID
());
addItem
(
item
);
}
if
(
!
mTrackingPhase
.
empty
())
{
selfStartPhase
(
mTrackingPhase
);
}
}
}
}
void
requestCopy
(
const
LLUUID
&
item_id
)
// Request or re-request operation for specified item.
void
addItem
(
LLViewerInventoryItem
*
item
)
{
{
LLViewerInventoryItem
*
item
=
gInventory
.
getItem
(
item_id
);
const
LLUUID
&
item_id
=
item
->
getUUID
(
);
if
(
!
item
)
if
(
!
item
)
{
{
llwarns
<<
"
requestCopy
item not found "
<<
item_id
<<
llendl
;
llwarns
<<
"item not found
for
"
<<
item_id
<<
llendl
;
return
;
return
;
}
}
copy_inventory_item
(
mPendingRequests
++
;
gAgent
.
getID
(),
// On a re-request, this will reset the timer.
item
->
getPermissions
().
getOwner
(),
mWaitTimes
[
item_id
]
=
LLTimer
();
item
->
getUUID
(),
if
(
mRetryCounts
.
find
(
item_id
)
==
mRetryCounts
.
end
())
mDstCatID
,
{
std
::
string
(),
mRetryCounts
[
item_id
]
=
0
;
make_inventory_func_callback
(
boost
::
bind
(
&
LLInventoryCopyMgr
::
onCopy
,
this
,
item
->
getUUID
(),
_1
))
}
);
else
{
mRetryCounts
[
item_id
]
++
;
}
if
(
ll_frand
()
<
gSavedSettings
.
getF32
(
"InventoryDebugSimulateOpFailureRate"
))
{
// simulate server failure by not sending the request.
return
;
}
}
void
onCopy
(
const
LLUUID
&
src_id
,
const
LLUUID
&
dst_id
)
requestOperation
(
item
);
}
virtual
void
requestOperation
(
LLViewerInventoryItem
*
item
)
=
0
;
void
onOp
(
const
LLUUID
&
src_id
,
const
LLUUID
&
dst_id
)
{
{
LL_DEBUGS
(
"Avatar"
)
<<
"copied, src_id "
<<
src_id
<<
" to dst_id "
<<
dst_id
<<
" after "
<<
mSrcTimes
[
src_id
].
getElapsedTimeF32
()
<<
" seconds"
<<
llendl
;
LL_DEBUGS
(
"Avatar"
)
<<
"copied, src_id "
<<
src_id
<<
" to dst_id "
<<
dst_id
<<
" after "
<<
mWaitTimes
[
src_id
].
getElapsedTimeF32
()
<<
" seconds"
<<
llendl
;
mSrcTimes
.
erase
(
src_id
);
mPendingRequests
--
;
if
(
mSrcTimes
.
empty
())
F32
wait_time
=
mWaitTimes
[
src_id
].
getElapsedTimeF32
();
mTimeStats
.
push
(
wait_time
);
mWaitTimes
.
erase
(
src_id
);
if
(
mWaitTimes
.
empty
())
{
{
onCompletion
();
onCompletion
OrFailure
();
}
}
}
}
void
onCompletion
()
void
onCompletion
OrFailure
()
{
{
llinfos
<<
"done"
<<
llendl
;
// Will never call onCompletion() if any item has been flagged as
// a failure - otherwise could wind up with corrupted
// outfit, involuntary nudity, etc.
reportStats
();
if
(
!
mTrackingPhase
.
empty
())
if
(
!
mTrackingPhase
.
empty
())
{
{
selfStopPhase
(
mTrackingPhase
);
selfStopPhase
(
mTrackingPhase
);
}
}
LLAppearanceMgr
::
instance
().
wearInventoryCategoryOnAvatar
(
gInventory
.
getCategory
(
mDstCatID
),
mAppend
);
if
(
!
mFailCount
)
{
onCompletion
();
}
else
{
onFailure
();
}
}
void
onFailure
()
{
llinfos
<<
"failed"
<<
llendl
;
mOnFailureFunc
();
}
void
onCompletion
()
{
llinfos
<<
"done"
<<
llendl
;
mOnCompletionFunc
();
}
}
// virtual
// virtual
// Will be deleted after returning true - only safe to do this if all callbacks have fired.
// Will be deleted after returning true - only safe to do this if all callbacks have fired.
BOOL
tick
()
BOOL
tick
()
{
{
bool
all_done
=
mSrcTimes
.
empty
();
// mPendingRequests will be zero if all requests have been
// responded to. mWaitTimes.empty() will be true if we have
// received at least one reply for each UUID. If requests
// have been dropped and retried, these will not necessarily
// be the same. Only safe to return true if all requests have
// been serviced, since it will result in this object being
// deleted.
bool
all_done
=
(
mPendingRequests
==
0
);
if
(
!
mWaitTimes
.
empty
())
{
llwarns
<<
"still waiting on "
<<
mWaitTimes
.
size
()
<<
" items"
<<
llendl
;
for
(
std
::
map
<
LLUUID
,
LLTimer
>::
const_iterator
it
=
mWaitTimes
.
begin
();
it
!=
mWaitTimes
.
end
();)
{
// Use a copy of iterator because it may be erased/invalidated.
std
::
map
<
LLUUID
,
LLTimer
>::
const_iterator
curr_it
=
it
;
++
it
;
if
(
!
all_done
)
F32
time_waited
=
curr_it
->
second
.
getElapsedTimeF32
();
S32
retries
=
mRetryCounts
[
curr_it
->
first
];
if
(
time_waited
>
mRetryAfter
)
{
{
llwarns
<<
"possible hang in copy, waiting on "
<<
mSrcTimes
.
size
()
<<
" items"
<<
llendl
;
if
(
retries
<
mMaxRetries
)
// TODO possibly add retry logic here.
{
LL_DEBUGS
(
"Avatar"
)
<<
"Waited "
<<
time_waited
<<
" for "
<<
curr_it
->
first
<<
", retrying"
<<
llendl
;
mRetryCount
++
;
addItem
(
gInventory
.
getItem
(
curr_it
->
first
));
}
else
{
llwarns
<<
"Giving up on "
<<
curr_it
->
first
<<
" after too many retries"
<<
llendl
;
mWaitTimes
.
erase
(
curr_it
);
mFailCount
++
;
}
}
if
(
mWaitTimes
.
empty
())
{
onCompletionOrFailure
();
}
}
}
}
return
all_done
;
return
all_done
;
}
}
private
:
void
reportStats
()
{
LL_DEBUGS
(
"Avatar"
)
<<
"mFailCount: "
<<
mFailCount
<<
llendl
;
LL_DEBUGS
(
"Avatar"
)
<<
"mRetryCount: "
<<
mRetryCount
<<
llendl
;
LL_DEBUGS
(
"Avatar"
)
<<
"Times: n "
<<
mTimeStats
.
getCount
()
<<
" min "
<<
mTimeStats
.
getMinValue
()
<<
" max "
<<
mTimeStats
.
getMaxValue
()
<<
llendl
;
LL_DEBUGS
(
"Avatar"
)
<<
"Mean "
<<
mTimeStats
.
getMean
()
<<
" stddev "
<<
mTimeStats
.
getStdDev
()
<<
llendl
;
}
virtual
~
LLCallAfterInventoryBatchMgr
()
{
LL_DEBUGS
(
"Avatar"
)
<<
"deleting"
<<
llendl
;
}
protected
:
std
::
string
mTrackingPhase
;
std
::
string
mTrackingPhase
;
std
::
map
<
LLUUID
,
LLTimer
>
mSrcTimes
;
std
::
map
<
LLUUID
,
LLTimer
>
mWaitTimes
;
std
::
map
<
LLUUID
,
S32
>
mRetryCounts
;
LLUUID
mDstCatID
;
LLUUID
mDstCatID
;
bool
mAppend
;
nullary_func_t
mOnCompletionFunc
;
nullary_func_t
mOnFailureFunc
;
F32
mRetryAfter
;
S32
mMaxRetries
;
S32
mPendingRequests
;
S32
mFailCount
;
S32
mRetryCount
;
LLViewerStats
::
StatsAccumulator
mTimeStats
;
};
};
class
LL
Wea
rInventoryC
ategoryCallback
:
public
LLInventory
Callback
class
LL
CallAfte
rInventoryC
opyMgr
:
public
LL
CallAfter
Inventory
BatchMgr
{
{
public:
public:
LLWearInventoryCategoryCallback
(
const
LLUUID
&
cat_id
,
bool
append
)
LLCallAfterInventoryCopyMgr
(
LLInventoryModel
::
item_array_t
&
src_items
,
const
LLUUID
&
dst_cat_id
,
const
std
::
string
&
phase_name
,
nullary_func_t
on_completion_func
,
nullary_func_t
on_failure_func
)
:
LLCallAfterInventoryBatchMgr
(
dst_cat_id
,
phase_name
,
on_completion_func
,
on_failure_func
)
{
{
mCatID
=
cat_id
;
addItems
(
src_items
);
mAppend
=
append
;
LL_INFOS
(
"Avatar"
)
<<
self_av_string
()
<<
"starting"
<<
LL_ENDL
;
selfStartPhase
(
"wear_inventory_category_callback"
);
}
}
void
fire
(
const
LLUUID
&
item_id
)
virtual
void
requestOperation
(
LLViewerInventoryItem
*
item
)
{
{
/*
copy_inventory_item
(
* Do nothing. We only care about the destructor
gAgent
.
getID
(),
*
item
->
getPermissions
().
getOwner
(),
* The reason for this is that this callback is used in a hack where the
item
->
getUUID
(),
* same callback is given to dozens of items, and the destructor is called
mDstCatID
,
* after the last item has fired the event and dereferenced it -- if all
std
::
string
(),
* the events actually fire!
make_inventory_func_callback
(
boost
::
bind
(
&
LLCallAfterInventoryBatchMgr
::
onOp
,
this
,
item
->
getUUID
(),
_1
))
*/
);
LL_DEBUGS
(
"Avatar"
)
<<
self_av_string
()
<<
" fired on copied item, id "
<<
item_id
<<
LL_ENDL
;
}
}
};
protected
:
class
LLCallAfterInventoryLinkMgr
:
public
LLCallAfterInventoryBatchMgr
~
LLWearInventoryCategoryCallback
()
{
{
LL
_INFOS
(
"Avatar"
)
<<
self_av_string
()
<<
"done all inventory callbacks"
<<
LL_ENDL
;
LL
CallAfterInventoryLinkMgr
(
LLInventoryModel
::
item_array_t
&
src_items
,
const
LLUUID
&
dst_cat_id
,
selfStopPhase
(
"wear_inventory_category_callback"
);
const
std
::
string
&
phase_name
,
nullary_func_t
on_completion_func
,
// Is the destructor called by ordinary dereference, or because the app's shutting down?
nullary_func_t
on_failure_func
// If the inventory callback manager goes away, we're shutting down, no longer want the callback.
)
:
if
(
LLInventoryCallbackManager
::
is_instantiated
()
)
LLCallAfterInventoryBatchMgr
(
dst_cat_id
,
phase_name
,
on_completion_func
,
on_failure_func
)
{
{
LLAppearanceMgr
::
instance
().
wearInventoryCategoryOnAvatar
(
gInventory
.
getCategory
(
mCatID
),
mAppend
);
addItems
(
src_items
);
}
}
else
virtual
void
requestOperation
(
LLViewerInventoryItem
*
item
)
{
{
llwarns
<<
self_av_string
()
<<
"Dropping unhandled LLWearInventoryCategoryCallback"
<<
llendl
;
link_inventory_item
(
gAgent
.
getID
(),
}
item
->
getLinkedUUID
(),
mDstCatID
,
item
->
getName
(),
item
->
LLInventoryItem
::
getDescription
(),
LLAssetType
::
AT_LINK
,
make_inventory_func_callback
(
boost
::
bind
(
&
LLCallAfterInventoryBatchMgr
::
onOp
,
this
,
item
->
getUUID
(),
_1
)));
}
}
private
:
LLUUID
mCatID
;
bool
mAppend
;
};
};
//Inventory callback updating "dirty" state when destroyed
//Inventory callback updating "dirty" state when destroyed
class
LLUpdateDirtyState
:
public
LLInventoryCallback
class
LLUpdateDirtyState
:
public
LLInventoryCallback
{
{
...
@@ -2097,7 +2212,13 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
...
@@ -2097,7 +2212,13 @@ void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool ap
name
);
name
);
// Create a CopyMgr that will copy items, manage its own destruction
// Create a CopyMgr that will copy items, manage its own destruction
new
LLInventoryCopyMgr
(
*
items
,
new_cat_id
,
append
,
std
::
string
(
"wear_inventory_category_callback"
));
new
LLCallAfterInventoryCopyMgr
(
*
items
,
new_cat_id
,
std
::
string
(
"wear_inventory_category_callback"
),
boost
::
bind
(
&
LLAppearanceMgr
::
wearInventoryCategoryOnAvatar
,
LLAppearanceMgr
::
getInstance
(),
gInventory
.
getCategory
(
new_cat_id
),
append
),
boost
::
function
<
void
()
>
());
// BAP fixes a lag in display of created dir.
// BAP fixes a lag in display of created dir.
gInventory
.
notifyObservers
();
gInventory
.
notifyObservers
();
...
@@ -2119,6 +2240,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
...
@@ -2119,6 +2240,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
if
(
!
LLInventoryCallbackManager
::
is_instantiated
()
)
if
(
!
LLInventoryCallbackManager
::
is_instantiated
()
)
{
{
// shutting down, ignore.
return
;
return
;
}
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment