Question

I am running some SHRINKFILE operations to clean up a bunch of tiny, unnecessary files in a filegroup. For one of the shrinks, the command below results in an error:

DBCC SHRINKFILE (N'myfile' , EMPTYFILE)'

File ID x of database ID x cannot be shrunk as it is either being shrunk by another process or is empty

It is not empty nor being shrunk. It is being run on a database not currently in use by anyone except myself. Auto shrink is not enabled and never was. However, there were manual shrinks performed on this database on a regular basis prior to me getting my hands on it, if that matters at all.

On SQLServerCentral, a thread from a decade ago suggests adding a few MB to the file because that "resets an internal counter or switch that tells it it's not in the middle of a shrink now."

This worked - awesome. But can anyone explain with greater detail how/why this works in regard to SQL Server internals?

Was it helpful?

Solution

I poked around in the file header page, as suggested by Martin Smith in the comments. I think this is part of the answer, but it's mostly speculation based on observing changes to the file header page flag values between performing shrinks and other operations.


First I created a database to test with, including a secondary filegroup:

CREATE DATABASE [Shrinkfile_Test]
ON PRIMARY
(
    NAME = N'Shrinkfile_Test',
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test.mdf',
    SIZE = 8192KB,
    FILEGROWTH = 65536KB
),
FILEGROUP [SECONDARY]
(
    NAME = N'ShrinkFile_Test_Secondary',
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\ShrinkFile_Test_Secondary.ndf',
    SIZE = 1024KB,
    FILEGROWTH = 65536KB
)
LOG ON
(
    NAME = N'Shrinkfile_Test_log',
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test_log.ldf',
    SIZE = 73728KB,
    FILEGROWTH = 65536KB 
)
GO

USE Shrinkfile_Test;
GO

The I looked at "page 0" for the secondary file, which is file_id 3:

DBCC TRACEON (3604);
GO
DBCC PAGE (N'Shrinkfile_Test', 3, 0, 3);

There's a field called m_flagBits that has a value of 0x208.

If I empty this file:

DBCC SHRINKFILE (N'ShrinkFile_Test_Secondary' , EMPTYFILE);

That m_flagbits field stays the same (0x208). Not that interesting, but now I'm in the situation you reported: if I try to empty the file again, I get this error:

File ID 3 of database ID 19 cannot be shrunk as it is either being shrunk by another process or is empty.

I'll try growing the file (the solution that worked for you):

ALTER DATABASE ShrinkFile_Test
MODIFY FILE
(
    NAME = ShrinkFile_Test_Secondary,
    SIZE = 1025KB
);
GO

Now m_flagbits is 0x8!

At this point, emptying the file again is successful returns the value to 0x208 as you might expect.

The thing that I find interesting is that if I do this after growing the file back out (AKA flagbits value is 0x8):

USE [master]
GO
ALTER DATABASE [Shrinkfile_Test] MODIFY FILEGROUP [SECONDARY] READONLY
GO

The file is marked as is_read_only in the sys.databases table, and m_flagbits is set back to 0x208. So it appears there is some similar file-level flag set when shrinking a file and when setting it to read only.

My best guess is that this value is used along with some other (internal) flag to indicate that a file is eligible to be shrunk. Growing the file appears to un-set that flag (at least the one visible in m_flagbits).

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top